From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.bugs Subject: bug#13425: new css-mode indenter Date: Tue, 15 Jan 2013 00:00:19 -0500 Message-ID: References: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1358226041 6151 80.91.229.3 (15 Jan 2013 05:00:41 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 15 Jan 2013 05:00:41 +0000 (UTC) Cc: 13425@debbugs.gnu.org To: E Sabof Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Tue Jan 15 06:00:59 2013 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Tuydt-0002Af-Om for geb-bug-gnu-emacs@m.gmane.org; Tue, 15 Jan 2013 06:00:57 +0100 Original-Received: from localhost ([::1]:36739 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Tuydd-0006cl-HM for geb-bug-gnu-emacs@m.gmane.org; Tue, 15 Jan 2013 00:00:41 -0500 Original-Received: from eggs.gnu.org ([208.118.235.92]:55675) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuydZ-0006cg-W2 for bug-gnu-emacs@gnu.org; Tue, 15 Jan 2013 00:00:40 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TuydX-0001kI-2q for bug-gnu-emacs@gnu.org; Tue, 15 Jan 2013 00:00:37 -0500 Original-Received: from debbugs.gnu.org ([140.186.70.43]:55215) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TuydW-0001kD-Uv for bug-gnu-emacs@gnu.org; Tue, 15 Jan 2013 00:00:34 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.72) (envelope-from ) id 1Tuydx-0007zt-TL for bug-gnu-emacs@gnu.org; Tue, 15 Jan 2013 00:01:02 -0500 X-Loop: help-debbugs@gnu.org 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: Original-Received: via spool by 13425-submit@debbugs.gnu.org id=B13425.135822605430727 (code B ref 13425); Tue, 15 Jan 2013 05:01:01 +0000 Original-Received: (at 13425) by debbugs.gnu.org; 15 Jan 2013 05:00:54 +0000 Original-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 Original-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" Original-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 Original-Received: by pastel.home (Postfix, from userid 20848) id 4BF4B59499; Tue, 15 Jan 2013 00:00:19 -0500 (EST) 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) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.13 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:69795 Archived-At: > 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."