unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: Stefan Monnier <monnier@iro.umontreal.ca>
To: E Sabof <esabof@gmail.com>
Cc: 13425@debbugs.gnu.org
Subject: bug#13425: new css-mode indenter
Date: Tue, 15 Jan 2013 00:00:19 -0500	[thread overview]
Message-ID: <jwvwqvfgibr.fsf-monnier+emacs@gnu.org> (raw)
In-Reply-To: <CAEp6DyZKEVqAZyYCvYfy2b9_p4MSNPWoubajJcL4FObMCDEBwQ@mail.gmail.com> (E. Sabof's message of "Sun, 13 Jan 2013 07:43:31 +0000")

> 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."






  reply	other threads:[~2013-01-15  5:00 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-13  7:43 bug#13425: new css-mode indenter E Sabof
2013-01-15  5:00 ` Stefan Monnier [this message]
2013-01-15 19:32   ` E Sabof
2013-01-17  0:17     ` E Sabof
2017-01-25 23:06 ` bug#13425: close this bug? Tom Tromey
2017-01-29 14:01   ` Simen Heggestøyl
2017-01-29 17:16   ` Stefan Monnier
2017-01-29 17:38     ` Simen Heggestøyl
2017-01-29 18:15       ` Stefan Monnier
2017-02-02 19:12         ` Simen Heggestøyl
2017-02-03  0:02           ` Stefan Monnier
2017-02-04 19:31             ` Simen Heggestøyl
2017-01-30 22:17     ` Tom Tromey
2017-01-30 22:28       ` Stefan Monnier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jwvwqvfgibr.fsf-monnier+emacs@gnu.org \
    --to=monnier@iro.umontreal.ca \
    --cc=13425@debbugs.gnu.org \
    --cc=esabof@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).