From: Stefan Monnier Date: Wed, 25 Nov 2015 19:43:03 +0000 (-0500) Subject: * sm-c-mode.el: Improve "Commentary:" and docstrings X-Git-Url: https://code.delx.au/gnu-emacs-elpa/commitdiff_plain/7e76d0968317ff83b6310e9fed4d10de0fd05403 * sm-c-mode.el: Improve "Commentary:" and docstrings * sm-c-mode.el: Improve "Commentary:" and docstrings. (sm-c-smie--*-token): Fix inf-loop at BOB. * GNUmakefile (%.reindent): New rule. (HIJACK): New var. (%.test): Use $<. --- diff --git a/packages/sm-c-mode/GNUmakefile b/packages/sm-c-mode/GNUmakefile index 2c6da32fc..c9d648a14 100644 --- a/packages/sm-c-mode/GNUmakefile +++ b/packages/sm-c-mode/GNUmakefile @@ -1,6 +1,7 @@ EMACS=emacs DIFF=diff +HIJACK=--eval "(defalias 'c-mode 'sm-c-mode)" test: sm-c-mode-test.c.test @@ -12,10 +13,16 @@ refresh: %.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) $@ + +%.reindent: % sm-c-mode.elc refresh + $(EMACS) --batch -l sm-c-mode-autoloads.el $(HIJACK) \ + $< \ + --eval '(indent-region (point-min) (point-max) nil)' \ + --eval '(save-buffer)' diff --git a/packages/sm-c-mode/sm-c-mode.el b/packages/sm-c-mode/sm-c-mode.el index 1ac263eab..72cd75ef0 100644 --- a/packages/sm-c-mode/sm-c-mode.el +++ b/packages/sm-c-mode/sm-c-mode.el @@ -29,15 +29,53 @@ ;; might even do it OK for simple cases, but it really doesn't benefit much ;; from SMIE: ;; - it does a lot of its own parsing by hand. -;; - its smie-ruled-function also does a lot of indentation by hand. +;; - its smie-rules-function also does a lot of indentation by hand. ;; Hopefully at some point, someone will find a way to extend SMIE such that ;; it can handle C without having to constantly work around SMIE, e.g. -;; 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. +;; it'd be nice to hook sm-c--while-to-do, sm-c--else-to-if, sm-c--boi, +;; sm-c--boe, ... into SMIE at some level. ;; Note that this mode makes no attempt to try and handle sanely K&R style ;; function definitions. +;;;; Benchmarks + +;; This code can't be compared to CC-mode since its scope is much more limited +;; (only tries to handle the kind of code found in Emacs's source code, for +;; example; does not intend to be extensible to handle C++ or ObjC; does not +;; offer the same kind of customizability of indentation style, ...). +;; But in order to make sure it's doing a good enough job on the code for which +;; it was tuned, I did run some quick benchmarks against CC-mode: +;; +;; Benchmarks: reindent emacs/src/*.[ch] (skipping macuvs.h and globals.h +;; because CC-mode gets pathologically slow on them). +;; (cd src/emacs/work/; git reset --hard; mv src/macuvs.h src/globals.h ./); +;; files=($(echo ~/src/emacs/work/src/*.[ch])); +;; (cd src/emacs/work/; mv macuvs.h globals.h src/); +;; time make -j4 ${^${files}}.reindent EMACS="emacs24 -Q"; +;; (cd src/emacs/work/; git diff|wc) +;; - Default settings: +;; diff|wc => 86800 379362 2879534 +;; make -j4 191.57s user 1.77s system 334% cpu 57.78 total +;; - With (setq sm-c-indent-cpp-basic 0) +;; diff|wc => 59909 275415 2034045 +;; make -j4 177.88s user 1.70s system 340% cpu 52.80 total +;; - For reference, CC-mode gets: +;; diff|wc => 79164 490894 3428542 +;; make -j4 804.83s user 2.79s system 277% cpu 4:51.08 total +;; +;; Again: take this with a large grain of salt, since this is testing sm-c-mode +;; in the most favorable light (IOW it's a very strongly biased benchmark). +;; All this says, is that sm-c-mode's indentation might actually be usable if +;; you use it on C code that is sufficiently similar to Emacs's. + +;;;; FIXME: + +;; - We "use but don't use" SMIE. +;; - CPP directives are treated as comments. To some extent this is OK, but in +;; many other cases it isn't. See for instance the comment-only-p advice. +;; - M-q in a comment doesn't do the right thing. + ;;; Code: (require 'cl-lib) @@ -53,7 +91,10 @@ Typically 2 for GNU style and `tab-width' for Linux style." :type 'integer) (defcustom sm-c-indent-braces t - "If non-nil, braces in if/while/... are indented." + "If nil, braces in if/while/... are aligned with the if/while/... +Else, they're indented by `sm-c-indent-basic' columns. +For braces placed at the end of lines (which SMIE calls \"hanging\"), it makes +no difference." :type 'boolean) ;;; Handling CPP directives. @@ -115,7 +156,9 @@ Typically 2 for GNU style and `tab-width' for Linux style." ;;;; Indenting CPP directives. (defcustom sm-c-indent-cpp-basic 1 - "Indent step for CPP directives." + "Indent step for CPP directives. +If non-zero, CPP directives are indented according to CPP depth. +E.g. a #define nested within 2 #ifs will be turned into \"# define\"." :type 'integer) (defun sm-c--cpp-prev (tok) @@ -503,7 +546,7 @@ if INNER is non-nil, it stops at the innermost one." (`nil (goto-char pos) (let ((res nil)) - (while (not res) + (while (not (or res (bobp))) (pcase (smie-backward-sexp) (`(,_ ,_ ,(or ";" "{")) (setq res "* deref")) ((and `nil (guard (looking-at "{"))) (setq res "* deref")) @@ -514,7 +557,7 @@ if INNER is non-nil, it stops at the innermost one." (nth 1 (assoc "* mult" smie-grammar)))) (smie-backward-sexp 'halfsexp) (setq res "* mult"))))) - res)) + (or res "* mult"))) (_ "* mult"))))) (defun sm-c-smie-hanging-eolp () @@ -839,7 +882,8 @@ if INNER is non-nil, it stops at the innermost one." (let ((parse-sexp-lookup-properties nil)) (apply args)))) -;; FIXME: Clearly, we should change newcomment.el instead. +;; FIXME: Maybe we should change newcomment.el instead; or maybe CPP directives +;; should not be defined as comments, or at least "not always"! (advice-add 'comment-only-p :around #'sm-c--cpp-is-not-really-a-comment) (provide 'sm-c-mode)