From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: new css-mode indenter Resent-From: E Sabof Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 13 Jan 2013 07:45:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: 13425@debbugs.gnu.org X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.135806306130507 (code B ref -1); Sun, 13 Jan 2013 07:45:01 +0000 Received: (at submit) by debbugs.gnu.org; 13 Jan 2013 07:44:21 +0000 Received: from localhost ([127.0.0.1]:57581 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TuIEu-0007vz-PR for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:44:21 -0500 Received: from eggs.gnu.org ([208.118.235.92]:57013) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TuIEt-0007vm-6Z for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:44:20 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TuIEP-0006LW-Co for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:43:57 -0500 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_LOW,T_DKIM_INVALID autolearn=unavailable version=3.3.2 Received: from lists.gnu.org ([208.118.235.17]:43375) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuIEP-0006LS-9L for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:43:49 -0500 Received: from eggs.gnu.org ([208.118.235.92]:40108) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuIEH-0006K1-2v for bug-gnu-emacs@gnu.org; Sun, 13 Jan 2013 02:43:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TuIE9-0006HH-Jy for bug-gnu-emacs@gnu.org; Sun, 13 Jan 2013 02:43:41 -0500 Received: from mail-qc0-f172.google.com ([209.85.216.172]:48028) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuIE9-0006H8-FZ for bug-gnu-emacs@gnu.org; Sun, 13 Jan 2013 02:43:33 -0500 Received: by mail-qc0-f172.google.com with SMTP id b25so1964104qca.31 for ; Sat, 12 Jan 2013 23:43:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=S3pCcGnOrRPyQTJepVVSWx22Ws4YABiuU1FWTMEhzms=; b=GyoPsaZp9MsbqLr+7RY/hMKq8qVyqwOcU5FwNBQhuqgrPjw5KKHS5SKj4UchF1Yfu9 ggi/RUhE/Eom8fTNc6iqj4Wtfl/KLBXZVTFfCv9IW3PHrygj6JllH/cx2rsttQgjorKE vx5ggsRJkG+FmgtNSQZfVu7E232XZ6ifln9FOqYtLYTdM7IIHHcFwgIGU7cKopRNJQ2u Ie6BYy21l6L/niTLX827pGQ3iZhq/p6rVG0XlyemjbrTcnudR5GCOPAR9Gx5O5vpCzMk c6xgg6B8WnP9q+aY15QHJNXEdYSBWYMse+4WJZ9DuPHs8pnzQdksNZYvYxkBhw/F/adf 5cLA== MIME-Version: 1.0 Received: by 10.224.78.209 with SMTP id m17mr68677168qak.45.1358063012099; Sat, 12 Jan 2013 23:43:32 -0800 (PST) Received: by 10.49.4.102 with HTTP; Sat, 12 Jan 2013 23:43:31 -0800 (PST) Date: Sun, 13 Jan 2013 07:43:31 +0000 Message-ID: From: E Sabof Content-Type: multipart/alternative; boundary=20cf3074b1ba6b347e04d326af9d X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 208.118.235.17 X-Spam-Score: -3.4 (---) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: debbugs-submit-bounces@debbugs.gnu.org Errors-To: debbugs-submit-bounces@debbugs.gnu.org X-Spam-Score: -4.2 (----) --20cf3074b1ba6b347e04d326af9d Content-Type: text/plain; charset=ISO-8859-1 I've written a new indenter for CSS, which fixes issues with mulitline statements following a colon, and comments: body { color: #333; font: 15px "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", sans-serif; font-weight: 300; line-height: 1.625; a { /* It also handles SCSS */ font: 15px "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", sans-serif; /* Some comment */ } /* Some comment at the end of a block */ } I wondered whether this functionality could be integrated into Emacs. https://github.com/sabof/es-css-mode https://github.com/sabof/es-lib (it takes some functions from it) Evgeni --20cf3074b1ba6b347e04d326af9d Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
I've written a new indenter for CSS, which fixes issue= s with mulitline statements following a colon, and comments:=A0

body {
=A0 =A0 color: #333;
=A0 =A0 font: = 15px "Helvetica Neue",
=A0 =A0 =A0 =A0 Helvetica,
=A0 =A0 =A0 =A0 Arial,=A0
=A0 =A0 =A0 =A0 "Nimbus Sans L",
=A0 =A0 =A0 =A0 san= s-serif;
=A0 =A0 font-weight: 300;
=A0 =A0 line-height:= 1.625;
=A0 =A0 a { /* It also handles SCSS */
=A0 =A0 =A0 =A0 font: 15px "Helvetica Neue",
=A0 = =A0 =A0 =A0 =A0 =A0 Helvetica,
=A0 =A0 =A0 =A0 =A0 =A0 Arial,=A0<= /div>
=A0 =A0 =A0 =A0 =A0 =A0 "Nimbus Sans L",
=A0 = =A0 =A0 =A0 =A0 =A0 sans-serif;
=A0 =A0 =A0 =A0 /* Some comment *= /
=A0 =A0 }
=A0 =A0 /* Some comment at the end of a block */
}

I wondered whether this fun= ctionality could be integrated into Emacs.
https://github= .com/sabof/es-lib=A0(it takes some functions from it)

Evgeni

--20cf3074b1ba6b347e04d326af9d-- From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: new css-mode indenter Resent-From: Stefan Monnier Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 15 Jan 2013 05:01:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: E Sabof Cc: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.135822605430727 (code B ref 13425); Tue, 15 Jan 2013 05:01:01 +0000 Received: (at 13425) by debbugs.gnu.org; 15 Jan 2013 05:00:54 +0000 Received: from localhost ([127.0.0.1]:60679 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1Tuydp-0007zX-KH for submit@debbugs.gnu.org; Tue, 15 Jan 2013 00:00:54 -0500 Received: from ironport2-out.teksavvy.com ([206.248.154.182]:14662) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1Tuydn-0007zQ-90 for 13425@debbugs.gnu.org; Tue, 15 Jan 2013 00:00:52 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AhkUAG6Zu09FpZpV/2dsb2JhbABEgXuBa7ArgQiCFQEBBAEnLyMFCws0EhQYDSSIHAULuXoEkEQDiEKacYFYgwc X-IronPort-AV: E=Sophos;i="4.75,637,1330923600"; d="scan'208";a="212575541" Received: from 69-165-154-85.dsl.teksavvy.com (HELO pastel.home) ([69.165.154.85]) by ironport2-out.teksavvy.com with ESMTP/TLS/ADH-AES256-SHA; 15 Jan 2013 00:00:21 -0500 Received: by pastel.home (Postfix, from userid 20848) id 4BF4B59499; Tue, 15 Jan 2013 00:00:19 -0500 (EST) From: Stefan Monnier Message-ID: References: Date: Tue, 15 Jan 2013 00:00:19 -0500 In-Reply-To: (E. Sabof's message of "Sun, 13 Jan 2013 07:43:31 +0000") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: debbugs-submit-bounces@debbugs.gnu.org Errors-To: debbugs-submit-bounces@debbugs.gnu.org X-Spam-Score: -1.9 (-) > I've written a new indenter for CSS, which fixes issues with mulitline > statements following a colon, and comments: Interesting, I don't use CSS myself very much, but I've toyed with an SMIE indenter for css-mode (see below). > body { > color: #333; > font: 15px "Helvetica Neue", > Helvetica, > Arial, > "Nimbus Sans L", > sans-serif; > font-weight: 300; > line-height: 1.625; > a { /* It also handles SCSS */ > font: 15px "Helvetica Neue", > Helvetica, > Arial, > "Nimbus Sans L", > sans-serif; > /* Some comment */ > } > /* Some comment at the end of a block */ > } I've tried it on the above test case and the SMIE code seems to handle it OK (tho differently), with the main exception being the comment-at-end-of-block, which is probably a general problem which should be fixed in smie.el (probably in smie-indent-comment). But I have basically never used/tested my code, so... > I wondered whether this functionality could be integrated into Emacs. > https://github.com/sabof/es-css-mode > https://github.com/sabof/es-lib (it takes some functions from it) If you could provide a patch against css-mode.el, that would be more convenient. Also it would be good to add a good set of test cases (in the form of a new file test/indent/css-mode.css). Stefan === modified file 'lisp/textmodes/css-mode.el' --- lisp/textmodes/css-mode.el 2013-01-02 16:13:04 +0000 +++ lisp/textmodes/css-mode.el 2013-01-15 04:53:03 +0000 @@ -263,6 +263,22 @@ (defvar css-font-lock-defaults '(css-font-lock-keywords nil t)) +(defcustom css-indent-offset 4 + "Basic size of one indentation step." + :version "22.2" + :type 'integer) + +(defconst css-smie-grammar + (smie-prec2->grammar + (smie-precs->prec2 '((assoc ";") (left ":") (assoc ","))))) + +(defun css-smie-rules (kind token) + (pcase (cons kind token) + (`(:elem . basic) css-indent-offset) + (`(:elem . arg) 0) + (`(:before . "{") (if (smie-rule-hanging-p) + (smie-rule-parent 0))))) + ;;;###autoload (define-derived-mode css-mode fundamental-mode "CSS" "Major mode to edit Cascading Style Sheets." @@ -271,11 +287,11 @@ (setq-local comment-start-skip "/\\*+[ \t]*") (setq-local comment-end "*/") (setq-local comment-end-skip "[ \t]*\\*+/") - (setq-local forward-sexp-function 'css-forward-sexp) (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) (when css-electric-keys (let ((fc (make-char-table 'auto-fill-chars))) (set-char-table-parent fc auto-fill-chars) @@ -355,131 +371,6 @@ ;; Don't use the default filling code. t))))))) -;;; Navigation and indentation. - -(defconst css-navigation-syntax-table - (let ((st (make-syntax-table css-mode-syntax-table))) - (map-char-table (lambda (c v) - ;; Turn punctuation (code = 1) into symbol (code = 1). - (if (eq (car-safe v) 1) - (set-char-table-range st c (cons 3 (cdr v))))) - st) - st)) - -(defun css-backward-sexp (n) - (let ((forward-sexp-function nil)) - (if (< n 0) (css-forward-sexp (- n)) - (while (> n 0) - (setq n (1- n)) - (forward-comment (- (point-max))) - (if (not (eq (char-before) ?\;)) - (backward-sexp 1) - (while (progn (backward-sexp 1) - (save-excursion - (forward-comment (- (point-max))) - ;; FIXME: We should also skip punctuation. - (not (or (bobp) (memq (char-before) '(?\; ?\{)))))))))))) - -(defun css-forward-sexp (n) - (let ((forward-sexp-function nil)) - (if (< n 0) (css-backward-sexp (- n)) - (while (> n 0) - (setq n (1- n)) - (forward-comment (point-max)) - (if (not (eq (char-after) ?\;)) - (forward-sexp 1) - (while (progn (forward-sexp 1) - (save-excursion - (forward-comment (point-max)) - ;; FIXME: We should also skip punctuation. - (not (memq (char-after) '(?\; ?\}))))))))))) - -(defun css-indent-calculate-virtual () - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) - (if (looking-at "\\s(") - (save-excursion - (forward-char 1) (skip-chars-forward " \t") - (not (or (eolp) (looking-at comment-start-skip)))))) - (current-column) - (css-indent-calculate))) - -(defcustom css-indent-offset 4 - "Basic size of one indentation step." - :version "22.2" - :type 'integer - :group 'css) - -(defun css-indent-calculate () - (let ((ppss (syntax-ppss)) - pos) - (with-syntax-table css-navigation-syntax-table - (save-excursion - (cond - ;; Inside a string. - ((nth 3 ppss) 'noindent) - ;; Inside a comment. - ((nth 4 ppss) - (setq pos (point)) - (forward-line -1) - (skip-chars-forward " \t") - (if (>= (nth 8 ppss) (point)) - (progn - (goto-char (nth 8 ppss)) - (if (eq (char-after pos) ?*) - (forward-char 1) - (if (not (looking-at comment-start-skip)) - (error "Internal css-mode error") - (goto-char (match-end 0)))) - (current-column)) - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) - (current-column) - ;; 'noindent - (current-column) - ))) - ;; In normal code. - (t - (or - (when (looking-at "\\s)") - (forward-char 1) - (backward-sexp 1) - (css-indent-calculate-virtual)) - (when (looking-at comment-start-skip) - (forward-comment (point-max)) - (css-indent-calculate)) - (when (save-excursion (forward-comment (- (point-max))) - (setq pos (point)) - (eq (char-syntax (preceding-char)) ?\()) - (goto-char (1- pos)) - (if (not (looking-at "\\s([ \t]*")) - (error "Internal css-mode error") - (if (or (memq (char-after (match-end 0)) '(?\n nil)) - (save-excursion (goto-char (match-end 0)) - (looking-at comment-start-skip))) - (+ (css-indent-calculate-virtual) css-indent-offset) - (progn (goto-char (match-end 0)) (current-column))))) - (progn - (css-backward-sexp 1) - (if (looking-at "\\s(") - (css-indent-calculate) - (css-indent-calculate-virtual)))))))))) - - -(defun css-indent-line () - "Indent current line according to CSS indentation rules." - (interactive) - (let* ((savep (point)) - (forward-sexp-function nil) - (indent (condition-case nil - (save-excursion - (forward-line 0) - (skip-chars-forward " \t") - (if (>= (point) savep) (setq savep nil)) - (css-indent-calculate)) - (error nil)))) - (if (not (numberp indent)) 'noindent - (if savep - (save-excursion (indent-line-to indent)) - (indent-line-to indent))))) (defun css-current-defun-name () "Return the name of the CSS section at point, or nil." From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: new css-mode indenter Resent-From: E Sabof Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 15 Jan 2013 19:34:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Stefan Monnier Cc: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.135827840426477 (code B ref 13425); Tue, 15 Jan 2013 19:34:02 +0000 Received: (at 13425) by debbugs.gnu.org; 15 Jan 2013 19:33:24 +0000 Received: from localhost ([127.0.0.1]:33802 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TvCG9-0006sw-KG for submit@debbugs.gnu.org; Tue, 15 Jan 2013 14:33:24 -0500 Received: from mail-qc0-f172.google.com ([209.85.216.172]:49054) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TvCG4-0006sk-Ib for 13425@debbugs.gnu.org; Tue, 15 Jan 2013 14:33:20 -0500 Received: by mail-qc0-f172.google.com with SMTP id b25so320372qca.17 for <13425@debbugs.gnu.org>; Tue, 15 Jan 2013 11:32:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=25ypSqCG25oYvLNZQtNTGT3tIqJpNRUT5PsfYBFzmDM=; b=yFpCFbqSddfqnyb4gkzyEL3RwQS9qYsp1ZkP5oghFu/6S5+IxWLqb/aicecdEek2EV lVfpXlzzA11YT/oDA5QrwMmWLMLEKDRfobwVwUhZUHaq6I7rrrG1Fa605c6WJQxRve4W 5u20fedInp8J97oi2vT4lvBjfS2Y+WI+OViq/9xWR3dftFjxLa1Sdyq87zVhYyBVc6Dx EfTXed6rjmMz9jAngTMSVlWRvDB7unnj2osN7w2Ph+vZSPlbt3WrzM9My/nqorT1GE5j layisKlbwAjwB2PsN5kjmHvFloO3w+ClQ6wnopbCmtA1sXf1Xuj7Pjowm+dvah4roTyR U+Yw== MIME-Version: 1.0 Received: by 10.49.75.226 with SMTP id f2mr90743036qew.43.1358278363739; Tue, 15 Jan 2013 11:32:43 -0800 (PST) Received: by 10.49.4.102 with HTTP; Tue, 15 Jan 2013 11:32:43 -0800 (PST) In-Reply-To: References: Date: Tue, 15 Jan 2013 19:32:43 +0000 Message-ID: From: E Sabof Content-Type: multipart/alternative; boundary=047d7bdcab5260749f04d358d381 X-Spam-Score: -2.6 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: debbugs-submit-bounces@debbugs.gnu.org Errors-To: debbugs-submit-bounces@debbugs.gnu.org X-Spam-Score: -2.6 (--) --047d7bdcab5260749f04d358d381 Content-Type: text/plain; charset=ISO-8859-1 Here is a patch, including a more advanced test case. In the end there is a "failing" section - although I haven't seen anyone breaking at spaces. There is a varaiable called css-colon - the default is ":". If set to ": ", it will also indent statements like this in SASS (a CSS pre-processor) a { &:hover, &:active { background: green; } } However, it will no longer correctly indent statements like this: background:#000, /* no space */ url('image.png'); If I manage to fix the "breaking at spaces" case, I'll send another patch. Evgeni New css-mode.css diff --git a/css-mode.css b/css-mode.css new file mode 100644 index 0000000..40a732f --- /dev/null +++ b/css-mode.css @@ -0,0 +1,86 @@ +#top_menu .button.active, +#top_menu .button.active:active { + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Comment */ +} +#top_menu .button.active, +#top_menu .button.active:active +{ + /* Comment */ + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Multiline + comment1 */ + /* Multiline + * comment2 */ +} +/* Multiline + comment1 */ +/* Multiline + * comment2 */ +#glass { + z-index: 2; + position: absolute; + top: -112px; + left: 0; + right: 0; + margin: 0 0 0 0; + margin: + 0 0 0 0; + text-shadow: + 1px 1px #FDE31D, + -1px -1px #B36300; + height: 140px; + background-image: url('images/honey_blurred2.png'); + background-image: url( + 'images/honey_blurred2.png'); + background-image: + #fff, + url('images/honey_blurred2.png'), + url('images/honey_blurred2.png'); + background-image: + #fff, + /* #fff, */ + url('images/honey_blurred2.png'); + background-image: #fff, + url('images/honey_blurred2.png'); + -webkit-mask-image: + -webkit-gradient( + linear, + left top, + /* left bottom, */ + left bottom, + color-stop( + 1, + rgba(0,0,0,0.2) + ), + color-stop(1, + rgba(0,0,0,0.2) + ), + /* comment */ + color-stop(0.7, rgba(0,0,0,.0)), + color-stop + ( + 0.7, rgba(0,0,0,.0) + ) + /* comment*/ ); + background-repeat: repeat-x; + background-position: center top; + background-attachment: fixed; } + +#failing { + margin: 0 + 0 + 0 + 0; + margin: + 0 + 0 + 0 + 0; +} \ No newline at end of file Modified css-mode.el diff --git a/css-mode.el b/css-mode.el index 1abe9a8..44682e1 100644 --- a/css-mode.el +++ b/css-mode.el @@ -33,6 +33,8 @@ ;;; Code: +(require 'cl-lib) + (defgroup css nil "Cascading Style Sheets (CSS) editing mode." :group 'languages) @@ -92,7 +94,6 @@ (t nil))) elems)) - (defun css-extract-props-and-vals () (with-temp-buffer (url-insert-file-contents "http://www.w3.org/TR/CSS21/propidx.html") @@ -122,7 +123,7 @@ (defconst css-pseudo-ids '("active" "after" "before" "first" "first-child" "first-letter" "first-line" - "focus" "hover" "lang" "left" "link" "right" "visited") + "focus" "hover" "lang" "last-child" "left" "link" "right" "visited") "Identifiers for pseudo-elements and pseudo-classes.") (defconst css-at-ids @@ -264,8 +265,8 @@ '(css-font-lock-keywords nil t)) ;;;###autoload -(define-derived-mode css-mode fundamental-mode "CSS" - "Major mode to edit Cascading Style Sheets." +(define-derived-mode css-mode fundamental-mode + "CSS" "Major mode to edit Cascading Style Sheets." (setq-local font-lock-defaults css-font-lock-defaults) (setq-local comment-start "/*") (setq-local comment-start-skip "/\\*+[ \t]*") @@ -276,6 +277,8 @@ (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) + (setq-local beginning-of-defun-function 'css-beginning-of-defun) + (setq-local end-of-defun-function 'css-end-of-defun) (when css-electric-keys (let ((fc (make-char-table 'auto-fill-chars))) (set-char-table-parent fc auto-fill-chars) @@ -394,102 +397,178 @@ ;; FIXME: We should also skip punctuation. (not (memq (char-after) '(?\; ?\}))))))))))) -(defun css-indent-calculate-virtual () - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) - (if (looking-at "\\s(") - (save-excursion - (forward-char 1) (skip-chars-forward " \t") - (not (or (eolp) (looking-at comment-start-skip)))))) - (current-column) - (css-indent-calculate))) +(defun css-comment-line-p () + (interactive) + (cond ( (save-excursion + (back-to-indentation) + (looking-at "/\\*")) + 1 ) + ( (nth 4 (syntax-ppss)) + t))) + +(defun css-beginning-of-defun (&optional arg) + (unless arg (setq arg 1)) + (when (progn + ;; What for? + (unless (zerop (current-column)) + (end-of-line)) + (re-search-backward "^[^\n ].+{[ ]?$" nil t arg)) + (while (save-excursion + (and (zerop (forward-line -1)) + (string-match-p + "^[^}[:space:]/]" + (buffer-substring + (line-beginning-position) + (line-end-position))))) + (forward-line -1)))) + +(defun css-end-of-defun (&optional arg) + (interactive) + (unless arg (setq arg 1)) + (ignore-errors + (when (cl-plusp (first (syntax-ppss))) + (css-beginning-of-defun)) + (progn + (search-forward "{" nil t arg) + (backward-char) + (forward-sexp) + (ignore-errors + (forward-char))) + t)) + +;; To make writing derived modes easier. Ex. SASS also supports // type comments +(defvar css-comment-line-p-function 'css-comment-line-p + "Should return 1 if at the beginning of a comment, t if inside.") + +(defun css--goto-prev-struct-line () + (while (and (zerop (forward-line -1)) + (funcall css-comment-line-p-function)))) + +(defvar css-debug nil) + +(defun css-indent-debug-msg (name) + (when css-debug + (message "%s" name))) + +(defun css-visible-end-of-line () + (save-excursion + (end-of-line) + (skip-syntax-backward + " " (line-beginning-position)) + (point))) -(defcustom css-indent-offset 4 - "Basic size of one indentation step." - :version "22.2" - :type 'integer - :group 'css) +(defun css-indentation-end-pos () + (save-excursion + (back-to-indentation) + (point))) -(defun css-indent-calculate () - (let ((ppss (syntax-ppss)) - pos) - (with-syntax-table css-navigation-syntax-table - (save-excursion - (cond - ;; Inside a string. - ((nth 3 ppss) 'noindent) - ;; Inside a comment. - ((nth 4 ppss) - (setq pos (point)) - (forward-line -1) - (skip-chars-forward " \t") - (if (>= (nth 8 ppss) (point)) - (progn - (goto-char (nth 8 ppss)) - (if (eq (char-after pos) ?*) - (forward-char 1) - (if (not (looking-at comment-start-skip)) - (error "Internal css-mode error") - (goto-char (match-end 0)))) - (current-column)) - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) - (current-column) - ;; 'noindent - (current-column) - ))) - ;; In normal code. - (t - (or - (when (looking-at "\\s)") - (forward-char 1) - (backward-sexp 1) - (css-indent-calculate-virtual)) - (when (looking-at comment-start-skip) - (forward-comment (point-max)) - (css-indent-calculate)) - (when (save-excursion (forward-comment (- (point-max))) - (setq pos (point)) - (eq (char-syntax (preceding-char)) ?\()) - (goto-char (1- pos)) - (if (not (looking-at "\\s([ \t]*")) - (error "Internal css-mode error") - (if (or (memq (char-after (match-end 0)) '(?\n nil)) - (save-excursion (goto-char (match-end 0)) - (looking-at comment-start-skip))) - (+ (css-indent-calculate-virtual) css-indent-offset) - (progn (goto-char (match-end 0)) (current-column))))) - (progn - (css-backward-sexp 1) - (if (looking-at "\\s(") - (css-indent-calculate) - (css-indent-calculate-virtual)))))))))) +(defun css-current-character-indentation () + "Like (current-indentation), but counts tabs as single characters." + (save-excursion + (back-to-indentation) + (- (point) (line-beginning-position)))) + +(defvar css-colon ":" + "A dervied mode for SASS or LESS might want to set this to +\": \", to make nested pseudo-classes work.") +(defun css-indent-calculate () + ;; If I go to the beginning of line, MC stops working + (back-to-indentation) + (with-syntax-table css-navigation-syntax-table + (let* (psl-indent + psl-last-char + psl-first-char + ( psl + (save-excursion + (css--goto-prev-struct-line) + (setq psl-indent (current-indentation)) + (setq psl-last-char (char-before (css-visible-end-of-line))) + (setq psl-first-char (char-after (css-indentation-end-pos))) + (buffer-substring + (line-beginning-position) + (line-end-position)))) + ( psl-closing-brackets + (+ (cl-count ?} psl) + (cl-count ?\) psl))) + ( psl-open-brackets (+ (cl-count ?{ psl) (cl-count ?\( psl))) + ( psl-has-colon (cl-plusp (cl-count ?: psl))) + (ppss (syntax-ppss)) + previous-comment-indent + previous-line-was-comment + pos) + (cond ( ;; Inside a multiline comment + ( eq (funcall css-comment-line-p-function) t) + (css-indent-debug-msg "MC") + (save-excursion + (nth 4 ppss) + (setq pos (point)) + (forward-line -1) + (skip-chars-forward " \t") + (if (>= (nth 8 ppss) (point)) + (progn + (goto-char (nth 8 ppss)) + (if (eq (char-after pos) ?*) + (forward-char 1) + (if (not (looking-at comment-start-skip)) + (error "Internal css-mode error") + (goto-char (match-end 0)))) + (current-column)) + (current-column)))) + ( ;; If "outside" indent to 0 + (zerop (nth 0 ppss)) + (css-indent-debug-msg "ZERO") + 0) + ( ;; Not-first member of comma ending lines + (and (not (cl-search css-colon psl)) + (equal psl-last-char ?\, ) + (= psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg "MCB") + psl-indent) + ( ;; Line after beginning of comma block + (and (member psl-last-char '( ?: ?\, ) ) + (= psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg "LABOC") + (+ psl-indent css-indent-offset)) + ( ;; Default, based on nesting level + t + (css-indent-debug-msg "LAST") + (let (( parent-indent + (save-excursion + (backward-up-list) + (css-current-character-indentation))) + ( block-ending-line + (member (char-after (css-indentation-end-pos)) + '( ?\} ?\) ) ))) + (+ parent-indent + (* (+ (if block-ending-line -1 0) + 1) + css-indent-offset)))) + )))) (defun css-indent-line () "Indent current line according to CSS indentation rules." (interactive) - (let* ((savep (point)) - (forward-sexp-function nil) - (indent (condition-case nil - (save-excursion - (forward-line 0) - (skip-chars-forward " \t") - (if (>= (point) savep) (setq savep nil)) - (css-indent-calculate)) - (error nil)))) - (if (not (numberp indent)) 'noindent - (if savep - (save-excursion (indent-line-to indent)) - (indent-line-to indent))))) + (save-excursion + (indent-line-to (css-indent-calculate))) + (when (< (current-column) (current-indentation)) + (back-to-indentation))) + +(defcustom css-indent-offset 4 + "Basic size of one indentation step." + :version "22.2" + :type 'integer + :group 'css) (defun css-current-defun-name () "Return the name of the CSS section at point, or nil." (save-excursion (let ((max (max (point-min) (- (point) 1600)))) ; approx 20 lines back (when (search-backward "{" max t) - (skip-chars-backward " \t\r\n") - (beginning-of-line) - (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") - (match-string-no-properties 1)))))) + (skip-chars-backward " \t\r\n") + (beginning-of-line) + (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") + (match-string-no-properties 1)))))) (provide 'css-mode) ;;; css-mode.el ends here \ No newline at end of file On Tue, Jan 15, 2013 at 5:00 AM, Stefan Monnier wrote: > > I've written a new indenter for CSS, which fixes issues with mulitline > > statements following a colon, and comments: > > Interesting, I don't use CSS myself very much, but I've toyed with an > SMIE indenter for css-mode (see below). > > > body { > > color: #333; > > font: 15px "Helvetica Neue", > > Helvetica, > > Arial, > > "Nimbus Sans L", > > sans-serif; > > font-weight: 300; > > line-height: 1.625; > > a { /* It also handles SCSS */ > > font: 15px "Helvetica Neue", > > Helvetica, > > Arial, > > "Nimbus Sans L", > > sans-serif; > > /* Some comment */ > > } > > /* Some comment at the end of a block */ > > } > > I've tried it on the above test case and the SMIE code seems to handle > it OK (tho differently), with the main exception being the > comment-at-end-of-block, which is probably a general problem which > should be fixed in smie.el (probably in smie-indent-comment). > > But I have basically never used/tested my code, so... > > > I wondered whether this functionality could be integrated into Emacs. > > https://github.com/sabof/es-css-mode > > https://github.com/sabof/es-lib (it takes some functions from it) > > If you could provide a patch against css-mode.el, that would be more > convenient. Also it would be good to add a good set of test cases (in > the form of a new file test/indent/css-mode.css). > > > Stefan > > > === modified file 'lisp/textmodes/css-mode.el' > --- lisp/textmodes/css-mode.el 2013-01-02 16:13:04 +0000 > +++ lisp/textmodes/css-mode.el 2013-01-15 04:53:03 +0000 > @@ -263,6 +263,22 @@ > (defvar css-font-lock-defaults > '(css-font-lock-keywords nil t)) > > +(defcustom css-indent-offset 4 > + "Basic size of one indentation step." > + :version "22.2" > + :type 'integer) > + > +(defconst css-smie-grammar > + (smie-prec2->grammar > + (smie-precs->prec2 '((assoc ";") (left ":") (assoc ","))))) > + > +(defun css-smie-rules (kind token) > + (pcase (cons kind token) > + (`(:elem . basic) css-indent-offset) > + (`(:elem . arg) 0) > + (`(:before . "{") (if (smie-rule-hanging-p) > + (smie-rule-parent 0))))) > + > ;;;###autoload > (define-derived-mode css-mode fundamental-mode "CSS" > "Major mode to edit Cascading Style Sheets." > @@ -271,11 +287,11 @@ > (setq-local comment-start-skip "/\\*+[ \t]*") > (setq-local comment-end "*/") > (setq-local comment-end-skip "[ \t]*\\*+/") > - (setq-local forward-sexp-function 'css-forward-sexp) > (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) > (when css-electric-keys > (let ((fc (make-char-table 'auto-fill-chars))) > (set-char-table-parent fc auto-fill-chars) > @@ -355,131 +371,6 @@ > ;; Don't use the default filling code. > t))))))) > > -;;; Navigation and indentation. > - > -(defconst css-navigation-syntax-table > - (let ((st (make-syntax-table css-mode-syntax-table))) > - (map-char-table (lambda (c v) > - ;; Turn punctuation (code = 1) into symbol (code = > 1). > - (if (eq (car-safe v) 1) > - (set-char-table-range st c (cons 3 (cdr v))))) > - st) > - st)) > - > -(defun css-backward-sexp (n) > - (let ((forward-sexp-function nil)) > - (if (< n 0) (css-forward-sexp (- n)) > - (while (> n 0) > - (setq n (1- n)) > - (forward-comment (- (point-max))) > - (if (not (eq (char-before) ?\;)) > - (backward-sexp 1) > - (while (progn (backward-sexp 1) > - (save-excursion > - (forward-comment (- (point-max))) > - ;; FIXME: We should also skip punctuation. > - (not (or (bobp) (memq (char-before) '(?\; > ?\{)))))))))))) > - > -(defun css-forward-sexp (n) > - (let ((forward-sexp-function nil)) > - (if (< n 0) (css-backward-sexp (- n)) > - (while (> n 0) > - (setq n (1- n)) > - (forward-comment (point-max)) > - (if (not (eq (char-after) ?\;)) > - (forward-sexp 1) > - (while (progn (forward-sexp 1) > - (save-excursion > - (forward-comment (point-max)) > - ;; FIXME: We should also skip punctuation. > - (not (memq (char-after) '(?\; ?\}))))))))))) > - > -(defun css-indent-calculate-virtual () > - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) > - (if (looking-at "\\s(") > - (save-excursion > - (forward-char 1) (skip-chars-forward " \t") > - (not (or (eolp) (looking-at comment-start-skip)))))) > - (current-column) > - (css-indent-calculate))) > - > -(defcustom css-indent-offset 4 > - "Basic size of one indentation step." > - :version "22.2" > - :type 'integer > - :group 'css) > - > -(defun css-indent-calculate () > - (let ((ppss (syntax-ppss)) > - pos) > - (with-syntax-table css-navigation-syntax-table > - (save-excursion > - (cond > - ;; Inside a string. > - ((nth 3 ppss) 'noindent) > - ;; Inside a comment. > - ((nth 4 ppss) > - (setq pos (point)) > - (forward-line -1) > - (skip-chars-forward " \t") > - (if (>= (nth 8 ppss) (point)) > - (progn > - (goto-char (nth 8 ppss)) > - (if (eq (char-after pos) ?*) > - (forward-char 1) > - (if (not (looking-at comment-start-skip)) > - (error "Internal css-mode error") > - (goto-char (match-end 0)))) > - (current-column)) > - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) > - (current-column) > - ;; 'noindent > - (current-column) > - ))) > - ;; In normal code. > - (t > - (or > - (when (looking-at "\\s)") > - (forward-char 1) > - (backward-sexp 1) > - (css-indent-calculate-virtual)) > - (when (looking-at comment-start-skip) > - (forward-comment (point-max)) > - (css-indent-calculate)) > - (when (save-excursion (forward-comment (- (point-max))) > - (setq pos (point)) > - (eq (char-syntax (preceding-char)) ?\()) > - (goto-char (1- pos)) > - (if (not (looking-at "\\s([ \t]*")) > - (error "Internal css-mode error") > - (if (or (memq (char-after (match-end 0)) '(?\n nil)) > - (save-excursion (goto-char (match-end 0)) > - (looking-at comment-start-skip))) > - (+ (css-indent-calculate-virtual) css-indent-offset) > - (progn (goto-char (match-end 0)) (current-column))))) > - (progn > - (css-backward-sexp 1) > - (if (looking-at "\\s(") > - (css-indent-calculate) > - (css-indent-calculate-virtual)))))))))) > - > - > -(defun css-indent-line () > - "Indent current line according to CSS indentation rules." > - (interactive) > - (let* ((savep (point)) > - (forward-sexp-function nil) > - (indent (condition-case nil > - (save-excursion > - (forward-line 0) > - (skip-chars-forward " \t") > - (if (>= (point) savep) (setq savep nil)) > - (css-indent-calculate)) > - (error nil)))) > - (if (not (numberp indent)) 'noindent > - (if savep > - (save-excursion (indent-line-to indent)) > - (indent-line-to indent))))) > > (defun css-current-defun-name () > "Return the name of the CSS section at point, or nil." > > --047d7bdcab5260749f04d358d381 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
Here is a patch, including a more advanced test case. In the end there is= a "failing" section - although I haven't seen anyone breakin= g at spaces.

There is a varaiable ca= lled css-colon - the default is ":". If set to ": ", it= will also indent statements like this in SASS (a CSS pre-processor)=

a { &:hover,=20 &:active { background: green; } }

However, it w= ill no longer correctly indent statements like this:

backgrou= nd:#000, /* no space */ url('image.png');

If I manage to fix the "breaking at spaces" case, I&= #39;ll send another patch.

Evgeni
<= span class=3D"" style=3D"white-space:pre">
=A0New css-mode.css diff --git a/css-mode.css b/css-mode.css new file mode 100644 index 0000000..40a732f --- /dev/null +++ b/css-mode.css @@ -0,0 +1,86 @@ +#top_menu .button.active, +#top_menu .button.active:active { + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Comment */ +} +#top_menu .button.active, +#top_menu .button.active:active +{ + /* Comment */ + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Multiline + comment1 */ + /* Multiline + * comment2 */ +} +/* Multiline + comment1 */ +/* Multiline + * comment2 */ +#glass { + z-index: 2; + position: absolute; + top: -112px; + left: 0; + right: 0; + margin: 0 0 0 0; + margin: + 0 0 0 0; + text-shadow: + 1px 1px #FDE31D, + -1px -1px #B36300; + height: 140px; + background-image: url('images/honey_blurred2.png'); + background-image: url( + 'images/honey_blurred2.png'); + background-image: + #fff, + url('images/honey_blurred2.png'), + url('images/honey_blurred2.png'); + background-image: + #fff, + /* #fff, */ + url('images/honey_blurred2.png'); + background-image: #fff, + url('images/honey_blurred2.png'); + -webkit-mask-image: + -webkit-gradient( + linear, + left top, + /* left bottom, */ + left bottom, + color-stop( + 1, + rgba(0,0,0,0.2) + ), + color-stop(1, + rgba(0,0,0,0.2) + ), + /* comment */ + color-stop(0.7, rgba(0,0,0,.0)), + color-stop + ( + 0.7, rgba(0,0,0,.0) + ) + /* comment*/ ); + background-repeat: repeat-x; + background-position: center top; + background-attachment: fixed; } + +#failing { + margin: 0 + 0 + 0 + 0; + margin: + 0 + 0 + 0 + 0; +} \ No newline at end of file Modified css-mode.el diff --git a/css-mode.el b/css-mode.el index 1abe9a8..44682e1 100644 --- a/css-mode.el +++ b/css-mode.el @@ -33,6 +33,8 @@ =20 ;;; Code: =20 +(require 'cl-lib) + (defgroup css nil "Cascading Style Sheets (CSS) editing mode." :group 'languages) @@ -92,7 +94,6 @@ (t nil))) elems)) =20 - (defun css-extract-props-and-vals () (with-temp-buffer (url-insert-file-contents "http://www.w3.org/TR/CSS21/propidx.html") @@ -122,7 +123,7 @@ =20 (defconst css-pseudo-ids '("active" "after" "before" "firs= t" "first-child" "first-letter" "first-line&q= uot; - "focus" "hover" "lang" "left" = "link" "right" "visited") + "focus" "hover" "lang" "last-child&= quot; "left" "link" "right" "visited&quo= t;) "Identifiers for pseudo-elements and pseudo-classes.") =20 (defconst css-at-ids @@ -264,8 +265,8 @@ '(css-font-lock-keywords nil t)) =20 ;;;###autoload -(define-derived-mode css-mode fundamental-mode "CSS" - "Major mode to edit Cascading Style Sheets." +(define-derived-mode css-mode fundamental-mode + "CSS" "Major mode to edit Cascading Style Sheets." (setq-local font-lock-defaults css-font-lock-defaults) (setq-local comment-start "/*") (setq-local comment-start-skip "/\\*+[ \t]*") @@ -276,6 +277,8 @@ (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) + (setq-local beginning-of-defun-function 'css-beginning-of-defun) + (setq-local end-of-defun-function 'css-end-of-defun) (when css-electric-keys (let ((fc (make-char-table 'auto-fill-chars))) (set-char-table-parent fc auto-fill-chars) @@ -394,102 +397,178 @@ ;; FIXME: We should also skip punctuation. (not (memq (char-after) '(?\; ?\}))))))))))) =20 -(defun css-indent-calculate-virtual () - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) - (if (looking-at "\\s(") - (save-excursion - (forward-char 1) (skip-chars-forward " \t") - (not (or (eolp) (looking-at comment-start-skip)))))) - (current-column) - (css-indent-calculate))) +(defun css-comment-line-p () + (interactive) + (cond ( (save-excursion + (back-to-indentation) + (looking-at "/\\*")) + 1 ) + ( (nth 4 (syntax-ppss)) + t))) + +(defun css-beginning-of-defun (&optional arg) + (unless arg (setq arg 1)) + (when (progn + ;; What for? + (unless (zerop (current-column)) + (end-of-line)) + (re-search-backward "^[^\n ].+{[ ]?$" nil t arg)) + (while (save-excursion + (and (zerop (forward-line -1)) + (string-match-p + "^[^}[:space:]/]" + (buffer-substring + (line-beginning-position) + (line-end-position))))) + (forward-line -1)))) + +(defun css-end-of-defun (&optional arg) + (interactive) + (unless arg (setq arg 1)) + (ignore-errors + (when (cl-plusp (first (syntax-ppss))) + (css-beginning-of-defun)) + (progn + (search-forward "{" nil t arg) + (backward-char) + (forward-sexp) + (ignore-errors + (forward-char))) + t)) + +;; To make writing derived modes easier. Ex. SASS also supports // type co= mments +(defvar css-comment-line-p-function 'css-comment-line-p + "Should return 1 if at the beginning of a comment, t if inside.&quo= t;) + +(defun css--goto-prev-struct-line () + (while (and (zerop (forward-line -1)) + (funcall css-comment-line-p-function)))) + +(defvar css-debug nil) + +(defun css-indent-debug-msg (name) + (when css-debug + (message "%s" name))) + +(defun css-visible-end-of-line () + (save-excursion + (end-of-line) + (skip-syntax-backward + " " (line-beginning-position)) + (point))) =20 -(defcustom css-indent-offset 4 - "Basic size of one indentation step." - :version "22.2" - :type 'integer - :group 'css) +(defun css-indentation-end-pos () + (save-excursion + (back-to-indentation) + (point))) =20 -(defun css-indent-calculate () - (let ((ppss (syntax-ppss)) - pos) - (with-syntax-table css-navigation-syntax-table - (save-excursion - (cond - ;; Inside a string. - ((nth 3 ppss) 'noindent) - ;; Inside a comment. - ((nth 4 ppss) - (setq pos (point)) - (forward-line -1) - (skip-chars-forward " \t") - (if (>=3D (nth 8 ppss) (point)) - (progn - (goto-char (nth 8 ppss)) - (if (eq (char-after pos) ?*) - (forward-char 1) - (if (not (looking-at comment-start-skip)) - (error "Internal css-mode error") - (goto-char (match-end 0)))) - (current-column)) - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) - (current-column) - ;; 'noindent - (current-column) - ))) - ;; In normal code. - (t - (or - (when (looking-at "\\s)") - (forward-char 1) - (backward-sexp 1) - (css-indent-calculate-virtual)) - (when (looking-at comment-start-skip) - (forward-comment (point-max)) - (css-indent-calculate)) - (when (save-excursion (forward-comment (- (point-max))) - (setq pos (point)) - (eq (char-syntax (preceding-char)) ?\()) - (goto-char (1- pos)) - (if (not (looking-at "\\s([ \t]*")) - (error "Internal css-mode error") - (if (or (memq (char-after (match-end 0)) '(?\n nil)) - (save-excursion (goto-char (match-end 0)) - (looking-at comment-start-skip))) - (+ (css-indent-calculate-virtual) css-indent-offset) - (progn (goto-char (match-end 0)) (current-column))))) - (progn - (css-backward-sexp 1) - (if (looking-at "\\s(") - (css-indent-calculate) - (css-indent-calculate-virtual)))))))))) +(defun css-current-character-indentation () + "Like (current-indentation), but counts tabs as single characters.&= quot; + (save-excursion + (back-to-indentation) + (- (point) (line-beginning-position)))) + +(defvar css-colon ":" + "A dervied mode for SASS or LESS might want to set this to +\": \", to make nested pseudo-classes work.") =20 +(defun css-indent-calculate () + ;; If I go to the beginning of line, MC stops working + (back-to-indentation) + (with-syntax-table css-navigation-syntax-table + (let* (psl-indent + psl-last-char + psl-first-char + ( psl + (save-excursion + (css--goto-prev-struct-line) + (setq psl-indent (current-indentation)) + (setq psl-last-char (char-before (css-visible-end-of-line))= ) + (setq psl-first-char (char-after (css-indentation-end-pos))= ) + (buffer-substring + (line-beginning-position) + (line-end-position)))) + ( psl-closing-brackets + (+ (cl-count ?} psl) + (cl-count ?\) psl))) + ( psl-open-brackets (+ (cl-count ?{ psl) (cl-count ?\( psl))) + ( psl-has-colon (cl-plusp (cl-count ?: psl))) + (ppss (syntax-ppss)) + previous-comment-indent + previous-line-was-comment + pos) + (cond ( ;; Inside a multiline comment + ( eq (funcall css-comment-line-p-function) t) + (css-indent-debug-msg "MC") + (save-excursion + (nth 4 ppss) + (setq pos (point)) + (forward-line -1) + (skip-chars-forward " \t") + (if (>=3D (nth 8 ppss) (point)) + (progn + (goto-char (nth 8 ppss)) + (if (eq (char-after pos) ?*) + (forward-char 1) + (if (not (looking-at comment-start-skip)) + (error "Internal css-mode error") + (goto-char (match-end 0)))) + (current-column)) + (current-column)))) + ( ;; If "outside" indent to 0 + (zerop (nth 0 ppss)) + (css-indent-debug-msg "ZERO") + 0) + ( ;; Not-first member of comma ending lines + (and (not (cl-search css-colon psl)) + (equal psl-last-char ?\, ) + (=3D psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg "MCB") + psl-indent) + ( ;; Line after beginning of comma block + (and (member psl-last-char '( ?: ?\, ) ) + (=3D psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg "LABOC") + (+ psl-indent css-indent-offset)) + ( ;; Default, based on nesting level + t + (css-indent-debug-msg "LAST") + (let (( parent-indent + (save-excursion + (backward-up-list) + (css-current-character-indentation))) + ( block-ending-line + (member (char-after (css-indentation-end-pos)) + '( ?\} ?\) ) ))) + (+ parent-indent + (* (+ (if block-ending-line -1 0) + 1) + css-indent-offset)))) + )))) =20 (defun css-indent-line () "Indent current line according to CSS indentation rules." (interactive) - (let* ((savep (point)) - (forward-sexp-function nil) - (indent (condition-case nil - (save-excursion - (forward-line 0) - (skip-chars-forward " \t") - (if (>=3D (point) savep) (setq savep nil)) - (css-indent-calculate)) - (error nil)))) - (if (not (numberp indent)) 'noindent - (if savep - (save-excursion (indent-line-to indent)) - (indent-line-to indent))))) + (save-excursion + (indent-line-to (css-indent-calculate))) + (when (< (current-column) (current-indentation)) + (back-to-indentation))) + +(defcustom css-indent-offset 4 + "Basic size of one indentation step." + :version "22.2" + :type 'integer + :group 'css) =20 (defun css-current-defun-name () "Return the name of the CSS section at point, or nil." (save-excursion (let ((max (max (point-min) (- (point) 1600)))) ; approx 20 lines bac= k (when (search-backward "{" max t) - (skip-chars-backward " \t\r\n") - (beginning-of-line) - (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") - (match-string-no-properties 1)))))) + (skip-chars-backward " \t\r\n") + (beginning-of-line) + (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") + (match-string-no-properties 1)))))) =20 (provide 'css-mode) ;;; css-mode.el ends here \ No newline at end of file


O= n Tue, Jan 15, 2013 at 5:00 AM, Stefan Monnier <monnier@iro.umontre= al.ca> wrote:
> I've written a new indenter for CSS= , which fixes issues with mulitline
> statements following a colon, and comments:

Interesting, I don't use CSS myself very much, but I've toyed with = an
SMIE indenter for css-mode (see below).

> body {
> =A0 =A0 color: #333;
> =A0 =A0 font: 15px "Helvetica Neue",
> =A0 =A0 =A0 =A0 Helvetica,
> =A0 =A0 =A0 =A0 Arial,
> =A0 =A0 =A0 =A0 "Nimbus Sans L",
> =A0 =A0 =A0 =A0 sans-serif;
> =A0 =A0 font-weight: 300;
> =A0 =A0 line-height: 1.625;
> =A0 =A0 a { /* It also handles SCSS */
> =A0 =A0 =A0 =A0 font: 15px "Helvetica Neue",
> =A0 =A0 =A0 =A0 =A0 =A0 Helvetica,
> =A0 =A0 =A0 =A0 =A0 =A0 Arial,
> =A0 =A0 =A0 =A0 =A0 =A0 "Nimbus Sans L",
> =A0 =A0 =A0 =A0 =A0 =A0 sans-serif;
> =A0 =A0 =A0 =A0 /* Some comment */
> =A0 =A0 }
> =A0 =A0 /* Some comment at the end of a block */
> }

I've tried it on the above test case and the SMIE code seems to handle<= br> it OK (tho differently), with the main exception being the
comment-at-end-of-block, which is probably a general problem which
should be fixed in smie.el (probably in smie-indent-comment).

But I have basically never used/tested my code, so...

> I wondered whether this functionality could be integrated into Emacs.<= br> > htt= ps://github.com/sabof/es-css-mode
> https://= github.com/sabof/es-lib (it takes some functions from it)

If you could provide a patch against css-mode.el, that would be more
convenient. =A0Also it would be good to add a good set of test cases (in the form of a new file test/indent/css-mode.css).


=A0 =A0 =A0 =A0 Stefan


=3D=3D=3D modified file 'lisp/textmodes/css-mode.el'
--- lisp/textmodes/css-mode.el =A02013-01-02 16:13:04 +0000
+++ lisp/textmodes/css-mode.el =A02013-01-15 04:53:03 +0000
@@ -263,6 +263,22 @@
=A0(defvar css-font-lock-defaults
=A0 =A0'(css-font-lock-keywords nil t))

+(defcustom css-indent-offset 4
+ =A0"Basic size of one indentation step."
+ =A0:version "22.2"
+ =A0:type 'integer)
+
+(defconst css-smie-grammar
+ =A0(smie-prec2->grammar
+ =A0 (smie-precs->prec2 '((assoc ";") (left ":"= ) (assoc ",")))))
+
+(defun css-smie-rules (kind token)
+ =A0(pcase (cons kind token)
+ =A0 =A0(`(:elem . basic) css-indent-offset)
+ =A0 =A0(`(:elem . arg) 0)
+ =A0 =A0(`(:before . "{") (if (smie-rule-hanging-p)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (smie-rule-parent 0)))))<= br> +
=A0;;;###autoload
=A0(define-derived-mode css-mode fundamental-mode "CSS"
=A0 =A0"Major mode to edit Cascading Style Sheets."
@@ -271,11 +287,11 @@
=A0 =A0(setq-local comment-start-skip "/\\*+[ \t]*")
=A0 =A0(setq-local comment-end "*/")
=A0 =A0(setq-local comment-end-skip "[ \t]*\\*+/")
- =A0(setq-local forward-sexp-function 'css-forward-sexp)
=A0 =A0(setq-local parse-sexp-ignore-comments t)
=A0 =A0(setq-local indent-line-function 'css-indent-line)
=A0 =A0(setq-local fill-paragraph-function 'css-fill-paragraph)
=A0 =A0(setq-local add-log-current-defun-function #'css-current-defun-n= ame)
+ =A0(smie-setup css-smie-grammar #'css-smie-rules)
=A0 =A0(when css-electric-keys
=A0 =A0 =A0(let ((fc (make-char-table 'auto-fill-chars)))
=A0 =A0 =A0 =A0(set-char-table-parent fc auto-fill-chars)
@@ -355,131 +371,6 @@
=A0 =A0 =A0 =A0 =A0 =A0 =A0;; Don't use the default filling code.
=A0 =A0 =A0 =A0 =A0 =A0 =A0t)))))))

-;;; Navigation and indentation.
-
-(defconst css-navigation-syntax-table
- =A0(let ((st (make-syntax-table css-mode-syntax-table)))
- =A0 =A0(map-char-table (lambda (c v)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; Turn punctuation (code =3D = 1) into symbol (code =3D 1).
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (eq (car-safe v) 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(set-char-table-range = st c (cons 3 (cdr v)))))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0st)
- =A0 =A0st))
-
-(defun css-backward-sexp (n)
- =A0(let ((forward-sexp-function nil))
- =A0 =A0(if (< n 0) (css-forward-sexp (- n))
- =A0 =A0 =A0(while (> n 0)
- =A0 =A0 =A0 =A0(setq n (1- n))
- =A0 =A0 =A0 =A0(forward-comment (- (point-max)))
- =A0 =A0 =A0 =A0(if (not (eq (char-before) ?\;))
- =A0 =A0 =A0 =A0 =A0 =A0(backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0(while (progn (backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-comment (- (p= oint-max)))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; FIXME: We should al= so skip punctuation.
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (or (bobp) (memq = (char-before) '(?\; ?\{))))))))))))
-
-(defun css-forward-sexp (n)
- =A0(let ((forward-sexp-function nil))
- =A0 =A0(if (< n 0) (css-backward-sexp (- n))
- =A0 =A0 =A0(while (> n 0)
- =A0 =A0 =A0 =A0(setq n (1- n))
- =A0 =A0 =A0 =A0(forward-comment (point-max))
- =A0 =A0 =A0 =A0(if (not (eq (char-after) ?\;))
- =A0 =A0 =A0 =A0 =A0 =A0(forward-sexp 1)
- =A0 =A0 =A0 =A0 =A0(while (progn (forward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-comment (poin= t-max))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; FIXME: We should al= so skip punctuation.
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (memq (char-after= ) '(?\; ?\})))))))))))
-
-(defun css-indent-calculate-virtual ()
- =A0(if (or (save-excursion (skip-chars-backward " \t") (bolp))<= br> - =A0 =A0 =A0 =A0 =A0(if (looking-at "\\s(")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-char 1) (skip-chars-forward "= ; \t")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (or (eolp) (looking-at comment-start-= skip))))))
- =A0 =A0 =A0(current-column)
- =A0 =A0(css-indent-calculate)))
-
-(defcustom css-indent-offset 4
- =A0"Basic size of one indentation step."
- =A0:version "22.2"
- =A0:type 'integer
- =A0:group 'css)
-
-(defun css-indent-calculate ()
- =A0(let ((ppss (syntax-ppss))
- =A0 =A0 =A0 =A0pos)
- =A0 =A0(with-syntax-table css-navigation-syntax-table
- =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0(cond
- =A0 =A0 =A0 =A0 ;; Inside a string.
- =A0 =A0 =A0 =A0 ((nth 3 ppss) 'noindent)
- =A0 =A0 =A0 =A0 ;; Inside a comment.
- =A0 =A0 =A0 =A0 ((nth 4 ppss)
- =A0 =A0 =A0 =A0 =A0(setq pos (point))
- =A0 =A0 =A0 =A0 =A0(forward-line -1)
- =A0 =A0 =A0 =A0 =A0(skip-chars-forward " \t")
- =A0 =A0 =A0 =A0 =A0(if (>=3D (nth 8 ppss) (point))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0(progn
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(goto-char (nth 8 ppss))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (eq (char-after pos) ?*)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-char 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (not (looking-at comment-start-ski= p))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(error "Internal css-mode= error")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(goto-char (match-end 0))))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column))
- =A0 =A0 =A0 =A0 =A0 =A0(if (and (eq (char-after pos) ?*) (eq (char-after)= ?*))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0;; 'noindent
- =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0)))
- =A0 =A0 =A0 =A0 ;; In normal code.
- =A0 =A0 =A0 =A0 (t
- =A0 =A0 =A0 =A0 =A0(or
- =A0 =A0 =A0 =A0 =A0 (when (looking-at "\\s)")
- =A0 =A0 =A0 =A0 =A0 =A0 (forward-char 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate-virtual))
- =A0 =A0 =A0 =A0 =A0 (when (looking-at comment-start-skip)
- =A0 =A0 =A0 =A0 =A0 =A0 (forward-comment (point-max))
- =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate))
- =A0 =A0 =A0 =A0 =A0 (when (save-excursion (forward-comment (- (point-max)= ))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (setq pos= (point))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (eq (char= -syntax (preceding-char)) ?\())
- =A0 =A0 =A0 =A0 =A0 =A0 (goto-char (1- pos))
- =A0 =A0 =A0 =A0 =A0 =A0 (if (not (looking-at "\\s([ \t]*"))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (error "Internal css-mode error"= ;)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 (if (or (memq (char-after (match-end 0)) '= ;(?\n nil))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (save-excursion (goto-char (m= atch-end 0))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (looking-at comment-start-skip)))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (+ (css-indent-calculate-virtual) css= -indent-offset)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (progn (goto-char (match-end 0)) (current= -column)))))
- =A0 =A0 =A0 =A0 =A0 (progn
- =A0 =A0 =A0 =A0 =A0 =A0 (css-backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (if (looking-at "\\s(")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate-virtual))))))))))
-
-
-(defun css-indent-line ()
- =A0"Indent current line according to CSS indentation rules." - =A0(interactive)
- =A0(let* ((savep (point))
- =A0 =A0 =A0 =A0 (forward-sexp-function nil)
- =A0 =A0 =A0 =A0(indent (condition-case nil
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-line 0)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(skip-chars-forward " \t&= quot;)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (>=3D (point) savep) (s= etq savep nil))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(css-indent-calculate))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(error nil))))
- =A0 =A0(if (not (numberp indent)) 'noindent
- =A0 =A0 =A0(if savep
- =A0 =A0 =A0 =A0 =A0(save-excursion (indent-line-to indent))
- =A0 =A0 =A0 =A0(indent-line-to indent)))))

=A0(defun css-current-defun-name ()
=A0 =A0"Return the name of the CSS section at point, or nil."


--047d7bdcab5260749f04d358d381-- From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: new css-mode indenter Resent-From: E Sabof Original-Sender: debbugs-submit-bounces@debbugs.gnu.org Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 17 Jan 2013 00:19:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Stefan Monnier Cc: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.135838189416658 (code B ref 13425); Thu, 17 Jan 2013 00:19:02 +0000 Received: (at 13425) by debbugs.gnu.org; 17 Jan 2013 00:18:14 +0000 Received: from localhost ([127.0.0.1]:35841 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TvdBO-0004Kd-In for submit@debbugs.gnu.org; Wed, 16 Jan 2013 19:18:14 -0500 Received: from mail-qa0-f49.google.com ([209.85.216.49]:40406) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TvdBN-0004KW-2s for 13425@debbugs.gnu.org; Wed, 16 Jan 2013 19:18:13 -0500 Received: by mail-qa0-f49.google.com with SMTP id r4so1686286qaq.1 for <13425@debbugs.gnu.org>; Wed, 16 Jan 2013 16:17:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:x-received:in-reply-to:references:date:message-id :subject:from:to:cc:content-type; bh=7OfVoUnfLRVRBNsicFQUhM5nQXgEcDN9Ug0AkhYfnhs=; b=i5JTfSoCxhsjloAIII3C3XWf3M3kk5oiP0miwXMCvUsmaE28wjrX2GfJe1moc+QGfz RZVyqmq5V4yVjfMOscCzQWJgio996tpciGsQDibqPvM8S+CEmr65YpUeL/QbEWyyO4JR y3keU/pLwQqItFVYDsSag+4Sd/jOKumdlt1EuLA9hJ4CHHi8q5QvmnJDPKLZO69bpf94 OTvMWJVNv0G5mzhlG7CZ8I2QTd23qyba6p7R1e1rfxGvLzm++uP4im2iEcxSyj7LtxYH LXpwLFlagdz1YH7wBB9r+nQkXGU8BaRNWmMyqa+UsbwltcQwT3XquXZd1uBqbfqd1h9P XsUw== MIME-Version: 1.0 X-Received: by 10.224.30.203 with SMTP id v11mr3790616qac.31.1358381854817; Wed, 16 Jan 2013 16:17:34 -0800 (PST) Received: by 10.49.4.102 with HTTP; Wed, 16 Jan 2013 16:17:34 -0800 (PST) In-Reply-To: References: Date: Thu, 17 Jan 2013 00:17:34 +0000 Message-ID: From: E Sabof Content-Type: multipart/alternative; boundary=20cf3074d594ecfdb804d370ebd7 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: debbugs-submit-bounces@debbugs.gnu.org Errors-To: debbugs-submit-bounces@debbugs.gnu.org --20cf3074d594ecfdb804d370ebd7 Content-Type: text/plain; charset=ISO-8859-1 I've rewritten the indenter - this time I've added a parser for statements within curly brackets, so there is a lot less hackery. I've also added some more tests cases. Evgeni New css-mode.css diff --git a/css-mode.css b/css-mode.css new file mode 100644 index 0000000..f101971 --- /dev/null +++ b/css-mode.css @@ -0,0 +1,230 @@ +#top_menu .button.active, +#top_menu .button.active:active { + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Comment */ +} + +#top_menu .button.active, +#top_menu .button.active:active +{ + /* Comment */ + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Multiline + comment1 */ + /* Multiline + * comment2 */ +} +/* Multiline + comment1 */ +/* Multiline + * comment2 */ +#glass { + z-index: 2; + position: absolute; + top: -112px; + left: 0; + right: 0; + margin: 0 0 0 0; + margin: + 0 0 0 0; + text-shadow: + 1px 1px #FDE31D, + -1px -1px #B36300; + height: 140px; + background-image: url('images/honey_blurred2.png'); + background-image: url( + 'images/honey_blurred2.png'); + background-image: + #fff, + url('images/honey_blurred2.png'), + url('images/honey_blurred2.png'); + background-image: + #fff, + /* #fff, */ + url('images/honey_blurred2.png'); + background-image: #fff, + url('images/honey_blurred2.png'); + -webkit-mask-image: + -webkit-gradient( + linear, + left top, + /* left bottom, */ + left bottom, + color-stop( + 1, + rgba(0,0,0,0.2) + ), + color-stop(1, + + rgba(0,0,0,0.2) + ), + /* comment */ + color-stop(0.7, rgba(0,0,0,.0)), + color-stop + ( + 0.7, rgba(0,0,0,.0) + + ) + /* comment*/ ); + background-repeat: repeat-x; + background-position: center top; + background-attachment: fixed; } + +#glass { + margin: + /* 0 0 0 0; */ + /* text-shadow: */ + 1px 1px #FDE31D, + -1px -1px #B36300; + height: 140px; + background-image: url('images/honey_blurred2.png'); + /* background-image: url( */ + /* 'images/honey_blurred2.png'); */ + + background-image: + #fff, + url('images/honey_blurred2.png'), + url('images/honey_blurred2.png'); + background-image: + #fff, + /* #fff, */ + /* url('images/honey_blurred2.png'); */ + /* background-image: #fff, */ + url('images/honey_blurred2.png'); + -webkit-mask-image: + -webkit-gradient( + linear, + left top, + /* left bottom, */ + left bottom, + color-stop( + /* 1, */ + /* rgba(0,0,0,0.2) */ + ), + color-stop(1, + /* com */ + rgba(0,0,0,0.2) + + ), + /* comment */ + color-stop(0.7, rgba(0,0,0,.0)), + color-stop + ( + + 0.7, rgba(0,0,0,.0) + ) + /* comment*/); + -webkit-mask-image: + /* -webkit- */gradient( + linear, + left /* top */, + /* left */bottom, + left bottom, + color-stop( + /* 1, */ + /* rgba(0,0,0,0.2) */ + ), + color-stop(1, + /* com */ + rgba(0,0,0,0.2) + + ), + /* comment */ + color-stop(0.7/* , rgba(0,0,0,.0) */ + , rgba(0,0,0,.0) ), + color-stop + ( + + 0.7, rgba(0,0,0,.0) + ) + /* comment*/); + color: black, + /* red */, + blue; + /* -webkit-mask-image: */ + background: + -webkit-gradient( + /* com */ + ); + -webkit-mask-image: -webkit-gradient( + /* Forgivable? Better? */ + ), + -webkit-mask-image( + /* Back on track */ + ); + background-attachment: fixed + /* sdfsdf */ +} + +p:nth-child(2) { + margin: + 0 + 0 + 0 + 0; + margin: 0 0 + 0 + 0; + + /* comment */ + + text-shadow:1px 1px #FDE31D, /* no space */ + -1px -1px #B36300; +} + +p:nth-child +( + 2 +) +{ + height: 2px +} + +#field_message { + width: 100%; + display: block; + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ + /* resize: vertical; */ + resize: none; + height: 160px +} + + +some { + +} + +/* SASS */ + +.some { + /* resize: vertical; */ + resize: none; + + height: 160px; + .other, + .another, + &:a, + #id { + /* resize: vertical; */ + resize: none; + + height: 160px; + } + /* Comment */ + resize: none; + height: 160px; + /* Comment */ +} + + +/* Local Variables: */ +/* css-debug: t */ +/* End: */ \ No newline at end of file Modified css-mode.el diff --git a/css-mode.el b/css-mode.el index 1abe9a8..9f3a786 100644 --- a/css-mode.el +++ b/css-mode.el @@ -31,12 +31,95 @@ ;; - completion ;; - fix font-lock errors with multi-line selectors +;;; TODO: +;; extra empty line indentation + ;;; Code: +(require 'cl-lib) + (defgroup css nil "Cascading Style Sheets (CSS) editing mode." :group 'languages) +;; Debugging + +(defvar css-debug-overlays nil) + +(defun css-debug-overlay (beginning end color) + (let ((overlay (make-overlay beginning end))) + (overlay-put overlay 'face `(:background ,color)) + (push overlay css-debug-overlays))) + +(defvar css-debug nil) + +(defun css-debug-msg (name) + (when css-debug + (message "%s" name))) + +(defun css-debug-goto-root-declaration () + (let* (( ppss (syntax-ppss)) + ( depth (nth 0 ppss))) + (when (nth 3 ppss) + (goto-char (nth 8 ppss))) + (while (and (cl-plusp depth) + (not (equal (char-after) ?\{ ))) + (up-list -1) + (cl-decf depth)))) + +(defun css-debug-parser-current () + (interactive) + (mapc 'delete-overlay css-debug-overlays) + (let* (( point + (save-excursion + (back-to-indentation) + (point))) + ( parsed + (save-excursion + (css-debug-goto-root-declaration) + (css-parse-curly))) + ( relevant + (css-pc-get-relevant parsed point))) + (css-debug-overlay + (car relevant) + (cadr relevant) + "DarkRed") + nil)) + +(defun css-debug-highight-parsed (parsed) + (mapc 'delete-overlay css-debug-overlays) + (cl-mapc (lambda (item) + (css-debug-overlay + (car item) + (cadr item) + (case (caddr item) + ('nested-selector "DarkGreen") + ('comment "SaddleBrown") + ( t "DarkRed")))) + parsed)) + +(defun css-debug-parser-all () + (interactive) + (let* (( parsed + (save-excursion + (css-debug-goto-root-declaration) + (css-parse-curly)))) + (css-debug-highight-parsed + parsed) + nil)) + +(defun css-debug-parser-inside () + (interactive) + (let* (( parsed + (save-excursion + (css-debug-goto-root-declaration) + (css-parse-curly))) + ( inside + (css-pc-inside-statement + parsed (point)))) + (message "P %s" inside))) + +;; EOF Debugging (defun css-extract-keyword-list (res) (with-temp-buffer @@ -92,7 +175,6 @@ (t nil))) elems)) - (defun css-extract-props-and-vals () (with-temp-buffer (url-insert-file-contents "http://www.w3.org/TR/CSS21/propidx.html") @@ -122,7 +204,7 @@ (defconst css-pseudo-ids '("active" "after" "before" "first" "first-child" "first-letter" "first-line" - "focus" "hover" "lang" "left" "link" "right" "visited") + "focus" "hover" "lang" "last-child" "left" "link" "right" "visited") "Identifiers for pseudo-elements and pseudo-classes.") (defconst css-at-ids @@ -264,8 +346,8 @@ '(css-font-lock-keywords nil t)) ;;;###autoload -(define-derived-mode css-mode fundamental-mode "CSS" - "Major mode to edit Cascading Style Sheets." +(define-derived-mode css-mode fundamental-mode + "CSS" "Major mode to edit Cascading Style Sheets." (setq-local font-lock-defaults css-font-lock-defaults) (setq-local comment-start "/*") (setq-local comment-start-skip "/\\*+[ \t]*") @@ -276,6 +358,8 @@ (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) + (setq-local beginning-of-defun-function 'css-beginning-of-defun) + (setq-local end-of-defun-function 'css-end-of-defun) (when css-electric-keys (let ((fc (make-char-table 'auto-fill-chars))) (set-char-table-parent fc auto-fill-chars) @@ -394,102 +478,188 @@ ;; FIXME: We should also skip punctuation. (not (memq (char-after) '(?\; ?\}))))))))))) -(defun css-indent-calculate-virtual () - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) - (if (looking-at "\\s(") - (save-excursion - (forward-char 1) (skip-chars-forward " \t") - (not (or (eolp) (looking-at comment-start-skip)))))) - (current-column) - (css-indent-calculate))) - -(defcustom css-indent-offset 4 - "Basic size of one indentation step." - :version "22.2" - :type 'integer - :group 'css) +(defun css-beginning-of-defun (&optional arg) + (unless arg (setq arg 1)) + (when (progn + ;; What for? + (unless (zerop (current-column)) + (end-of-line)) + (re-search-backward "^[^\n ].+{[ ]?$" nil t arg)) + (while (save-excursion + (and (zerop (forward-line -1)) + (string-match-p + "^[^}[:space:]/]" + (buffer-substring + (line-beginning-position) + (line-end-position))))) + (forward-line -1)))) + +(defun css-end-of-defun (&optional arg) + (interactive) + (unless arg (setq arg 1)) + (ignore-errors + (when (cl-plusp (car (syntax-ppss))) + (css-beginning-of-defun)) + (progn + (search-forward "{" nil t arg) + (backward-char) + (forward-sexp) + (ignore-errors + (forward-char))) + t)) + +(defun css-go-up () + (let* (( ppss (syntax-ppss))) + (when (or (nth 3 ppss) (nth 4 ppss)) + (goto-char (nth 8 ppss))) + (when (cl-plusp (nth 0 ppss)) + (up-list -1)))) + +(defmacro css-while-point-moving (&rest rest) + (let ((old-point (cl-gensym))) + `(let (,old-point) + (while (not (equal (point) ,old-point)) + (setq ,old-point (point)) + ,@rest)))) + +(defun css-parse-curly () + (let (( start (point)) + ( indentation (current-indentation)) + ( end (save-excursion + (forward-sexp) + (point))) + point result) + (forward-char) + (cl-loop named main-loop + do + (skip-chars-forward "\n\t " end) + (when (>= (point) (1- end)) + (cl-return-from main-loop)) + (setq point (point)) + (if (forward-comment 1) + (push (list point (point) 'comment) result) + (progn + (cl-loop (unless (re-search-forward ";\\|{\\|}" end t) + (cl-return-from main-loop)) + (unless (nth 4 (syntax-ppss)) + (cl-return))) + (cond ( (equal (char-before) ?\{ ) + (backward-char) + (forward-sexp) + (push (list point (point) 'nested-selector) result)) + ( (equal (char-before) ?\} ) + (backward-char) + (css-while-point-moving + (skip-chars-backward "\n\t " start) + (forward-comment -1)) + (push (list point (point) 'statement) result)) + ( t (push (list point (point) 'statement) result)))))) + (nreverse result))) + +(defun css-pc-get-relevant (parsed point) + (car (reverse (cl-remove-if (apply-partially '< point) + parsed :key 'car)))) + +(defun css-pc-inside-statement (parsed point) + (cl-some (lambda (item) + (and (<= (car item) point) + (<= point (cadr item)))) + parsed)) (defun css-indent-calculate () - (let ((ppss (syntax-ppss)) - pos) - (with-syntax-table css-navigation-syntax-table - (save-excursion - (cond - ;; Inside a string. - ((nth 3 ppss) 'noindent) - ;; Inside a comment. - ((nth 4 ppss) - (setq pos (point)) - (forward-line -1) - (skip-chars-forward " \t") - (if (>= (nth 8 ppss) (point)) - (progn - (goto-char (nth 8 ppss)) - (if (eq (char-after pos) ?*) - (forward-char 1) - (if (not (looking-at comment-start-skip)) - (error "Internal css-mode error") - (goto-char (match-end 0)))) - (current-column)) - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) - (current-column) - ;; 'noindent - (current-column) - ))) - ;; In normal code. - (t - (or - (when (looking-at "\\s)") - (forward-char 1) - (backward-sexp 1) - (css-indent-calculate-virtual)) - (when (looking-at comment-start-skip) - (forward-comment (point-max)) - (css-indent-calculate)) - (when (save-excursion (forward-comment (- (point-max))) - (setq pos (point)) - (eq (char-syntax (preceding-char)) ?\()) - (goto-char (1- pos)) - (if (not (looking-at "\\s([ \t]*")) - (error "Internal css-mode error") - (if (or (memq (char-after (match-end 0)) '(?\n nil)) - (save-excursion (goto-char (match-end 0)) - (looking-at comment-start-skip))) - (+ (css-indent-calculate-virtual) css-indent-offset) - (progn (goto-char (match-end 0)) (current-column))))) - (progn - (css-backward-sexp 1) - (if (looking-at "\\s(") - (css-indent-calculate) - (css-indent-calculate-virtual)))))))))) - + (save-match-data + (condition-case error + (with-syntax-table css-navigation-syntax-table + (back-to-indentation) + (let* ((point (point)) + (ppss (syntax-ppss)) + ( css-curly-parsed + (save-excursion + (css-go-up) + (when (equal (char-after) ?{ ) + (css-parse-curly)))) + css-parsed-relevant + (block-ending-line + (member (char-after + (save-excursion + (back-to-indentation) + (point))) + '( ?\} ?\) ) ))) + (cond ( (nth 4 ppss) + ;; Inside a multiline comment + (css-debug-msg "MC") + (save-excursion + (forward-line -1) + (skip-chars-forward " \t") + (if (>= (nth 8 ppss) (point)) + (progn + (goto-char (nth 8 ppss)) + (if (eq (char-after point) ?*) + (forward-char 1) + (if (not (looking-at comment-start-skip)) + (error "Internal css-mode error") + (goto-char (match-end 0)))) + (current-column)) + (current-column)))) + ( ;; If "outside" indent to 0 + (zerop (nth 0 ppss)) + (css-debug-msg "ZERO") + 0) + ( ;; inside curly brackets + (and css-curly-parsed + (not block-ending-line) + (setq css-parsed-relevant + (css-pc-get-relevant + css-curly-parsed point)) + (not (eq (nth 2 css-parsed-relevant) + 'nested-selector))) + (css-debug-msg "C") + (+ css-indent-offset + (save-excursion + (css-go-up) + (current-indentation)) + (if (and (not (equal (line-number-at-pos + (car css-parsed-relevant)) + (line-number-at-pos))) + (css-pc-inside-statement + css-curly-parsed point)) + css-indent-offset 0))) + ( ;; Inside parentheses, closing brackets + t + (css-debug-msg "P") + (+ (save-excursion + (css-go-up) + (current-indentation)) + (if block-ending-line + 0 css-indent-offset)))))) + (error ;; My best error-less guess + (css-debug-msg "Err") + (* (car (syntax-ppss)) + css-indent-offset))))) (defun css-indent-line () "Indent current line according to CSS indentation rules." (interactive) - (let* ((savep (point)) - (forward-sexp-function nil) - (indent (condition-case nil - (save-excursion - (forward-line 0) - (skip-chars-forward " \t") - (if (>= (point) savep) (setq savep nil)) - (css-indent-calculate)) - (error nil)))) - (if (not (numberp indent)) 'noindent - (if savep - (save-excursion (indent-line-to indent)) - (indent-line-to indent))))) + (save-excursion + (indent-line-to (css-indent-calculate))) + (when (< (current-column) (current-indentation)) + (back-to-indentation))) + +(defcustom css-indent-offset 4 + "Basic size of one indentation step." + :version "22.2" + :type 'integer + :group 'css) (defun css-current-defun-name () "Return the name of the CSS section at point, or nil." (save-excursion (let ((max (max (point-min) (- (point) 1600)))) ; approx 20 lines back (when (search-backward "{" max t) - (skip-chars-backward " \t\r\n") - (beginning-of-line) - (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") - (match-string-no-properties 1)))))) + (skip-chars-backward " \t\r\n") + (beginning-of-line) + (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") + (match-string-no-properties 1)))))) (provide 'css-mode) ;;; css-mode.el ends here \ No newline at end of file On Tue, Jan 15, 2013 at 7:32 PM, E Sabof wrote: > Here is a patch, including a more advanced test case. In the end there is > a "failing" section - although I haven't seen anyone breaking at spaces. > > There is a varaiable called css-colon - the default is ":". If set to ": > ", it will also indent statements like this in SASS (a CSS pre-processor) > > a { &:hover, &:active { background: green; } } > > However, it will no longer correctly indent statements like this: > > background:#000, /* no space */ url('image.png'); > > If I manage to fix the "breaking at spaces" case, I'll send another patch. > > Evgeni > > New css-mode.css diff --git a/css-mode.css b/css-mode.css new file mode > 100644 index 0000000..40a732f --- /dev/null +++ b/css-mode.css @@ -0,0 > +1,86 @@ +#top_menu .button.active, +#top_menu .button.active:active { + > background-image: url('images/header_button_active.png'); + cursor: > default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Comment */ +} > +#top_menu .button.active, +#top_menu .button.active:active +{ + /* Comment > */ + background-image: url('images/header_button_active.png'); + cursor: > default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Multiline + > comment1 */ + /* Multiline + * comment2 */ +} +/* Multiline + comment1 */ > +/* Multiline + * comment2 */ +#glass { + z-index: 2; + position: absolute; > + top: -112px; + left: 0; + right: 0; + margin: 0 0 0 0; + margin: + 0 0 0 > 0; + text-shadow: + 1px 1px #FDE31D, + -1px -1px #B36300; + height: 140px; > + background-image: url('images/honey_blurred2.png'); + background-image: > url( + 'images/honey_blurred2.png'); + background-image: + #fff, + > url('images/honey_blurred2.png'), + url('images/honey_blurred2.png'); + > background-image: + #fff, + /* #fff, */ + url('images/honey_blurred2.png'); > + background-image: #fff, + url('images/honey_blurred2.png'); + > -webkit-mask-image: + -webkit-gradient( + linear, + left top, + /* left > bottom, */ + left bottom, + color-stop( + 1, + rgba(0,0,0,0.2) + ), + > color-stop(1, + rgba(0,0,0,0.2) + ), + /* comment */ + color-stop(0.7, > rgba(0,0,0,.0)), + color-stop + ( + 0.7, rgba(0,0,0,.0) + ) + /* comment*/ > ); + background-repeat: repeat-x; + background-position: center top; + > background-attachment: fixed; } + +#failing { + margin: 0 + 0 + 0 + 0; + > margin: + 0 + 0 + 0 + 0; +} \ No newline at end of file Modified > css-mode.el diff --git a/css-mode.el b/css-mode.el index 1abe9a8..44682e1 > 100644 --- a/css-mode.el +++ b/css-mode.el @@ -33,6 +33,8 @@ ;;; Code: > +(require 'cl-lib) + (defgroup css nil "Cascading Style Sheets (CSS) > editing mode." :group 'languages) @@ -92,7 +94,6 @@ (t nil))) elems)) - > (defun css-extract-props-and-vals () (with-temp-buffer > (url-insert-file-contents "http://www.w3.org/TR/CSS21/propidx.html") @@ > -122,7 +123,7 @@ (defconst css-pseudo-ids '("active" "after" "before" > "first" "first-child" "first-letter" "first-line" - "focus" "hover" "lang" > "left" "link" "right" "visited") + "focus" "hover" "lang" "last-child" > "left" "link" "right" "visited") "Identifiers for pseudo-elements and > pseudo-classes.") (defconst css-at-ids @@ -264,8 +265,8 @@ > '(css-font-lock-keywords nil t)) ;;;###autoload -(define-derived-mode > css-mode fundamental-mode "CSS" - "Major mode to edit Cascading Style > Sheets." +(define-derived-mode css-mode fundamental-mode + "CSS" "Major > mode to edit Cascading Style Sheets." (setq-local font-lock-defaults > css-font-lock-defaults) (setq-local comment-start "/*") (setq-local > comment-start-skip "/\\*+[ \t]*") @@ -276,6 +277,8 @@ (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) + (setq-local beginning-of-defun-function > 'css-beginning-of-defun) + (setq-local end-of-defun-function > 'css-end-of-defun) (when css-electric-keys (let ((fc (make-char-table > 'auto-fill-chars))) (set-char-table-parent fc auto-fill-chars) @@ -394,102 > +397,178 @@ ;; FIXME: We should also skip punctuation. (not (memq > (char-after) '(?\; ?\}))))))))))) -(defun css-indent-calculate-virtual () - > (if (or (save-excursion (skip-chars-backward " \t") (bolp)) - (if > (looking-at "\\s(") - (save-excursion - (forward-char 1) > (skip-chars-forward " \t") - (not (or (eolp) (looking-at > comment-start-skip)))))) - (current-column) - (css-indent-calculate))) > +(defun css-comment-line-p () + (interactive) + (cond ( (save-excursion + > (back-to-indentation) + (looking-at "/\\*")) + 1 ) + ( (nth 4 > (syntax-ppss)) + t))) + +(defun css-beginning-of-defun (&optional arg) + > (unless arg (setq arg 1)) + (when (progn + ;; What for? + (unless (zerop > (current-column)) + (end-of-line)) + (re-search-backward "^[^\n ].+{[ ]?$" > nil t arg)) + (while (save-excursion + (and (zerop (forward-line -1)) + > (string-match-p + "^[^}[:space:]/]" + (buffer-substring + > (line-beginning-position) + (line-end-position))))) + (forward-line -1)))) > + +(defun css-end-of-defun (&optional arg) + (interactive) + (unless arg > (setq arg 1)) + (ignore-errors + (when (cl-plusp (first (syntax-ppss))) + > (css-beginning-of-defun)) + (progn + (search-forward "{" nil t arg) + > (backward-char) + (forward-sexp) + (ignore-errors + (forward-char))) + t)) > + +;; To make writing derived modes easier. Ex. SASS also supports // type > comments +(defvar css-comment-line-p-function 'css-comment-line-p + "Should > return 1 if at the beginning of a comment, t if inside.") + +(defun > css--goto-prev-struct-line () + (while (and (zerop (forward-line -1)) + > (funcall css-comment-line-p-function)))) + +(defvar css-debug nil) + > +(defun css-indent-debug-msg (name) + (when css-debug + (message "%s" > name))) + +(defun css-visible-end-of-line () + (save-excursion + > (end-of-line) + (skip-syntax-backward + " " (line-beginning-position)) + > (point))) -(defcustom css-indent-offset 4 - "Basic size of one indentation > step." - :version "22.2" - :type 'integer - :group 'css) +(defun > css-indentation-end-pos () + (save-excursion + (back-to-indentation) + > (point))) -(defun css-indent-calculate () - (let ((ppss (syntax-ppss)) - > pos) - (with-syntax-table css-navigation-syntax-table - (save-excursion - > (cond - ;; Inside a string. - ((nth 3 ppss) 'noindent) - ;; Inside a > comment. - ((nth 4 ppss) - (setq pos (point)) - (forward-line -1) - > (skip-chars-forward " \t") - (if (>= (nth 8 ppss) (point)) - (progn - > (goto-char (nth 8 ppss)) - (if (eq (char-after pos) ?*) - (forward-char 1) > - (if (not (looking-at comment-start-skip)) - (error "Internal css-mode > error") - (goto-char (match-end 0)))) - (current-column)) - (if (and (eq > (char-after pos) ?*) (eq (char-after) ?*)) - (current-column) - ;; > 'noindent - (current-column) - ))) - ;; In normal code. - (t - (or - (when > (looking-at "\\s)") - (forward-char 1) - (backward-sexp 1) - > (css-indent-calculate-virtual)) - (when (looking-at comment-start-skip) - > (forward-comment (point-max)) - (css-indent-calculate)) - (when > (save-excursion (forward-comment (- (point-max))) - (setq pos (point)) - > (eq (char-syntax (preceding-char)) ?\()) - (goto-char (1- pos)) - (if (not > (looking-at "\\s([ \t]*")) - (error "Internal css-mode error") - (if (or > (memq (char-after (match-end 0)) '(?\n nil)) - (save-excursion (goto-char > (match-end 0)) - (looking-at comment-start-skip))) - (+ > (css-indent-calculate-virtual) css-indent-offset) - (progn (goto-char > (match-end 0)) (current-column))))) - (progn - (css-backward-sexp 1) - (if > (looking-at "\\s(") - (css-indent-calculate) - > (css-indent-calculate-virtual)))))))))) +(defun > css-current-character-indentation () + "Like (current-indentation), but > counts tabs as single characters." + (save-excursion + > (back-to-indentation) + (- (point) (line-beginning-position)))) + +(defvar > css-colon ":" + "A dervied mode for SASS or LESS might want to set this to > +\": \", to make nested pseudo-classes work.") +(defun css-indent-calculate > () + ;; If I go to the beginning of line, MC stops working + > (back-to-indentation) + (with-syntax-table css-navigation-syntax-table + > (let* (psl-indent + psl-last-char + psl-first-char + ( psl + > (save-excursion + (css--goto-prev-struct-line) + (setq psl-indent > (current-indentation)) + (setq psl-last-char (char-before > (css-visible-end-of-line))) + (setq psl-first-char (char-after > (css-indentation-end-pos))) + (buffer-substring + (line-beginning-position) > + (line-end-position)))) + ( psl-closing-brackets + (+ (cl-count ?} psl) + > (cl-count ?\) psl))) + ( psl-open-brackets (+ (cl-count ?{ psl) (cl-count > ?\( psl))) + ( psl-has-colon (cl-plusp (cl-count ?: psl))) + (ppss > (syntax-ppss)) + previous-comment-indent + previous-line-was-comment + pos) > + (cond ( ;; Inside a multiline comment + ( eq (funcall > css-comment-line-p-function) t) + (css-indent-debug-msg "MC") + > (save-excursion + (nth 4 ppss) + (setq pos (point)) + (forward-line -1) + > (skip-chars-forward " \t") + (if (>= (nth 8 ppss) (point)) + (progn + > (goto-char (nth 8 ppss)) + (if (eq (char-after pos) ?*) + (forward-char 1) > + (if (not (looking-at comment-start-skip)) + (error "Internal css-mode > error") + (goto-char (match-end 0)))) + (current-column)) + > (current-column)))) + ( ;; If "outside" indent to 0 + (zerop (nth 0 ppss)) > + (css-indent-debug-msg "ZERO") + 0) + ( ;; Not-first member of comma > ending lines + (and (not (cl-search css-colon psl)) + (equal psl-last-char > ?\, ) + (= psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg > "MCB") + psl-indent) + ( ;; Line after beginning of comma block + (and > (member psl-last-char '( ?: ?\, ) ) + (= psl-open-brackets > psl-closing-brackets)) + (css-indent-debug-msg "LABOC") + (+ psl-indent > css-indent-offset)) + ( ;; Default, based on nesting level + t + > (css-indent-debug-msg "LAST") + (let (( parent-indent + (save-excursion + > (backward-up-list) + (css-current-character-indentation))) + ( > block-ending-line + (member (char-after (css-indentation-end-pos)) + '( ?\} > ?\) ) ))) + (+ parent-indent + (* (+ (if block-ending-line -1 0) + 1) + > css-indent-offset)))) + )))) (defun css-indent-line () "Indent current line > according to CSS indentation rules." (interactive) - (let* ((savep (point)) > - (forward-sexp-function nil) - (indent (condition-case nil - > (save-excursion - (forward-line 0) - (skip-chars-forward " \t") - (if (>= > (point) savep) (setq savep nil)) - (css-indent-calculate)) - (error nil)))) > - (if (not (numberp indent)) 'noindent - (if savep - (save-excursion > (indent-line-to indent)) - (indent-line-to indent))))) + (save-excursion + > (indent-line-to (css-indent-calculate))) + (when (< (current-column) > (current-indentation)) + (back-to-indentation))) + +(defcustom > css-indent-offset 4 + "Basic size of one indentation step." + :version > "22.2" + :type 'integer + :group 'css) (defun css-current-defun-name () > "Return the name of the CSS section at point, or nil." (save-excursion (let > ((max (max (point-min) (- (point) 1600)))) ; approx 20 lines back (when > (search-backward "{" max t) - (skip-chars-backward " \t\r\n") - > (beginning-of-line) - (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") > - (match-string-no-properties 1)))))) + (skip-chars-backward " \t\r\n") + > (beginning-of-line) + (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") > + (match-string-no-properties 1)))))) (provide 'css-mode) ;;; css-mode.el > ends here \ No newline at end of file > > > On Tue, Jan 15, 2013 at 5:00 AM, Stefan Monnier wrote: > >> > I've written a new indenter for CSS, which fixes issues with mulitline >> > statements following a colon, and comments: >> >> Interesting, I don't use CSS myself very much, but I've toyed with an >> SMIE indenter for css-mode (see below). >> >> > body { >> > color: #333; >> > font: 15px "Helvetica Neue", >> > Helvetica, >> > Arial, >> > "Nimbus Sans L", >> > sans-serif; >> > font-weight: 300; >> > line-height: 1.625; >> > a { /* It also handles SCSS */ >> > font: 15px "Helvetica Neue", >> > Helvetica, >> > Arial, >> > "Nimbus Sans L", >> > sans-serif; >> > /* Some comment */ >> > } >> > /* Some comment at the end of a block */ >> > } >> >> I've tried it on the above test case and the SMIE code seems to handle >> it OK (tho differently), with the main exception being the >> comment-at-end-of-block, which is probably a general problem which >> should be fixed in smie.el (probably in smie-indent-comment). >> >> But I have basically never used/tested my code, so... >> >> > I wondered whether this functionality could be integrated into Emacs. >> > https://github.com/sabof/es-css-mode >> > https://github.com/sabof/es-lib (it takes some functions from it) >> >> If you could provide a patch against css-mode.el, that would be more >> convenient. Also it would be good to add a good set of test cases (in >> the form of a new file test/indent/css-mode.css). >> >> >> Stefan >> >> >> === modified file 'lisp/textmodes/css-mode.el' >> --- lisp/textmodes/css-mode.el 2013-01-02 16:13:04 +0000 >> +++ lisp/textmodes/css-mode.el 2013-01-15 04:53:03 +0000 >> @@ -263,6 +263,22 @@ >> (defvar css-font-lock-defaults >> '(css-font-lock-keywords nil t)) >> >> +(defcustom css-indent-offset 4 >> + "Basic size of one indentation step." >> + :version "22.2" >> + :type 'integer) >> + >> +(defconst css-smie-grammar >> + (smie-prec2->grammar >> + (smie-precs->prec2 '((assoc ";") (left ":") (assoc ","))))) >> + >> +(defun css-smie-rules (kind token) >> + (pcase (cons kind token) >> + (`(:elem . basic) css-indent-offset) >> + (`(:elem . arg) 0) >> + (`(:before . "{") (if (smie-rule-hanging-p) >> + (smie-rule-parent 0))))) >> + >> ;;;###autoload >> (define-derived-mode css-mode fundamental-mode "CSS" >> "Major mode to edit Cascading Style Sheets." >> @@ -271,11 +287,11 @@ >> (setq-local comment-start-skip "/\\*+[ \t]*") >> (setq-local comment-end "*/") >> (setq-local comment-end-skip "[ \t]*\\*+/") >> - (setq-local forward-sexp-function 'css-forward-sexp) >> (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) >> (when css-electric-keys >> (let ((fc (make-char-table 'auto-fill-chars))) >> (set-char-table-parent fc auto-fill-chars) >> @@ -355,131 +371,6 @@ >> ;; Don't use the default filling code. >> t))))))) >> >> -;;; Navigation and indentation. >> - >> -(defconst css-navigation-syntax-table >> - (let ((st (make-syntax-table css-mode-syntax-table))) >> - (map-char-table (lambda (c v) >> - ;; Turn punctuation (code = 1) into symbol (code = >> 1). >> - (if (eq (car-safe v) 1) >> - (set-char-table-range st c (cons 3 (cdr v))))) >> - st) >> - st)) >> - >> -(defun css-backward-sexp (n) >> - (let ((forward-sexp-function nil)) >> - (if (< n 0) (css-forward-sexp (- n)) >> - (while (> n 0) >> - (setq n (1- n)) >> - (forward-comment (- (point-max))) >> - (if (not (eq (char-before) ?\;)) >> - (backward-sexp 1) >> - (while (progn (backward-sexp 1) >> - (save-excursion >> - (forward-comment (- (point-max))) >> - ;; FIXME: We should also skip punctuation. >> - (not (or (bobp) (memq (char-before) '(?\; >> ?\{)))))))))))) >> - >> -(defun css-forward-sexp (n) >> - (let ((forward-sexp-function nil)) >> - (if (< n 0) (css-backward-sexp (- n)) >> - (while (> n 0) >> - (setq n (1- n)) >> - (forward-comment (point-max)) >> - (if (not (eq (char-after) ?\;)) >> - (forward-sexp 1) >> - (while (progn (forward-sexp 1) >> - (save-excursion >> - (forward-comment (point-max)) >> - ;; FIXME: We should also skip punctuation. >> - (not (memq (char-after) '(?\; ?\}))))))))))) >> - >> -(defun css-indent-calculate-virtual () >> - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) >> - (if (looking-at "\\s(") >> - (save-excursion >> - (forward-char 1) (skip-chars-forward " \t") >> - (not (or (eolp) (looking-at comment-start-skip)))))) >> - (current-column) >> - (css-indent-calculate))) >> - >> -(defcustom css-indent-offset 4 >> - "Basic size of one indentation step." >> - :version "22.2" >> - :type 'integer >> - :group 'css) >> - >> -(defun css-indent-calculate () >> - (let ((ppss (syntax-ppss)) >> - pos) >> - (with-syntax-table css-navigation-syntax-table >> - (save-excursion >> - (cond >> - ;; Inside a string. >> - ((nth 3 ppss) 'noindent) >> - ;; Inside a comment. >> - ((nth 4 ppss) >> - (setq pos (point)) >> - (forward-line -1) >> - (skip-chars-forward " \t") >> - (if (>= (nth 8 ppss) (point)) >> - (progn >> - (goto-char (nth 8 ppss)) >> - (if (eq (char-after pos) ?*) >> - (forward-char 1) >> - (if (not (looking-at comment-start-skip)) >> - (error "Internal css-mode error") >> - (goto-char (match-end 0)))) >> - (current-column)) >> - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) >> - (current-column) >> - ;; 'noindent >> - (current-column) >> - ))) >> - ;; In normal code. >> - (t >> - (or >> - (when (looking-at "\\s)") >> - (forward-char 1) >> - (backward-sexp 1) >> - (css-indent-calculate-virtual)) >> - (when (looking-at comment-start-skip) >> - (forward-comment (point-max)) >> - (css-indent-calculate)) >> - (when (save-excursion (forward-comment (- (point-max))) >> - (setq pos (point)) >> - (eq (char-syntax (preceding-char)) ?\()) >> - (goto-char (1- pos)) >> - (if (not (looking-at "\\s([ \t]*")) >> - (error "Internal css-mode error") >> - (if (or (memq (char-after (match-end 0)) '(?\n nil)) >> - (save-excursion (goto-char (match-end 0)) >> - (looking-at comment-start-skip))) >> - (+ (css-indent-calculate-virtual) css-indent-offset) >> - (progn (goto-char (match-end 0)) (current-column))))) >> - (progn >> - (css-backward-sexp 1) >> - (if (looking-at "\\s(") >> - (css-indent-calculate) >> - (css-indent-calculate-virtual)))))))))) >> - >> - >> -(defun css-indent-line () >> - "Indent current line according to CSS indentation rules." >> - (interactive) >> - (let* ((savep (point)) >> - (forward-sexp-function nil) >> - (indent (condition-case nil >> - (save-excursion >> - (forward-line 0) >> - (skip-chars-forward " \t") >> - (if (>= (point) savep) (setq savep nil)) >> - (css-indent-calculate)) >> - (error nil)))) >> - (if (not (numberp indent)) 'noindent >> - (if savep >> - (save-excursion (indent-line-to indent)) >> - (indent-line-to indent))))) >> >> (defun css-current-defun-name () >> "Return the name of the CSS section at point, or nil." >> >> > --20cf3074d594ecfdb804d370ebd7 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
I've rewritten the indenter - this time I&#= 39;ve added a parser for statements within curly brackets, so there is a lo= t less hackery. I've also added some more tests cases.

Evgeni


New =A0= =A0 =A0 =A0css-mode.css
diff --git a/css-mode.css b/css-mode.css=
new file mode 100644
index 0000000..f101971
= --- /dev/null
+++ b/css-mode.css
@@ -0,0 +1,230 @@
+#top_menu .b= utton.active,
+#top_menu .button.active:active {
+ =A0 = =A0background-image: url('images/header_button_active.png');
<= div> + =A0 =A0cursor: default;
+ =A0 =A0color: #999;
+ =A0 = =A0text-shadow: 1px 1px 2px #111;
+ =A0 =A0/* Comment */
+}
+
+#top_menu .button.active,
+#top_menu = .button.active:active
+{
+ =A0 =A0/* Comment */
+ =A0 =A0background-imag= e: url('images/header_button_active.png');
+ =A0 =A0curso= r: default;
+ =A0 =A0color: #999;
+ =A0 =A0text-shadow:= 1px 1px 2px #111;
+ =A0 =A0/* Multiline
+ =A0 =A0 =A0 comment1 */
+ = =A0 =A0/* Multiline
+ =A0 =A0 * comment2 */
+}
+/* Multiline
+ =A0 comment1 */
+/* Multiline
+ * comment2 */
+#glass {
+ =A0 =A0z-index: 2;
+ =A0 =A0position: = absolute;
+ =A0 =A0top: -112px;
+ =A0 =A0left: 0;
=
+ =A0 =A0right: 0;
+ =A0 =A0margin: 0 0 0 0;
+ =A0= =A0margin:
+ =A0 =A0 =A0 =A00 0 0 0;
+ =A0 =A0text-shadow:
+ =A0 =A0 =A0 =A01px 1px #FDE31D,
+ =A0 =A0 =A0 =A0-1px -1px #B36300;
+ =A0 =A0height: 140px;=
+ =A0 =A0background-image: url('images/honey_blurred2.png= 9;);
+ =A0 =A0background-image: url(
+ =A0 =A0 =A0 =A0'images/honey_blurred2.png');
+ =A0= =A0background-image:
+ =A0 =A0 =A0 =A0#fff,
+ =A0 =A0 = =A0 =A0url('images/honey_blurred2.png'),
+ =A0 =A0 =A0 = =A0url('images/honey_blurred2.png');
+ =A0 =A0background-image:
+ =A0 =A0 =A0 =A0#fff,
= + =A0 =A0 =A0 =A0/* #fff, */
+ =A0 =A0 =A0 =A0url('images/hon= ey_blurred2.png');
+ =A0 =A0background-image: #fff,
+ =A0 =A0 =A0 =A0url('images/honey_blurred2.png');
+ =A0 =A0-webkit-mask-image:
+ =A0 =A0 =A0 =A0-webkit-gradie= nt(
+ =A0 =A0 =A0 =A0 =A0 =A0linear,
+ =A0 =A0 =A0 =A0 = =A0 =A0left top,
+ =A0 =A0 =A0 =A0 =A0 =A0/* left bottom, */
+ =A0 =A0 =A0 =A0 =A0 =A0left bottom,
+ =A0 =A0 =A0 =A0 =A0= =A0color-stop(
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A01,
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0rgba(0,0,0,0.2)
+ =A0 =A0 =A0 =A0 =A0 =A0),
= + =A0 =A0 =A0 =A0 =A0 =A0color-stop(1,
+
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0rgba(0,0,0,0.2)
+ =A0 =A0 =A0 =A0 =A0 =A0),
+ =A0 =A0 =A0 =A0 =A0 =A0/* comment */
+ =A0 =A0 =A0 =A0 =A0 =A0c= olor-stop(0.7, rgba(0,0,0,.0)),
+ =A0 =A0 =A0 =A0 =A0 =A0color-st= op
+ =A0 =A0 =A0 =A0 =A0 =A0(
+ =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A00.7, rgba(0,0,0,.0)
+
+ =A0 =A0 =A0 =A0 =A0 =A0= )
+ =A0 =A0 =A0 =A0 =A0 =A0/* comment*/ );
+ =A0 =A0background= -repeat: repeat-x;
+ =A0 =A0background-position: center top;
+ =A0 =A0background-attachment: fixed; }
+
+#glas= s {
+ =A0 =A0margin:
+ =A0 =A0 =A0 =A0/* =A0 =A0 0 0 0 0; */
+ =A0 =A0 =A0 =A0/* = text-shadow: */
+ =A0 =A0 =A0 =A01px 1px #FDE31D,
+ =A0= =A0 =A0 =A0-1px -1px #B36300;
+ =A0 =A0height: 140px;
= + =A0 =A0background-image: url('images/honey_blurred2.png');
+ =A0 =A0/* background-image: url( */
+ =A0 =A0/* =A0 =A0 &#= 39;images/honey_blurred2.png'); */
+
+ =A0 =A0backg= round-image:
+ =A0 =A0 =A0 =A0#fff,
+ =A0 =A0 =A0 =A0ur= l('images/honey_blurred2.png'),
+ =A0 =A0 =A0 =A0url('images/honey_blurred2.png');
+= =A0 =A0background-image:
+ =A0 =A0 =A0 =A0#fff,
+ =A0 = =A0 =A0 =A0/* #fff, */
+ =A0 =A0 =A0 =A0/* =A0 =A0 url('image= s/honey_blurred2.png'); */
+ =A0 =A0 =A0 =A0/* background-image: #fff, */
+ =A0 =A0 =A0= =A0url('images/honey_blurred2.png');
+ =A0 =A0-webkit-ma= sk-image:
+ =A0 =A0 =A0 =A0-webkit-gradient(
+ =A0 =A0 = =A0 =A0 =A0 =A0linear,
+ =A0 =A0 =A0 =A0 =A0 =A0left top,
+ =A0 =A0 =A0 =A0 =A0 =A0/* left bottom, */
+ =A0 =A0 =A0 = =A0 =A0 =A0left bottom,
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop(
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* 1, */
+ =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0/* rgba(0,0,0,0.2) */
+ =A0 =A0 =A0 =A0 =A0 =A0),=
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop(1,
+ =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0/* com */
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rgba(0,0,0= ,0.2)
+
+ =A0 =A0 =A0 =A0 =A0 =A0),
+ =A0 =A0= =A0 =A0 =A0 =A0/* comment */
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop= (0.7, rgba(0,0,0,.0)),
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop
+ =A0 =A0 =A0 =A0 =A0 = =A0(
+
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00.7, rgba(0,0,0= ,.0)
+ =A0 =A0 =A0 =A0 =A0 =A0)
+ =A0 =A0 =A0 =A0 =A0 = =A0/* comment*/);
+ =A0 =A0-webkit-mask-image:
+ =A0 =A0 =A0 =A0/* -webkit- */gradient(
+ =A0 =A0 =A0 =A0 =A0 = =A0linear,
+ =A0 =A0 =A0 =A0 =A0 =A0left /* top */,
+ = =A0 =A0 =A0 =A0 =A0 =A0/* left =A0*/bottom,
+ =A0 =A0 =A0 =A0 =A0= =A0left bottom,
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop(
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* 1, */
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0/* rgba(0,0,0,0.2) */
+ =A0 =A0 =A0 =A0 =A0 =A0),<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop(1,
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0/* com */
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rgb= a(0,0,0,0.2)
+
+ =A0 =A0 =A0 =A0 =A0 =A0),
+ =A0 =A0 =A0 =A0 = =A0 =A0/* comment */
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop(0.7/* , = rgba(0,0,0,.0) */
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0, rgba(0,0,0,.= 0) ),
+ =A0 =A0 =A0 =A0 =A0 =A0color-stop
+ =A0 =A0 =A0 =A0 =A0 =A0(
+
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A00.7, rgba(0,0,0,.0)
+ =A0 =A0 =A0 =A0 =A0 =A0)
+= =A0 =A0 =A0 =A0 =A0 =A0/* comment*/);
+ =A0 =A0color: black,
+ =A0 =A0 =A0 =A0/* red */,
+ =A0 =A0 =A0 =A0blue;
+ =A0 =A0/* -webkit-mask-image: */
+ =A0 =A0background:
+ =A0 =A0 =A0 =A0-webkit-gradient(
+ =A0 =A0 =A0 =A0 =A0 = =A0/* com */
+ =A0 =A0);
+ =A0 =A0-webkit-mask-image: -= webkit-gradient(
+ =A0 =A0 =A0 =A0/* Forgivable? Better? */
+ =A0 =A0),
+ =A0 =A0 =A0 =A0-webkit-mask-image(
+= =A0 =A0 =A0 =A0 =A0 =A0/* Back on track */
+ =A0 =A0 =A0 =A0);
+ =A0 =A0background-attachment: fixed
+ =A0 =A0/* sdfsdf= */
+}
+
+p:nth-child(2) {
+ =A0 =A0margin:
+ =A0 =A0 =A0 =A00
+ =A0 =A0 =A0 =A00
+ =A0 =A0 =A0 =A00
+ =A0 = =A0 =A0 =A00;
+ =A0 =A0margin: 0 0
+ =A0 =A0 =A0 =A00
+ =A0 =A0 =A0 =A00;
+
+ =A0 =A0/* comment */
+
+ =A0 =A0text-shadow:1px 1px #FDE31D, /* no space */
=
+ =A0 =A0 =A0 =A0-1px -1px #B36300;
+}
+
+p:nth-child
+(
+ =A0 =A02
+)
+{
+ =A0 =A0height: 2px
+}
+
+#field_message {
+ =A0 =A0width: 1= 00%;
+ =A0 =A0display: block;
+ =A0 =A0-webkit-box-sizi= ng: border-box; /* Safari/Chrome, other WebKit */
+ =A0 =A0-moz-b= ox-sizing: border-box; =A0 =A0/* Firefox, other Gecko */
+ =A0 =A0box-sizing: border-box; =A0 =A0 =A0 =A0 /* Opera/IE 8+ */
+ =A0 =A0/* resize: vertical; */
+ =A0 =A0resize: none;
+ =A0 =A0height: 160px
+}
+
+
+some {
+
+}
+
+/* SASS */
+
+.so= me {
+ =A0 =A0/* resize: vertical; */
+ =A0 =A0resize: = none;
+
+ =A0 =A0height: 160px;
+ =A0 =A0.oth= er,
+ =A0 =A0.another,
+ =A0 =A0&:a,
+ =A0 =A0#id {
+ =A0 =A0 =A0 =A0/* resize: vertical; */
+ =A0 =A0 =A0 =A0= resize: none;
+
+ =A0 =A0 =A0 =A0height: 160px;
+ =A0 =A0}
+ =A0 =A0/* Comment */
+ =A0 =A0resize: none;
+ =A0 =A0height: 160px;
+ = =A0 =A0/* Comment */
+}
+
+
+/* Loc= al Variables: */
+/* css-debug: t */
+/* End: */
<= div>\ No newline at end of file
Modified =A0 css-mo= de.el
diff --git a/css-mode.el b/css-mode.el
index 1abe= 9a8..9f3a786 100644
--- a/css-mode.el
+++ b/css-mode.el=
@@ -31,12 +31,95 @@
=A0;; - completion
=A0;; - fix= font-lock errors with multi-line selectors
=A0
+;;; TO= DO:
+;; =A0extra empty line indentation
+
=A0= ;;; Code:
=A0
+(require 'cl-lib)
+
=A0(defgrou= p css nil
=A0 =A0"Cascading Style Sheets (CSS) editing mode.= "
=A0 =A0:group 'languages)
=A0
+;; = Debugging
+
+(defvar css-debug-overlays nil)
+
+(d= efun css-debug-overlay (beginning end color)
+ =A0(let ((overlay = (make-overlay beginning end)))
+ =A0 =A0(overlay-put overlay '= ;face `(:background ,color))
+ =A0 =A0(push overlay css-debug-overlays)))
+
+(d= efvar css-debug nil)
+
+(defun css-debug-msg (name)
+ =A0(when css-debug
+ =A0 =A0(message "%s" name= )))
+
+(defun css-debug-goto-root-declaration ()
+ =A0= (let* (( ppss (syntax-ppss))
+ =A0 =A0 =A0 =A0 ( depth (nth 0 =A0= ppss)))
+ =A0 =A0(when (nth 3 ppss)
+ =A0 =A0 =A0(goto-= char (nth 8 ppss)))
+ =A0 =A0(while (and (cl-plusp depth)
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0(not (equal (char-after) ?\{ )))
+ =A0 =A0 =A0(up-list= -1)
+ =A0 =A0 =A0(cl-decf depth))))
+
+(defu= n css-debug-parser-current ()
+ =A0(interactive)
+ =A0(mapc 'delete-overlay css-debug-= overlays)
+ =A0(let* (( point
+ =A0 =A0 =A0 =A0 =A0 (sa= ve-excursion
+ =A0 =A0 =A0 =A0 =A0 =A0 (back-to-indentation)
+ =A0 =A0 =A0 =A0 =A0 =A0 (point)))
+ =A0 =A0 =A0 =A0 ( parsed
+ =A0 =A0 =A0 =A0 =A0 (save-excur= sion
+ =A0 =A0 =A0 =A0 =A0 =A0 (css-debug-goto-root-declaration)<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 (css-parse-curly)))
+ =A0 =A0= =A0 =A0 ( relevant
+ =A0 =A0 =A0 =A0 =A0 (css-pc-get-relevant pa= rsed point)))
+ =A0 =A0(css-debug-overlay
+ =A0 =A0 (car relevant)
+ =A0 =A0 (cadr relevant)
+ =A0 =A0 "DarkRed")
=
+ =A0 =A0nil))
+
+(defun css-debug-highight-parsed= (parsed)
+ =A0(mapc 'delete-overlay css-debug-overlays)
+ =A0(cl-mapc = (lambda (item)
+ =A0 =A0 =A0 =A0 =A0 =A0 (css-debug-overlay
=
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0(car item)
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0(cadr item)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0(case (caddr = item)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0('nested-selector =A0"DarkGr= een")
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0('comment =A0 =A0= =A0 =A0 =A0"SaddleBrown")
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0( t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"DarkRed"))))
+ =A0 =A0 =A0 =A0 =A0 parsed))
+
+(defun css-debug-pars= er-all ()
+ =A0(interactive)
+ =A0(let* (( parsed
=
+ =A0 =A0 =A0 =A0 =A0 (save-excursion
+ =A0 =A0 =A0 =A0 =A0 = =A0 (css-debug-goto-root-declaration)
+ =A0 =A0 =A0 =A0 =A0 =A0 (css-parse-curly))))
+ =A0 =A0(css= -debug-highight-parsed
+ =A0 =A0 parsed)
+ =A0 =A0nil))=
+
+(defun css-debug-parser-inside ()
+ =A0(i= nteractive)
+ =A0(let* (( parsed
+ =A0 =A0 =A0 =A0 =A0 (save-excursion
<= div>+ =A0 =A0 =A0 =A0 =A0 =A0 (css-debug-goto-root-declaration)
+= =A0 =A0 =A0 =A0 =A0 =A0 (css-parse-curly)))
+ =A0 =A0 =A0 =A0 ( = inside
+ =A0 =A0 =A0 =A0 =A0 (css-pc-inside-statement
+ =A0 =A0 =A0 =A0 =A0 =A0parsed (point))))
+ =A0 =A0(message= "P %s" inside)))
+
+;; EOF Debugging
=A0
=A0(defun css-extract-keyword-list (res)
=A0 =A0= (with-temp-buffer
@@ -92,7 +175,6 @@
=A0 =A0 =A0 =A0 (t nil)))
=A0 = =A0 =A0elems))
=A0
-
=A0(defun css-extract-pr= ops-and-vals ()
=A0 =A0(with-temp-buffer
=A0 =A0 =A0(ur= l-insert-file-contents "http://www.w3.org/TR/CSS21/propidx.html")
@@ -122,7 +204,7 @@
=A0
=A0(defconst css-pseudo-id= s
=A0 =A0'("active" "after" "before&= quot; "first" "first-child" "first-letter" &q= uot;first-line"
- =A0 =A0"focus" "hover" "lang" "le= ft" "link" "right" "visited")
= + =A0 =A0"focus" "hover" "lang" "last-ch= ild" "left" "link" "right" "visited= ")
=A0 =A0"Identifiers for pseudo-elements and pseudo-classes."= )
=A0
=A0(defconst css-at-ids
@@ -264,8 +346,= 8 @@
=A0 =A0'(css-font-lock-keywords nil t))
=A0
=A0;;;###autoload
-(define-derived-mode css-mode fundamental-mode "CSS"
<= div>- =A0"Major mode to edit Cascading Style Sheets."
+= (define-derived-mode css-mode fundamental-mode
+ =A0"CSS&quo= t; "Major mode to edit Cascading Style Sheets."
=A0 =A0(setq-local font-lock-defaults css-font-lock-defaults)
=A0 =A0(setq-local comment-start "/*")
=A0 =A0(setq-l= ocal comment-start-skip "/\\*+[ \t]*")
@@ -276,6 +358,8= @@
=A0 =A0(setq-local indent-line-function 'css-indent-line)
=A0 =A0(setq-local fill-paragraph-function 'css-fill-paragraph)
=
=A0 =A0(setq-local add-log-current-defun-function #'css-current-de= fun-name)
+ =A0(setq-local beginning-of-defun-function 'css-beginning-of-def= un)
+ =A0(setq-local end-of-defun-function 'css-end-of-defun)=
=A0 =A0(when css-electric-keys
=A0 =A0 =A0(let ((fc (m= ake-char-table 'auto-fill-chars)))
=A0 =A0 =A0 =A0(set-char-table-parent fc auto-fill-chars)
@@= -394,102 +478,188 @@
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0;; FIXME: We should also skip punctuation.
=A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (memq (char-after) '= ;(?\; ?\})))))))))))
=A0
-(defun css-indent-calculate-virtual ()
- =A0(= if (or (save-excursion (skip-chars-backward " \t") (bolp))
<= div>- =A0 =A0 =A0 =A0 =A0(if (looking-at "\\s(")
- =A0 = =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-char 1) (skip-chars-forward = " \t")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (or (eolp)= (looking-at comment-start-skip))))))
- =A0 =A0 =A0(current-colum= n)
- =A0 =A0(css-indent-calculate)))
-
-(defcustom css-indent-offset 4
- =A0"Basic= size of one indentation step."
- =A0:version "22.2&quo= t;
- =A0:type 'integer
- =A0:group 'css)
<= div> +(defun css-beginning-of-defun (&optional arg)
+ =A0(unless a= rg (setq arg 1))
+ =A0(when (progn
+ =A0 =A0 =A0 =A0 = =A0;; What for?
+ =A0 =A0 =A0 =A0 =A0(unless (zerop (current-colu= mn))
+ =A0 =A0 =A0 =A0 =A0 =A0(end-of-line))
+ =A0 =A0 =A0 =A0 =A0(re-search-backward "^[^\n ].+{[ ]?$" nil t arg))
+ = =A0 =A0(while (save-excursion
+ =A0 =A0 =A0 =A0 =A0 =A0 (and (zer= op (forward-line -1))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(string-match-p
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "^[^}[:space:]/]"
+ =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (buffer-substring
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0(line-beginning-position)
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(line-end-position)))))
+ =A0 =A0 =A0(forward-line -1))))
+
+(defun css-en= d-of-defun (&optional arg)
+ =A0(interactive)
+ =A0= (unless arg (setq arg 1))
+ =A0(ignore-errors
+ =A0 =A0= (when (cl-plusp (car (syntax-ppss)))
+ =A0 =A0 =A0(css-beginning-of-defun))
+ =A0 =A0(progn
=
+ =A0 =A0 =A0(search-forward "{" nil t arg)
+ =A0 = =A0 =A0(backward-char)
+ =A0 =A0 =A0(forward-sexp)
+ = =A0 =A0 =A0(ignore-errors
+ =A0 =A0 =A0 =A0(forward-char)))
+ =A0 =A0t))
+
<= div>+(defun css-go-up ()
+ =A0(let* (( ppss (syntax-ppss)))
=
+ =A0 =A0(when (or (nth 3 ppss) (nth 4 ppss))
+ =A0 =A0 =A0(= goto-char (nth 8 ppss)))
+ =A0 =A0(when (cl-plusp (nth 0 ppss))
+ =A0 =A0 =A0(up-list= -1))))
+
+(defmacro css-while-point-moving (&rest = rest)
+ =A0(let ((old-point (cl-gensym)))
+ =A0 =A0`(le= t (,old-point)
+ =A0 =A0 =A0 (while (not (equal (point) ,old-point))
+ =A0 = =A0 =A0 =A0 (setq ,old-point (point))
+ =A0 =A0 =A0 =A0 ,@rest)))= )
+
+(defun css-parse-curly ()
+ =A0(let (( s= tart (point))
+ =A0 =A0 =A0 =A0( indentation (current-indentation))
+ =A0 =A0 = =A0 =A0( end (save-excursion
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(fo= rward-sexp)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(point)))
= + =A0 =A0 =A0 =A0point result)
+ =A0 =A0(forward-char)
+ =A0 =A0(cl-loop named main-loop
+ =A0 =A0 =A0 =A0 =A0 =A0 = do
+ =A0 =A0 =A0 =A0 =A0 =A0 (skip-chars-forward "\n\t "= ; end)
+ =A0 =A0 =A0 =A0 =A0 =A0 (when (>=3D (point) (1- end))=
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 (cl-return-from main-loop))
+ =A0 =A0 =A0 =A0 =A0 =A0 (setq point (point))
+ =A0 =A0 =A0= =A0 =A0 =A0 (if (forward-comment 1)
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 (push (list point (point) 'comment) result)
+ =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 (progn
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 (cl-loop (unless (re-search-forward ";\\|{\\|}" end t)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(cl-retur= n-from main-loop))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0(unless (nth 4 (syntax-ppss))
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(cl-return)))
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 (cond ( (equal (char-before) ?\{ )
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (backward-char)<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (forward-se= xp)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (push (= list point (point) 'nested-selector) result))
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ( (equal (char-before) ?\} )
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (backward-char)<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-while-= point-moving
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0(skip-chars-backward "\n\t " start)
+ =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-comment -1))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (push (list poin= t (point) 'statement) result))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 ( t (push (list point (point) 'statement) result)))= )))
+ =A0 =A0(nreverse result)))
+
+(defun css-pc-get-relevant (parsed point)
+ =A0(car = (reverse (cl-remove-if (apply-partially '< point)
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0parsed :key 'car= ))))
+
+(defun css-pc-inside-statement (parsed point)
+ =A0(cl-some (lambda (item)
+ =A0 =A0 =A0 =A0 =A0 (and (<= ;=3D (car item) point)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(<=3D = point (cadr item))))
+ =A0 =A0 =A0 =A0 parsed))
=A0
=A0(defun css-indent-calculate ()
- =A0(let ((ppss (syntax-ppss))
- =A0 =A0 =A0 =A0pos)
<= div>- =A0 =A0(with-syntax-table css-navigation-syntax-table
- =A0= =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0(cond
- =A0 = =A0 =A0 =A0 ;; Inside a string.
- =A0 =A0 =A0 =A0 ((nth 3 ppss) 'noindent)
- =A0 =A0 =A0= =A0 ;; Inside a comment.
- =A0 =A0 =A0 =A0 ((nth 4 ppss)
- =A0 =A0 =A0 =A0 =A0(setq pos (point))
- =A0 =A0 =A0 =A0 =A0(= forward-line -1)
- =A0 =A0 =A0 =A0 =A0(skip-chars-forward " = \t")
- =A0 =A0 =A0 =A0 =A0(if (>=3D (nth 8 ppss) (point))
- = =A0 =A0 =A0 =A0 =A0 =A0 =A0(progn
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0(goto-char (nth 8 ppss))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if = (eq (char-after pos) ?*)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0(forward-char 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (not (looking-at comment-star= t-skip))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(error &quo= t;Internal css-mode error")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0(goto-char (match-end 0))))
- =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0(current-column))
- =A0 =A0 =A0 =A0 =A0 =A0(if (and (eq (char-after pos) ?*) (eq (char-a= fter) ?*))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0;; 'noindent
- =A0 =A0 =A0= =A0 =A0 =A0 =A0(current-column)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0)))=
- =A0 =A0 =A0 =A0 ;; In normal code.
- =A0 =A0 =A0 =A0 (t
- =A0 =A0 =A0 =A0 =A0(or
- =A0 =A0 =A0 =A0 =A0 (when (loo= king-at "\\s)")
- =A0 =A0 =A0 =A0 =A0 =A0 (forward-char= 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate-virtual))
- = =A0 =A0 =A0 =A0 =A0 (when (looking-at comment-start-skip)
- =A0 = =A0 =A0 =A0 =A0 =A0 (forward-comment (point-max))
- =A0 =A0 =A0 = =A0 =A0 =A0 (css-indent-calculate))
- =A0 =A0 =A0 =A0 =A0 (when (save-excursion (forward-comment (- (point-max)= ))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (setq pos (point))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 (eq (char-syntax (preceding-char)) ?\())
- =A0 =A0 =A0 =A0 =A0 =A0 (goto-char (1- pos))
- =A0 =A0 =A0= =A0 =A0 =A0 (if (not (looking-at "\\s([ \t]*"))
- =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 (error "Internal css-mode error")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 (if (or (memq (char-after (match-end 0= )) '(?\n nil))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (save-excursion (goto-ch= ar (match-end 0))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (looking-at comment-start-skip)))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (+ (css-indent-calculate-virtual) cs= s-indent-offset)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (progn (goto-char (match-end 0)) (cu= rrent-column)))))
- =A0 =A0 =A0 =A0 =A0 (progn
- =A0 = =A0 =A0 =A0 =A0 =A0 (css-backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 = =A0 (if (looking-at "\\s(")
- =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 (css-indent-calculate)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate-virtual))))))))))<= /div>
-
+ =A0(save-match-data
+ =A0 =A0(condition-c= ase error
+ =A0 =A0 =A0 =A0(with-syntax-table css-navigation-synt= ax-table
+ =A0 =A0 =A0 =A0 =A0(back-to-indentation)
+ =A0 =A0 =A0 =A0 =A0(let* ((point (point))
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 (ppss (syntax-ppss))
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 ( css-curly-parsed
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (save-excursion
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (cs= s-go-up)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (when (equal (char-after) ?{= )
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-parse-curly= ))))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 css-parsed-relevant
<= div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (block-ending-line
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(member (char-after
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (save-excursion<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (back-t= o-indentation)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 (point)))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0'( ?\} ?\) ) )))
+ =A0 =A0 =A0 =A0 =A0 =A0(cond ( (nth 4 ppss)
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0;; Inside a multiline comment
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(css-debug-msg "MC")
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-line -1)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(skip-chars-forward "= ; \t")
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (>= ;=3D (nth 8 ppss) (point))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0(progn
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0(goto-char (nth 8 ppss))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (eq (char= -after point) ?*)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0(forward-char 1)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (not (looking-at comment-start-skip= ))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 (error "Internal css-mode error")
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = (goto-char (match-end 0))))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 (current-column))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 (current-column))))
+ =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 ( ;; If "outside" indent to 0
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(zerop (nth 0 ppss))
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(css-debug-msg "ZERO")
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00)
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 ( ;; inside curly brackets
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0(and css-curly-parsed
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (not block-ending-line)<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (setq css-parsed-re= levant
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = (css-pc-get-relevant
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0css-curly-parsed point))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (not (eq (nth 2 css-pars= ed-relevant)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0'nested-selector)))
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0(css-debug-msg "C")
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0(+ css-indent-offset
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (save-excursion
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-go-up)
+ =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (current-indentation))
+ =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (if (and (not (equal (line-number-at-p= os
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 (car css-parsed-relevant))
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(line-number= -at-pos)))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0(css-pc-inside-statement
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 css-curl= y-parsed point))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 css-indent-offset 0)))
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ( ;;= Inside parentheses, closing brackets
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0t
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(css-debug-msg "P")
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(+ (save-excursion
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-go-up)
+ =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (current-indentation))
+ =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (if block-ending-line
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 0 css-indent-offset)= )))))
+ =A0 =A0 =A0(error ;; My best error-less guess
+= =A0 =A0 =A0 (css-debug-msg "Err")
+ =A0 =A0 =A0 (* (ca= r (syntax-ppss))
+ =A0 =A0 =A0 =A0 =A0css-indent-offset)))))
=A0
=A0(defun css-indent-line ()
=A0 =A0"Inde= nt current line according to CSS indentation rules."
=A0 =A0= (interactive)
- =A0(let* ((savep (point))
- =A0 =A0 =A0= =A0 (forward-sexp-function nil)
- (indent (conditio= n-case nil
- = =A0 =A0 (save-excursion
- =A0 =A0 =A0 (forward-line 0)
- =A0 =A0 =A0 (ski= p-chars-forward " \t")
- =A0 =A0 =A0 (if (>=3D (point) savep) (setq savep n= il))
- =A0 = =A0 =A0 (css-indent-calculate))
- =A0 (error nil))= ))
- =A0 =A0(if (not (numberp indent)) 'noindent
- = =A0 =A0 =A0(if savep
- =A0 =A0 =A0 =A0 =A0(save-excursion (indent= -line-to indent))
- =A0 =A0 =A0 =A0(indent-line-to indent)))))
+ =A0(save-excu= rsion
+ =A0 =A0(indent-line-to (css-indent-calculate)))
+ =A0(when (< (current-column) (current-indentation))
+ =A0 = =A0(back-to-indentation)))
+
+(defcustom css-indent-offset 4
+ =A0"Basic= size of one indentation step."
+ =A0:version "22.2&quo= t;
+ =A0:type 'integer
+ =A0:group 'css)
<= div> =A0
=A0(defun css-current-defun-name ()
=A0 =A0"Re= turn the name of the CSS section at point, or nil."
=A0 =A0(= save-excursion
=A0 =A0 =A0(let ((max (max (point-min) (- (point) = 1600)))) =A0; approx 20 lines back
=A0 =A0 =A0 =A0(when (search-backward "{" max t)
-= (skip-chars-backward &qu= ot; \t\r\n")
- (beginning-of-line)
- (if (looking-at &q= uot;^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)")
- =A0 =A0(match-string-no-properties 1))))))=
+ =A0 =A0 =A0 =A0(skip-chars-backward " \t\r\n")
+ =A0 = =A0 =A0 =A0(beginning-of-line)
+ =A0 =A0 =A0 =A0(if (looking-at &= quot;^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)")
+ =A0 =A0 =A0 =A0 = =A0 =A0(match-string-no-properties 1))))))
=A0
=A0(provide 'css-mode)
=A0;;; css-mode.el = ends here
\ No newline at end of file

<= div class=3D"gmail_extra">

On Tue, Jan 15= , 2013 at 7:32 PM, E Sabof <esabof@gmail.com> wrote:
Here is a patch, including a more advanced test case. = In the end there is a "failing" section - although I haven't = seen anyone breaking at spaces.

There is a varaiable called css-colo= n - the default is ":". If set to ": ", it will also in= dent statements like this in SASS (a CSS pre-processor)

a { &:hover,=20 &:active { background: green; } }

However, it will no longer corr= ectly indent statements like this:

background:#000, /* = no space */ url('image.png');

If I manage= to fix the "breaking at spaces" case, I'll send another patc= h.

Evgeni

=A0New css-mode.css diff --git a/css-mode.css b/css-mode.css new file mode 100644 index 0000000..40a732f --- /dev/null +++ b/css-mode.css @@ -0,0 +1,86 @@ +#top_menu .button.active, +#top_menu .button.active:active { + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Comment */ +} +#top_menu .button.active, +#top_menu .button.active:active +{ + /* Comment */ + background-image: url('images/header_button_active.png'); + cursor: default; + color: #999; + text-shadow: 1px 1px 2px #111; + /* Multiline + comment1 */ + /* Multiline + * comment2 */ +} +/* Multiline + comment1 */ +/* Multiline + * comment2 */ +#glass { + z-index: 2; + position: absolute; + top: -112px; + left: 0; + right: 0; + margin: 0 0 0 0; + margin: + 0 0 0 0; + text-shadow: + 1px 1px #FDE31D, + -1px -1px #B36300; + height: 140px; + background-image: url('images/honey_blurred2.png'); + background-image: url( + 'images/honey_blurred2.png'); + background-image: + #fff, + url('images/honey_blurred2.png'), + url('images/honey_blurred2.png'); + background-image: + #fff, + /* #fff, */ + url('images/honey_blurred2.png'); + background-image: #fff, + url('images/honey_blurred2.png'); + -webkit-mask-image: + -webkit-gradient( + linear, + left top, + /* left bottom, */ + left bottom, + color-stop( + 1, + rgba(0,0,0,0.2) + ), + color-stop(1, + rgba(0,0,0,0.2) + ), + /* comment */ + color-stop(0.7, rgba(0,0,0,.0)), + color-stop + ( + 0.7, rgba(0,0,0,.0) + ) + /* comment*/ ); + background-repeat: repeat-x; + background-position: center top; + background-attachment: fixed; } + +#failing { + margin: 0 + 0 + 0 + 0; + margin: + 0 + 0 + 0 + 0; +} \ No newline at end of file Modified css-mode.el diff --git a/css-mode.el b/css-mode.el index 1abe9a8..44682e1 100644 --- a/css-mode.el +++ b/css-mode.el @@ -33,6 +33,8 @@ =20 ;;; Code: =20 +(require 'cl-lib) + (defgroup css nil "Cascading Style Sheets (CSS) editing mode." :group 'languages) @@ -92,7 +94,6 @@ (t nil))) elems)) =20 - (defun css-extract-props-and-vals () (with-temp-buffer (url-insert-file-contents "http://www.w3.org/TR/CSS21/propidx.html= ") @@ -122,7 +123,7 @@ =20 (defconst css-pseudo-ids '("active" "after" "before" "firs= t" "first-child" "first-letter" "first-line&q= uot; - "focus" "hover" "lang" "left" = "link" "right" "visited") + "focus" "hover" "lang" "last-child&= quot; "left" "link" "right" "visited&quo= t;) "Identifiers for pseudo-elements and pseudo-classes.") =20 (defconst css-at-ids @@ -264,8 +265,8 @@ '(css-font-lock-keywords nil t)) =20 ;;;###autoload -(define-derived-mode css-mode fundamental-mode "CSS" - "Major mode to edit Cascading Style Sheets." +(define-derived-mode css-mode fundamental-mode + "CSS" "Major mode to edit Cascading Style Sheets." (setq-local font-lock-defaults css-font-lock-defaults) (setq-local comment-start "/*") (setq-local comment-start-skip "/\\*+[ \t]*") @@ -276,6 +277,8 @@ (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) + (setq-local beginning-of-defun-function 'css-beginning-of-defun) + (setq-local end-of-defun-function 'css-end-of-defun) (when css-electric-keys (let ((fc (make-char-table 'auto-fill-chars))) (set-char-table-parent fc auto-fill-chars) @@ -394,102 +397,178 @@ ;; FIXME: We should also skip punctuation. (not (memq (char-after) '(?\; ?\}))))))))))) =20 -(defun css-indent-calculate-virtual () - (if (or (save-excursion (skip-chars-backward " \t") (bolp)) - (if (looking-at "\\s(") - (save-excursion - (forward-char 1) (skip-chars-forward " \t") - (not (or (eolp) (looking-at comment-start-skip)))))) - (current-column) - (css-indent-calculate))) +(defun css-comment-line-p () + (interactive) + (cond ( (save-excursion + (back-to-indentation) + (looking-at "/\\*")) + 1 ) + ( (nth 4 (syntax-ppss)) + t))) + +(defun css-beginning-of-defun (&optional arg) + (unless arg (setq arg 1)) + (when (progn + ;; What for? + (unless (zerop (current-column)) + (end-of-line)) + (re-search-backward "^[^\n ].+{[ ]?$" nil t arg)) + (while (save-excursion + (and (zerop (forward-line -1)) + (string-match-p + "^[^}[:space:]/]" + (buffer-substring + (line-beginning-position) + (line-end-position))))) + (forward-line -1)))) + +(defun css-end-of-defun (&optional arg) + (interactive) + (unless arg (setq arg 1)) + (ignore-errors + (when (cl-plusp (first (syntax-ppss))) + (css-beginning-of-defun)) + (progn + (search-forward "{" nil t arg) + (backward-char) + (forward-sexp) + (ignore-errors + (forward-char))) + t)) + +;; To make writing derived modes easier. Ex. SASS also supports // type co= mments +(defvar css-comment-line-p-function 'css-comment-line-p + "Should return 1 if at the beginning of a comment, t if inside.&quo= t;) + +(defun css--goto-prev-struct-line () + (while (and (zerop (forward-line -1)) + (funcall css-comment-line-p-function)))) + +(defvar css-debug nil) + +(defun css-indent-debug-msg (name) + (when css-debug + (message "%s" name))) + +(defun css-visible-end-of-line () + (save-excursion + (end-of-line) + (skip-syntax-backward + " " (line-beginning-position)) + (point))) =20 -(defcustom css-indent-offset 4 - "Basic size of one indentation step." - :version "22.2" - :type 'integer - :group 'css) +(defun css-indentation-end-pos () + (save-excursion + (back-to-indentation) + (point))) =20 -(defun css-indent-calculate () - (let ((ppss (syntax-ppss)) - pos) - (with-syntax-table css-navigation-syntax-table - (save-excursion - (cond - ;; Inside a string. - ((nth 3 ppss) 'noindent) - ;; Inside a comment. - ((nth 4 ppss) - (setq pos (point)) - (forward-line -1) - (skip-chars-forward " \t") - (if (>=3D (nth 8 ppss) (point)) - (progn - (goto-char (nth 8 ppss)) - (if (eq (char-after pos) ?*) - (forward-char 1) - (if (not (looking-at comment-start-skip)) - (error "Internal css-mode error") - (goto-char (match-end 0)))) - (current-column)) - (if (and (eq (char-after pos) ?*) (eq (char-after) ?*)) - (current-column) - ;; 'noindent - (current-column) - ))) - ;; In normal code. - (t - (or - (when (looking-at "\\s)") - (forward-char 1) - (backward-sexp 1) - (css-indent-calculate-virtual)) - (when (looking-at comment-start-skip) - (forward-comment (point-max)) - (css-indent-calculate)) - (when (save-excursion (forward-comment (- (point-max))) - (setq pos (point)) - (eq (char-syntax (preceding-char)) ?\()) - (goto-char (1- pos)) - (if (not (looking-at "\\s([ \t]*")) - (error "Internal css-mode error") - (if (or (memq (char-after (match-end 0)) '(?\n nil)) - (save-excursion (goto-char (match-end 0)) - (looking-at comment-start-skip))) - (+ (css-indent-calculate-virtual) css-indent-offset) - (progn (goto-char (match-end 0)) (current-column))))) - (progn - (css-backward-sexp 1) - (if (looking-at "\\s(") - (css-indent-calculate) - (css-indent-calculate-virtual)))))))))) +(defun css-current-character-indentation () + "Like (current-indentation), but counts tabs as single characters.&= quot; + (save-excursion + (back-to-indentation) + (- (point) (line-beginning-position)))) + +(defvar css-colon ":" + "A dervied mode for SASS or LESS might want to set this to +\": \", to make nested pseudo-classes work.") =20 +(defun css-indent-calculate () + ;; If I go to the beginning of line, MC stops working + (back-to-indentation) + (with-syntax-table css-navigation-syntax-table + (let* (psl-indent + psl-last-char + psl-first-char + ( psl + (save-excursion + (css--goto-prev-struct-line) + (setq psl-indent (current-indentation)) + (setq psl-last-char (char-before (css-visible-end-of-line))= ) + (setq psl-first-char (char-after (css-indentation-end-pos))= ) + (buffer-substring + (line-beginning-position) + (line-end-position)))) + ( psl-closing-brackets + (+ (cl-count ?} psl) + (cl-count ?\) psl))) + ( psl-open-brackets (+ (cl-count ?{ psl) (cl-count ?\( psl))) + ( psl-has-colon (cl-plusp (cl-count ?: psl))) + (ppss (syntax-ppss)) + previous-comment-indent + previous-line-was-comment + pos) + (cond ( ;; Inside a multiline comment + ( eq (funcall css-comment-line-p-function) t) + (css-indent-debug-msg "MC") + (save-excursion + (nth 4 ppss) + (setq pos (point)) + (forward-line -1) + (skip-chars-forward " \t") + (if (>=3D (nth 8 ppss) (point)) + (progn + (goto-char (nth 8 ppss)) + (if (eq (char-after pos) ?*) + (forward-char 1) + (if (not (looking-at comment-start-skip)) + (error "Internal css-mode error") + (goto-char (match-end 0)))) + (current-column)) + (current-column)))) + ( ;; If "outside" indent to 0 + (zerop (nth 0 ppss)) + (css-indent-debug-msg "ZERO") + 0) + ( ;; Not-first member of comma ending lines + (and (not (cl-search css-colon psl)) + (equal psl-last-char ?\, ) + (=3D psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg "MCB") + psl-indent) + ( ;; Line after beginning of comma block + (and (member psl-last-char '( ?: ?\, ) ) + (=3D psl-open-brackets psl-closing-brackets)) + (css-indent-debug-msg "LABOC") + (+ psl-indent css-indent-offset)) + ( ;; Default, based on nesting level + t + (css-indent-debug-msg "LAST") + (let (( parent-indent + (save-excursion + (backward-up-list) + (css-current-character-indentation))) + ( block-ending-line + (member (char-after (css-indentation-end-pos)) + '( ?\} ?\) ) ))) + (+ parent-indent + (* (+ (if block-ending-line -1 0) + 1) + css-indent-offset)))) + )))) =20 (defun css-indent-line () "Indent current line according to CSS indentation rules." (interactive) - (let* ((savep (point)) - (forward-sexp-function nil) - (indent (condition-case nil - (save-excursion - (forward-line 0) - (skip-chars-forward " \t") - (if (>=3D (point) savep) (setq savep nil)) - (css-indent-calculate)) - (error nil)))) - (if (not (numberp indent)) 'noindent - (if savep - (save-excursion (indent-line-to indent)) - (indent-line-to indent))))) + (save-excursion + (indent-line-to (css-indent-calculate))) + (when (< (current-column) (current-indentation)) + (back-to-indentation))) + +(defcustom css-indent-offset 4 + "Basic size of one indentation step." + :version "22.2" + :type 'integer + :group 'css) =20 (defun css-current-defun-name () "Return the name of the CSS section at point, or nil." (save-excursion (let ((max (max (point-min) (- (point) 1600)))) ; approx 20 lines bac= k (when (search-backward "{" max t) - (skip-chars-backward " \t\r\n") - (beginning-of-line) - (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") - (match-string-no-properties 1)))))) + (skip-chars-backward " \t\r\n") + (beginning-of-line) + (if (looking-at "^[ \t]*\\([^{\r\n]*[^ {\t\r\n]\\)") + (match-string-no-properties 1)))))) =20 (provide 'css-mode) ;;; css-mode.el ends here \ No newline at end of file


On Tue, Jan 15, 2013 at 5:00 AM, Ste= fan Monnier <monnier@iro.umontreal.ca> wrote:
> I've written a new indenter for CSS= , which fixes issues with mulitline
> statements following a colon, and comments:

Interesting, I don't use CSS myself very much, but I've toyed with = an
SMIE indenter for css-mode (see below).

> body {
> =A0 =A0 color: #333;
> =A0 =A0 font: 15px "Helvetica Neue",
> =A0 =A0 =A0 =A0 Helvetica,
> =A0 =A0 =A0 =A0 Arial,
> =A0 =A0 =A0 =A0 "Nimbus Sans L",
> =A0 =A0 =A0 =A0 sans-serif;
> =A0 =A0 font-weight: 300;
> =A0 =A0 line-height: 1.625;
> =A0 =A0 a { /* It also handles SCSS */
> =A0 =A0 =A0 =A0 font: 15px "Helvetica Neue",
> =A0 =A0 =A0 =A0 =A0 =A0 Helvetica,
> =A0 =A0 =A0 =A0 =A0 =A0 Arial,
> =A0 =A0 =A0 =A0 =A0 =A0 "Nimbus Sans L",
> =A0 =A0 =A0 =A0 =A0 =A0 sans-serif;
> =A0 =A0 =A0 =A0 /* Some comment */
> =A0 =A0 }
> =A0 =A0 /* Some comment at the end of a block */
> }

I've tried it on the above test case and the SMIE code seems to handle<= br> it OK (tho differently), with the main exception being the
comment-at-end-of-block, which is probably a general problem which
should be fixed in smie.el (probably in smie-indent-comment).

But I have basically never used/tested my code, so...

> I wondered whether this functionality could be integrated into Emacs.<= br> > htt= ps://github.com/sabof/es-css-mode
> https://= github.com/sabof/es-lib (it takes some functions from it)

If you could provide a patch against css-mode.el, that would be more
convenient. =A0Also it would be good to add a good set of test cases (in the form of a new file test/indent/css-mode.css).


=A0 =A0 =A0 =A0 Stefan


=3D=3D=3D modified file 'lisp/textmodes/css-mode.el'
--- lisp/textmodes/css-mode.el =A02013-01-02 16:13:04 +0000
+++ lisp/textmodes/css-mode.el =A02013-01-15 04:53:03 +0000
@@ -263,6 +263,22 @@
=A0(defvar css-font-lock-defaults
=A0 =A0'(css-font-lock-keywords nil t))

+(defcustom css-indent-offset 4
+ =A0"Basic size of one indentation step."
+ =A0:version "22.2"
+ =A0:type 'integer)
+
+(defconst css-smie-grammar
+ =A0(smie-prec2->grammar
+ =A0 (smie-precs->prec2 '((assoc ";") (left ":"= ) (assoc ",")))))
+
+(defun css-smie-rules (kind token)
+ =A0(pcase (cons kind token)
+ =A0 =A0(`(:elem . basic) css-indent-offset)
+ =A0 =A0(`(:elem . arg) 0)
+ =A0 =A0(`(:before . "{") (if (smie-rule-hanging-p)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (smie-rule-parent 0)))))<= br> +
=A0;;;###autoload
=A0(define-derived-mode css-mode fundamental-mode "CSS"
=A0 =A0"Major mode to edit Cascading Style Sheets."
@@ -271,11 +287,11 @@
=A0 =A0(setq-local comment-start-skip "/\\*+[ \t]*")
=A0 =A0(setq-local comment-end "*/")
=A0 =A0(setq-local comment-end-skip "[ \t]*\\*+/")
- =A0(setq-local forward-sexp-function 'css-forward-sexp)
=A0 =A0(setq-local parse-sexp-ignore-comments t)
=A0 =A0(setq-local indent-line-function 'css-indent-line)
=A0 =A0(setq-local fill-paragraph-function 'css-fill-paragraph)
=A0 =A0(setq-local add-log-current-defun-function #'css-current-defun-n= ame)
+ =A0(smie-setup css-smie-grammar #'css-smie-rules)
=A0 =A0(when css-electric-keys
=A0 =A0 =A0(let ((fc (make-char-table 'auto-fill-chars)))
=A0 =A0 =A0 =A0(set-char-table-parent fc auto-fill-chars)
@@ -355,131 +371,6 @@
=A0 =A0 =A0 =A0 =A0 =A0 =A0;; Don't use the default filling code.
=A0 =A0 =A0 =A0 =A0 =A0 =A0t)))))))

-;;; Navigation and indentation.
-
-(defconst css-navigation-syntax-table
- =A0(let ((st (make-syntax-table css-mode-syntax-table)))
- =A0 =A0(map-char-table (lambda (c v)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; Turn punctuation (code =3D = 1) into symbol (code =3D 1).
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (eq (car-safe v) 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(set-char-table-range = st c (cons 3 (cdr v)))))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0st)
- =A0 =A0st))
-
-(defun css-backward-sexp (n)
- =A0(let ((forward-sexp-function nil))
- =A0 =A0(if (< n 0) (css-forward-sexp (- n))
- =A0 =A0 =A0(while (> n 0)
- =A0 =A0 =A0 =A0(setq n (1- n))
- =A0 =A0 =A0 =A0(forward-comment (- (point-max)))
- =A0 =A0 =A0 =A0(if (not (eq (char-before) ?\;))
- =A0 =A0 =A0 =A0 =A0 =A0(backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0(while (progn (backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-comment (- (p= oint-max)))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; FIXME: We should al= so skip punctuation.
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (or (bobp) (memq = (char-before) '(?\; ?\{))))))))))))
-
-(defun css-forward-sexp (n)
- =A0(let ((forward-sexp-function nil))
- =A0 =A0(if (< n 0) (css-backward-sexp (- n))
- =A0 =A0 =A0(while (> n 0)
- =A0 =A0 =A0 =A0(setq n (1- n))
- =A0 =A0 =A0 =A0(forward-comment (point-max))
- =A0 =A0 =A0 =A0(if (not (eq (char-after) ?\;))
- =A0 =A0 =A0 =A0 =A0 =A0(forward-sexp 1)
- =A0 =A0 =A0 =A0 =A0(while (progn (forward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-comment (poin= t-max))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;; FIXME: We should al= so skip punctuation.
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (memq (char-after= ) '(?\; ?\})))))))))))
-
-(defun css-indent-calculate-virtual ()
- =A0(if (or (save-excursion (skip-chars-backward " \t") (bolp))<= br> - =A0 =A0 =A0 =A0 =A0(if (looking-at "\\s(")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-char 1) (skip-chars-forward "= ; \t")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(not (or (eolp) (looking-at comment-start-= skip))))))
- =A0 =A0 =A0(current-column)
- =A0 =A0(css-indent-calculate)))
-
-(defcustom css-indent-offset 4
- =A0"Basic size of one indentation step."
- =A0:version "22.2"
- =A0:type 'integer
- =A0:group 'css)
-
-(defun css-indent-calculate ()
- =A0(let ((ppss (syntax-ppss))
- =A0 =A0 =A0 =A0pos)
- =A0 =A0(with-syntax-table css-navigation-syntax-table
- =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0(cond
- =A0 =A0 =A0 =A0 ;; Inside a string.
- =A0 =A0 =A0 =A0 ((nth 3 ppss) 'noindent)
- =A0 =A0 =A0 =A0 ;; Inside a comment.
- =A0 =A0 =A0 =A0 ((nth 4 ppss)
- =A0 =A0 =A0 =A0 =A0(setq pos (point))
- =A0 =A0 =A0 =A0 =A0(forward-line -1)
- =A0 =A0 =A0 =A0 =A0(skip-chars-forward " \t")
- =A0 =A0 =A0 =A0 =A0(if (>=3D (nth 8 ppss) (point))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0(progn
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(goto-char (nth 8 ppss))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (eq (char-after pos) ?*)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-char 1)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (not (looking-at comment-start-ski= p))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(error "Internal css-mode= error")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(goto-char (match-end 0))))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column))
- =A0 =A0 =A0 =A0 =A0 =A0(if (and (eq (char-after pos) ?*) (eq (char-after)= ?*))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0;; 'noindent
- =A0 =A0 =A0 =A0 =A0 =A0 =A0(current-column)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0)))
- =A0 =A0 =A0 =A0 ;; In normal code.
- =A0 =A0 =A0 =A0 (t
- =A0 =A0 =A0 =A0 =A0(or
- =A0 =A0 =A0 =A0 =A0 (when (looking-at "\\s)")
- =A0 =A0 =A0 =A0 =A0 =A0 (forward-char 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate-virtual))
- =A0 =A0 =A0 =A0 =A0 (when (looking-at comment-start-skip)
- =A0 =A0 =A0 =A0 =A0 =A0 (forward-comment (point-max))
- =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate))
- =A0 =A0 =A0 =A0 =A0 (when (save-excursion (forward-comment (- (point-max)= ))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (setq pos= (point))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (eq (char= -syntax (preceding-char)) ?\())
- =A0 =A0 =A0 =A0 =A0 =A0 (goto-char (1- pos))
- =A0 =A0 =A0 =A0 =A0 =A0 (if (not (looking-at "\\s([ \t]*"))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (error "Internal css-mode error"= ;)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 (if (or (memq (char-after (match-end 0)) '= ;(?\n nil))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (save-excursion (goto-char (m= atch-end 0))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 (looking-at comment-start-skip)))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (+ (css-indent-calculate-virtual) css= -indent-offset)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (progn (goto-char (match-end 0)) (current= -column)))))
- =A0 =A0 =A0 =A0 =A0 (progn
- =A0 =A0 =A0 =A0 =A0 =A0 (css-backward-sexp 1)
- =A0 =A0 =A0 =A0 =A0 =A0 (if (looking-at "\\s(")
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 (css-indent-calculate-virtual))))))))))
-
-
-(defun css-indent-line ()
- =A0"Indent current line according to CSS indentation rules." - =A0(interactive)
- =A0(let* ((savep (point))
- =A0 =A0 =A0 =A0 (forward-sexp-function nil)
- =A0 =A0 =A0 =A0(indent (condition-case nil
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(save-excursion
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(forward-line 0)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(skip-chars-forward " \t&= quot;)
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(if (>=3D (point) savep) (s= etq savep nil))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(css-indent-calculate))
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(error nil))))
- =A0 =A0(if (not (numberp indent)) 'noindent
- =A0 =A0 =A0(if savep
- =A0 =A0 =A0 =A0 =A0(save-excursion (indent-line-to indent))
- =A0 =A0 =A0 =A0(indent-line-to indent)))))

=A0(defun css-current-defun-name ()
=A0 =A0"Return the name of the CSS section at point, or nil."



--20cf3074d594ecfdb804d370ebd7-- From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? References: In-Reply-To: Resent-From: Tom Tromey Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 25 Jan 2017 23:07:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.148538560414137 (code B ref 13425); Wed, 25 Jan 2017 23:07:02 +0000 Received: (at 13425) by debbugs.gnu.org; 25 Jan 2017 23:06:44 +0000 Received: from localhost ([127.0.0.1]:43898 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cWWeK-0003fw-JN for submit@debbugs.gnu.org; Wed, 25 Jan 2017 18:06:44 -0500 Received: from gproxy2-pub.mail.unifiedlayer.com ([69.89.18.3]:35293) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1cWWeI-0003fi-Kn for 13425@debbugs.gnu.org; Wed, 25 Jan 2017 18:06:43 -0500 Received: (qmail 16566 invoked by uid 0); 25 Jan 2017 23:06:24 -0000 Received: from unknown (HELO cmgw3) (10.0.90.84) by gproxy2.mail.unifiedlayer.com with SMTP; 25 Jan 2017 23:06:24 -0000 Received: from box522.bluehost.com ([74.220.219.122]) by cmgw3 with id cn6J1u0092f2jeq01n6MY5; Wed, 25 Jan 2017 16:06:24 -0700 X-Authority-Analysis: v=2.1 cv=YuCcGeoX c=1 sm=1 tr=0 a=GsOEXm/OWkKvwdLVJsfwcA==:117 a=GsOEXm/OWkKvwdLVJsfwcA==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=IgFoBzBjUZAA:10 a=H2nnnKGNCx98qX3LowQA:9 a=T3EjWRVVJ0YA:10 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Content-Type:MIME-Version:Message-ID:Date:Subject:To:From: Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=fWuHZdMG35VuItMWP48dLeCIJii7KALIrQOAqRD61FQ=; b=eOhSK18YevAXI002D3A//80miA EJLWq5/DcBIv9sx3k6Ta3Y2RPinhjFkCNXHrnV9Fa/LXXJj9XuFeV4Wvd4wGvi5MiVss+k9UQ0Leq zwlII7JDV8rC+g8CSh4Ck8Bb8; Received: from 75-166-101-147.hlrn.qwest.net ([75.166.101.147]:33970 helo=bapiya) by box522.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.87) (envelope-from ) id 1cWWdt-0004jU-Lt; Wed, 25 Jan 2017 16:06:17 -0700 From: Tom Tromey X-Attribution: Tom Date: Wed, 25 Jan 2017 16:06:16 -0700 Message-ID: <87efzqhh93.fsf@tromey.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.90 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box522.bluehost.com X-AntiAbuse: Original Domain - debbugs.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 75.166.101.147 X-Exim-ID: 1cWWdt-0004jU-Lt X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 75-166-101-147.hlrn.qwest.net (bapiya) [75.166.101.147]:33970 X-Source-Auth: tom+tromey.com X-Email-Count: 1 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTIyLmJsdWVob3N0LmNvbQ== X-Spam-Score: -0.6 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.6 (/) Stefan's new SMIE-based indenter has been in css-mode for a while. It seems pretty good. I did spend a bit of time trying to get it to line up continued properties under the ":", like: font: 15px "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", sans-serif; ... but all I really accomplished was realizing that I don't understand SMIE. Anyway I think the issues in this bug are fixed. I recommend closing it. Tom From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 29 Jan 2017 14:03:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Tom Tromey , Stefan Monnier Cc: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.14856985264780 (code B ref 13425); Sun, 29 Jan 2017 14:03:02 +0000 Received: (at 13425) by debbugs.gnu.org; 29 Jan 2017 14:02:06 +0000 Received: from localhost ([127.0.0.1]:49780 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXq3S-0001F2-3a for submit@debbugs.gnu.org; Sun, 29 Jan 2017 09:02:06 -0500 Received: from mail-lf0-f51.google.com ([209.85.215.51]:34956) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXq3Q-0001EZ-LJ for 13425@debbugs.gnu.org; Sun, 29 Jan 2017 09:02:05 -0500 Received: by mail-lf0-f51.google.com with SMTP id n124so182508667lfd.2 for <13425@debbugs.gnu.org>; Sun, 29 Jan 2017 06:02:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:subject:to:cc:message-id:in-reply-to:references :mime-version; bh=HQGx+Hj+4IVKINLtmAJGJpiDSeZWAS1Q2STfkLrxknA=; b=osmhWTNLB3wu/OdIOqTHjstKSEWfw7vX6j9Ys8S1G/J3OPv1ICTBz/luJ+QvhyzYQg iiSAc0sdOpAaTWupadKsIvLpbp5J1ufJkJmZW1McgkS/ujywLJCpHXADxLLZlHHA5viQ MjA+xfPlQowZUzcyC1o3f57qtbvZYPm3nYOry9NxSEnpTGR3AFLp+1rot6znsF+W+Tjf fKghZAlfvc0fXLjfEbwMJ/cVI85YfoOCmN6/duBmfawqfAhQu6Cd6Y/tW2rD7KET5nLB AHQYpKi1FpSQSxWnIdP/Hze58+2jNyn0v0imrFapP8O5aO6kpZhXKLF9raKPJVNN3rRm siWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:subject:to:cc:message-id:in-reply-to :references:mime-version; bh=HQGx+Hj+4IVKINLtmAJGJpiDSeZWAS1Q2STfkLrxknA=; b=euu3PuKIqj8m3BdPvUochpFYMgJLHxBhUHr5Km10V1RW/VfetBI4CH8SD248JvezVM KZEfQeTL3cbGW8VblHXnbDKG0CM2ZY57yLxe1YJBndp97YiU0WFtQqP1G9WCa7/AQQXH kHoG474kVoZZGv6k3y4mi0xitiPrHIdefRKDDCpoXLErRUH1TbaVzaTVPr2i8SrIdO+A c3RjVcjLMuMjr7FYNkr5ssV6h2QTTbQT06O6/248gr65D2Y+33yalCJ/f5AhuPUxIziB MPNF9EiHpkEBKpC9+rh0j5hH8znhqkkEAZQgoQ7KwEKufWf1JQpMSz8x9O0UAYuYK6NI cdRA== X-Gm-Message-State: AIkVDXKMO3ZrVPyvzONOJGfvadvdZfJZQ0IMAxMr+Y3kNi3kVpV5yl8Xp8YQ9S7p4MTEVg== X-Received: by 10.25.199.9 with SMTP id x9mr4649804lff.95.1485698518332; Sun, 29 Jan 2017 06:01:58 -0800 (PST) Received: from [192.168.100.10] (cm-84.210.143.4.getinternet.no. [84.210.143.4]) by smtp.gmail.com with ESMTPSA id o91sm3012166lfg.17.2017.01.29.06.01.56 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 29 Jan 2017 06:01:57 -0800 (PST) Date: Sun, 29 Jan 2017 15:01:55 +0100 From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Message-Id: <1485698515.4344.0@smtp.gmail.com> In-Reply-To: <87efzqhh93.fsf@tromey.com> References: <87efzqhh93.fsf@tromey.com> X-Mailer: geary/0.11.3 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.0 (/) I agree that the SMIE-based indenter is good, and I'd like to keep it. The mentioned problem of aligning lines after a comma is indeed the only problem I've had with it. On Thu, Jan 26, 2017 at 12:06 AM, Tom Tromey wrote: > I did spend a bit of time trying to get it to line up continued > properties under the ":", like: > > font: 15px "Helvetica Neue", > Helvetica, > Arial, > "Nimbus Sans L", > sans-serif; > > ... but all I really accomplished was realizing that I don't > understand > SMIE. I did that too, but I had to reach the same conclusion... If we aren't able to fix this with problem the SMIE-based indenter, and Evgeni's indenter handles it better, I think we should consider it. But as said, I think it would be ideal to fix and keep the indenter we have. Stefan, do you have time to look into it, or do you have some pointers to how we could fix this problem with the SMIE-based indenter? -- Simen From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 29 Jan 2017 17:17:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Tom Tromey Cc: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.14857101842745 (code B ref 13425); Sun, 29 Jan 2017 17:17:01 +0000 Received: (at 13425) by debbugs.gnu.org; 29 Jan 2017 17:16:24 +0000 Received: from localhost ([127.0.0.1]:50386 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXt5U-0000iB-H4 for submit@debbugs.gnu.org; Sun, 29 Jan 2017 12:16:24 -0500 Received: from pruche.dit.umontreal.ca ([132.204.246.22]:53131) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXt5R-0000i2-NP for 13425@debbugs.gnu.org; Sun, 29 Jan 2017 12:16:22 -0500 Received: from ceviche.home (lechon.iro.umontreal.ca [132.204.27.242]) by pruche.dit.umontreal.ca (8.14.7/8.14.1) with ESMTP id v0THGKn4014887; Sun, 29 Jan 2017 12:16:20 -0500 Received: by ceviche.home (Postfix, from userid 20848) id 72BE766261; Sun, 29 Jan 2017 12:16:20 -0500 (EST) From: Stefan Monnier Message-ID: References: <87efzqhh93.fsf@tromey.com> Date: Sun, 29 Jan 2017 12:16:20 -0500 In-Reply-To: <87efzqhh93.fsf@tromey.com> (Tom Tromey's message of "Wed, 25 Jan 2017 16:06:16 -0700") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-NAI-Spam-Flag: NO X-NAI-Spam-Threshold: 5 X-NAI-Spam-Score: 0 X-NAI-Spam-Rules: 2 Rules triggered EDT_SA_DN_PASS=0, RV5934=0 X-NAI-Spam-Version: 2.3.0.9418 : core <5934> : inlines <5665> : streams <1730772> : uri <2367042> X-Spam-Score: -4.5 (----) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -4.5 (----) > I did spend a bit of time trying to get it to line up continued > properties under the ":", like: > font: 15px "Helvetica Neue", > Helvetica, > Arial, > "Nimbus Sans L", > sans-serif; > ... but all I really accomplished was realizing that I don't understand > SMIE. What have you tried? I don't know the CSS grammar well enough to know what we should do. The above problem is trivially fixed with the patch below, but it seems too easy, so it probably introduces problems elsewhere. Stefan diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index c81c3f62e1..499de8db2e 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el @@ -734,7 +734,7 @@ css-indent-offset (defconst css-smie-grammar (smie-prec2->grammar - (smie-precs->prec2 '((assoc ";") (assoc ",") (left ":"))))) + (smie-precs->prec2 '((assoc ";") (left ":") (assoc ","))))) (defun css-smie--forward-token () (cond From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 29 Jan 2017 17:39:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Stefan Monnier Cc: 13425@debbugs.gnu.org, Tom Tromey Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.148571151511211 (code B ref 13425); Sun, 29 Jan 2017 17:39:02 +0000 Received: (at 13425) by debbugs.gnu.org; 29 Jan 2017 17:38:35 +0000 Received: from localhost ([127.0.0.1]:50399 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXtQw-0002ul-VI for submit@debbugs.gnu.org; Sun, 29 Jan 2017 12:38:35 -0500 Received: from mail-lf0-f43.google.com ([209.85.215.43]:32885) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXtQv-0002uY-LE for 13425@debbugs.gnu.org; Sun, 29 Jan 2017 12:38:34 -0500 Received: by mail-lf0-f43.google.com with SMTP id x1so97637493lff.0 for <13425@debbugs.gnu.org>; Sun, 29 Jan 2017 09:38:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:subject:to:cc:message-id:in-reply-to:references :mime-version; bh=69mXfUJMt5Mld9ZxHbj91RZbSgDnH93j8ulgGUbmLnA=; b=Lq85YLyWGib+9UqDzix23IqPN3DbS4cWoVDFtGsHHNnAzYQJ0k0b+rZlaWoZztsY+B GnUJRvKzOrYmrsDbF5z6ffvR6BwXRHuY6BufTALVWEg5BsueJI5kTm8ivynl1HZ1MNKA 7Lmkm0nxI18c/q7ufxj/8ekz3iuaml5L15FH4Mg2ooozvUVxGysYKkiRPOzGJ3H0peOo JMPtfl90b+P4+ve2WnBfaO0eHjG1lji7FaaTZMon3UvEWMMZ6SDO8zBvOKMhz/LjYz6E KxD+uLbENqLgMkKbY78peneOSkCxCbeoN3IE7eRJ2NbQYybB2ai4RJxYSo7aBhjX0pD/ AIYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:subject:to:cc:message-id:in-reply-to :references:mime-version; bh=69mXfUJMt5Mld9ZxHbj91RZbSgDnH93j8ulgGUbmLnA=; b=qQsT7gLx0jUnOJFMuOa9pkaPfv8YkNFUclau4lNUoNw1udHX12huv9lsXPYdF9Ebpi wtIj0QEMjAKGH9nQRlnbNrfIS14vrWW6k1r2LmKzJLXPKcud7evrhEOmB4s5H1bzgCDl fJyx0k6jArjskbm0WGdPo1nEduwpIQ3majlopqBvHnQBNfUKglfddfwsaJluxoEilkam lhj4Z1Sde0GL++dXIFDqbbEnQgSqsjqMLCZtgWiZnHFzV8FHDnprcxZ89PX1F2IEJYQh kPJQ16opENvQSKR+d+rngpXNhNhYH8iBMTyBSspw5uLqTKq1xj1Jr6SoDPa5mBRf36mt cfVA== X-Gm-Message-State: AIkVDXLcB+CYtWbQp8fZJcMNHHkKW04J7bd5CPLbmk972Dtb5p7E9onDcXEgOGGN3s0mCg== X-Received: by 10.46.7.10 with SMTP id 10mr6358135ljh.58.1485711507325; Sun, 29 Jan 2017 09:38:27 -0800 (PST) Received: from [192.168.100.10] (cm-84.210.143.4.getinternet.no. [84.210.143.4]) by smtp.gmail.com with ESMTPSA id z26sm3054403lja.36.2017.01.29.09.38.26 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 29 Jan 2017 09:38:26 -0800 (PST) Date: Sun, 29 Jan 2017 18:38:25 +0100 From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Message-Id: <1485711505.6518.0@smtp.gmail.com> In-Reply-To: References: <87efzqhh93.fsf@tromey.com> X-Mailer: geary/0.11.3 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed X-Spam-Score: -0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.0 (/) On Sun, Jan 29, 2017 at 6:16 PM, Stefan Monnier wrote: > The above problem is trivially fixed with the patch below, but it > seems > too easy, so it probably introduces problems elsewhere. Indeed, that causes problems with selectors that contain colons, like: div:first-child, div:last-child { top: 1.5rem; } Which gets indented like: div:first-child, div:last-child { top: 1.5rem; } And SCSS mixins, like: @include foo-mixin( $foo: 'foo', $bar: 'bar, ); Which gets indented like: @include foo-mixin( $foo: 'foo', $bar: 'bar, ); -- Simen From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 29 Jan 2017 18:16:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Cc: 13425@debbugs.gnu.org, Tom Tromey Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.148571374714536 (code B ref 13425); Sun, 29 Jan 2017 18:16:02 +0000 Received: (at 13425) by debbugs.gnu.org; 29 Jan 2017 18:15:47 +0000 Received: from localhost ([127.0.0.1]:50420 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXu0w-0003mO-Tl for submit@debbugs.gnu.org; Sun, 29 Jan 2017 13:15:47 -0500 Received: from chene.dit.umontreal.ca ([132.204.246.20]:55354) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cXu0u-0003mF-MH for 13425@debbugs.gnu.org; Sun, 29 Jan 2017 13:15:45 -0500 Received: from ceviche.home (lechon.iro.umontreal.ca [132.204.27.242]) by chene.dit.umontreal.ca (8.14.7/8.14.1) with ESMTP id v0TIFhl8028167; Sun, 29 Jan 2017 13:15:43 -0500 Received: by ceviche.home (Postfix, from userid 20848) id EC91366261; Sun, 29 Jan 2017 13:15:42 -0500 (EST) From: Stefan Monnier Message-ID: References: <87efzqhh93.fsf@tromey.com> <1485711505.6518.0@smtp.gmail.com> Date: Sun, 29 Jan 2017 13:15:42 -0500 In-Reply-To: <1485711505.6518.0@smtp.gmail.com> ("Simen =?UTF-8?Q?Heggest=C3=B8yl?="'s message of "Sun, 29 Jan 2017 18:38:25 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-NAI-Spam-Flag: NO X-NAI-Spam-Threshold: 5 X-NAI-Spam-Score: 0 X-NAI-Spam-Rules: 2 Rules triggered EDT_SA_DN_PASS=0, RV5934=0 X-NAI-Spam-Version: 2.3.0.9418 : core <5934> : inlines <5665> : streams <1730772> : uri <2367074> X-Spam-Score: -4.5 (----) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -4.5 (----) >> The above problem is trivially fixed with the patch below, but it seems >> too easy, so it probably introduces problems elsewhere. > Indeed, that causes problems with selectors that contain colons, like: Then we need to change css-smie--forward-token and css-smie--backward-token. Two ways to fix it: - either make them distinguish between ", between selector" and ", between values". - or make them distinguish between ": for selectors" and ": for values". Then we can change the grammar to give different precedences for the two different cases. E.g. (defun css-smie--backward-token () [...] (if (css--colon-inside-selector-p) ":-selector" ":")) and then (defconst css-smie-grammar (smie-prec2->grammar (smie-precs->prec2 '((assoc ";") (left ":") (assoc ",") (left ":-selector"))))) So the question is mostly: whether it's easier to distinguish the two different kinds of commas, or whether it's easier to distinguish the two different kinds of colons. Stefan From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 30 Jan 2017 22:29:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Tom Tromey Cc: 13425@debbugs.gnu.org Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.148581532712818 (code B ref 13425); Mon, 30 Jan 2017 22:29:01 +0000 Received: (at 13425) by debbugs.gnu.org; 30 Jan 2017 22:28:47 +0000 Received: from localhost ([127.0.0.1]:51435 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYKRK-0003Kf-Va for submit@debbugs.gnu.org; Mon, 30 Jan 2017 17:28:47 -0500 Received: from pruche.dit.umontreal.ca ([132.204.246.22]:56850) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYKRH-0003KK-AD for 13425@debbugs.gnu.org; Mon, 30 Jan 2017 17:28:45 -0500 Received: from pastel.home (lechon.iro.umontreal.ca [132.204.27.242]) by pruche.dit.umontreal.ca (8.14.7/8.14.1) with ESMTP id v0UMSfYN023439; Mon, 30 Jan 2017 17:28:41 -0500 Received: by pastel.home (Postfix, from userid 20848) id 9D8F7601EA; Mon, 30 Jan 2017 17:28:40 -0500 (EST) From: Stefan Monnier Message-ID: References: <87efzqhh93.fsf@tromey.com> <877f5cchv7.fsf@tromey.com> Date: Mon, 30 Jan 2017 17:28:40 -0500 In-Reply-To: <877f5cchv7.fsf@tromey.com> (Tom Tromey's message of "Mon, 30 Jan 2017 15:17:48 -0700") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-NAI-Spam-Flag: NO X-NAI-Spam-Level: X-NAI-Spam-Threshold: 5 X-NAI-Spam-Score: 0.1 X-NAI-Spam-Rules: 3 Rules triggered GEN_SPAM_FEATRE=0.1, EDT_SA_DN_PASS=0, RV5935=0 X-NAI-Spam-Version: 2.3.0.9418 : core <5935> : inlines <5667> : streams <1730804> : uri <2367865> X-Spam-Score: -4.5 (----) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -4.5 (----) > In my view the simplest is treating ":" different inside and outside of > braces. That should work for CSS, but not for SCSS. Stefan From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Tom Tromey Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 31 Jan 2017 00:47:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Stefan Monnier Cc: 13425@debbugs.gnu.org, Tom Tromey Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.148582359421569 (code B ref 13425); Tue, 31 Jan 2017 00:47:02 +0000 Received: (at 13425) by debbugs.gnu.org; 31 Jan 2017 00:46:34 +0000 Received: from localhost ([127.0.0.1]:51497 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYMag-0005bo-0j for submit@debbugs.gnu.org; Mon, 30 Jan 2017 19:46:34 -0500 Received: from gproxy7-pub.mail.unifiedlayer.com ([70.40.196.235]:58660) by debbugs.gnu.org with smtp (Exim 4.84_2) (envelope-from ) id 1cYMad-0005bF-Em for 13425@debbugs.gnu.org; Mon, 30 Jan 2017 19:46:32 -0500 Received: (qmail 5033 invoked by uid 0); 31 Jan 2017 00:44:35 -0000 Received: from unknown (HELO CMOut01) (10.0.90.82) by gproxy7.mail.unifiedlayer.com with SMTP; 31 Jan 2017 00:44:35 -0000 Received: from box522.bluehost.com ([74.220.219.122]) by CMOut01 with id eokS1u00W2f2jeq01okVNf; Mon, 30 Jan 2017 17:44:30 -0700 X-Authority-Analysis: v=2.1 cv=NJxGpSKg c=1 sm=1 tr=0 a=GsOEXm/OWkKvwdLVJsfwcA==:117 a=GsOEXm/OWkKvwdLVJsfwcA==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=IgFoBzBjUZAA:10 a=zVy3hRbMEjeyw4H8_9IA:9 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=JMGSfxrkHqrEcGOmvofDesLMSGtTkEUwZHmknsUKLtI=; b=LIaja8M04EIwhUJ3VMbKDgJz1n NzNYMTa6J/J7sUzLn6MZ6/Hvk2/FAAvc7T3PKaypuUrLENpynDH5r5nIJsSFvceC/j7fIdmlweenO nwPMlqtbl8i7b2l5yNqM99AWO; Received: from 174-16-146-181.hlrn.qwest.net ([174.16.146.181]:48662 helo=bapiya) by box522.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.87) (envelope-from ) id 1cYKGl-0001fV-3U; Mon, 30 Jan 2017 15:17:51 -0700 From: Tom Tromey References: <87efzqhh93.fsf@tromey.com> X-Attribution: Tom Date: Mon, 30 Jan 2017 15:17:48 -0700 In-Reply-To: (Stefan Monnier's message of "Sun, 29 Jan 2017 12:16:20 -0500") Message-ID: <877f5cchv7.fsf@tromey.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.1.90 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box522.bluehost.com X-AntiAbuse: Original Domain - debbugs.gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 174.16.146.181 X-Exim-ID: 1cYKGl-0001fV-3U X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 174-16-146-181.hlrn.qwest.net (bapiya) [174.16.146.181]:48662 X-Source-Auth: tom+tromey.com X-Email-Count: 0 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTIyLmJsdWVob3N0LmNvbQ== X-Spam-Score: -1.1 (-) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.1 (-) Stefan> What have you tried? I don't know the CSS grammar well enough to know Stefan> what we should do. I've appended my first try, which also includes a test case. (Though the last stanza of the test case is actually not indented properly as-is, oops.) Like yours mine failed on ":"s in selectors. I had a second try but it worked even less well I think. Stefan> So the question is mostly: whether it's easier to distinguish Stefan> the two different kinds of commas, or whether it's easier to Stefan> distinguish the two different kinds of colons. In my view the simplest is treating ":" different inside and outside of braces. Outside of braces it acts as a separator in a selector, with the suffix being a pseudo-class or pseudo-element: p::after { blah } Inside braces it separates a property name from the value: p { property-name: value; } Tom diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el index 4d02b75..5cb9027 100644 --- a/lisp/emacs-lisp/smie.el +++ b/lisp/emacs-lisp/smie.el @@ -1140,7 +1140,7 @@ smie-rules-function - :before, in which case ARG is a token and the function should return the OFFSET to use to indent ARG itself. - :elem, in which case the function should return either: - - the offset to use to indent function arguments (ARG = `arg') + - the offset to use to indent function arguments (ARG = `args') - the basic indentation step (ARG = `basic'). - the token to use (when ARG = `empty-line-token') when we don't know how to indent an empty line. diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index c81c3f6..7f1b5ca 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el @@ -734,7 +734,7 @@ css-indent-offset (defconst css-smie-grammar (smie-prec2->grammar - (smie-precs->prec2 '((assoc ";") (assoc ",") (left ":"))))) + (smie-precs->prec2 '((assoc ";") (left ":"))))) (defun css-smie--forward-token () (cond @@ -764,6 +764,7 @@ css-smie--backward-token (defun css-smie-rules (kind token) (pcase (cons kind token) + (`(:list-intro . ":") t) (`(:elem . basic) css-indent-offset) (`(:elem . arg) 0) (`(:list-intro . ,(or `";" `"")) t) ;"" stands for BOB (bug#15467). diff --git a/test/manual/indent/css-mode.css b/test/manual/indent/css-mode.css index 3a00739..a7ee536 100644 --- a/test/manual/indent/css-mode.css +++ b/test/manual/indent/css-mode.css @@ -43,3 +43,44 @@ article:hover { color: black; } + +/* Example from bug#13425, with some changes. */ +body { + color: #333; + font: 15px "Helvetica Neue", + Helvetica, + Arial, + "Nimbus Sans L", + sans-serif; + font-x-commas: 15px "Helvetica Neue" + Helvetica + Arial + "Nimbus Sans L" + sans-serif; + font-weight: 300; + line-height: 1.625; + a { /* It also handles SCSS */ + font: 15px "Helvetica Neue", + Helvetica, + Arial, + "Nimbus Sans L", + sans-serif; + /* Some comment */ + font-x-commas: 15px "Helvetica Neue" + Helvetica + Arial + "Nimbus Sans L" + sans-serif; + } + /* Some comment at the end of a block */ +} + +/* Ensure bug#13425 doesn't regress this. */ +#navtable .current:link, +#navtable .current:visited, +#navtable .current:hover, +#navtable .current:active { + background-color: grey; + color: white; + border: thin solid black; +} From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 02 Feb 2017 19:13:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Stefan Monnier Cc: 13425@debbugs.gnu.org, Tom Tromey Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.148606274515537 (code B ref 13425); Thu, 02 Feb 2017 19:13:02 +0000 Received: (at 13425) by debbugs.gnu.org; 2 Feb 2017 19:12:25 +0000 Received: from localhost ([127.0.0.1]:54258 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cZMnx-00042W-Dy for submit@debbugs.gnu.org; Thu, 02 Feb 2017 14:12:25 -0500 Received: from mail-lf0-f41.google.com ([209.85.215.41]:36571) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cZMnv-00042J-1E for 13425@debbugs.gnu.org; Thu, 02 Feb 2017 14:12:23 -0500 Received: by mail-lf0-f41.google.com with SMTP id z134so13789651lff.3 for <13425@debbugs.gnu.org>; Thu, 02 Feb 2017 11:12:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:subject:to:cc:message-id:in-reply-to:references :mime-version; bh=S9nObAgVZoWWFW15eIqfhtOatQNjawINVn6HgQI1XLM=; b=iL+T0PnSHUGE6kFVeq9cM4jmio9EkNR2Bn7aXJY1JxokAdItq4JksJ1qdVGMJNfZlX BUkwe8MYzMusWVmcFWkeHbAXcsjkDL/bwILDE8WANUmWRi3nws0t1oVbQQxRcCHG21RS YKuawKLuD8wla98KLpkYyhDDRxCXMeLIlDP8UHoOJRrGyO0zA0AR4wAg8t4x8f/PKU00 r7holkim5ef1tqJW5t/Ce+41rfFLfz35v88QyuK8FcqAK8Qji6xbkuDxN+d/MVqYsipF gtKRP/3ql184SUc9NJcVb76F+3OX4eo6mEDtZCuggJfHjXN5mEF4Q/Znb8haiCQ9qOQT Vxag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:subject:to:cc:message-id:in-reply-to :references:mime-version; bh=S9nObAgVZoWWFW15eIqfhtOatQNjawINVn6HgQI1XLM=; b=hSF/ghrP7Z/H2GU5ysOmgKMj1kPa7y0YxJlB1tBVjmyAcJrLkm7iR+CGCj6p1+ryvl WkQjHmjirF0znOHJ+k8tpOgBC1vtWAK9ykkdN2EN6i5i8dc3wXqDH4gYnEMBQNdrYf3m 45SXLZgWqJl04lGwyDYQDFeiFAkZJdn5Lv8FoUtlB4zsty9HWqwbHEVcunIo0c7kkYjn nT+q4nOD5g4X4o1rBwTXupd8nAsx+xnYYLgfnsOBdDOt7B5bbSIM7r3+A0nroBipdALf 9xT3cnnmMp+QftfScA4rdwOzQXAKOgupsdAR30SDCFNL8vVVO1RS+FW1iL8GI6oA7+YV 2K7g== X-Gm-Message-State: AIkVDXICzPieWFVsh6w2sc3sQAqUG/H7ENMJTc+R94MIVPkkm74Yz4NUhtYR2ZwQcIhVPw== X-Received: by 10.46.80.71 with SMTP id v7mr4206220ljd.38.1486062736959; Thu, 02 Feb 2017 11:12:16 -0800 (PST) Received: from [192.168.100.10] (cm-84.210.143.4.getinternet.no. [84.210.143.4]) by smtp.gmail.com with ESMTPSA id d77sm6872306lfd.26.2017.02.02.11.12.15 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 02 Feb 2017 11:12:16 -0800 (PST) Date: Thu, 02 Feb 2017 20:12:14 +0100 From: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Message-Id: <1486062734.11108.0@smtp.gmail.com> In-Reply-To: References: <87efzqhh93.fsf@tromey.com> <1485711505.6518.0@smtp.gmail.com> <1485711505.6518.0@smtp.gmail.com> <"Simen =?UTF-8?Q?Heggest=C3=B8=3D=3FUTF-8=3FQ=3Fyl?="'s_message_of_"Sun, _29_Jan_2017_18:38:25_+0100"> X-Mailer: geary/0.11.3 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-QA5GbWI4koA1TI4QsdlF" X-Spam-Score: -0.7 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.7 (/) --=-QA5GbWI4koA1TI4QsdlF Content-Type: text/plain; charset=utf-8; format=flowed Thanks for the hints, Stefan. The attached patch seems sufficient in my tests. Do you see any problems with it? -- Simen --=-QA5GbWI4koA1TI4QsdlF Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-WIP.patch >From b2772f486ab833fc5221577811a5d517dfc77742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simen=20Heggest=C3=B8yl?= Date: Thu, 2 Feb 2017 20:05:32 +0100 Subject: [PATCH] WIP --- lisp/textmodes/css-mode.el | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index 19f74daec6..65a599d6d4 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el @@ -32,10 +32,11 @@ ;;; Code: +(require 'eww) (require 'seq) (require 'sgml-mode) (require 'smie) -(require 'eww) +(require 'subr-x) (defgroup css nil "Cascading Style Sheets (CSS) editing mode." @@ -741,7 +742,30 @@ css-indent-offset (defconst css-smie-grammar (smie-prec2->grammar - (smie-precs->prec2 '((assoc ";") (assoc ",") (left ":"))))) + (smie-precs->prec2 + '((assoc ";") + ;; Colons that belong to a CSS property. These get a higher + ;; precedence than other colons, such as colons in selectors, + ;; which are represented by a plain ":" token. + (left ":-property") + (assoc ",") + (assoc ":"))))) + +(defun css--colon-inside-selector-p () + "Return t if point looks to be inside a CSS selector. +This function is intended to be good enough to help SMIE during +tokenization, but should not be regarded as a reliable function +for determining wheter point is within a selector." + (save-excursion + (re-search-forward "[{};)]" nil t) + (eq (char-before) ?\{))) + +(defun css--colon-inside-funcall () + "Return t if point is inside a function call." + (when-let (opening-paren-pos (nth 1 (syntax-ppss))) + (save-excursion + (goto-char opening-paren-pos) + (eq (char-after) ?\()))) (defun css-smie--forward-token () (cond @@ -755,7 +779,13 @@ css-smie--forward-token ";") ((progn (forward-comment (point-max)) (looking-at "[;,:]")) - (forward-char 1) (match-string 0)) + (forward-char 1) + (if (equal (match-string 0) ":") + (if (or (css--colon-inside-selector-p) + (css--colon-inside-funcall)) + ":" + ":-property") + (match-string 0))) (t (smie-default-forward-token)))) (defun css-smie--backward-token () @@ -766,7 +796,13 @@ css-smie--backward-token ((and (eq (char-before) ?\}) (scss-smie--not-interpolation-p) (> pos (point))) ";") ((memq (char-before) '(?\; ?\, ?\:)) - (forward-char -1) (string (char-after))) + (forward-char -1) + (if (eq (char-after) ?\:) + (if (or (css--colon-inside-selector-p) + (css--colon-inside-funcall)) + ":" + ":-property") + (string (char-after)))) (t (smie-default-backward-token))))) (defun css-smie-rules (kind token) -- 2.11.0 --=-QA5GbWI4koA1TI4QsdlF-- From unknown Tue Jun 24 03:25:21 2025 X-Loop: help-debbugs@gnu.org Subject: bug#13425: close this bug? Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 03 Feb 2017 00:04:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 13425 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: To: Simen =?UTF-8?Q?Heggest=C3=B8yl?= Cc: 13425@debbugs.gnu.org, Tom Tromey Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.14860801868792 (code B ref 13425); Fri, 03 Feb 2017 00:04:01 +0000 Received: (at 13425) by debbugs.gnu.org; 3 Feb 2017 00:03:06 +0000 Received: from localhost ([127.0.0.1]:54316 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cZRLG-0002Hk-7v for submit@debbugs.gnu.org; Thu, 02 Feb 2017 19:03:06 -0500 Received: from ironport2-out.teksavvy.com ([206.248.154.181]:50121) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cZRLE-0002HF-8m for 13425@debbugs.gnu.org; Thu, 02 Feb 2017 19:03:05 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0ATKQAu3EVY/0gvq8AjOhoBAQEBAgEBAQEIAQEBAYM4AQEBAQEfhFuFVJwoAZZeGYYDBAICghFDEQECAQEBAQEBAWIohGkGViMQCzQSFBgNJC6IVK0Ui0QBAQEHAgEkixmKKQWPfIpqknOIJ4Y6kg81IXgTDoVzIIktAQEB X-IPAS-Result: A0ATKQAu3EVY/0gvq8AjOhoBAQEBAgEBAQEIAQEBAYM4AQEBAQEfhFuFVJwoAZZeGYYDBAICghFDEQECAQEBAQEBAWIohGkGViMQCzQSFBgNJC6IVK0Ui0QBAQEHAgEkixmKKQWPfIpqknOIJ4Y6kg81IXgTDoVzIIktAQEB X-IronPort-AV: E=Sophos;i="5.33,749,1477972800"; d="scan'208";a="291922653" Received: from 192-171-47-72.cpe.pppoe.ca (HELO pastel.home) ([192.171.47.72]) by smtp.teksavvy.com with ESMTP; 02 Feb 2017 19:02:57 -0500 Received: by pastel.home (Postfix, from userid 20848) id 3010B6577E; Thu, 2 Feb 2017 19:02:57 -0500 (EST) From: Stefan Monnier Message-ID: References: <87efzqhh93.fsf@tromey.com> <1485711505.6518.0@smtp.gmail.com> <=?UTF-8?Q?1485711505.6518.0@smtp.gmail.com> <1486062734.11108.0@smtp.gmail.com> Date: Thu, 02 Feb 2017 19:02:57 -0500 In-Reply-To: <1486062734.11108.0@smtp.gmail.com> ("Simen =?UTF-8?Q?Heggest=C3=B8yl?="'s message of "Thu, 02 Feb 2017 20:12:14 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: 0.3 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 0.3 (/) > + (save-excursion > + (re-search-forward "[{};)]" nil t) > + (eq (char-before) ?\{))) Looks OK. It will get confused if there's a comment jut at the wrong place with one of ";{})" inside, which is not unheard of. It's good enough for now, but a solution I've used frequently with SMIE is to call a "tokenize-backward" (usually a less discriminating one than the actual backward tokenizer I give to SMIE, to avoid inf-recursion) repeatedly rather than using a regexp-search. Stefan From unknown Tue Jun 24 03:25:21 2025 MIME-Version: 1.0 X-Mailer: MIME-tools 5.505 (Entity 5.505) X-Loop: help-debbugs@gnu.org From: help-debbugs@gnu.org (GNU bug Tracking System) To: E Sabof Subject: bug#13425: closed (Re: bug#13425: close this bug?) Message-ID: References: <1486236671.5094.0@smtp.gmail.com> X-Gnu-PR-Message: they-closed 13425 X-Gnu-PR-Package: emacs Reply-To: 13425@debbugs.gnu.org Date: Sat, 04 Feb 2017 19:32:02 +0000 Content-Type: multipart/mixed; boundary="----------=_1486236722-23133-1" This is a multi-part message in MIME format... ------------=_1486236722-23133-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Your bug report #13425: new css-mode indenter which was filed against the emacs package, has been closed. The explanation is attached below, along with your original report. If you require more details, please reply to 13425@debbugs.gnu.org. --=20 13425: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=3D13425 GNU Bug Tracking System Contact help-debbugs@gnu.org with problems ------------=_1486236722-23133-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at 13425-done) by debbugs.gnu.org; 4 Feb 2017 19:31:20 +0000 Received: from localhost ([127.0.0.1]:56306 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ca63M-00060B-F7 for submit@debbugs.gnu.org; Sat, 04 Feb 2017 14:31:20 -0500 Received: from mail-lf0-f68.google.com ([209.85.215.68]:34485) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ca63L-0005zy-Hx for 13425-done@debbugs.gnu.org; Sat, 04 Feb 2017 14:31:19 -0500 Received: by mail-lf0-f68.google.com with SMTP id q89so773611lfi.1 for <13425-done@debbugs.gnu.org>; Sat, 04 Feb 2017 11:31:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:subject:to:cc:message-id:in-reply-to:references :mime-version; bh=hpm5KPTs4fVIziCX6ujVg5bFfWXaHyAV0b651Gk4rAg=; b=Gx8KBBX/qqAgpGhDC40Geh7GmxJBBamPh3Pz2iOs1IApBlKHA3oLz5v2mtXe1USuh9 WQvO5JMEaqoeoww+LTHjtkx9yZeMJ5SvrzT4aZcy+7MuIZoYB6C56jnmbRI1gO5ij7um 5QMW9GrKO2qyYl4I+4AGzcRKPmofy7T94iqx1Aw0q6aT5G/jbgd67UR3JPYqy02zwRM8 BlCcsB3xDQ3q+dfyTaIChLIYeYFd12fSEkNwOwRVIDY9pgtSc7Qi21TdFIftEdxQruE5 EmA1tZKAN4aulewuVUi45/y9MUTKY4AB2zJ/be3QR+Bag+H7v97dLc4Va8Je829DgU/Y L5uA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:subject:to:cc:message-id:in-reply-to :references:mime-version; bh=hpm5KPTs4fVIziCX6ujVg5bFfWXaHyAV0b651Gk4rAg=; b=rLQ1x3EisAe24GzydHAXCoK0gNuIZfSyNLhbYhPV3n6UMTvL6+q7wRRJEdPkXNf4gS kgmg/ACPevLpimwfAWo8LVg30VP2fbLpVtySCcahFfmRMMFrXDLVlSWUFiYBM1VK0NTd z29NfDSrNFoHYfyeF9nNT2dL0CpA1st2ShCutRo1o7L0jvgmFqjohOmgr5qBhLmR1N9a 6P+6BWtBtkB0X3SZ6vFCx7GXSRW02PyoH4Mf9eVTy5L9pMyIx4T5cshsWLwnPrD0RCx8 0Va2472cLrfN9AiFjZl/61CGvoYSp1oessyxr+uL017VdbLqoU+kULOuBvc8Z01n81Sf vfgA== X-Gm-Message-State: AIkVDXKDq7NUNnoCXoVhuFi1VFdBJ+4iM4NUjbBMCZ7rq94w6MOX1UUsPRD9KbVSZ7JfpQ== X-Received: by 10.46.8.82 with SMTP id g18mr144656ljd.1.1486236673356; Sat, 04 Feb 2017 11:31:13 -0800 (PST) Received: from [192.168.100.10] (cm-84.210.143.4.getinternet.no. [84.210.143.4]) by smtp.gmail.com with ESMTPSA id x3sm8798446lfa.7.2017.02.04.11.31.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sat, 04 Feb 2017 11:31:12 -0800 (PST) Date: Sat, 04 Feb 2017 20:31:11 +0100 From: Simen =?iso-8859-1?q?Heggest=F8yl?= Subject: Re: bug#13425: close this bug? To: Stefan Monnier , esabof@gmail.com Message-Id: <1486236671.5094.0@smtp.gmail.com> In-Reply-To: References: <87efzqhh93.fsf@tromey.com> <1485711505.6518.0@smtp.gmail.com> <=?UTF-8?Q?1485711505.6518.0@smtp.gmail.com> <1486062734.11108.0@smtp.gmail.com> <=?UTF-8?Q?1486062734.11108.0@smtp.gmail.com> <"Simen_Heggest?= =?UTF-8?Q?=C3=B8yl"'s_message_of_"Thu, _02_Feb_2017_20:12:14_+0100"> X-Mailer: geary/0.11.3 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed X-Spam-Score: 0.5 (/) X-Debbugs-Envelope-To: 13425-done Cc: 13425-done@debbugs.gnu.org, Tom Tromey X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 0.5 (/) Good, I've installed the patch as f6ff7bb1fcd062fe. It should cover the mentioned test cases. I'm closing this bug since the current CSS indenter now handles multiline property values better. Evgeni, I'm sorry that your report had to sit around for so long. Thank you for prodding us to improve the indentation engine in this regard! -- Simen ------------=_1486236722-23133-1 Content-Type: message/rfc822 Content-Disposition: inline Content-Transfer-Encoding: 7bit Received: (at submit) by debbugs.gnu.org; 13 Jan 2013 07:44:21 +0000 Received: from localhost ([127.0.0.1]:57581 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TuIEu-0007vz-PR for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:44:21 -0500 Received: from eggs.gnu.org ([208.118.235.92]:57013) by debbugs.gnu.org with esmtp (Exim 4.72) (envelope-from ) id 1TuIEt-0007vm-6Z for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:44:20 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TuIEP-0006LW-Co for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:43:57 -0500 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_LOW,T_DKIM_INVALID autolearn=unavailable version=3.3.2 Received: from lists.gnu.org ([208.118.235.17]:43375) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuIEP-0006LS-9L for submit@debbugs.gnu.org; Sun, 13 Jan 2013 02:43:49 -0500 Received: from eggs.gnu.org ([208.118.235.92]:40108) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuIEH-0006K1-2v for bug-gnu-emacs@gnu.org; Sun, 13 Jan 2013 02:43:49 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TuIE9-0006HH-Jy for bug-gnu-emacs@gnu.org; Sun, 13 Jan 2013 02:43:41 -0500 Received: from mail-qc0-f172.google.com ([209.85.216.172]:48028) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuIE9-0006H8-FZ for bug-gnu-emacs@gnu.org; Sun, 13 Jan 2013 02:43:33 -0500 Received: by mail-qc0-f172.google.com with SMTP id b25so1964104qca.31 for ; Sat, 12 Jan 2013 23:43:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=S3pCcGnOrRPyQTJepVVSWx22Ws4YABiuU1FWTMEhzms=; b=GyoPsaZp9MsbqLr+7RY/hMKq8qVyqwOcU5FwNBQhuqgrPjw5KKHS5SKj4UchF1Yfu9 ggi/RUhE/Eom8fTNc6iqj4Wtfl/KLBXZVTFfCv9IW3PHrygj6JllH/cx2rsttQgjorKE vx5ggsRJkG+FmgtNSQZfVu7E232XZ6ifln9FOqYtLYTdM7IIHHcFwgIGU7cKopRNJQ2u Ie6BYy21l6L/niTLX827pGQ3iZhq/p6rVG0XlyemjbrTcnudR5GCOPAR9Gx5O5vpCzMk c6xgg6B8WnP9q+aY15QHJNXEdYSBWYMse+4WJZ9DuPHs8pnzQdksNZYvYxkBhw/F/adf 5cLA== MIME-Version: 1.0 Received: by 10.224.78.209 with SMTP id m17mr68677168qak.45.1358063012099; Sat, 12 Jan 2013 23:43:32 -0800 (PST) Received: by 10.49.4.102 with HTTP; Sat, 12 Jan 2013 23:43:31 -0800 (PST) Date: Sun, 13 Jan 2013 07:43:31 +0000 Message-ID: Subject: new css-mode indenter From: E Sabof To: bug-gnu-emacs@gnu.org Content-Type: multipart/alternative; boundary=20cf3074b1ba6b347e04d326af9d X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [fuzzy] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 208.118.235.17 X-Spam-Score: -3.4 (---) X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: debbugs-submit-bounces@debbugs.gnu.org Errors-To: debbugs-submit-bounces@debbugs.gnu.org X-Spam-Score: -4.2 (----) --20cf3074b1ba6b347e04d326af9d Content-Type: text/plain; charset=ISO-8859-1 I've written a new indenter for CSS, which fixes issues with mulitline statements following a colon, and comments: body { color: #333; font: 15px "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", sans-serif; font-weight: 300; line-height: 1.625; a { /* It also handles SCSS */ font: 15px "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", sans-serif; /* Some comment */ } /* Some comment at the end of a block */ } I wondered whether this functionality could be integrated into Emacs. https://github.com/sabof/es-css-mode https://github.com/sabof/es-lib (it takes some functions from it) Evgeni --20cf3074b1ba6b347e04d326af9d Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
I've written a new indenter for CSS, which fixes issue= s with mulitline statements following a colon, and comments:=A0

body {
=A0 =A0 color: #333;
=A0 =A0 font: = 15px "Helvetica Neue",
=A0 =A0 =A0 =A0 Helvetica,
=A0 =A0 =A0 =A0 Arial,=A0
=A0 =A0 =A0 =A0 "Nimbus Sans L",
=A0 =A0 =A0 =A0 san= s-serif;
=A0 =A0 font-weight: 300;
=A0 =A0 line-height:= 1.625;
=A0 =A0 a { /* It also handles SCSS */
=A0 =A0 =A0 =A0 font: 15px "Helvetica Neue",
=A0 = =A0 =A0 =A0 =A0 =A0 Helvetica,
=A0 =A0 =A0 =A0 =A0 =A0 Arial,=A0<= /div>
=A0 =A0 =A0 =A0 =A0 =A0 "Nimbus Sans L",
=A0 = =A0 =A0 =A0 =A0 =A0 sans-serif;
=A0 =A0 =A0 =A0 /* Some comment *= /
=A0 =A0 }
=A0 =A0 /* Some comment at the end of a block */
}

I wondered whether this fun= ctionality could be integrated into Emacs.
https://github= .com/sabof/es-lib=A0(it takes some functions from it)

Evgeni

--20cf3074b1ba6b347e04d326af9d-- ------------=_1486236722-23133-1--