branch: elpa/forth-mode commit 3ad7b9e9d6b9b69140ceed8ffabaa58aa89b78cb Author: Helmut Eller <eller.hel...@gmail.com> Commit: Lars Brinkhoff <l...@nocrew.org>
Make indentation rules customizable. * forth-smie.el (forth-smie-bnf-extensions): New customization variable. (forth-smie--grammar): Turn the variable into a function ... (forth-smie--bnf): ... and the default rules into a constant. (forth-smie-setup): Compute the grammer each time. * forth-mode.el (forth-mode): Call hack-local-variables so that forth-smie-setup sees file local variables. * test/tests.el (forth-indent-customization): Move the ?OF ... ENDOF test to a seperate test. Also add cl- prefix in some places. --- forth-mode.el | 1 + forth-smie.el | 61 +++++++++++++++++++++++++++++++++++++++-------------------- test/tests.el | 30 +++++++++++++++++++---------- 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/forth-mode.el b/forth-mode.el index 430712bc73..6662b460d9 100644 --- a/forth-mode.el +++ b/forth-mode.el @@ -193,6 +193,7 @@ (when (boundp 'syntax-propertize-function) (setq-local syntax-propertize-function #'forth-syntax-propertize)) (setq-local parse-sexp-lookup-properties t) + (hack-local-variables) (forth-smie-setup) (setq-local fill-paragraph-function #'forth-fill-paragraph) (setq-local beginning-of-defun-function #'forth-beginning-of-defun) diff --git a/forth-smie.el b/forth-smie.el index 9c10f7df7d..df6678151d 100644 --- a/forth-smie.el +++ b/forth-smie.el @@ -8,26 +8,47 @@ :group 'forth-smie :safe 'integerp) -(defvar forth-smie--grammar +(defcustom forth-smie-bnf-extensions '() + "Rules for non-standard syntax. + +We add this list of BNF rules to the default rules to support +user defined syntax. E.g., setting this variable to + + '((gforth-ext (\"?of\" words \"endof\"))) + +tells Emacs to recognize ?OF ... ENDOF as a matching pair of tokens. + +This variable can also be set in .dir-locals.el, e.g.: + + ((forth-mode . ((forth-smie-bnf-extensions + . ((my-stuff (\"import\" words \"{\" words \"}\"))))))). +" + :type '(alist :key-type symbol :value-type (list (list string symbol))) + :group 'forth-smie + :safe 'listp) + +(defconst forth-smie--bnf + '((control + ("if" words "else" words "then") + ("if" words "then") + ("begin" words "while" words "repeat") + ("begin" words "until") + ("begin" words "again") + ("of" words "endof") + ("case" words "endcase") + ("?do" words "loop") + ("?do" words "+loop") + ("do" words "loop") + ("do" words "+loop") + ("begin-structure" words "end-structure") + (":" words ";") + (":noname" words ";")) + (words))) + +(defun forth-smie--grammar () (smie-prec2->grammar - (smie-bnf->prec2 - '((control - ("if" words "else" words "then") - ("if" words "then") - ("begin" words "while" words "repeat") - ("begin" words "until") - ("begin" words "again") - ("?of" words "endof") - ("of" words "endof") - ("case" words "endcase") - ("?do" words "loop") - ("?do" words "+loop") - ("do" words "loop") - ("do" words "+loop") - ("begin-structure" words "end-structure") - (":" words ";") - (":noname" words ";")) - (words))))) + (smie-bnf->prec2 (append forth-smie--bnf + forth-smie-bnf-extensions)))) (unless (fboundp 'pcase) (defmacro pcase (form &rest forms) @@ -69,7 +90,7 @@ (point))))) (defun forth-smie-setup () - (smie-setup forth-smie--grammar #'forth-smie--indentation-rules + (smie-setup (forth-smie--grammar) #'forth-smie--indentation-rules :forward-token #'forth-smie--forward-token :backward-token #'forth-smie--backward-token)) diff --git a/test/tests.el b/test/tests.el index 27391893b9..94a87d2d12 100644 --- a/test/tests.el +++ b/test/tests.el @@ -52,7 +52,7 @@ (defun forth-assert-face (content face) (when (boundp 'syntax-propertize-function) - (destructuring-bind (content pos) (forth-strip-|-and-→ content) + (cl-destructuring-bind (content pos) (forth-strip-|-and-→ content) (forth-with-temp-buffer content (font-lock-ensure) (should (eq face (or (get-text-property pos 'face) @@ -72,14 +72,14 @@ The whitespace before and including \"|\" on each line is removed." (substring-no-properties (buffer-string)))))))) (defun forth-assert-forward-sexp (content) - (destructuring-bind (content start end) (forth-strip-|-and-¹² content) + (cl-destructuring-bind (content start end) (forth-strip-|-and-¹² content) (forth-with-temp-buffer content (goto-char start) (forward-sexp) (should (= (point) end))))) (defun forth-assert-forward-word (content) - (destructuring-bind (content start end) (forth-strip-|-and-¹² content) + (cl-destructuring-bind (content start end) (forth-strip-|-and-¹² content) (forth-with-temp-buffer content (goto-char start) (font-lock-ensure) ; Make sure syntax-propertize function is called @@ -87,8 +87,8 @@ The whitespace before and including \"|\" on each line is removed." (should (= (point) end))))) (defun forth-should-before/after (before after fun) - (destructuring-bind (before point-before) (forth-strip-|-and-→ before) - (destructuring-bind (after point-after) (forth-strip-|-and-→ after) + (cl-destructuring-bind (before point-before) (forth-strip-|-and-→ before) + (cl-destructuring-bind (after point-after) (forth-strip-|-and-→ after) (forth-with-temp-buffer before (goto-char point-before) (funcall fun) @@ -96,8 +96,8 @@ The whitespace before and including \"|\" on each line is removed." (should (= (point) point-after)))))) (defun forth-should-region-before/after (before after fun) - (destructuring-bind (before start1 end1) (forth-strip-|-and-¹² before) - (destructuring-bind (after point-after) (forth-strip-|-and-→ after) + (cl-destructuring-bind (before start1 end1) (forth-strip-|-and-¹² before) + (cl-destructuring-bind (after point-after) (forth-strip-|-and-→ after) (forth-with-temp-buffer before (set-mark start1) (goto-char end1) @@ -267,12 +267,22 @@ The whitespace before and including \"|\" on each line is removed." | [char] b of bar | baz | endof - | test ?of bar - | baz - | endof + | test ?of | drop exit |endcase")) +(ert-deftest forth-indent-customization () + (forth-should-indent + "\ -*- forth-smie-bnf-extensions: ((ext (\"?of\" words \"endof\"))) -*- + |x case + | [char] f of + | foo + | endof + | test ?of + | bar + | endof + |endcase")) + ;; This is an tricky case because SMIE thinks, depending on ;; `comment-start-skip` (which indirectly depends on `comment-start` ;; thru `comment-normalize-vars`), that (foo) is a comment. But since