From 5d79ce42f323cd10aed073aac50104a2d7920ec3 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 24 Nov 2015 16:06:06 -0500 Subject: [PATCH] * sm-c-mode: Improve indentation of struct; plus bug fixes * packages/sm-c-mode/GNUmakefile: New file. * packages/sm-c-mode/sm-c-mode-test.c: Add some "struct" tests. Plus a #include. * packages/sm-c-mode/sm-c-mode.el (sm-c-syntax-propertize): Mark the <...> of #include as a string. (sm-c-smie--*-token): Try not to look too far back. (sm-c-smie-rules): Indent the {...} of struct and enum definitions. (sm-c--bs-realign-1): Fix behavior at EOB. (sm-c--cpp-is-not-really-a-comment): New function. (comment-only-p): Use it. --- packages/sm-c-mode/GNUmakefile | 21 ++++++++++ packages/sm-c-mode/sm-c-mode-test.c | 16 +++++++- packages/sm-c-mode/sm-c-mode.el | 63 ++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 packages/sm-c-mode/GNUmakefile diff --git a/packages/sm-c-mode/GNUmakefile b/packages/sm-c-mode/GNUmakefile new file mode 100644 index 000000000..2c6da32fc --- /dev/null +++ b/packages/sm-c-mode/GNUmakefile @@ -0,0 +1,21 @@ + +EMACS=emacs +DIFF=diff + +test: sm-c-mode-test.c.test + +.PHONY: refresh +refresh: + +%.elc : %.el + $(EMACS) --batch -L . --no-init-file -f batch-byte-compile $< + +%.test: % sm-c-mode.elc refresh + $(EMACS) --batch -l sm-c-mode-autoloads.el \ + sm-c-mode-test.c \ + --eval '(setq indent-tabs-mode nil)' \ + --eval '(setq create-lockfiles nil)' \ + --eval '(indent-region (point-min) (point-max) nil)' \ + --eval '(indent-region (point-min) (point-max) nil)' \ + --eval '(write-region (point-min) (point-max) "$@")' + $(DIFF) $< $@ || true; $(RM) $@ diff --git a/packages/sm-c-mode/sm-c-mode-test.c b/packages/sm-c-mode/sm-c-mode-test.c index 94cf476ff..4690105a3 100644 --- a/packages/sm-c-mode/sm-c-mode-test.c +++ b/packages/sm-c-mode/sm-c-mode-test.c @@ -1,5 +1,7 @@ /* -*- sm-c -*- */ +#include + #define toto(arg) /* bla bla */ \ if (a) { /* toto @@ -11,7 +13,19 @@ #define test(arg) \ (hello + arg) -struct foo; +struct foo + { + int field; + }; + +struct foo { + int field; +}; + +struct foo *getfoo (void) +{ + return NULL; +} #define titi(arg) { \ if (a) { \ diff --git a/packages/sm-c-mode/sm-c-mode.el b/packages/sm-c-mode/sm-c-mode.el index 7616616c2..1ac263eab 100644 --- a/packages/sm-c-mode/sm-c-mode.el +++ b/packages/sm-c-mode/sm-c-mode.el @@ -35,9 +35,8 @@ ;; it'd be nice to hook the sm-c--while-to-do, sm-c--else-to-if, and sm-c--boi ;; functions into SMIE at some level. -;; FIXME: -;; - M-; mistakes # for a comment in CPP directives! -;; Ha! As if this was the only/main problem! +;; Note that this mode makes no attempt to try and handle sanely K&R style +;; function definitions. ;;; Code: @@ -233,7 +232,15 @@ Typically 2 for GNU style and `tab-width' for Linux style." (sm-c--cpp-syntax-propertize end) (funcall (syntax-propertize-rules - (sm-c--cpp-regexp (2 (prog1 "< c" (sm-c--cpp-syntax-propertize end))))) + (sm-c--cpp-regexp + (2 (prog1 "< c" + (when (and (equal (match-string 3) "include") + (looking-at "[ \t]*\\(<\\)[^>\n]*\\(>\\)")) + (put-text-property (match-beginning 1) (match-end 1) + 'syntax-table (string-to-syntax "|")) + (put-text-property (match-beginning 2) (match-end 2) + 'syntax-table (string-to-syntax "|"))) + (sm-c--cpp-syntax-propertize end))))) (point) end)) (defun sm-c-syntactic-face-function (ppss) @@ -495,9 +502,19 @@ if INNER is non-nil, it stops at the innermost one." ((or "(" "[" "{" "}") "* deref") (`nil (goto-char pos) - (pcase (smie-backward-sexp "* mult") - (`(,_ ,_ ,(or ";" "{")) "* deref") - (_ "* mult"))) + (let ((res nil)) + (while (not res) + (pcase (smie-backward-sexp) + (`(,_ ,_ ,(or ";" "{")) (setq res "* deref")) + ((and `nil (guard (looking-at "{"))) (setq res "* deref")) + (`(,left ,_ ,op) + (if (and (numberp left) + (numberp (nth 2 (assoc op smie-grammar))) + (< (nth 2 (assoc op smie-grammar)) + (nth 1 (assoc "* mult" smie-grammar)))) + (smie-backward-sexp 'halfsexp) + (setq res "* mult"))))) + res)) (_ "* mult"))))) (defun sm-c-smie-hanging-eolp () @@ -565,8 +582,20 @@ if INNER is non-nil, it stops at the innermost one." (sm-c--boi 'inner) (sm-c--skip-labels (point-max)) (let ((tok (save-excursion (sm-c-smie-forward-token)))) (cond - ((member tok '("typedef")) ; "enum" "struct" - `(column . ,(+ (funcall smie-rules-function :elem 'basic) + ((or (equal tok "typedef") + (and (member tok '("enum" "struct")) + ;; Make sure that the {...} is about this struct/enum, + ;; as opposed to "struct foo *get_foo () {...}"! + (save-excursion + (smie-indent-forward-token) + (smie-indent-forward-token) + (forward-comment (point-max)) + (>= (point) pos)))) + `(column . ,(+ (if (save-excursion + (goto-char pos) + (smie-rule-hanging-p)) + 0 + (funcall smie-rules-function :elem 'basic)) (smie-indent-virtual)))) ((or (member tok sm-c-paren-block-keywords) (equal tok "do")) @@ -689,6 +718,7 @@ if INNER is non-nil, it stops at the innermost one." (end-of-line) (unless (zerop (mod (skip-chars-backward "\\\\") 2)) (skip-chars-backward " \t") + (setq from (point)) (let ((col (current-column)) start end) (while @@ -702,14 +732,14 @@ if INNER is non-nil, it stops at the innermost one." (while (progn (setq end (point)) (end-of-line 2) - (and (> (point) start) + (and (> (line-beginning-position) end) (not (zerop (mod (skip-chars-backward "\\\\") 2))))) (skip-chars-backward " \t") (setq col (max (current-column) col))) (goto-char to) (beginning-of-line) (unless (or (> (point) end) ;Don't realign if we changed outside! - (< end start)) ;A lone \ + (<= end start)) ;A lone \ (setq col (1+ col)) ;Add a space before the backslashes. (goto-char end) @@ -801,5 +831,16 @@ if INNER is non-nil, it stops at the innermost one." (add-hook 'after-change-functions #'sm-c--bs-after-change nil t) (add-hook 'post-command-hook #'sm-c--bs-realign nil t)) +(defun sm-c--cpp-is-not-really-a-comment (&rest args) + ;; Without this, placing the region around a CPP directive and hitting + ;; M-; would just strip the leading "#" instead of commenting things out. + (if (not (derived-mode-p 'sm-c-mode)) + (apply args) + (let ((parse-sexp-lookup-properties nil)) + (apply args)))) + +;; FIXME: Clearly, we should change newcomment.el instead. +(advice-add 'comment-only-p :around #'sm-c--cpp-is-not-really-a-comment) + (provide 'sm-c-mode) ;;; sm-c-mode.el ends here -- 2.39.2