[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master e9a7ea8: * externals-list: Convert sm-c-mode to :external
From: |
Stefan Monnier |
Subject: |
[elpa] master e9a7ea8: * externals-list: Convert sm-c-mode to :external |
Date: |
Sat, 28 Nov 2020 18:11:11 -0500 (EST) |
branch: master
commit e9a7ea8f1c09360023b63168e0d4bea436aa96a3
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
* externals-list: Convert sm-c-mode to :external
---
externals-list | 1 +
packages/sm-c-mode/GNUmakefile | 28 --
packages/sm-c-mode/sm-c-mode-test.c | 97 ----
packages/sm-c-mode/sm-c-mode.el | 972 ------------------------------------
4 files changed, 1 insertion(+), 1097 deletions(-)
diff --git a/externals-list b/externals-list
index 8929ddb..3da8a25 100644
--- a/externals-list
+++ b/externals-list
@@ -155,6 +155,7 @@
("scanner" :external "https://gitlab.com/rstocker/scanner.git")
("shell-command+" :external
"https://git.sr.ht/~zge/bang/tree/shell-command+")
("slime-volleyball" :external nil)
+ ("sm-c-mode" :external nil)
("smalltalk-mode" :external "git://git.sv.gnu.org/smalltalk")
("so-long" :core "lisp/so-long.el")
("soap-client" :core ("lisp/net/soap-client.el"
"lisp/net/soap-inspect.el"))
diff --git a/packages/sm-c-mode/GNUmakefile b/packages/sm-c-mode/GNUmakefile
deleted file mode 100644
index c9d648a..0000000
--- a/packages/sm-c-mode/GNUmakefile
+++ /dev/null
@@ -1,28 +0,0 @@
-
-EMACS=emacs
-DIFF=diff
-HIJACK=--eval "(defalias 'c-mode 'sm-c-mode)"
-
-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 \
- $< \
- --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-test.c
b/packages/sm-c-mode/sm-c-mode-test.c
deleted file mode 100644
index 4756064..0000000
--- a/packages/sm-c-mode/sm-c-mode-test.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- sm-c -*- */
-
-#include <toto>
-
-#define toto(arg) /* bla
- bla */ \
- if (a) { /* toto
- * titi
- */ \
- fs((arg) + 2); \
- }
-
-#define test(arg) \
- (hello + arg)
-
-struct foo
- {
- int field;
- };
-
-struct foo {
- int field;
-};
-
-typedef struct bar {
- int field;
-} *BarPtr;
-
-struct foo *getfoo (void)
-{
- return NULL;
-}
-
-#define titi(arg) { \
- if (a) { \
- f(arg + 1) \
- } \
- }
-
-DEFUN ()
- ()
-{
- return Qnil;
-}
-
-int main (void)
-{
- if (a)
- do
- if (b)
- if (c)
- printf ("hello\n");
- else
- printf ("there\n");
- else
- printf ("elsewhere\n");
- while (6);
- else if (b)
- printf ("wow\n");
- else
- if (c)
- printf
- ("weee\n");
- else
- printf ("wop\n");
-
- if (a)
- if (b) {
- c;
- }
-
- *a = b;
-
- if (pITORIG != pITCOPY)
- *(pITORIG)
- = *(pITCOPY);
-
- switch (a)
- {
- case 1:
- {
- if (a)
- {
- y = 5;
- case 2:
- x = 3;
- }
- }
- }
-}
-
-static struct myownspecialstruct *
-testfunction
- (args)
-{
- return NULL;
-}
diff --git a/packages/sm-c-mode/sm-c-mode.el b/packages/sm-c-mode/sm-c-mode.el
deleted file mode 100644
index 7422a66..0000000
--- a/packages/sm-c-mode/sm-c-mode.el
+++ /dev/null
@@ -1,972 +0,0 @@
-;;; sm-c-mode.el --- C major mode based on SMIE -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2015-2020 Free Software Foundation, Inc.
-
-;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
-;; Version: 1.1
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This started as an experiment to see concretely where&how SMIE falls down
-;; when trying to handle a language like C, to get an idea of maybe what it
-;; would take to change SMIE to better support C-style syntax.
-;;
-;; So, this does provide "SMIE-based indentation for C" and might even do it OK
-;; in practice, but it really doesn't benefit much from SMIE:
-;; - it does a lot of its own parsing 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
-;; we can handle C without having to constantly work around SMIE, e.g.
-;; 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.
-
-;; This is not designed to supplant Emacs's built-in c-mode, which does a more
-;; thorough job. It was not even meant to be used by anyone, really, but
-;; I finally decided to release this because some users pointed out that on
-;; slow machines it can be a worthy lightweigth alternative.
-
-;;;; Known limitations:
-
-;; - This mode makes no attempt to try and handle sanely K&R style function
-;; definitions (i.e. where the type of arguments is given between the list of
-;; arguments and the body). There are 2 good reasons for that: this old
-;; syntax sucks and should be laid to rest, and it'd be a lot of extra work
-;; to try and handle it.
-
-;;;; Todo:
-
-;; - This mode mostly limits itself to the C99 syntax, so it would be nice
-;; to make it handle the syntactic constructs introduced since then.
-;; - 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.
-
-
-;;;; 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 .../emacs/; git reset --hard; mv src/macuvs.h src/globals.h ./);
-;; files=($(echo .../emacs/src/*.[ch]));
-;; (cd .../emacs/; mv macuvs.h globals.h src/);
-;; time make -j4 ${^${files}}.reindent EMACS="emacs24 -Q";
-;; (cd .../emacs/; 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
-;;
-;; IOW, in this "best case" scenario, `sm-c-mode' indented almost as well
-;; as `c-mode' does (as measured by diff|wc), and it did it about
-;; 4 times faster.
-;; BEWARE: 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.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'smie)
-
-(defgroup sm-c-mode nil
- "Major mode to edit C code, based on SMIE."
- :group 'programming)
-
-(defcustom sm-c-indent-basic 2
- "Basic step of indentation.
-Typically 2 for GNU style and `tab-width' for Linux style."
- :type 'integer)
-
-(defcustom sm-c-indent-braces t
- "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.
-
-(defsubst sm-c--cpp-inside-p (ppss)
- (eq 2 (nth 7 ppss)))
-
-(eval-and-compile
- (defconst sm-c--cpp-regexp "^[ \t]*\\(\\(#\\)[ \t]*\\([a-z]+\\)\\)"))
-
-(defconst sm-c--cpp-syntax-table
- (let ((st (make-syntax-table)))
- (modify-syntax-entry ?/ ". 124" st)
- (modify-syntax-entry ?* ". 23b" st)
- (modify-syntax-entry ?\n ">" st)
- st))
-
-(defun sm-c--cpp-goto-end (ppss &optional limit)
- (cl-assert (sm-c--cpp-inside-p ppss))
- (let (found)
- (while
- (and (setq found (re-search-forward "\\(?:\\\\\\\\\\)*\n" limit 'move))
- ;; We could also check (nth 5 ppss) to figure out if we're
- ;; after a backslash, but this is a very common case, so it's good
- ;; to avoid calling parse-partial-sexp for that.
- (or (eq ?\\ (char-before (match-beginning 0)))
- (with-syntax-table sm-c--cpp-syntax-table
- (nth 4 (parse-partial-sexp (1+ (nth 8 ppss)) (point)))))))
- found))
-
-(defvar syntax-ppss-cache)
-(defvar syntax-ppss-last)
-
-(defun sm-c--cpp-fontify-syntactically (ppss)
- ;; FIXME: ¡¡BIG UGLY HACK!!
- ;; Copied from font-lock.el's font-lock-fontify-syntactically-region.
- (cl-assert (> (point) (nth 8 ppss)))
- (save-excursion
- (save-restriction
- (sm-c--cpp-goto-end ppss)
- (narrow-to-region (1+ (nth 8 ppss)) (point))
- ;; FIXME: We should add some "with-local-syntax-ppss" macro to
- ;; encapsulate this.
- (let ((syntax-propertize-function nil)
- (syntax-ppss-cache nil)
- (syntax-ppss-last nil))
- (font-lock-fontify-syntactically-region (point-min) (point-max))))))
-
-(defun sm-c--cpp-syntax-propertize (end)
- (let ((ppss (syntax-ppss))
- found)
- (when (sm-c--cpp-inside-p ppss)
- (while
- (and (setq found (re-search-forward "\\(\\\\\\\\\\)*\n" end 'move))
- (or (eq ?\\ (char-before (match-beginning 0)))
- (with-syntax-table sm-c--cpp-syntax-table
- (nth 4 (parse-partial-sexp (1+ (nth 8 ppss)) (point)))))))
- (when found
- (let* ((ppss-in
- (save-excursion
- (parse-partial-sexp (1+ (nth 8 ppss)) (1- (point)))))
- ;; Put the end before a closing //...\n comment so as to avoid
- ;; a bug in back_comment. The problem is that back_comment
- ;; otherwise will see "// <...> <...> \n" and will consider the
- ;; CPP pseudo-comments as nested within the //...\n comment.
- (end (if (and (nth 4 ppss-in) ;Inside a comment.
- (null (nth 7 ppss-in)) ;A style `a' comment.
- (memq (char-before (nth 8 ppss-in)) '(?\s ?\t)))
- (nth 8 ppss-in)
- (point))))
- (put-text-property (1- end) end
- 'syntax-table (string-to-syntax "> c")))))))
-
-;;;; Indenting CPP directives.
-
-(defcustom sm-c-indent-cpp-basic 1
- "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)
- (let ((offset nil))
- (while
- (when (re-search-backward sm-c--cpp-regexp nil t)
- (pcase (cons tok (match-string 3))
- (`(,_ . "endif") (sm-c--cpp-prev "endif"))
- ((or `(,(or "endif" "else" "elif") . ,(or "if" "ifdef" "ifndef"))
- `(,(or "else" "elif") . "elif"))
- (setq offset 0))
- (`(,(or "endif" "else" "elif") . ,_) nil)
- (`(,_ . ,(or "if" "ifdef" "ifndef" "elif" "else"))
- (setq offset sm-c-indent-cpp-basic))
- (_ (setq offset 0)))
- (not offset)))
- (when offset
- (goto-char (match-beginning 3))
- (+ offset (current-column)))))
-
-
-(defun sm-c--cpp-indent-line (&optional _arg)
- ;; FIXME: Also align the terminating \, if any.
- (when (> sm-c-indent-cpp-basic 0)
- (let* ((pos (point-marker))
- (beg)
- (indent
- (save-excursion
- (forward-line 0)
- (when (looking-at sm-c--cpp-regexp)
- (setq beg (match-beginning 3))
- (or (sm-c--cpp-prev (match-string 3)) 0)))))
- (when indent
- (let ((before (<= pos beg)))
- (goto-char beg)
- (unless (= (current-column) indent)
- (skip-chars-backward " \t")
- (delete-region (point)
- (progn (skip-chars-forward " \t") (point)))
- (indent-to indent))
- (unless before (goto-char pos)))))))
-
-;;;; Indenting inside CPP #define.
-
-(defconst sm-c--cpp-smie-indent-functions
- ;; FIXME: Don't just align line after #define with the "d"!
- (mapcar
- (lambda (f)
- (cond
- ((eq f #'smie-indent-comment-inside) #'sm-c--cpp-indent-comment-inside)
- ;; ((eq f #'smie-indent-exps) #'sm-c--cpp-indent-exps)
- (t f)))
- (default-value 'smie-indent-functions)))
-
-(defun sm-c--cpp-indent-comment-inside ()
- (let ((ppss (syntax-ppss)))
- (when (nth 4 ppss)
- ;; Indicate where's the comment start.
- `(noindent . ,(nth 8 ppss)))))
-
-(defun sm-c--cpp-smie-indent ()
- (let ((ppss (syntax-ppss)))
- (cond
- ((sm-c--cpp-inside-p ppss)
- (save-restriction
- (narrow-to-region (nth 8 ppss) (point-max))
- (let ((indent
- (let ((smie-indent-functions sm-c--cpp-smie-indent-functions)
- (syntax-ppss-cache nil)
- (syntax-ppss-last nil)
- (parse-sexp-lookup-properties nil))
- (smie-indent-calculate))))
- (if (not (eq 'noindent (car-safe indent)))
- (if (integerp indent)
- (max (funcall smie-rules-function :elem 'basic) indent)
- indent)
- ;; We can't just return `noindent' if we're inside a comment,
- ;; because the indent.el code would then be similarly confused,
- ;; thinking the `noindent' is because we're inside the cpp
- ;; pseudo-comment, and would hence align the code with the content
- ;; of the psuedo-comment rather than the nested real comment!
- ;;
- ;; FIXME: Copy&paste from indent--default-inside-comment.
- ;; FIXME: This will always re-indent inside these comments, even
- ;; during indent-region.
- (save-excursion
- (forward-line -1)
- (skip-chars-forward " \t")
- (when (< (1- (point)) (cdr indent) (line-end-position))
- (goto-char (cdr indent))
- (when (looking-at comment-start-skip)
- (goto-char (match-end 0))))
- (current-column))))))
-
- ((equal (syntax-after (point)) (string-to-syntax "< c")) 0)
- )))
-
-;;; Syntax table
-
-(defvar sm-c-mode-syntax-table
- (let ((st (make-syntax-table)))
- (modify-syntax-entry ?/ ". 124" st)
- (modify-syntax-entry ?* ". 23b" st)
- (modify-syntax-entry ?\n ">" st)
- (modify-syntax-entry ?\" "\"" st)
- (modify-syntax-entry ?\' "\"" st)
- (modify-syntax-entry ?= "." st)
- (modify-syntax-entry ?+ "." st)
- (modify-syntax-entry ?- "." st)
- (modify-syntax-entry ?< "." st)
- (modify-syntax-entry ?> "." st)
- st))
-
-(defun sm-c-syntax-propertize (start end)
- (goto-char start)
- (sm-c--cpp-syntax-propertize end)
- (funcall
- (syntax-propertize-rules
- (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))))
- ;; Handle // comments that span multiple lines via \\\n!
- ("\\\\\\(\n\\)"
- (1 (let ((ppss (save-excursion (syntax-ppss (match-beginning 0)))))
- (when (and (nth 4 ppss) ;Within a comment
- (null (nth 7 ppss)) ;Within a // comment
- (save-excursion ;The \ is not itself escaped
- (goto-char (match-beginning 0))
- (zerop (mod (skip-chars-backward "\\\\") 2))))
- (string-to-syntax "."))))))
- (point) end))
-
-(defun sm-c-syntactic-face-function (ppss)
- (if (sm-c--cpp-inside-p ppss)
- (prog1 nil (sm-c--cpp-fontify-syntactically ppss))
- (funcall (default-value 'font-lock-syntactic-face-function) ppss)))
-
-;;; SMIE support
-
-(defconst sm-c-paren-block-keywords '("if" "while" "for" "switch"))
-
-(defconst sm-c-smie-precedence-table
- '((assoc ";")
- ;; Compiled from https://en.wikipedia.org/wiki/Operators_in_C_and_C++.
- (assoc ",") ;1
- ;; (nonassoc "throw")
- (nonassoc "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>=" "&=" "^=" "|=") ;2
- ;; (nonassoc "?" ":") ;; Better handle it in the BNF.
- (assoc "||") ;3
- (assoc "&&") ;4
- (assoc "|") ;5
- (assoc "^") ;6
- ;; (assoc "&") ;; Binary and. Confused with address-of.
- (nonassoc "==" "!=") ;7
- (nonassoc "<" "<=" ">" ">=") ;8
- (nonassoc "<<" ">>") ;9
- (assoc "+" "-") ;10
- (assoc "/" "* mult" "%") ;11
- ;; (nonassoc ".*" "->*") ;12 ;; Only C++
- ;; (nonassoc "++" "--" "+" "-" "!" "~" "(type)" "*" "&"
- ;; "sizeof" "new" "delete");13 ;; All prefix.
- (left "." "->") ;; "++" "--" suffixes, "()", "[]", "typeid", "*_cast". ;14
- ;; (noassoc "::") ;; Only C++
- ))
-
-(defconst sm-c-smie-grammar
- ;; `((:smie-closer-alist ("{" . "}")) ("{" (39) 0) ("}" 0 (40)) ("else" 27
26) ("," 38 38) ("do" (41) 22) ("while" (42) 23) ("for" (43) 24) (";" 11 11)
("if" (44) 25))
- (let ((grm
- (smie-prec2->grammar
- (smie-merge-prec2s
- (smie-bnf->prec2
- '((decls ("typedef" decl) ("extern" decl)
- (decls ";" decls))
- (decl)
- (id)
- (insts ("{" insts "}")
- (insts ";" insts)
- ("return" exp)
- ("goto" exp)
- (":label")
- ("case" subexp ": case")
- ("else" exp-if))
- (exp-if ("if" exp) ("do" exp) ("while" exp) ("switch" exp)
("for" exp)
- (exp))
- (exp ("(" exp ")") (exp "," exp) (subexp "?" exp ":" exp))
- (subexp (subexp "||" subexp))
- ;; Some of the precedence table deals with pre/postfixes, which
- ;; smie-precs->prec2 can't handle, so handle it here instead.
- (exp11 (exp12) (exp11 "/" exp11))
- (exp12 (exp13)) ;C++ only.
- (exp13 (exp14) ("++ prefix" exp13) ("-- prefix" exp13)
- ("!" exp13) ("~" exp13) ("&" exp13) ("* deref" exp13))
- (exp14 (id) (exp14 "++ postfix") (exp14 "-- postfix")
- (exp14 "->" id) (exp14 "." id)))
- '((assoc ";") (assoc ",") (nonassoc "?" ":"))
- sm-c-smie-precedence-table)
- (smie-precs->prec2 sm-c-smie-precedence-table)
- (smie-precs->prec2 '((nonassoc ";") (nonassoc ":")))))))
- ;; SMIE gives (":label" 261 262), but really this could just as well be
- ;; (":label" nil nil) because labels don't have any argument to their left
- ;; or right. They're like both openers and closers at the same time.
- (mapcar (lambda (x)
- (if (equal (car-safe x) ":label")
- ;; Rather than (":label" (n1) (n2)) we use
- ;; (":label" (n1) n2) because SMIE otherwise complains:
- ;; cl--assertion-failed((numberp (funcall op-forw
toklevels)))
- ;; in smie-next-sexp.
- `(,(nth 0 x) (,(nth 1 x)) ,(nth 2 x)) x))
- grm)))
-
-;; (defun sm-c--:-discriminate ()
-;; (save-excursion
-;; (and (null (smie-backward-sexp))
-;; (let ((prev (smie-indent-backward-token)))
-;; (cond
-;; ((equal prev "case" ) ": case")
-;; ((member prev '(";" "{" "}")) ":-label")
-;; (t ":"))))))
-
-(defconst sm-c-smie-operator-regexp
- (let ((ops '()))
- (pcase-dolist (`(,token . ,_) sm-c-smie-grammar)
- (when (and (stringp token) (string-match "\\`[^ [:alnum:](){}]+" token))
- (push (match-string 0 token) ops)))
- (regexp-opt ops)))
-
-(defun sm-c-smie-forward-token ()
- (forward-comment (point-max))
- (let ((tok (if (looking-at sm-c-smie-operator-regexp)
- (progn (goto-char (match-end 0)) (match-string 0))
- (smie-default-forward-token))))
- (cond
- ((and (equal tok "") (looking-at "\\\\\n"))
- (goto-char (match-end 0))
- (sm-c-smie-forward-token))
- ((member tok '(":" "*"))
- (save-excursion (sm-c-smie-backward-token)))
- ((looking-at "[ \t]*:")
- (if (not (equal (save-excursion (sm-c-smie-forward-token)) ":label"))
- tok
- (looking-at "[ \t]*:")
- (goto-char (match-end 0)) ":label"))
- (t tok))))
-
-
-(defun sm-c-smie-backward-token ()
- (forward-comment (- (point)))
- (let ((tok (if (looking-back sm-c-smie-operator-regexp (- (point) 3) t)
- (progn (goto-char (match-beginning 0)) (match-string 0))
- (smie-default-backward-token))))
- (cond
- ((and (equal tok "") (looking-at "\n"))
- (let ((pos (point)))
- (if (not (= 0 (mod (skip-chars-backward "\\\\") 2)))
- (sm-c-smie-backward-token)
- (goto-char pos)
- tok)))
- ((equal tok "*") (sm-c-smie--*-token))
- ((equal tok ":")
- (let ((pos1 (point))
- (prev (sm-c-smie-backward-token)))
- (if (zerop (length prev))
- (progn (goto-char pos1) tok)
- (let ((pos2 (point)))
- (pcase (car (smie-indent-backward-token))
- ("case" (goto-char pos1) ": case")
- ((or ";" "{" "}") (goto-char pos2) ":label")
- (_ (goto-char pos1) tok))))))
- (t tok))))
-
-(defun sm-c--prev-token ()
- (car (smie-indent-backward-token)))
-
-(defun sm-c--else-to-if ()
- (let ((pos (point)))
- (unless (equal (sm-c--prev-token) ";")
- (goto-char pos))
- (while
- (pcase (smie-backward-sexp)
- (`(,_ ,pos "if") (goto-char pos) nil) ;Found it!
- (`(,_ ,_ ";") nil) ;Can't find it!
- (`(,_ ,pos "else") (goto-char pos) (sm-c--else-to-if) t)
- (`(,_ ,pos "while")
- (goto-char pos) (unless (sm-c--while-to-do) (goto-char pos)) t)
- (`(t . ,_) nil) ;Can't find it!
- (`(,_ ,pos . ,_) (goto-char pos) t)
- (`nil t)))))
-
-(defun sm-c--while-to-do ()
- "Jump to the matching `do' and return non-nil, if any. Return nil
otherwise."
- (pcase (sm-c--prev-token)
- ("}"
- ;; The easy case!
- (forward-char 1) (backward-sexp 1)
- (equal (sm-c--prev-token) "do"))
- (";"
- (let ((found-do nil))
- (while
- (pcase (smie-backward-sexp)
- (`(,_ ,pos "do") (goto-char pos) (setq found-do t) nil)
- (`(,_ ,_ ";") nil) ;Can't find it!
- (`(,_ ,pos "else") (goto-char pos) (sm-c--else-to-if) t)
- (`(,_ ,pos "while")
- (goto-char pos) (unless (sm-c--while-to-do) (goto-char pos)) t)
- (`(t . ,_) nil) ;Can't find it!
- (`(,_ ,pos . ,_) (goto-char pos) t)
- (`nil (or (not (looking-at "{"))
- (smie-rule-prev-p "=")))))
- found-do))))
-
-(defun sm-c--skip-labels (max)
- (while
- (let ((start (point)))
- (pcase (sm-c-smie-forward-token)
- ("case"
- (smie-forward-sexp "case")
- (forward-comment (point-max))
- (if (>= (point) max) (progn (goto-char start) nil)
- t))
- (":label"
- (forward-comment (point-max))
- (if (>= (point) max) (progn (goto-char start) nil)
- t))
- (_ (goto-char start) nil)))))
-
-(defun sm-c--boi (&optional inner)
- "Jump to the beginning-of-instruction.
-By default for things like nested ifs, it jumps to the outer if, but
-if INNER is non-nil, it stops at the innermost one."
- (while
- (let ((pos (point)))
- (pcase (smie-backward-sexp)
- (`(,_ ,_ ";") nil) ;Found it!
- (`(,_ ,pos "else") (goto-char pos) (sm-c--else-to-if) t)
- (`(,_ ,pos "while")
- (goto-char pos) (unless (sm-c--while-to-do) (goto-char pos)) t)
- (`(,(pred numberp) ,pos . ,_) (goto-char pos) t)
- ((or `nil `(nil . ,_))
- (if (and (or (not (looking-at "{"))
- (smie-rule-prev-p "="))
- (not (bobp)))
- t
- (goto-char pos) nil))
- (`(,_ ,_ ,(or "(" "{" "[")) nil) ;Found it!
- (`(,_ ,pos ,(and tok
- (guard (when inner
- (or (member tok sm-c-paren-block-keywords)
- (equal tok "do"))))))
- (goto-char pos) nil) ;Found it!
- (`(t ,(pred (eq (point-min))) . ,_) nil)
- (`(,_ ,pos . ,_) (goto-char pos) t)))))
-
-;; (defun sm-c--if-tail-to-head ()
-;; (pcase (sm-c--prev-token)
-;; (")"
-;; (forward-char 1) (backward-sexp 1)
-;; (pcase (sm-c--prev-token)
-;; ("if" nil)
-;; ((or "while" "for") (sm-c--if-tail-to-head))))
-;; ("do" (sm-c--if-tail-to-head))))
-
-(defun sm-c--boe (tok)
- (let ((start (point))
- (res (smie-backward-sexp tok)))
- (when (member (nth 2 res) '("if" "while" "do" "for" "else"))
- (when (member (nth 2 res) '("if" "for"))
- (let ((forward-sexp-function nil))
- (forward-sexp 1))
- (forward-comment (point-max)))
- (when (looking-at "{")
- (let ((forward-sexp-function nil))
- (forward-sexp 1))
- (forward-comment (point-max)))
- (if (> (point) start) (goto-char start)))))
-
-(defun sm-c-smie--*-token ()
- (save-excursion
- (let ((pos (point)))
- (pcase (car (smie-indent-backward-token))
- (")"
- ;; Can be a multiplication (as in "(a+b)*c"), or a deref
- ;; (as in "if (stop) *a = 0;")
- (if (and (goto-char (nth 1 (syntax-ppss)))
- (eq ?\( (char-after))
- (member (smie-default-backward-token) '("if" "for")))
- "* deref"
- "* mult"))
- ("]" "* mult") ;Multiplication.
- ((or "(" "[" "{" "}") "* deref")
- (`nil
- (goto-char pos)
- (let ((res nil))
- (while (not (or res (bobp)))
- (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")))))
- (or res "* mult")))
- (_ "* mult")))))
-
-(defun sm-c-smie-hanging-eolp ()
- (let ((start (point))
- (prev (smie-indent-backward-token)))
- (if (and (not (numberp (nth 1 prev)))
- (save-excursion (equal (sm-c-smie-backward-token) ";")))
- ;; Treat instructions that start after ";" as always "hanging".
- (end-of-line)
- (goto-char start)))
- (skip-chars-forward " \t")
- (or (eolp)
- (forward-comment (point-max))
- (and (looking-at "\\\\\n")
- (goto-char (match-end 0)))))
-
-(defvar sm-c-smie--inhibit-case/label-rule nil)
-
-(defun sm-c--smie-virtual ()
- (if (and (smie-indent--bolp)
- (not (save-excursion
- (member (sm-c-smie-forward-token)
- '("case" ":label")))))
- (current-column)
- (let ((sm-c-smie--inhibit-case/label-rule t))
- (smie-indent-calculate))))
-
-(defun sm-c-smie-rules (kind token)
- (pcase (cons kind token)
- (`(:elem . basic) sm-c-indent-basic)
- (`(:list-intro . ";")
- (save-excursion
- (forward-char 1)
- (if (and (null (smie-forward-sexp))
- ;; FIXME: Handle \\\n as well!
- (progn (forward-comment (point-max))
- (looking-at "(")))
- nil
- t)))
- (`(:before . "else")
- (save-excursion
- (sm-c--else-to-if)
- `(column . ,(smie-indent-virtual))))
- (`(:before . "while")
- (save-excursion
- (when (sm-c--while-to-do)
- `(column . ,(smie-indent-virtual)))))
- (`(:before . ,(or "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>=" "&=" "^=" "|="))
- (save-excursion
- (sm-c--boe token)
- `(column . ,(+ (funcall smie-rules-function :elem 'basic)
- (smie-indent-virtual)))))
- (`(:before . "if")
- (when (and (not (smie-rule-bolp)) (smie-rule-prev-p "else"))
- (save-excursion
- (smie-indent-backward-token)
- `(column . ,(sm-c--smie-virtual)))))
- ;; (`(:after . ,(or "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>=" "&=" "^="
"|="))
- ;; (funcall smie-rules-function :elem 'basic))
- (`(:before . "{")
- (cond
- ((smie-rule-prev-p "=") nil) ;Not a block of instructions!
- ((save-excursion
- (let ((pos (point)))
- (sm-c--boi 'inner) (sm-c--skip-labels (point-max))
- (let ((tok (save-excursion (sm-c-smie-forward-token))))
- (cond
- ((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))))
- ((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 . ,(+ (funcall smie-rules-function :elem 'basic)
- (smie-indent-virtual))))
- ((or (member tok sm-c-paren-block-keywords)
- (equal tok "do"))
- nil)
- ((save-excursion
- (goto-char pos)
- (when (and (> (car (syntax-ppss)) 0)
- (equal ")" (car (smie-indent-backward-token))))
- (up-list -1)
- `(column . ,(sm-c--smie-virtual)))))
- ((>= (point) pos) nil)
- (t `(column . ,(smie-indent-virtual))))))))
- ((smie-rule-hanging-p)
- (cond
- ((smie-rule-prev-p "do" "else")
- (smie-indent-backward-token))
- ((smie-rule-prev-p ")")
- (smie-backward-sexp)
- (smie-indent-backward-token))
- (t (sm-c--boi 'inner)))
- `(column . ,(sm-c--smie-virtual)))
- (t
- (let ((pos (point)))
- (pcase (sm-c--prev-token)
- ((or "do" "else")
- (cond
- (sm-c-indent-braces
- `(column . ,(+ (funcall smie-rules-function :elem 'basic)
- (smie-indent-virtual))))))
- (")" nil)
- (_ (goto-char pos) (sm-c--boi)
- (if (< (point) pos)
- `(column . ,(sm-c--smie-virtual)))))))))
- (`(:before . "(")
- (save-excursion
- (let ((res (smie-backward-sexp)))
- (pcase res
- (`nil
- (if (looking-at "(")
- ;; (unless (save-excursion
- ;; (member (sm-c-smie-backward-token)
- ;; sm-c-paren-block-keywords))
- ;; `(column . ,(sm-c--smie-virtual)))
- nil
- `(column . ,(+ (funcall smie-rules-function :elem 'basic)
- (sm-c--smie-virtual)))))))))
- (`(:after . "else")
- (save-excursion
- (funcall smie-rules-function :elem 'basic)))
- (`(:after . ")")
- (save-excursion
- (let ((_ (progn (forward-char 1) (backward-sexp 1)))
- (pos (point))
- (prev (sm-c-smie-backward-token)))
- (cond
- ((member prev sm-c-paren-block-keywords)
- `(column . ,(+ (funcall smie-rules-function :elem 'basic)
- (smie-indent-virtual))))
- ((and (looking-at "[[:alnum:]_]+(")
- (save-excursion
- (forward-line 0)
- (and (bobp) (looking-at sm-c--cpp-regexp))))
- ;; Will be bumped up presumably by the "max" in
- ;; sm-c--cpp-smie-indent.
- `(column . 0))
- (t (goto-char pos) `(column . ,(sm-c--smie-virtual)))))))
- (`(:after . "}")
- (save-excursion
- (forward-char 1) (backward-sexp 1)
- (sm-c--boi)
- `(column . ,(sm-c--smie-virtual))))
- (`(:after . ";")
- (save-excursion
- (sm-c--boi)
- `(column . ,(sm-c--smie-virtual))))
- (`(:after . ":label")
- ;; Yuck!
- `(column . ,(sm-c--smie-virtual)))
- (`(:after . ": case")
- ;; Yuck!
- (save-excursion
- (smie-backward-sexp ": case")
- `(column . ,(sm-c--smie-virtual))))
- (`(:after . "* deref") `(column . ,(sm-c--smie-virtual)))
- ((and `(:before . ":label") (guard (not
sm-c-smie--inhibit-case/label-rule)))
- (let ((ppss (syntax-ppss)))
- (when (nth 1 ppss)
- (save-excursion
- (goto-char (nth 1 ppss))
- `(column . ,(smie-indent-virtual))))))
- ((and `(:before . "case") (guard (not sm-c-smie--inhibit-case/label-rule)))
- (catch 'found
- (dolist (pos (reverse (nth 9 (syntax-ppss))))
- (save-excursion
- (goto-char pos)
- (and (looking-at "{")
- (null (car-safe (smie-backward-sexp)))
- (equal "switch" (sm-c-smie-backward-token))
- (goto-char pos)
- (throw 'found `(column . ,(smie-indent-virtual))))))))))
-
-;;; Backslash alignment
-
-(defvar-local sm-c--bs-changed nil)
-
-(defun sm-c--bs-after-change (beg end _len)
- (unless undo-in-progress
- (if (null sm-c--bs-changed)
- (setq sm-c--bs-changed (cons beg end))
- (cl-callf (lambda (x) (min x beg)) (car sm-c--bs-changed))
- (cl-callf (lambda (x) (max x end)) (cdr sm-c--bs-changed)))))
-
-(defun sm-c--bs-realign ()
- (when sm-c--bs-changed
- (sm-c--bs-realign-1 (car sm-c--bs-changed) (cdr sm-c--bs-changed))
- (setq sm-c--bs-changed nil)))
-
-(defcustom sm-c-backslash-max-align-column 78
- "Maximum column to align backslashes.
-Past this column, we do not try to align the backslashes."
- :type 'integer)
-
-(defun sm-c--bs-current-column ()
- (let ((col (current-column)))
- (if (> col sm-c-backslash-max-align-column)
- 0 col)))
-
-(defun sm-c--bs-realign-1 (from to)
- (save-excursion
- (goto-char from)
- (end-of-line)
- (unless (zerop (mod (skip-chars-backward "\\\\") 2))
- (skip-chars-backward " \t")
- (setq from (point))
- (let ((col (sm-c--bs-current-column))
- start end)
- (while
- (progn (setq start (point))
- (end-of-line 0)
- (and (< (point) start)
- (not (zerop (mod (skip-chars-backward "\\\\") 2)))))
- (unless (>= col sm-c-backslash-max-align-column)
- (skip-chars-backward " \t")
- (setq col (max (sm-c--bs-current-column) col))))
- (goto-char from)
- (while
- (progn (setq end (point))
- (end-of-line 2)
- (and (> (line-beginning-position) end)
- (not (zerop (mod (skip-chars-backward "\\\\") 2)))))
- (unless (>= col sm-c-backslash-max-align-column)
- (skip-chars-backward " \t")
- (setq col (max (sm-c--bs-current-column) col))))
- (goto-char to)
- (beginning-of-line)
- (unless (or (> (point) end) ;Don't realign if we changed outside!
- (<= end start)) ;A lone \
-
- (setq col (1+ col)) ;Add a space before the backslashes.
- (goto-char end)
- (end-of-line)
- (while (>= (point) start)
- (cl-assert (eq (char-before) ?\\))
- (forward-char -1)
- (let ((curcol (current-column)))
- (cond
- ((> col curcol) (indent-to col))
- ((< col curcol)
- (skip-chars-backward " \t")
- (unless (> (current-column) col)
- (move-to-column col t)
- (delete-region (point) (1- (line-end-position)))))))
- (end-of-line 0)))))))
-
-;;; Font-lock support
-
-(defconst sm-c--comment-regexp
- "/\\(?:/.*\n\\|\\*[^*]*\\(?:\\*+[^/*][^*]*\\)*\\*+/\\)")
-
-(defconst sm-c--defun-regexp
- (let* ((spc0 (concat "\\(?:\n?[ \t]\\|" sm-c--comment-regexp "\\)*"))
- (spc1 (concat "\n?[ \t]" spc0))
- (id "\\(?:\\sw\\|\\s_\\)+"))
- (cl-flet ((repeat (repetition &rest res)
- (concat "\\(?:" (apply #'concat res) "\\)"
- (pcase repetition
- ((pred symbolp) (symbol-name repetition))
- (1 "")))))
- (concat
- "^\\(?:"
- (repeat '* "\\*" spc0) ;Pointer symbols.
- (repeat '* id (repeat 1 spc1 "\\|" spc0 "\\*" spc0)) ;Type(s).
- "\\(" id "\\)[ \t\n]*(" ;Function name.
- "\\|"
- "[ \t]*#[ \t]*define[ \t]+\\(?1:" id "\\)("
- "\\)"))))
-
-(defconst sm-c-font-lock-keywords
- `((,sm-c--cpp-regexp (1 font-lock-preprocessor-face))
- ("\\_<\\(?:true\\|false\\)\\_>" (0 font-lock-constant-face))
- ("\\_<\\(case\\)\\_>[ \t]*\\([^: \t]+\\)"
- (1 font-lock-keyword-face)
- (2 font-lock-constant-face))
- ("\\(?:[{};]\\(\\)\\|^\\)[ \t]*\\([[:alpha:]_][[:alnum:]_]*\\)[ \t]*:"
- (2 (if (or (match-beginning 1)
- (save-excursion (equal ":label" (sm-c-smie-backward-token))))
- font-lock-constant-face)))
- (,(let ((kws (delq nil (mapcar (lambda (x)
- (setq x (car x))
- (and (stringp x)
- (string-match "\\`[a-z]" x)
- x))
- sm-c-smie-grammar))))
- (concat "\\_<" (regexp-opt
- (append
- ;; Elements not in SMIE's grammar. Either because
- ;; they're uninteresting from a parsing point of view,
- ;; or because SMIE's parsing engine can't handle them
- ;; even poorly.
- '("break" "continue" "struct" "enum" "union" "static")
- ;; "case" already handled above.
- (delete "case" kws)))
- "\\_>"))
- (0 font-lock-keyword-face))
- (,sm-c--defun-regexp
- (1
- (prog1 font-lock-function-name-face
- (if (< (match-beginning 0) (line-beginning-position))
- (put-text-property (match-beginning 0) (match-end 0)
- 'font-lock-multiline t)))))))
-
-(defconst sm-c--def-regexp
- (let ((spc0 (concat "\\(?:[ \t\n]\\|" sm-c--comment-regexp "\\)*"))
- (id "\\(?:\\sw\\|\\s_\\)+"))
- (concat sm-c--defun-regexp
- "\\|"
- "\\_<\\(?1:\\(?:struct\\|enum\\)[ \t]+" id "\\)" spc0 "{")))
-
-;;;###autoload
-(define-derived-mode sm-c-mode prog-mode "smC"
- "C editing mode based on SMIE."
- ;; (setq-local font-lock-support-mode nil) ;; To help debugging.
- (setq-local comment-start "/* ")
- (setq-local comment-end " */")
- (setq-local parse-sexp-lookup-properties t)
- (setq-local open-paren-in-column-0-is-defun-start nil)
- (setq-local syntax-propertize-function #'sm-c-syntax-propertize)
- (setq-local font-lock-defaults '(sm-c-font-lock-keywords))
- (setq-local font-lock-syntactic-face-function #'sm-c-syntactic-face-function)
- (smie-setup sm-c-smie-grammar #'sm-c-smie-rules
- :backward-token #'sm-c-smie-backward-token
- :forward-token #'sm-c-smie-forward-token)
- ;; FIXME: The stock SMIE forward-sexp-function is not good enough here, since
- ;; our grammar is much too poor. We should setup another function instead
- ;; (or ideally teach SMIE to use it).
- (kill-local-variable 'forward-sexp-function)
- (add-hook 'smie-indent-functions #'sm-c--cpp-smie-indent nil t)
- (add-function :after (local 'indent-line-function)
- #'sm-c--cpp-indent-line)
- (setq-local smie--hanging-eolp-function #'sm-c-smie-hanging-eolp)
- ;; Backslash auto-realign.
- (add-hook 'after-change-functions #'sm-c--bs-after-change nil t)
- (add-hook 'post-command-hook #'sm-c--bs-realign nil t)
- (setq-local add-log-current-defun-header-regexp sm-c--def-regexp)
- (setq-local imenu-generic-expression `((nil ,sm-c--def-regexp 1))))
-
-(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: 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)
-;;; sm-c-mode.el ends here
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [elpa] master e9a7ea8: * externals-list: Convert sm-c-mode to :external,
Stefan Monnier <=