aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2019-07-22 15:41:17 -0400
committerStefan Monnier2019-07-22 15:41:17 -0400
commit33ed5718083333d4c74d49a57e627c29918dbed2 (patch)
treee220a80f33abacbf9e695188eac715998df53094
parent3f571bdd6889b09b8dee85d7d995097392a7cf1e (diff)
downloademacs-33ed5718083333d4c74d49a57e627c29918dbed2.tar.gz
emacs-33ed5718083333d4c74d49a57e627c29918dbed2.zip
* lisp/progmodes/opascal.el: Tweak code to ease edebugging
(opascal-strings): Inline in its sole use. (opascal-save-excursion): Add Edebug spec. (opascal-is): Remove. Use `memq` directly instead. (opascal--in): New pcase pattern. (opascal-literal-end-pattern): Remove unused function. (opascal--scan-non-whitespace-backward): New macro. (opascal-block-start, opascal-else-start, opascal-is-use-clause-end) (opascal-previous-indent-of, opascal-section-indent-of) (opascal-enclosing-indent-of): Use it. (opascal-corrected-indentation): Presume we're already at first token. (opascal-indent-line): Use indent-line-to. (opascal-new-comment-line): Declare obsolete. (opascal-mode-map): Keep the default M-j binding instead.
-rw-r--r--lisp/progmodes/opascal.el1009
1 files changed, 496 insertions, 513 deletions
diff --git a/lisp/progmodes/opascal.el b/lisp/progmodes/opascal.el
index 9bb62ced3bd..95589c2add1 100644
--- a/lisp/progmodes/opascal.el
+++ b/lisp/progmodes/opascal.el
@@ -42,6 +42,8 @@
42 42
43;;; Code: 43;;; Code:
44 44
45(eval-when-compile (require 'cl-lib))
46
45(defgroup opascal nil 47(defgroup opascal nil
46 "Major mode for editing OPascal source in Emacs." 48 "Major mode for editing OPascal source in Emacs."
47 :version "24.4" 49 :version "24.4"
@@ -147,10 +149,6 @@ That is, regardless of where in the line point is at the time."
147 '(comment-single-line comment-multi-line-1 comment-multi-line-2) 149 '(comment-single-line comment-multi-line-1 comment-multi-line-2)
148 "Tokens that represent comments.") 150 "Tokens that represent comments.")
149 151
150(defconst opascal-strings
151 '(string double-quoted-string)
152 "Tokens that represent string literals.")
153
154(defconst opascal-whitespace `(space newline ,@opascal-comments) 152(defconst opascal-whitespace `(space newline ,@opascal-comments)
155 "Tokens that are considered whitespace.") 153 "Tokens that are considered whitespace.")
156 154
@@ -274,15 +272,17 @@ routine.")
274(defmacro opascal-save-excursion (&rest forms) 272(defmacro opascal-save-excursion (&rest forms)
275 ;; Executes the forms such that any movements have no effect, including 273 ;; Executes the forms such that any movements have no effect, including
276 ;; searches. 274 ;; searches.
275 (declare (debug t))
277 `(save-excursion 276 `(save-excursion
278 (save-match-data 277 (save-match-data
279 (let ((inhibit-point-motion-hooks t) 278 (let ((inhibit-point-motion-hooks t)
280 (deactivate-mark nil)) 279 (deactivate-mark nil))
281 (progn ,@forms))))) 280 (progn ,@forms)))))
282 281
283(defsubst opascal-is (element in-set) 282
284 ;; If the element is in the set, the element cdr is returned, otherwise nil. 283(eval-when-compile
285 (memq element in-set)) 284 (pcase-defmacro opascal--in (set)
285 `(pred (pcase--flip memq ,set))))
286 286
287(defun opascal-string-of (start end) 287(defun opascal-string-of (start end)
288 ;; Returns the buffer string from start to end. 288 ;; Returns the buffer string from start to end.
@@ -415,15 +415,6 @@ routine.")
415 (string . "'") 415 (string . "'")
416 (double-quoted-string . "\""))))) 416 (double-quoted-string . "\"")))))
417 417
418(defun opascal-literal-end-pattern (literal-kind)
419 ;; Returns the end pattern of the literal kind.
420 (cdr (assoc literal-kind
421 '((comment-single-line . "\n")
422 (comment-multi-line-1 . "}")
423 (comment-multi-line-2 . "*)")
424 (string . "'")
425 (double-quoted-string . "\"")))))
426
427(defun opascal-literal-stop-pattern (literal-kind) 418(defun opascal-literal-stop-pattern (literal-kind)
428 ;; Returns the pattern that delimits end of the search for the literal kind. 419 ;; Returns the pattern that delimits end of the search for the literal kind.
429 ;; These are regular expressions. 420 ;; These are regular expressions.
@@ -495,7 +486,7 @@ routine.")
495 (let* ((word-image (downcase (opascal-token-string word))) 486 (let* ((word-image (downcase (opascal-token-string word)))
496 (keyword (intern-soft word-image))) 487 (keyword (intern-soft word-image)))
497 (when (and (or keyword (string= "nil" word-image)) 488 (when (and (or keyword (string= "nil" word-image))
498 (opascal-is keyword opascal-keywords)) 489 (memq keyword opascal-keywords))
499 (opascal-set-token-kind word keyword)) 490 (opascal-set-token-kind word keyword))
500 word)))) 491 word))))
501 492
@@ -562,7 +553,7 @@ routine.")
562 (let (next-token) 553 (let (next-token)
563 (while (progn 554 (while (progn
564 (setq next-token (opascal-next-token token)) 555 (setq next-token (opascal-next-token token))
565 (opascal-is (opascal-token-kind next-token) '(space newline)))) 556 (memq (opascal-token-kind next-token) '(space newline))))
566 next-token)) 557 next-token))
567 558
568(defun opascal-group-start (from-token) 559(defun opascal-group-start (from-token)
@@ -608,6 +599,18 @@ routine.")
608 indent (if offset offset 0))) 599 indent (if offset offset 0)))
609 indent)) 600 indent))
610 601
602(defmacro opascal--scan-non-whitespace-backward (token-var last-var
603 &rest pcases)
604 (declare (debug (symbolp symbolp &rest (pcase-PAT body)))
605 (indent 2))
606 `(let ((,token-var ,token-var))
607 (while (setq ,token-var (opascal-previous-token ,token-var))
608 ,(macroexp-let2 nil kind-var `(opascal-token-kind ,token-var)
609 `(unless (memq ,kind-var opascal-whitespace)
610 (pcase ,kind-var
611 ,@pcases)
612 ,(when last-var `(setq ,last-var ,token-var)))))))
613
611(defun opascal-line-indent-of (from-token &optional offset &rest terminators) 614(defun opascal-line-indent-of (from-token &optional offset &rest terminators)
612 ;; Returns the column of first non-space character on the token's line, plus 615 ;; Returns the column of first non-space character on the token's line, plus
613 ;; any offset. We also stop if one of the terminators or an open ( or [ is 616 ;; any offset. We also stop if one of the terminators or an open ( or [ is
@@ -616,6 +619,8 @@ routine.")
616 (last-token from-token) 619 (last-token from-token)
617 (kind nil)) 620 (kind nil))
618 (catch 'done 621 (catch 'done
622 ;; FIXME: Can't use opascal--scan-non-whitespace-backward here, because
623 ;; we do need to pay attention to `newline'!
619 (while token 624 (while token
620 (setq kind (opascal-token-kind token)) 625 (setq kind (opascal-token-kind token))
621 (cond 626 (cond
@@ -623,11 +628,11 @@ routine.")
623 ((eq 'close-group kind) (setq token (opascal-group-start token))) 628 ((eq 'close-group kind) (setq token (opascal-group-start token)))
624 629
625 ;; Stop at the beginning of the line or an open group. 630 ;; Stop at the beginning of the line or an open group.
626 ((opascal-is kind '(newline open-group)) (throw 'done nil)) 631 ((memq kind '(newline open-group)) (throw 'done nil))
627 632
628 ;; Stop at one of the specified terminators. 633 ;; Stop at one of the specified terminators.
629 ((opascal-is kind terminators) (throw 'done nil))) 634 ((memq kind terminators) (throw 'done nil)))
630 (unless (opascal-is kind opascal-whitespace) (setq last-token token)) 635 (unless (memq kind opascal-whitespace) (setq last-token token))
631 (setq token (opascal-previous-token token)))) 636 (setq token (opascal-previous-token token))))
632 (opascal-indent-of last-token offset))) 637 (opascal-indent-of last-token offset)))
633 638
@@ -638,23 +643,25 @@ routine.")
638 (last-token from-token) 643 (last-token from-token)
639 (kind nil)) 644 (kind nil))
640 (catch 'done 645 (catch 'done
646 ;; FIXME: Can't use opascal--scan-non-whitespace-backward here, because
647 ;; we do need to pay attention to `newline'!
641 (while token 648 (while token
642 (setq kind (opascal-token-kind token)) 649 (setq kind (opascal-token-kind token))
643 (cond 650 (cond
644 ((and (eq 'colon kind) 651 ((and (eq 'colon kind)
645 (opascal-is (opascal-token-kind last-token) 652 (memq (opascal-token-kind last-token)
646 `(,@opascal-block-statements 653 `(,@opascal-block-statements
647 ,@opascal-expr-statements))) 654 ,@opascal-expr-statements)))
648 ;; We hit a label followed by a statement. Indent to the statement. 655 ;; We hit a label followed by a statement. Indent to the statement.
649 (throw 'done nil)) 656 (throw 'done nil))
650 657
651 ;; Skip over ()/[] groups. 658 ;; Skip over ()/[] groups.
652 ((eq 'close-group kind) (setq token (opascal-group-start token))) 659 ((eq 'close-group kind) (setq token (opascal-group-start token)))
653 660
654 ((opascal-is kind `(newline open-group ,@opascal-use-clauses)) 661 ((memq kind `(newline open-group ,@opascal-use-clauses))
655 ;; Stop at the beginning of the line, an open group, or a use clause 662 ;; Stop at the beginning of the line, an open group, or a use clause
656 (throw 'done nil))) 663 (throw 'done nil)))
657 (unless (opascal-is kind opascal-whitespace) (setq last-token token)) 664 (unless (memq kind opascal-whitespace) (setq last-token token))
658 (setq token (opascal-previous-token token)))) 665 (setq token (opascal-previous-token token))))
659 (opascal-indent-of last-token offset))) 666 (opascal-indent-of last-token offset)))
660 667
@@ -671,7 +678,7 @@ routine.")
671 ;; dispinterface), (= interface), (= object), or (= record), and nil 678 ;; dispinterface), (= interface), (= object), or (= record), and nil
672 ;; otherwise. 679 ;; otherwise.
673 (if (and (eq 'equals (opascal-token-kind token)) 680 (if (and (eq 'equals (opascal-token-kind token))
674 (opascal-is (opascal-token-kind last-token) opascal-composite-types)) 681 (memq (opascal-token-kind last-token) opascal-composite-types))
675 last-token)) 682 last-token))
676 683
677(defun opascal-is-simple-class-type (at-token limit-token) 684(defun opascal-is-simple-class-type (at-token limit-token)
@@ -679,7 +686,7 @@ routine.")
679 ;; class of TClass; 686 ;; class of TClass;
680 ;; class (TBaseClass); 687 ;; class (TBaseClass);
681 ;; class; 688 ;; class;
682 (when (opascal-is (opascal-token-kind at-token) opascal-class-types) 689 (when (memq (opascal-token-kind at-token) opascal-class-types)
683 (catch 'done 690 (catch 'done
684 ;; Scan until the semi colon. 691 ;; Scan until the semi colon.
685 (let ((token (opascal-next-token at-token)) 692 (let ((token (opascal-next-token at-token))
@@ -695,7 +702,7 @@ routine.")
695 ((eq 'open-group token-kind) (setq token (opascal-group-end token))) 702 ((eq 'open-group token-kind) (setq token (opascal-group-end token)))
696 703
697 ;; Only allow "of" and whitespace, and an identifier 704 ;; Only allow "of" and whitespace, and an identifier
698 ((opascal-is token-kind `(of word ,@opascal-whitespace))) 705 ((memq token-kind `(of word ,@opascal-whitespace)))
699 706
700 ;; Otherwise we are not in a simple class declaration. 707 ;; Otherwise we are not in a simple class declaration.
701 ((throw 'done nil))) 708 ((throw 'done nil)))
@@ -703,85 +710,76 @@ routine.")
703 710
704(defun opascal-block-start (from-token &optional stop-on-class) 711(defun opascal-block-start (from-token &optional stop-on-class)
705 ;; Returns the token that denotes the start of the block. 712 ;; Returns the token that denotes the start of the block.
706 (let ((token (opascal-previous-token from-token)) 713 (let ((token from-token)
707 (last-token nil) 714 (last-token nil))
708 (token-kind nil))
709 (catch 'done 715 (catch 'done
710 (while token 716 (opascal--scan-non-whitespace-backward token last-token
711 (setq token-kind (opascal-token-kind token)) 717 ;; Skip over nested blocks.
712 (cond 718 ((opascal--in opascal-end-block-statements)
713 ;; Skip over nested blocks. 719 (setq token (opascal-block-start token)))
714 ((opascal-is token-kind opascal-end-block-statements) 720
715 (setq token (opascal-block-start token))) 721 ;; Case block start found.
716 722 ('case
717 ;; Regular block start found. 723 (throw 'done
718 ((opascal-is token-kind opascal-block-statements) 724 ;; As a special case, when a "case" block appears
719 (throw 'done 725 ;; within a record declaration (to denote a variant
720 ;; As a special case, when a "case" block appears 726 ;; part), the record declaration should be considered
721 ;; within a record declaration (to denote a variant 727 ;; the enclosing block.
722 ;; part), the record declaration should be considered 728 (let ((enclosing-token
723 ;; the enclosing block. 729 (opascal-block-start token
724 (if (eq 'case token-kind) 730 'stop-on-class)))
725 (let ((enclosing-token 731 (if (eq 'record
726 (opascal-block-start token 732 (opascal-token-kind enclosing-token))
727 'stop-on-class))) 733 (if stop-on-class
728 (if 734 enclosing-token
729 (eq 'record 735 (opascal-previous-token enclosing-token))
730 (opascal-token-kind enclosing-token)) 736 token))))
731 (if stop-on-class 737
732 enclosing-token 738 ;; Regular block start found.
733 (opascal-previous-token enclosing-token)) 739 ((opascal--in opascal-block-statements)
734 token)) 740 (throw 'done token))
735 token))) 741
736 742 ;; A class/record start also begins a block.
737 ;; A class/record start also begins a block. 743 ((guard (opascal-composite-type-start token last-token))
738 ((opascal-composite-type-start token last-token) 744 (throw 'done (if stop-on-class last-token token)))
739 (throw 'done (if stop-on-class last-token token))) 745 )
740 )
741 (unless (opascal-is token-kind opascal-whitespace)
742 (setq last-token token))
743 (setq token (opascal-previous-token token)))
744 ;; Start not found. 746 ;; Start not found.
745 nil))) 747 nil)))
746 748
747(defun opascal-else-start (from-else) 749(defun opascal-else-start (from-else)
748 ;; Returns the token of the if or case statement. 750 ;; Returns the token of the if or case statement.
749 (let ((token (opascal-previous-token from-else)) 751 (let ((token from-else)
750 (token-kind nil)
751 (semicolon-count 0)) 752 (semicolon-count 0))
752 (catch 'done 753 (catch 'done
753 (while token 754 (opascal--scan-non-whitespace-backward token nil
754 (setq token-kind (opascal-token-kind token)) 755 ;; Skip over nested groups.
755 (cond 756 ('close-group (setq token (opascal-group-start token)))
756 ;; Skip over nested groups. 757
757 ((eq 'close-group token-kind) (setq token (opascal-group-start token))) 758 ;; Skip over any nested blocks.
758 759 ((opascal--in opascal-end-block-statements)
759 ;; Skip over any nested blocks. 760 (setq token (opascal-block-start token)))
760 ((opascal-is token-kind opascal-end-block-statements) 761
761 (setq token (opascal-block-start token))) 762 ('semicolon
762 763 ;; Semicolon means we are looking for an enclosing if, unless we
763 ((eq 'semicolon token-kind) 764 ;; are in a case statement. Keep counts of the semicolons and decide
764 ;; Semicolon means we are looking for an enclosing if, unless we 765 ;; later.
765 ;; are in a case statement. Keep counts of the semicolons and decide 766 (setq semicolon-count (1+ semicolon-count)))
766 ;; later. 767
767 (setq semicolon-count (1+ semicolon-count))) 768 ((and 'if (guard (= semicolon-count 0)))
768 769 ;; We only can match an if when there have been no intervening
769 ((and (eq 'if token-kind) (= semicolon-count 0)) 770 ;; semicolons.
770 ;; We only can match an if when there have been no intervening 771 (throw 'done token))
771 ;; semicolons. 772
772 (throw 'done token)) 773 ('case
773 774 ;; We have hit a case statement start.
774 ((eq 'case token-kind) 775 (throw 'done token)))
775 ;; We have hit a case statement start.
776 (throw 'done token)))
777 (setq token (opascal-previous-token token)))
778 ;; No if or case statement found. 776 ;; No if or case statement found.
779 nil))) 777 nil)))
780 778
781(defun opascal-comment-content-start (comment) 779(defun opascal-comment-content-start (comment)
782 ;; Returns the point of the first non-space character in the comment. 780 ;; Returns the point of the first non-space character in the comment.
783 (let ((kind (opascal-token-kind comment))) 781 (let ((kind (opascal-token-kind comment)))
784 (when (opascal-is kind opascal-comments) 782 (when (memq kind opascal-comments)
785 (opascal-save-excursion 783 (opascal-save-excursion
786 (goto-char (+ (opascal-token-start comment) 784 (goto-char (+ (opascal-token-start comment)
787 (length (opascal-literal-start-pattern kind)))) 785 (length (opascal-literal-start-pattern kind))))
@@ -851,7 +849,8 @@ routine.")
851 (opascal-indent-of comment)) 849 (opascal-indent-of comment))
852 850
853 ;; Indent according to the comment's content start. 851 ;; Indent according to the comment's content start.
854 ((opascal-column-of (opascal-comment-content-start comment))))))) 852 (t
853 (opascal-column-of (opascal-comment-content-start comment)))))))
855 )) 854 ))
856 855
857(defun opascal-is-use-clause-end (at-token last-token last-colon from-kind) 856(defun opascal-is-use-clause-end (at-token last-token last-colon from-kind)
@@ -861,442 +860,426 @@ routine.")
861 (eq 'comma (opascal-token-kind at-token)) 860 (eq 'comma (opascal-token-kind at-token))
862 (eq 'semicolon from-kind)) 861 (eq 'semicolon from-kind))
863 ;; Scan for the uses statement, just to be sure. 862 ;; Scan for the uses statement, just to be sure.
864 (let ((token (opascal-previous-token at-token)) 863 (let ((token at-token))
865 (token-kind nil))
866 (catch 'done 864 (catch 'done
867 (while token 865 (opascal--scan-non-whitespace-backward token nil
868 (setq token-kind (opascal-token-kind token)) 866 ((opascal--in opascal-use-clauses)
869 (cond ((opascal-is token-kind opascal-use-clauses) 867 (throw 'done t))
870 (throw 'done t)) 868
871 869 ;; Identifiers, strings, "in" keyword, and commas
872 ;; Whitespace, identifiers, strings, "in" keyword, and commas 870 ;; are allowed in use clauses.
873 ;; are allowed in use clauses. 871 ((or 'word 'comma 'in 'string 'double-quoted-string))
874 ((or (opascal-is token-kind '(word comma in newline)) 872
875 (opascal-is token-kind opascal-whitespace) 873 ;; Nothing else is.
876 (opascal-is token-kind opascal-strings))) 874 (_ (throw 'done nil)))
877
878 ;; Nothing else is.
879 ((throw 'done nil)))
880 (setq token (opascal-previous-token token)))
881 nil)))) 875 nil))))
882 876
883(defun opascal-is-block-after-expr-statement (token) 877(defun opascal-is-block-after-expr-statement (token)
884 ;; Returns true if we have a block token trailing an expression delimiter (of 878 ;; Returns true if we have a block token trailing an expression delimiter (of
885 ;; presumably an expression statement). 879 ;; presumably an expression statement).
886 (when (opascal-is (opascal-token-kind token) opascal-block-statements) 880 (when (memq (opascal-token-kind token) opascal-block-statements)
887 (let ((previous (opascal-previous-token token)) 881 (let ((previous (opascal-previous-token token))
888 (previous-kind nil)) 882 (previous-kind nil))
889 (while (progn 883 (while (progn
890 (setq previous-kind (opascal-token-kind previous)) 884 (setq previous-kind (opascal-token-kind previous))
891 (eq previous-kind 'space)) 885 (eq previous-kind 'space))
892 (setq previous (opascal-previous-token previous))) 886 (setq previous (opascal-previous-token previous)))
893 (or (opascal-is previous-kind opascal-expr-delimiters) 887 (or (memq previous-kind opascal-expr-delimiters)
894 (eq previous-kind 'else))))) 888 (eq previous-kind 'else)))))
895 889
896(defun opascal-previous-indent-of (from-token) 890(defun opascal-previous-indent-of (from-token)
897 ;; Returns the indentation of the previous statement of the token. 891 ;; Returns the indentation of the previous statement of the token.
898 (let ((token (opascal-previous-token from-token)) 892 (let ((token from-token)
899 (token-kind nil)
900 (from-kind (opascal-token-kind from-token)) 893 (from-kind (opascal-token-kind from-token))
901 (last-colon nil) 894 (last-colon nil)
902 (last-of nil) 895 (last-of nil)
903 (last-token nil)) 896 (last-token nil))
904 (catch 'done 897 (catch 'done
905 (while token 898 (opascal--scan-non-whitespace-backward token last-token
906 (setq token-kind (opascal-token-kind token)) 899 ;; An open ( or [ always is an indent point.
907 (cond 900 ('open-group
908 ;; An open ( or [ always is an indent point. 901 (throw 'done (opascal-open-group-indent token last-token)))
909 ((eq 'open-group token-kind) 902
910 (throw 'done (opascal-open-group-indent token last-token))) 903 ;; Skip over any ()/[] groups.
911 904 ('close-group (setq token (opascal-group-start token)))
912 ;; Skip over any ()/[] groups. 905
913 ((eq 'close-group token-kind) (setq token (opascal-group-start token))) 906 ((opascal--in opascal-end-block-statements)
914 907 (if (eq 'newline (opascal-token-kind (opascal-previous-token token)))
915 ((opascal-is token-kind opascal-end-block-statements) 908 ;; We can stop at an end token that is right up against the
916 (if (eq 'newline (opascal-token-kind (opascal-previous-token token))) 909 ;; margin.
917 ;; We can stop at an end token that is right up against the 910 (throw 'done 0)
918 ;; margin. 911 ;; Otherwise, skip over any nested blocks.
919 (throw 'done 0) 912 (setq token (opascal-block-start token))))
920 ;; Otherwise, skip over any nested blocks. 913
921 (setq token (opascal-block-start token)))) 914 ;; Special case: if we encounter a ", word;" then we assume that we
922 915 ;; are in some kind of uses clause, and thus indent to column 0. This
923 ;; Special case: if we encounter a ", word;" then we assume that we 916 ;; works because no other constructs are known to have that form.
924 ;; are in some kind of uses clause, and thus indent to column 0. This 917 ;; This fixes the irritating case of having indents after a uses
925 ;; works because no other constructs are known to have that form. 918 ;; clause look like:
926 ;; This fixes the irritating case of having indents after a uses 919 ;; uses
927 ;; clause look like: 920 ;; someUnit,
928 ;; uses 921 ;; someOtherUnit;
929 ;; someUnit, 922 ;; // this should be at column 0!
930 ;; someOtherUnit; 923 ((guard
931 ;; // this should be at column 0! 924 (opascal-is-use-clause-end token last-token last-colon from-kind))
932 ((opascal-is-use-clause-end token last-token last-colon from-kind) 925 (throw 'done 0))
933 (throw 'done 0)) 926
934 927 ;; A previous terminator means we can stop. If we are on a directive,
935 ;; A previous terminator means we can stop. If we are on a directive, 928 ;; however, then we are not actually encountering a new statement.
936 ;; however, then we are not actually encountering a new statement. 929 ((and (guard last-token)
937 ((and last-token 930 (opascal--in opascal-previous-terminators)
938 (opascal-is token-kind opascal-previous-terminators) 931 (guard (not (memq (opascal-token-kind last-token)
939 (not (opascal-is (opascal-token-kind last-token) 932 opascal-directives))))
940 opascal-directives))) 933 (throw 'done (opascal-stmt-line-indent-of last-token 0)))
941 (throw 'done (opascal-stmt-line-indent-of last-token 0))) 934
942 935 ;; Remember any "of" we encounter, since that affects how we
943 ;; Ignore whitespace. 936 ;; indent to a case statement within a record declaration
944 ((opascal-is token-kind opascal-whitespace)) 937 ;; (i.e. a variant part).
945 938 ('of
946 ;; Remember any "of" we encounter, since that affects how we 939 (setq last-of token))
947 ;; indent to a case statement within a record declaration 940
948 ;; (i.e. a variant part). 941 ;; Remember any ':' we encounter (until we reach an "of"),
949 ((eq 'of token-kind) 942 ;; since that affects how we indent to case statements in
950 (setq last-of token)) 943 ;; general.
951 944 ('colon
952 ;; Remember any ':' we encounter (until we reach an "of"), 945 (unless last-of (setq last-colon token)))
953 ;; since that affects how we indent to case statements in 946
954 ;; general. 947 ;; A case statement delimits a previous statement. We indent labels
955 ((eq 'colon token-kind) 948 ;; specially.
956 (unless last-of (setq last-colon token))) 949 ('case
957 950 (throw 'done
958 ;; A case statement delimits a previous statement. We indent labels
959 ;; specially.
960 ((eq 'case token-kind)
961 (throw 'done
962 (if last-colon (opascal-line-indent-of last-colon) 951 (if last-colon (opascal-line-indent-of last-colon)
963 (opascal-line-indent-of token opascal-case-label-indent)))) 952 (opascal-line-indent-of token opascal-case-label-indent))))
964 953
965 ;; If we are in a use clause then commas mark an enclosing rather than 954 ;; If we are in a use clause then commas mark an enclosing rather than
966 ;; a previous statement. 955 ;; a previous statement.
967 ((opascal-is token-kind opascal-use-clauses) 956 ((opascal--in opascal-use-clauses)
968 (throw 'done 957 (throw 'done
969 (if (eq 'comma from-kind) 958 (if (eq 'comma from-kind)
970 (if last-token 959 (if last-token
971 ;; Indent to first unit in use clause. 960 ;; Indent to first unit in use clause.
972 (opascal-indent-of last-token) 961 (opascal-indent-of last-token)
973 ;; Indent from use clause keyword. 962 ;; Indent from use clause keyword.
974 (opascal-line-indent-of token opascal-indent-level)) 963 (opascal-line-indent-of token opascal-indent-level))
975 ;; Indent to use clause keyword. 964 ;; Indent to use clause keyword.
976 (opascal-line-indent-of token)))) 965 (opascal-line-indent-of token))))
977 966
978 ;; Assembly sections always indent in from the asm keyword. 967 ;; Assembly sections always indent in from the asm keyword.
979 ((eq token-kind 'asm) 968 ('asm
980 (throw 'done (opascal-stmt-line-indent-of token opascal-indent-level))) 969 (throw 'done (opascal-stmt-line-indent-of token opascal-indent-level)))
981 970
982 ;; An enclosing statement delimits a previous statement. 971 ;; An enclosing statement delimits a previous statement.
983 ;; We try to use the existing indent of the previous statement, 972 ;; We try to use the existing indent of the previous statement,
984 ;; otherwise we calculate from the enclosing statement. 973 ;; otherwise we calculate from the enclosing statement.
985 ((opascal-is token-kind opascal-previous-enclosing-statements) 974 ((opascal--in opascal-previous-enclosing-statements)
986 (throw 'done (if last-token 975 (throw 'done (if last-token
987 ;; Otherwise indent to the last token 976 ;; Otherwise indent to the last token
988 (opascal-line-indent-of last-token) 977 (opascal-line-indent-of last-token)
989 ;; Just indent from the enclosing keyword 978 ;; Just indent from the enclosing keyword
990 (opascal-line-indent-of token opascal-indent-level)))) 979 (opascal-line-indent-of token opascal-indent-level))))
991 980
992 ;; A class or record declaration also delimits a previous statement. 981 ;; A class or record declaration also delimits a previous statement.
993 ((opascal-composite-type-start token last-token) 982 ((guard (opascal-composite-type-start token last-token))
994 (throw 983 (throw
995 'done 984 'done
996 (if (opascal-is-simple-class-type last-token from-token) 985 (if (opascal-is-simple-class-type last-token from-token)
997 ;; c = class; or c = class of T; are previous statements. 986 ;; c = class; or c = class of T; are previous statements.
998 (opascal-line-indent-of token) 987 (opascal-line-indent-of token)
999 ;; Otherwise c = class ... or r = record ... are enclosing 988 ;; Otherwise c = class ... or r = record ... are enclosing
1000 ;; statements. 989 ;; statements.
1001 (opascal-line-indent-of last-token opascal-indent-level)))) 990 (opascal-line-indent-of last-token opascal-indent-level))))
1002 991
1003 ;; We have a definite previous statement delimiter. 992 ;; We have a definite previous statement delimiter.
1004 ((opascal-is token-kind opascal-previous-statements) 993 ((opascal--in opascal-previous-statements)
1005 (throw 'done (opascal-stmt-line-indent-of token 0))) 994 (throw 'done (opascal-stmt-line-indent-of token 0)))
1006 ) 995 )
1007 (unless (opascal-is token-kind opascal-whitespace)
1008 (setq last-token token))
1009 (setq token (opascal-previous-token token)))
1010 ;; We ran out of tokens. Indent to column 0. 996 ;; We ran out of tokens. Indent to column 0.
1011 0))) 997 0)))
1012 998
1013(defun opascal-section-indent-of (section-token) 999(defun opascal-section-indent-of (section-token)
1014 ;; Returns the indentation appropriate for begin/var/const/type/label 1000 ;; Returns the indentation appropriate for begin/var/const/type/label
1015 ;; tokens. 1001 ;; tokens.
1016 (let* ((token (opascal-previous-token section-token)) 1002 (let* ((token section-token)
1017 (token-kind nil)
1018 (last-token nil) 1003 (last-token nil)
1019 (nested-block-count 0) 1004 (nested-block-count 0)
1020 (expr-delimited nil) 1005 (expr-delimited nil)
1021 (last-terminator nil)) 1006 (last-terminator nil))
1022 (catch 'done 1007 (catch 'done
1023 (while token 1008 (opascal--scan-non-whitespace-backward token last-token
1024 (setq token-kind (opascal-token-kind token)) 1009 ;; Always stop at unmatched ( or [.
1025 (cond 1010 ('open-group
1026 ;; Always stop at unmatched ( or [. 1011 (throw 'done (opascal-open-group-indent token last-token)))
1027 ((eq token-kind 'open-group) 1012
1028 (throw 'done (opascal-open-group-indent token last-token))) 1013 ;; Skip over any ()/[] groups.
1029 1014 ('close-group (setq token (opascal-group-start token)))
1030 ;; Skip over any ()/[] groups. 1015
1031 ((eq 'close-group token-kind) (setq token (opascal-group-start token))) 1016 ((opascal--in opascal-end-block-statements)
1032 1017 (if (eq 'newline (opascal-token-kind (opascal-previous-token token)))
1033 ((opascal-is token-kind opascal-end-block-statements) 1018 ;; We can stop at an end token that is right up against the
1034 (if (eq 'newline (opascal-token-kind (opascal-previous-token token))) 1019 ;; margin.
1035 ;; We can stop at an end token that is right up against the 1020 (throw 'done 0)
1036 ;; margin. 1021 ;; Otherwise, skip over any nested blocks.
1037 (throw 'done 0) 1022 (setq token (opascal-block-start token)
1038 ;; Otherwise, skip over any nested blocks. 1023 nested-block-count (1+ nested-block-count))))
1039 (setq token (opascal-block-start token) 1024
1040 nested-block-count (1+ nested-block-count)))) 1025 ;; Remember if we have encountered any forward routine declarations.
1041 1026 ('forward
1042 ;; Remember if we have encountered any forward routine declarations. 1027 (setq nested-block-count (1+ nested-block-count)))
1043 ((eq 'forward token-kind) 1028
1044 (setq nested-block-count (1+ nested-block-count))) 1029 ;; Mark the completion of a nested routine traversal.
1045 1030 ((and (opascal--in opascal-routine-statements)
1046 ;; Mark the completion of a nested routine traversal. 1031 (guard (> nested-block-count 0)))
1047 ((and (opascal-is token-kind opascal-routine-statements) 1032 (setq nested-block-count (1- nested-block-count)))
1048 (> nested-block-count 0)) 1033
1049 (setq nested-block-count (1- nested-block-count))) 1034 ;; Remember if we have encountered any statement terminators.
1050 1035 ('semicolon (setq last-terminator token))
1051 ;; Remember if we have encountered any statement terminators. 1036
1052 ((eq 'semicolon token-kind) (setq last-terminator token)) 1037 ;; Remember if we have encountered any expression delimiters.
1053 1038 ((opascal--in opascal-expr-delimiters)
1054 ;; Remember if we have encountered any expression delimiters. 1039 (setq expr-delimited token))
1055 ((opascal-is token-kind opascal-expr-delimiters) 1040
1056 (setq expr-delimited token)) 1041 ;; Enclosing body statements are delimiting. We indent the compound
1057 1042 ;; bodies specially.
1058 ;; Enclosing body statements are delimiting. We indent the compound 1043 ((and (guard (not last-terminator))
1059 ;; bodies specially. 1044 (opascal--in opascal-body-statements))
1060 ((and (not last-terminator) 1045 (throw 'done
1061 (opascal-is token-kind opascal-body-statements)) 1046 (opascal-stmt-line-indent-of token
1062 (throw 'done 1047 opascal-compound-block-indent)))
1063 (opascal-stmt-line-indent-of token opascal-compound-block-indent))) 1048
1064 1049 ;; An enclosing ":" means a label.
1065 ;; An enclosing ":" means a label. 1050 ((and 'colon
1066 ((and (eq 'colon token-kind) 1051 (guard (and (memq (opascal-token-kind section-token)
1067 (opascal-is (opascal-token-kind section-token) 1052 opascal-block-statements)
1068 opascal-block-statements) 1053 (not last-terminator)
1069 (not last-terminator) 1054 (not expr-delimited)
1070 (not expr-delimited) 1055 (not (eq 'equals
1071 (not (eq 'equals (opascal-token-kind last-token)))) 1056 (opascal-token-kind last-token))))))
1072 (throw 'done 1057 (throw 'done
1073 (opascal-stmt-line-indent-of token opascal-indent-level))) 1058 (opascal-stmt-line-indent-of token opascal-indent-level)))
1074 1059
1075 ;; Block and mid block tokens are always enclosing 1060 ;; Block and mid block tokens are always enclosing
1076 ((opascal-is token-kind opascal-begin-enclosing-tokens) 1061 ((opascal--in opascal-begin-enclosing-tokens)
1077 (throw 'done 1062 (throw 'done
1078 (opascal-stmt-line-indent-of token opascal-indent-level))) 1063 (opascal-stmt-line-indent-of token opascal-indent-level)))
1079 1064
1080 ;; Declaration sections and routines are delimiters, unless they 1065 ;; Declaration sections and routines are delimiters, unless they
1081 ;; are part of a nested routine. 1066 ;; are part of a nested routine.
1082 ((and (opascal-is token-kind opascal-decl-delimiters) 1067 ((and (opascal--in opascal-decl-delimiters)
1083 (= 0 nested-block-count)) 1068 (guard (= 0 nested-block-count)))
1084 (throw 'done (opascal-line-indent-of token 0))) 1069 (throw 'done (opascal-line-indent-of token 0)))
1085 1070
1086 ;; Unit statements mean we indent right to the left. 1071 ;; Unit statements mean we indent right to the left.
1087 ((opascal-is token-kind opascal-unit-statements) (throw 'done 0)) 1072 ((opascal--in opascal-unit-statements) (throw 'done 0))
1088 ) 1073 )
1089 (unless (opascal-is token-kind opascal-whitespace)
1090 (setq last-token token))
1091 (setq token (opascal-previous-token token)))
1092 ;; We ran out of tokens. Indent to column 0. 1074 ;; We ran out of tokens. Indent to column 0.
1093 0))) 1075 0)))
1094 1076
1095(defun opascal-enclosing-indent-of (from-token) 1077(defun opascal-enclosing-indent-of (from-token)
1096 ;; Returns the indentation offset from the enclosing statement of the token. 1078 ;; Returns the indentation offset from the enclosing statement of the token.
1097 (let ((token (opascal-previous-token from-token)) 1079 (let ((token from-token)
1098 (from-kind (opascal-token-kind from-token)) 1080 (from-kind (opascal-token-kind from-token))
1099 (token-kind nil)
1100 (stmt-start nil) 1081 (stmt-start nil)
1101 (last-token nil) 1082 (last-token nil)
1102 (equals-encountered nil) 1083 (equals-encountered nil)
1103 (before-equals nil) 1084 (before-equals nil)
1104 (expr-delimited nil)) 1085 (expr-delimited nil))
1105 (catch 'done 1086 (catch 'done
1106 (while token 1087 (opascal--scan-non-whitespace-backward token last-token
1107 (setq token-kind (opascal-token-kind token)) 1088 ;; An open ( or [ always is an indent point.
1108 (cond 1089 ('open-group
1109 ;; An open ( or [ always is an indent point. 1090 (throw 'done
1110 ((eq 'open-group token-kind) 1091 (opascal-open-group-indent
1111 (throw 'done 1092 token last-token
1112 (opascal-open-group-indent 1093 (if (memq from-kind opascal-binary-ops)
1113 token last-token 1094 ;; Keep binary operations aligned with the open group.
1114 (if (opascal-is from-kind opascal-binary-ops) 1095 0
1115 ;; Keep binary operations aligned with the open group. 1096 opascal-indent-level))))
1116 0 1097
1117 opascal-indent-level)))) 1098 ;; Skip over any ()/[] groups.
1118 1099 ('close-group (setq token (opascal-group-start token)))
1119 ;; Skip over any ()/[] groups. 1100
1120 ((eq 'close-group token-kind) (setq token (opascal-group-start token))) 1101 ;; Skip over any nested blocks.
1121 1102 ((opascal--in opascal-end-block-statements)
1122 ;; Skip over any nested blocks. 1103 (setq token (opascal-block-start token)))
1123 ((opascal-is token-kind opascal-end-block-statements) 1104
1124 (setq token (opascal-block-start token))) 1105 ;; An expression delimiter affects indentation depending on whether
1125 1106 ;; the point is before or after it. Remember that we encountered one.
1126 ;; An expression delimiter affects indentation depending on whether 1107 ;; Also remember the last encountered token, since if it exists it
1127 ;; the point is before or after it. Remember that we encountered one. 1108 ;; should be the actual indent point.
1128 ;; Also remember the last encountered token, since if it exists it 1109 ((opascal--in opascal-expr-delimiters)
1129 ;; should be the actual indent point. 1110 (setq expr-delimited token stmt-start last-token))
1130 ((opascal-is token-kind opascal-expr-delimiters) 1111
1131 (setq expr-delimited token stmt-start last-token)) 1112 ;; With a non-delimited expression statement we indent after the
1132 1113 ;; statement's keyword, unless we are on the delimiter itself.
1133 ;; With a non-delimited expression statement we indent after the 1114 ((and (guard (not expr-delimited))
1134 ;; statement's keyword, unless we are on the delimiter itself. 1115 (opascal--in opascal-expr-statements))
1135 ((and (not expr-delimited) 1116 (throw 'done
1136 (opascal-is token-kind opascal-expr-statements)) 1117 (cond
1137 (throw 'done 1118 ((memq from-kind opascal-expr-delimiters)
1138 (cond ((opascal-is from-kind opascal-expr-delimiters) 1119 ;; We are indenting a delimiter. Indent to the statement.
1139 ;; We are indenting a delimiter. Indent to the statement. 1120 (opascal-stmt-line-indent-of token 0))
1140 (opascal-stmt-line-indent-of token 0)) 1121
1141 1122 ((and last-token (memq from-kind opascal-binary-ops))
1142 ((and last-token (opascal-is from-kind opascal-binary-ops)) 1123 ;; Align binary ops with the expression.
1143 ;; Align binary ops with the expression. 1124 (opascal-indent-of last-token))
1144 (opascal-indent-of last-token)) 1125
1145 1126 (last-token
1146 (last-token 1127 ;; Indent in from the expression.
1147 ;; Indent in from the expression. 1128 (opascal-indent-of last-token opascal-indent-level))
1148 (opascal-indent-of last-token opascal-indent-level)) 1129
1149 1130 ;; Indent in from the statement's keyword.
1150 ;; Indent in from the statement's keyword. 1131 ((opascal-indent-of token opascal-indent-level)))))
1151 ((opascal-indent-of token opascal-indent-level))))) 1132
1152 1133 ;; A delimited case statement indents the label according to
1153 ;; A delimited case statement indents the label according to 1134 ;; a special rule.
1154 ;; a special rule. 1135 ('case
1155 ((eq 'case token-kind) 1136 (throw 'done
1156 (throw 'done 1137 (if stmt-start
1157 (if stmt-start 1138 ;; We are not actually indenting to the case statement,
1158 ;; We are not actually indenting to the case statement, 1139 ;; but are within a label expression.
1159 ;; but are within a label expression. 1140 (opascal-stmt-line-indent-of
1160 (opascal-stmt-line-indent-of 1141 stmt-start opascal-indent-level)
1161 stmt-start opascal-indent-level) 1142 ;; Indent from the case keyword.
1162 ;; Indent from the case keyword. 1143 (opascal-stmt-line-indent-of
1163 (opascal-stmt-line-indent-of 1144 token opascal-case-label-indent))))
1164 token opascal-case-label-indent)))) 1145
1165 1146 ;; Body expression statements are enclosing. Indent from the
1166 ;; Body expression statements are enclosing. Indent from the 1147 ;; statement's keyword, unless we have a non-block statement following
1167 ;; statement's keyword, unless we have a non-block statement following 1148 ;; it.
1168 ;; it. 1149 ((opascal--in opascal-body-expr-statements)
1169 ((opascal-is token-kind opascal-body-expr-statements) 1150 (throw 'done (opascal-stmt-line-indent-of
1170 (throw 'done 1151 (or stmt-start token) opascal-indent-level)))
1171 (opascal-stmt-line-indent-of 1152
1172 (or stmt-start token) opascal-indent-level))) 1153 ;; An else statement is enclosing, but it doesn't have an expression.
1173 1154 ;; Thus we take into account last-token instead of stmt-start.
1174 ;; An else statement is enclosing, but it doesn't have an expression. 1155 ('else
1175 ;; Thus we take into account last-token instead of stmt-start. 1156 (throw 'done (opascal-stmt-line-indent-of
1176 ((eq 'else token-kind) 1157 (or last-token token) opascal-indent-level)))
1177 (throw 'done (opascal-stmt-line-indent-of 1158
1178 (or last-token token) opascal-indent-level))) 1159 ;; We indent relative to an enclosing declaration section,
1179 1160 ;; unless this is within the a delimited expression
1180 ;; We indent relative to an enclosing declaration section, 1161 ;; (bug#36348).
1181 ;; unless this is within the a delimited expression 1162 ((and (guard (not expr-delimited))
1182 ;; (bug#36348). 1163 (opascal--in opascal-decl-sections))
1183 ((and (not expr-delimited) 1164 (throw 'done (opascal-indent-of (if last-token last-token token)
1184 (opascal-is token-kind opascal-decl-sections))
1185 (throw 'done (opascal-indent-of (if last-token last-token token)
1186 opascal-indent-level))) 1165 opascal-indent-level)))
1187 1166
1188 ;; In unit sections we indent right to the left. 1167 ;; In unit sections we indent right to the left.
1189 ((opascal-is token-kind opascal-unit-sections) 1168 ;; Handle specially the case of "interface", which can be used
1190 (throw 'done 1169 ;; to start either a unit section or an interface definition.
1191 ;; Handle specially the case of "interface", which can be used 1170 ('interface ;FIXME: Generalize to all `opascal-interface-types'?
1192 ;; to start either a unit section or an interface definition. 1171 (throw 'done
1193 (if (opascal-is token-kind opascal-interface-types) 1172 (let (token-kind)
1194 (progn 1173 ;; Find the previous non-whitespace token.
1195 ;; Find the previous non-whitespace token. 1174 (while (progn
1196 (while (progn 1175 (setq last-token token
1197 (setq last-token token 1176 token (opascal-previous-token token)
1198 token (opascal-previous-token token) 1177 token-kind (opascal-token-kind token))
1199 token-kind (opascal-token-kind token)) 1178 (and token
1200 (and token 1179 (memq token-kind
1201 (opascal-is token-kind 1180 opascal-whitespace))))
1202 opascal-whitespace)))) 1181 ;; If this token is an equals sign, "interface" is being
1203 ;; If this token is an equals sign, "interface" is being 1182 ;; used to start an interface definition and we should
1204 ;; used to start an interface definition and we should 1183 ;; treat it as a composite type; otherwise, we should
1205 ;; treat it as a composite type; otherwise, we should 1184 ;; consider it the start of a unit section.
1206 ;; consider it the start of a unit section. 1185 (if (and token (eq token-kind 'equals))
1207 (if (and token (eq token-kind 'equals)) 1186 (opascal-line-indent-of last-token
1208 (opascal-line-indent-of last-token 1187 opascal-indent-level)
1209 opascal-indent-level) 1188 0))))
1210 0)) 1189
1211 0))) 1190 ;; In unit sections we indent right to the left.
1212 1191 ((opascal--in opascal-unit-sections)
1213 ;; A previous terminator means we can stop. 1192 ;; Note: The `interface' case is handled specially above.
1214 ((opascal-is token-kind opascal-previous-terminators) 1193 (throw 'done 0))
1215 (throw 'done 1194
1216 (cond ((and last-token 1195 ;; A previous terminator means we can stop.
1217 (eq 'comma token-kind) 1196 ((and (opascal--in opascal-previous-terminators) token-kind)
1218 (opascal-is from-kind opascal-binary-ops)) 1197 (throw 'done
1219 ;; Align binary ops with the expression. 1198 (cond ((and last-token
1220 (opascal-indent-of last-token)) 1199 (eq 'comma token-kind)
1221 1200 (memq from-kind opascal-binary-ops))
1222 (last-token 1201 ;; Align binary ops with the expression.
1223 ;; Indent in from the expression. 1202 (opascal-indent-of last-token))
1224 (opascal-indent-of last-token opascal-indent-level)) 1203
1225 1204 (last-token
1226 ;; No enclosing expression; use the previous statement's 1205 ;; Indent in from the expression.
1227 ;; indent. 1206 (opascal-indent-of last-token opascal-indent-level))
1228 ((opascal-previous-indent-of token))))) 1207
1229 1208 ;; No enclosing expression; use the previous statement's
1230 ;; A block statement after an expression delimiter has its start 1209 ;; indent.
1231 ;; column as the expression statement. E.g. 1210 ((opascal-previous-indent-of token)))))
1232 ;; if (a = b) 1211
1233 ;; and (a != c) then begin 1212 ;; A block statement after an expression delimiter has its start
1234 ;; //... 1213 ;; column as the expression statement. E.g.
1235 ;; end; 1214 ;; if (a = b)
1236 ;; Remember it for when we encounter the expression statement start. 1215 ;; and (a != c) then begin
1237 ((opascal-is-block-after-expr-statement token) 1216 ;; //...
1238 (throw 'done 1217 ;; end;
1239 (cond (last-token (opascal-indent-of last-token opascal-indent-level)) 1218 ;; Remember it for when we encounter the expression statement start.
1240 1219 ((guard (opascal-is-block-after-expr-statement token))
1241 ((+ (opascal-section-indent-of token) opascal-indent-level))))) 1220 (throw 'done
1242 1221 (cond (last-token
1243 ;; Assembly sections always indent in from the asm keyword. 1222 (opascal-indent-of last-token opascal-indent-level))
1244 ((eq token-kind 'asm) 1223
1245 (throw 'done (opascal-stmt-line-indent-of token opascal-indent-level))) 1224 (t (+ (opascal-section-indent-of token)
1246 1225 opascal-indent-level)))))
1247 ;; Stop at an enclosing statement and indent from it. 1226
1248 ((opascal-is token-kind opascal-enclosing-statements) 1227 ;; Assembly sections always indent in from the asm keyword.
1249 (throw 'done (opascal-stmt-line-indent-of 1228 ('asm
1250 (or last-token token) opascal-indent-level))) 1229 (throw 'done (opascal-stmt-line-indent-of token opascal-indent-level)))
1251 1230
1252 ;; A class/record declaration is also enclosing. 1231 ;; Stop at an enclosing statement and indent from it.
1253 ((opascal-composite-type-start token last-token) 1232 ((opascal--in opascal-enclosing-statements)
1254 (throw 'done 1233 (throw 'done (opascal-stmt-line-indent-of
1255 (opascal-line-indent-of last-token opascal-indent-level))) 1234 (or last-token token) opascal-indent-level)))
1256 1235
1257 ;; A ":" we indent relative to its line beginning. If we are in a 1236 ;; A class/record declaration is also enclosing.
1258 ;; parameter list, then stop also if we hit a ";". 1237 ((guard (opascal-composite-type-start token last-token))
1259 ((and (eq token-kind 'colon) 1238 (throw 'done
1260 (not expr-delimited) 1239 (opascal-line-indent-of last-token opascal-indent-level)))
1261 (not (opascal-is from-kind opascal-expr-delimiters)) 1240
1262 (not equals-encountered) 1241 ;; A ":" we indent relative to its line beginning. If we are in a
1263 (not (eq from-kind 'equals))) 1242 ;; parameter list, then stop also if we hit a ";".
1264 (throw 'done 1243 ((and 'colon
1265 (if last-token 1244 (guard (not (or expr-delimited
1266 (opascal-indent-of last-token opascal-indent-level) 1245 (memq from-kind opascal-expr-delimiters)
1267 (opascal-line-indent-of token opascal-indent-level 'semicolon)))) 1246 equals-encountered
1268 1247 (eq from-kind 'equals)))))
1269 ;; If the ":" was not processed above and we have token after the "=", 1248 (throw 'done
1270 ;; then indent from the "=". Ignore :=, however. 1249 (if last-token
1271 ((and (eq token-kind 'colon) equals-encountered before-equals) 1250 (opascal-indent-of last-token opascal-indent-level)
1272 (cond 1251 (opascal-line-indent-of token opascal-indent-level
1273 ;; Ignore binary ops for now. It would do, for example: 1252 'semicolon))))
1274 ;; val := 1 + 2 1253
1275 ;; + 3; 1254 ;; If the ":" was not processed above and we have token after the "=",
1276 ;; which is good, but also 1255 ;; then indent from the "=". Ignore :=, however.
1277 ;; val := Foo 1256 ((and 'colon (guard (and equals-encountered before-equals)))
1278 ;; (foo, args) 1257 (cond
1279 ;; + 2; 1258 ;; Ignore binary ops for now. It would do, for example:
1280 ;; which doesn't look right. 1259 ;; val := 1 + 2
1281 ;;;; Align binary ops with the before token. 1260 ;; + 3;
1282 ;;((opascal-is from-kind opascal-binary-ops) 1261 ;; which is good, but also
1283 ;;(throw 'done (opascal-indent-of before-equals 0))) 1262 ;; val := Foo
1284 1263 ;; (foo, args)
1285 ;; Assignments (:=) we skip over to get a normal indent. 1264 ;; + 2;
1286 ((eq (opascal-token-kind last-token) 'equals)) 1265 ;; which doesn't look right.
1287 1266
1288 ;; Otherwise indent in from the equals. 1267 ;; ;; Align binary ops with the before token.
1289 ((throw 'done 1268 ;;((memq from-kind opascal-binary-ops)
1290 (opascal-indent-of before-equals opascal-indent-level))))) 1269 ;;(throw 'done (opascal-indent-of before-equals 0)))
1291 1270
1292 ;; Remember any "=" we encounter if it has not already been processed. 1271 ;; Assignments (:=) we skip over to get a normal indent.
1293 ((eq token-kind 'equals) 1272 ((eq (opascal-token-kind last-token) 'equals))
1294 (setq equals-encountered token 1273
1295 before-equals last-token)) 1274 ;; Otherwise indent in from the equals.
1296 ) 1275 (t (throw 'done
1297 (unless (opascal-is token-kind opascal-whitespace) 1276 (opascal-indent-of before-equals opascal-indent-level)))))
1298 (setq last-token token)) 1277
1299 (setq token (opascal-previous-token token))) 1278 ;; Remember any "=" we encounter if it has not already been processed.
1279 ('equals
1280 (setq equals-encountered token
1281 before-equals last-token))
1282 )
1300 ;; We ran out of tokens. Indent to column 0. 1283 ;; We ran out of tokens. Indent to column 0.
1301 0))) 1284 0)))
1302 1285
@@ -1304,9 +1287,12 @@ routine.")
1304 ;; Returns the corrected indentation for the current line. 1287 ;; Returns the corrected indentation for the current line.
1305 (opascal-save-excursion 1288 (opascal-save-excursion
1306 (opascal-progress-start) 1289 (opascal-progress-start)
1307 ;; Move to the first token on the line. 1290 ;; The caller should make sure we're at the first token on the line.
1308 (beginning-of-line) 1291 (cl-assert (eql (point)
1309 (skip-chars-forward opascal-space-chars) 1292 (save-excursion
1293 (beginning-of-line)
1294 (skip-chars-forward opascal-space-chars)
1295 (point))))
1310 (let* ((token (opascal-current-token)) 1296 (let* ((token (opascal-current-token))
1311 (token-kind (opascal-token-kind token)) 1297 (token-kind (opascal-token-kind token))
1312 (indent 1298 (indent
@@ -1314,17 +1300,17 @@ routine.")
1314 ;; Indent to the matching start ( or [. 1300 ;; Indent to the matching start ( or [.
1315 (opascal-indent-of (opascal-group-start token))) 1301 (opascal-indent-of (opascal-group-start token)))
1316 1302
1317 ((opascal-is token-kind opascal-unit-statements) 0) 1303 ((memq token-kind opascal-unit-statements) 0)
1318 1304
1319 ((opascal-is token-kind opascal-comments) 1305 ((memq token-kind opascal-comments)
1320 ;; In a comment. 1306 ;; In a comment.
1321 (opascal-comment-indent-of token)) 1307 (opascal-comment-indent-of token))
1322 1308
1323 ((opascal-is token-kind opascal-decl-matchers) 1309 ((memq token-kind opascal-decl-matchers)
1324 ;; Use a previous section/routine's indent. 1310 ;; Use a previous section/routine's indent.
1325 (opascal-section-indent-of token)) 1311 (opascal-section-indent-of token))
1326 1312
1327 ((opascal-is token-kind opascal-match-block-statements) 1313 ((memq token-kind opascal-match-block-statements)
1328 ;; Use the block's indentation. 1314 ;; Use the block's indentation.
1329 (let ((block-start 1315 (let ((block-start
1330 (opascal-block-start token 'stop-on-class))) 1316 (opascal-block-start token 'stop-on-class)))
@@ -1342,8 +1328,9 @@ routine.")
1342 (opascal-stmt-line-indent-of (opascal-else-start token) 0)) 1328 (opascal-stmt-line-indent-of (opascal-else-start token) 0))
1343 1329
1344 ;; Otherwise indent in from enclosing statement. 1330 ;; Otherwise indent in from enclosing statement.
1345 ((opascal-enclosing-indent-of 1331 (t
1346 (if token token (opascal-token-at (1- (point))))))))) 1332 (opascal-enclosing-indent-of
1333 (or token (opascal-token-at (1- (point)))))))))
1347 (opascal-progress-done) 1334 (opascal-progress-done)
1348 indent))) 1335 indent)))
1349 1336
@@ -1352,25 +1339,18 @@ routine.")
1352If before the indent, the point is moved to the indent." 1339If before the indent, the point is moved to the indent."
1353 (interactive) 1340 (interactive)
1354 (save-match-data 1341 (save-match-data
1355 (let ((marked-point (point-marker)) ; Maintain our position reliably. 1342 (let ((marked-point (point-marker))) ; Maintain our position reliably.
1356 (line-start nil) 1343 (beginning-of-line)
1357 (old-indent 0) 1344 (skip-chars-forward opascal-space-chars)
1358 (new-indent 0)) 1345 (let ((new-indent (opascal-corrected-indentation)))
1359 (beginning-of-line) 1346 (if (< marked-point (point))
1360 (setq line-start (point)) 1347 ;; If before the indent column, then move to it.
1361 (skip-chars-forward opascal-space-chars) 1348 (set-marker marked-point (point)))
1362 (setq old-indent (current-column)) 1349 ;; Advance our marked point after inserted spaces.
1363 (setq new-indent (opascal-corrected-indentation)) 1350 (set-marker-insertion-type marked-point t)
1364 (if (< marked-point (point)) 1351 (indent-line-to new-indent)
1365 ;; If before the indent column, then move to it. 1352 (goto-char marked-point)
1366 (set-marker marked-point (point))) 1353 (set-marker marked-point nil)))))
1367 ;; Advance our marked point after inserted spaces.
1368 (set-marker-insertion-type marked-point t)
1369 (when (/= old-indent new-indent)
1370 (delete-region line-start (point))
1371 (insert (make-string new-indent ?\s)))
1372 (goto-char marked-point)
1373 (set-marker marked-point nil))))
1374 1354
1375(defvar opascal-mode-abbrev-table nil 1355(defvar opascal-mode-abbrev-table nil
1376 "Abbrev table in use in OPascal mode buffers.") 1356 "Abbrev table in use in OPascal mode buffers.")
@@ -1583,7 +1563,7 @@ An error is raised if not in a comment."
1583 (save-restriction 1563 (save-restriction
1584 (let* ((comment (opascal-current-token)) 1564 (let* ((comment (opascal-current-token))
1585 (comment-kind (opascal-token-kind comment))) 1565 (comment-kind (opascal-token-kind comment)))
1586 (if (not (opascal-is comment-kind opascal-comments)) 1566 (if (not (memq comment-kind opascal-comments))
1587 (error "Not in a comment") 1567 (error "Not in a comment")
1588 (let* ((start-comment (opascal-comment-block-start comment)) 1568 (let* ((start-comment (opascal-comment-block-start comment))
1589 (end-comment (opascal-comment-block-end comment)) 1569 (end-comment (opascal-comment-block-end comment))
@@ -1661,6 +1641,9 @@ An error is raised if not in a comment."
1661 "If in a // comment, do a newline, indented such that one is still in the 1641 "If in a // comment, do a newline, indented such that one is still in the
1662comment block. If not in a // comment, just does a normal newline." 1642comment block. If not in a // comment, just does a normal newline."
1663 (interactive) 1643 (interactive)
1644 (declare
1645 (obsolete "use comment-indent-new-line with comment-multi-line instead"
1646 "27.1"))
1664 (let ((comment (opascal-current-token))) 1647 (let ((comment (opascal-current-token)))
1665 (if (not (eq 'comment-single-line (opascal-token-kind comment))) 1648 (if (not (eq 'comment-single-line (opascal-token-kind comment)))
1666 ;; Not in a // comment. Just do the normal newline. 1649 ;; Not in a // comment. Just do the normal newline.
@@ -1736,7 +1719,7 @@ comment block. If not in a // comment, just does a normal newline."
1736 ;; '("\C-cb" opascal-find-current-body) 1719 ;; '("\C-cb" opascal-find-current-body)
1737 '("\C-cu" opascal-find-unit) 1720 '("\C-cu" opascal-find-unit)
1738 '("\M-q" opascal-fill-comment) 1721 '("\M-q" opascal-fill-comment)
1739 '("\M-j" opascal-new-comment-line) 1722 ;; '("\M-j" opascal-new-comment-line)
1740 ;; Debug bindings: 1723 ;; Debug bindings:
1741 (list "\C-c\C-d" opascal-debug-mode-map))) 1724 (list "\C-c\C-d" opascal-debug-mode-map)))
1742 (define-key kmap (car binding) (cadr binding))) 1725 (define-key kmap (car binding) (cadr binding)))
@@ -1745,7 +1728,7 @@ comment block. If not in a // comment, just does a normal newline."
1745 1728
1746(define-obsolete-variable-alias 'delphi-mode-hook 'opascal-mode-hook "24.4") 1729(define-obsolete-variable-alias 'delphi-mode-hook 'opascal-mode-hook "24.4")
1747;;;###autoload 1730;;;###autoload
1748(define-obsolete-function-alias 'delphi-mode 'opascal-mode "24.4") 1731(define-obsolete-function-alias 'delphi-mode #'opascal-mode "24.4")
1749;;;###autoload 1732;;;###autoload
1750(define-derived-mode opascal-mode prog-mode "OPascal" 1733(define-derived-mode opascal-mode prog-mode "OPascal"
1751 "Major mode for editing OPascal code.\\<opascal-mode-map> 1734 "Major mode for editing OPascal code.\\<opascal-mode-map>