diff options
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 702 |
1 files changed, 360 insertions, 342 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 13ff439bef2..d340550a017 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -463,9 +463,14 @@ The type returned can be `comment', `string' or `paren'." | |||
| 463 | ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string)) | 463 | ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string)) |
| 464 | ((nth 1 ppss) 'paren)))) | 464 | ((nth 1 ppss) 'paren)))) |
| 465 | 465 | ||
| 466 | (defsubst python-syntax-comment-or-string-p () | 466 | (defsubst python-syntax-comment-or-string-p (&optional ppss) |
| 467 | "Return non-nil if point is inside 'comment or 'string." | 467 | "Return non-nil if PPSS is inside 'comment or 'string." |
| 468 | (nth 8 (syntax-ppss))) | 468 | (nth 8 (or ppss (syntax-ppss)))) |
| 469 | |||
| 470 | (defsubst python-syntax-closing-paren-p () | ||
| 471 | "Return non-nil if char after point is a closing paren." | ||
| 472 | (= (syntax-class (syntax-after (point))) | ||
| 473 | (syntax-class (string-to-syntax ")")))) | ||
| 469 | 474 | ||
| 470 | (define-obsolete-function-alias | 475 | (define-obsolete-function-alias |
| 471 | 'python-info-ppss-context #'python-syntax-context "24.3") | 476 | 'python-info-ppss-context #'python-syntax-context "24.3") |
| @@ -704,11 +709,28 @@ It makes underscores and dots word constituent chars.") | |||
| 704 | 'python-guess-indent 'python-indent-guess-indent-offset "24.3") | 709 | 'python-guess-indent 'python-indent-guess-indent-offset "24.3") |
| 705 | 710 | ||
| 706 | (defvar python-indent-current-level 0 | 711 | (defvar python-indent-current-level 0 |
| 707 | "Current indentation level `python-indent-line-function' is using.") | 712 | "Deprecated var available for compatibility.") |
| 708 | 713 | ||
| 709 | (defvar python-indent-levels '(0) | 714 | (defvar python-indent-levels '(0) |
| 710 | "Levels of indentation available for `python-indent-line-function'. | 715 | "Deprecated var available for compatibility.") |
| 711 | Can also be `noindent' if automatic indentation can't be used.") | 716 | |
| 717 | (make-obsolete-variable | ||
| 718 | 'python-indent-current-level | ||
| 719 | "The indentation API changed to avoid global state. | ||
| 720 | The function `python-indent-calculate-levels' does not use it | ||
| 721 | anymore. If you were defadvising it and or depended on this | ||
| 722 | variable for indentation customizations, refactor your code to | ||
| 723 | work on `python-indent-calculate-indentation' instead." | ||
| 724 | "24.5") | ||
| 725 | |||
| 726 | (make-obsolete-variable | ||
| 727 | 'python-indent-levels | ||
| 728 | "The indentation API changed to avoid global state. | ||
| 729 | The function `python-indent-calculate-levels' does not use it | ||
| 730 | anymore. If you were defadvising it and or depended on this | ||
| 731 | variable for indentation customizations, refactor your code to | ||
| 732 | work on `python-indent-calculate-indentation' instead." | ||
| 733 | "24.5") | ||
| 712 | 734 | ||
| 713 | (defun python-indent-guess-indent-offset () | 735 | (defun python-indent-guess-indent-offset () |
| 714 | "Guess and set `python-indent-offset' for the current buffer." | 736 | "Guess and set `python-indent-offset' for the current buffer." |
| @@ -748,362 +770,358 @@ Can also be `noindent' if automatic indentation can't be used.") | |||
| 748 | python-indent-offset))))))) | 770 | python-indent-offset))))))) |
| 749 | 771 | ||
| 750 | (defun python-indent-context () | 772 | (defun python-indent-context () |
| 751 | "Get information on indentation context. | 773 | "Get information about the current indentation context. |
| 752 | Context information is returned with a cons with the form: | 774 | Context is returned in a cons with the form (STATUS . START). |
| 753 | (STATUS . START) | 775 | |
| 754 | 776 | STATUS can be one of the following: | |
| 755 | Where status can be any of the following symbols: | 777 | |
| 756 | 778 | keyword | |
| 757 | * after-comment: When current line might continue a comment block | 779 | ------- |
| 758 | * inside-paren: If point in between (), {} or [] | 780 | |
| 759 | * inside-string: If point is inside a string | 781 | :after-comment |
| 760 | * after-backslash: Previous line ends in a backslash | 782 | - Point is after a comment line. |
| 761 | * after-beginning-of-block: Point is after beginning of block | 783 | - START is the position of the \"#\" character. |
| 762 | * after-line: Point is after normal line | 784 | :inside-string |
| 763 | * dedenter-statement: Point is on a dedenter statement. | 785 | - Point is inside string. |
| 764 | * no-indent: Point is at beginning of buffer or other special case | 786 | - START is the position of the first quote that starts it. |
| 765 | START is the buffer position where the sexp starts." | 787 | :no-indent |
| 788 | - No possible indentation case matches. | ||
| 789 | - START is always zero. | ||
| 790 | |||
| 791 | :inside-paren | ||
| 792 | - Fallback case when point is inside paren. | ||
| 793 | - START is the first non space char position *after* the open paren. | ||
| 794 | :inside-paren-at-closing-nested-paren | ||
| 795 | - Point is on a line that contains a nested paren closer. | ||
| 796 | - START is the position of the open paren it closes. | ||
| 797 | :inside-paren-at-closing-paren | ||
| 798 | - Point is on a line that contains a paren closer. | ||
| 799 | - START is the position of the open paren. | ||
| 800 | :inside-paren-newline-start | ||
| 801 | - Point is inside a paren with items starting in their own line. | ||
| 802 | - START is the position of the open paren. | ||
| 803 | :inside-paren-newline-start-from-block | ||
| 804 | - Point is inside a paren with items starting in their own line | ||
| 805 | from a block start. | ||
| 806 | - START is the position of the open paren. | ||
| 807 | |||
| 808 | :after-backslash | ||
| 809 | - Fallback case when point is after backslash. | ||
| 810 | - START is the char after the position of the backslash. | ||
| 811 | :after-backslash-assignment-continuation | ||
| 812 | - Point is after a backslashed assignment. | ||
| 813 | - START is the char after the position of the backslash. | ||
| 814 | :after-backslash-block-continuation | ||
| 815 | - Point is after a backslashed block continuation. | ||
| 816 | - START is the char after the position of the backslash. | ||
| 817 | :after-backslash-dotted-continuation | ||
| 818 | - Point is after a backslashed dotted continuation. Previous | ||
| 819 | line must contain a dot to align with. | ||
| 820 | - START is the char after the position of the backslash. | ||
| 821 | :after-backslash-first-line | ||
| 822 | - First line following a backslashed continuation. | ||
| 823 | - START is the char after the position of the backslash. | ||
| 824 | |||
| 825 | :after-block-end | ||
| 826 | - Point is after a line containing a block ender. | ||
| 827 | - START is the position where the ender starts. | ||
| 828 | :after-block-start | ||
| 829 | - Point is after a line starting a block. | ||
| 830 | - START is the position where the block starts. | ||
| 831 | :after-line | ||
| 832 | - Point is after a simple line. | ||
| 833 | - START is the position where the previous line starts. | ||
| 834 | :at-dedenter-block-start | ||
| 835 | - Point is on a line starting a dedenter block. | ||
| 836 | - START is the position where the dedenter block starts." | ||
| 766 | (save-restriction | 837 | (save-restriction |
| 767 | (widen) | 838 | (widen) |
| 768 | (let ((ppss (save-excursion (beginning-of-line) (syntax-ppss))) | 839 | (let ((ppss (save-excursion |
| 769 | (start)) | 840 | (beginning-of-line) |
| 770 | (cons | 841 | (syntax-ppss)))) |
| 771 | (cond | 842 | (cond |
| 772 | ;; Beginning of buffer | 843 | ;; Beginning of buffer. |
| 773 | ((save-excursion | 844 | ((= (line-number-at-pos) 1) |
| 774 | (goto-char (line-beginning-position)) | 845 | (cons :no-indent 0)) |
| 775 | (bobp)) | 846 | ;; Comment continuation (maybe). |
| 776 | 'no-indent) | 847 | ((save-excursion |
| 777 | ;; Comment continuation | 848 | (when (and |
| 778 | ((save-excursion | 849 | (or |
| 779 | (when (and | 850 | (python-info-current-line-comment-p) |
| 780 | (or | 851 | (python-info-current-line-empty-p)) |
| 781 | (python-info-current-line-comment-p) | 852 | (forward-comment -1) |
| 782 | (python-info-current-line-empty-p)) | 853 | (python-info-current-line-comment-p)) |
| 783 | (progn | 854 | (cons :after-comment (point))))) |
| 784 | (forward-comment -1) | 855 | ;; Inside a string. |
| 785 | (python-info-current-line-comment-p))) | 856 | ((let ((start (python-syntax-context 'string ppss))) |
| 786 | (setq start (point)) | 857 | (when start |
| 787 | 'after-comment))) | 858 | (cons :inside-string start)))) |
| 788 | ;; Inside string | 859 | ;; Inside a paren. |
| 789 | ((setq start (python-syntax-context 'string ppss)) | 860 | ((let* ((start (python-syntax-context 'paren ppss)) |
| 790 | 'inside-string) | 861 | (starts-in-newline |
| 791 | ;; Inside a paren | 862 | (when start |
| 792 | ((setq start (python-syntax-context 'paren ppss)) | 863 | (save-excursion |
| 793 | 'inside-paren) | 864 | (goto-char start) |
| 794 | ;; After backslash | 865 | (forward-char) |
| 795 | ((setq start (when (not (or (python-syntax-context 'string ppss) | 866 | (not |
| 796 | (python-syntax-context 'comment ppss))) | 867 | (= (line-number-at-pos) |
| 797 | (let ((line-beg-pos (line-number-at-pos))) | 868 | (progn |
| 798 | (python-info-line-ends-backslash-p | 869 | (python-util-forward-comment) |
| 799 | (1- line-beg-pos))))) | 870 | (line-number-at-pos)))))))) |
| 800 | 'after-backslash) | 871 | (when start |
| 801 | ;; After beginning of block | 872 | (cond |
| 802 | ((setq start (save-excursion | 873 | ;; Current line only holds the closing paren. |
| 803 | (when (progn | 874 | ((save-excursion |
| 804 | (back-to-indentation) | 875 | (skip-syntax-forward " ") |
| 805 | (python-util-forward-comment -1) | 876 | (when (and (python-syntax-closing-paren-p) |
| 806 | (equal (char-before) ?:)) | 877 | (progn |
| 807 | ;; Move to the first block start that's not in within | 878 | (forward-char 1) |
| 808 | ;; a string, comment or paren and that's not a | 879 | (not (python-syntax-context 'paren)))) |
| 809 | ;; continuation line. | 880 | (cons :inside-paren-at-closing-paren start)))) |
| 810 | (while (and (re-search-backward | 881 | ;; Current line only holds a closing paren for nested. |
| 811 | (python-rx block-start) nil t) | 882 | ((save-excursion |
| 812 | (or | 883 | (back-to-indentation) |
| 813 | (python-syntax-context-type) | 884 | (python-syntax-closing-paren-p)) |
| 814 | (python-info-continuation-line-p)))) | 885 | (cons :inside-paren-at-closing-nested-paren start)) |
| 815 | (when (looking-at (python-rx block-start)) | 886 | ;; This line starts from a opening block in its own line. |
| 816 | (point-marker))))) | 887 | ((save-excursion |
| 817 | 'after-beginning-of-block) | 888 | (goto-char start) |
| 818 | ((when (setq start (python-info-dedenter-statement-p)) | 889 | (when (and |
| 819 | 'dedenter-statement)) | 890 | starts-in-newline |
| 820 | ;; After normal line | 891 | (save-excursion |
| 821 | ((setq start (save-excursion | 892 | (back-to-indentation) |
| 893 | (looking-at (python-rx block-start)))) | ||
| 894 | (cons | ||
| 895 | :inside-paren-newline-start-from-block start)))) | ||
| 896 | (starts-in-newline | ||
| 897 | (cons :inside-paren-newline-start start)) | ||
| 898 | ;; General case. | ||
| 899 | (t (cons :inside-paren | ||
| 900 | (save-excursion | ||
| 901 | (goto-char (1+ start)) | ||
| 902 | (skip-syntax-forward "(" 1) | ||
| 903 | (skip-syntax-forward " ") | ||
| 904 | (point)))))))) | ||
| 905 | ;; After backslash. | ||
| 906 | ((let ((start (when (not (python-syntax-comment-or-string-p ppss)) | ||
| 907 | (python-info-line-ends-backslash-p | ||
| 908 | (1- (line-number-at-pos)))))) | ||
| 909 | (when start | ||
| 910 | (cond | ||
| 911 | ;; Continuation of dotted expression. | ||
| 912 | ((save-excursion | ||
| 913 | (back-to-indentation) | ||
| 914 | (when (eq (char-after) ?\.) | ||
| 915 | ;; Move point back until it's not inside a paren. | ||
| 916 | (while (prog2 | ||
| 917 | (forward-line -1) | ||
| 918 | (and (not (bobp)) | ||
| 919 | (python-syntax-context 'paren)))) | ||
| 920 | (goto-char (line-end-position)) | ||
| 921 | (while (and (search-backward | ||
| 922 | "." (line-beginning-position) t) | ||
| 923 | (python-syntax-context-type))) | ||
| 924 | ;; Ensure previous statement has dot to align with. | ||
| 925 | (when (and (eq (char-after) ?\.) | ||
| 926 | (not (python-syntax-context-type))) | ||
| 927 | (cons :after-backslash-dotted-continuation (point)))))) | ||
| 928 | ;; Continuation of block definition. | ||
| 929 | ((let ((block-continuation-start | ||
| 930 | (python-info-block-continuation-line-p))) | ||
| 931 | (when block-continuation-start | ||
| 932 | (save-excursion | ||
| 933 | (goto-char block-continuation-start) | ||
| 934 | (re-search-forward | ||
| 935 | (python-rx block-start (* space)) | ||
| 936 | (line-end-position) t) | ||
| 937 | (cons :after-backslash-block-continuation (point)))))) | ||
| 938 | ;; Continuation of assignment. | ||
| 939 | ((let ((assignment-continuation-start | ||
| 940 | (python-info-assignment-continuation-line-p))) | ||
| 941 | (when assignment-continuation-start | ||
| 942 | (save-excursion | ||
| 943 | (goto-char assignment-continuation-start) | ||
| 944 | (cons :after-backslash-assignment-continuation (point)))))) | ||
| 945 | ;; First line after backslash continuation start. | ||
| 946 | ((save-excursion | ||
| 947 | (goto-char start) | ||
| 948 | (when (or (= (line-number-at-pos) 1) | ||
| 949 | (not (python-info-beginning-of-backslash | ||
| 950 | (1- (line-number-at-pos))))) | ||
| 951 | (cons :after-backslash-first-line start)))) | ||
| 952 | ;; General case. | ||
| 953 | (t (cons :after-backslash start)))))) | ||
| 954 | ;; After beginning of block. | ||
| 955 | ((let ((start (save-excursion | ||
| 956 | (back-to-indentation) | ||
| 957 | (python-util-forward-comment -1) | ||
| 958 | (when (equal (char-before) ?:) | ||
| 959 | (python-nav-beginning-of-block))))) | ||
| 960 | (when start | ||
| 961 | (cons :after-block-start start)))) | ||
| 962 | ;; At dedenter statement. | ||
| 963 | ((let ((start (python-info-dedenter-statement-p))) | ||
| 964 | (when start | ||
| 965 | (cons :at-dedenter-block-start start)))) | ||
| 966 | ;; After normal line. | ||
| 967 | ((let ((start (save-excursion | ||
| 822 | (back-to-indentation) | 968 | (back-to-indentation) |
| 823 | (skip-chars-backward (rx (or whitespace ?\n))) | 969 | (skip-chars-backward " \t\n") |
| 824 | (python-nav-beginning-of-statement) | 970 | (python-nav-beginning-of-statement) |
| 825 | (point-marker))) | 971 | (point)))) |
| 826 | 'after-line) | 972 | (when start |
| 827 | ;; Do not indent | 973 | (if (save-excursion |
| 828 | (t 'no-indent)) | 974 | (python-util-forward-comment -1) |
| 829 | start)))) | 975 | (python-nav-beginning-of-statement) |
| 830 | 976 | (looking-at (python-rx block-ender))) | |
| 831 | (defun python-indent-calculate-indentation () | 977 | (cons :after-block-end start) |
| 832 | "Calculate correct indentation offset for the current line. | 978 | (cons :after-line start))))) |
| 833 | Returns `noindent' if the indentation does not depend on Python syntax, | 979 | ;; Default case: do not indent. |
| 834 | such as in strings." | 980 | (t (cons :no-indent 0)))))) |
| 835 | (let* ((indentation-context (python-indent-context)) | 981 | |
| 836 | (context-status (car indentation-context)) | 982 | (defun python-indent--calculate-indentation () |
| 837 | (context-start (cdr indentation-context))) | 983 | "Internal implementation of `python-indent-calculate-indentation'. |
| 838 | (save-restriction | 984 | May return an integer for the maximum possible indentation at |
| 839 | (widen) | 985 | current context or a list of integers. The latter case is only |
| 840 | (save-excursion | 986 | happening for :at-dedenter-block-start context since the |
| 841 | (pcase context-status | 987 | possibilities can be narrowed to especific indentation points." |
| 842 | (`no-indent 0) | 988 | (save-restriction |
| 843 | (`after-comment | 989 | (widen) |
| 844 | (goto-char context-start) | 990 | (save-excursion |
| 845 | (current-indentation)) | 991 | (pcase (python-indent-context) |
| 846 | ;; When point is after beginning of block just add one level | 992 | (`(:no-indent . ,_) 0) |
| 847 | ;; of indentation relative to the context-start | 993 | (`(,(or :after-line |
| 848 | (`after-beginning-of-block | 994 | :after-comment |
| 849 | (goto-char context-start) | 995 | :inside-string |
| 850 | (+ (current-indentation) python-indent-offset)) | 996 | :after-backslash |
| 851 | ;; When after a simple line just use previous line | 997 | :inside-paren-at-closing-paren |
| 852 | ;; indentation. | 998 | :inside-paren-at-closing-nested-paren) . ,start) |
| 853 | (`after-line | 999 | ;; Copy previous indentation. |
| 854 | (let* ((pair (save-excursion | 1000 | (goto-char start) |
| 855 | (goto-char context-start) | 1001 | (current-indentation)) |
| 856 | (cons | 1002 | (`(,(or :after-block-start |
| 857 | (current-indentation) | 1003 | :after-backslash-first-line |
| 858 | (python-info-beginning-of-block-p)))) | 1004 | :inside-paren-newline-start) . ,start) |
| 859 | (context-indentation (car pair)) | 1005 | ;; Add one indentation level. |
| 860 | ;; TODO: Separate block enders into its own case. | 1006 | (goto-char start) |
| 861 | (adjustment | 1007 | (+ (current-indentation) python-indent-offset)) |
| 862 | (if (save-excursion | 1008 | (`(,(or :inside-paren |
| 863 | (python-util-forward-comment -1) | 1009 | :after-backslash-block-continuation |
| 864 | (python-nav-beginning-of-statement) | 1010 | :after-backslash-assignment-continuation |
| 865 | (looking-at (python-rx block-ender))) | 1011 | :after-backslash-dotted-continuation) . ,start) |
| 866 | python-indent-offset | 1012 | ;; Use the column given by the context. |
| 867 | 0))) | 1013 | (goto-char start) |
| 868 | (- context-indentation adjustment))) | 1014 | (current-column)) |
| 869 | ;; When point is on a dedenter statement, search for the | 1015 | (`(:after-block-end . ,start) |
| 870 | ;; opening block that corresponds to it and use its | 1016 | ;; Subtract one indentation level. |
| 871 | ;; indentation. If no opening block is found just remove | 1017 | (goto-char start) |
| 872 | ;; indentation as this is an invalid python file. | 1018 | (- (current-indentation) python-indent-offset)) |
| 873 | (`dedenter-statement | 1019 | (`(:at-dedenter-block-start . ,_) |
| 874 | (let ((block-start-point | 1020 | ;; List all possible indentation levels from opening blocks. |
| 875 | (python-info-dedenter-opening-block-position))) | 1021 | (let ((opening-block-start-points |
| 876 | (save-excursion | 1022 | (python-info-dedenter-opening-block-positions))) |
| 877 | (if (not block-start-point) | 1023 | (if (not opening-block-start-points) |
| 878 | 0 | 1024 | 0 ; if not found default to first column |
| 879 | (goto-char block-start-point) | 1025 | (mapcar (lambda (pos) |
| 880 | (current-indentation))))) | 1026 | (save-excursion |
| 881 | ;; When inside of a string, do nothing. just use the current | 1027 | (goto-char pos) |
| 882 | ;; indentation. XXX: perhaps it would be a good idea to | 1028 | (current-indentation))) |
| 883 | ;; invoke standard text indentation here | 1029 | opening-block-start-points)))) |
| 884 | (`inside-string 'noindent) | 1030 | (`(,(or :inside-paren-newline-start-from-block) . ,start) |
| 885 | ;; After backslash we have several possibilities. | 1031 | ;; Add two indentation levels to make the suite stand out. |
| 886 | (`after-backslash | 1032 | (goto-char start) |
| 887 | (cond | 1033 | (+ (current-indentation) (* python-indent-offset 2))))))) |
| 888 | ;; Check if current line is a dot continuation. For this | 1034 | |
| 889 | ;; the current line must start with a dot and previous | 1035 | (defun python-indent--calculate-levels (indentation) |
| 890 | ;; line must contain a dot too. | 1036 | "Calculate levels list given INDENTATION. |
| 891 | ((save-excursion | 1037 | Argument INDENTATION can either be an integer or a list of |
| 892 | (back-to-indentation) | 1038 | integers. Levels are returned in ascending order, and in the |
| 893 | (when (looking-at "\\.") | 1039 | case INDENTATION is a list, this order is enforced." |
| 894 | ;; If after moving one line back point is inside a paren it | 1040 | (if (listp indentation) |
| 895 | ;; needs to move back until it's not anymore | 1041 | (sort (copy-sequence indentation) #'<) |
| 896 | (while (prog2 | 1042 | (let* ((remainder (% indentation python-indent-offset)) |
| 897 | (forward-line -1) | 1043 | (steps (/ (- indentation remainder) python-indent-offset)) |
| 898 | (and (not (bobp)) | 1044 | (levels (mapcar (lambda (step) |
| 899 | (python-syntax-context 'paren)))) | 1045 | (* python-indent-offset step)) |
| 900 | (goto-char (line-end-position)) | 1046 | (number-sequence steps 0 -1)))) |
| 901 | (while (and (re-search-backward | 1047 | (reverse |
| 902 | "\\." (line-beginning-position) t) | 1048 | (if (not (zerop remainder)) |
| 903 | (python-syntax-context-type))) | 1049 | (cons indentation levels) |
| 904 | (if (and (looking-at "\\.") | 1050 | levels))))) |
| 905 | (not (python-syntax-context-type))) | 1051 | |
| 906 | ;; The indentation is the same column of the | 1052 | (defun python-indent--previous-level (levels indentation) |
| 907 | ;; first matching dot that's not inside a | 1053 | "Return previous level from LEVELS relative to INDENTATION." |
| 908 | ;; comment, a string or a paren | 1054 | (let* ((levels (sort (copy-sequence levels) #'>)) |
| 909 | (current-column) | 1055 | (default (car levels))) |
| 910 | ;; No dot found on previous line, just add another | 1056 | (catch 'return |
| 911 | ;; indentation level. | 1057 | (dolist (level levels) |
| 912 | (+ (current-indentation) python-indent-offset))))) | 1058 | (when (funcall #'< level indentation) |
| 913 | ;; Check if prev line is a block continuation | 1059 | (throw 'return level))) |
| 914 | ((let ((block-continuation-start | 1060 | default))) |
| 915 | (python-info-block-continuation-line-p))) | 1061 | |
| 916 | (when block-continuation-start | 1062 | (defun python-indent-calculate-indentation (&optional previous) |
| 917 | ;; If block-continuation-start is set jump to that | 1063 | "Calculate indentation. |
| 918 | ;; marker and use first column after the block start | 1064 | Get indentation of PREVIOUS level when argument is non-nil. |
| 919 | ;; as indentation value. | 1065 | Return the max level of the cycle when indentation reaches the |
| 920 | (goto-char block-continuation-start) | 1066 | minimum." |
| 921 | (re-search-forward | 1067 | (let* ((indentation (python-indent--calculate-indentation)) |
| 922 | (python-rx block-start (* space)) | 1068 | (levels (python-indent--calculate-levels indentation))) |
| 923 | (line-end-position) t) | 1069 | (if previous |
| 924 | (current-column)))) | 1070 | (python-indent--previous-level levels (current-indentation)) |
| 925 | ;; Check if current line is an assignment continuation | 1071 | (apply #'max levels)))) |
| 926 | ((let ((assignment-continuation-start | 1072 | |
| 927 | (python-info-assignment-continuation-line-p))) | 1073 | (defun python-indent-line (&optional previous) |
| 928 | (when assignment-continuation-start | ||
| 929 | ;; If assignment-continuation is set jump to that | ||
| 930 | ;; marker and use first column after the assignment | ||
| 931 | ;; operator as indentation value. | ||
| 932 | (goto-char assignment-continuation-start) | ||
| 933 | (current-column)))) | ||
| 934 | (t | ||
| 935 | (forward-line -1) | ||
| 936 | (goto-char (python-info-beginning-of-backslash)) | ||
| 937 | (if (save-excursion | ||
| 938 | (and | ||
| 939 | (forward-line -1) | ||
| 940 | (goto-char | ||
| 941 | (or (python-info-beginning-of-backslash) (point))) | ||
| 942 | (python-info-line-ends-backslash-p))) | ||
| 943 | ;; The two previous lines ended in a backslash so we must | ||
| 944 | ;; respect previous line indentation. | ||
| 945 | (current-indentation) | ||
| 946 | ;; What happens here is that we are dealing with the second | ||
| 947 | ;; line of a backslash continuation, in that case we just going | ||
| 948 | ;; to add one indentation level. | ||
| 949 | (+ (current-indentation) python-indent-offset))))) | ||
| 950 | ;; When inside a paren there's a need to handle nesting | ||
| 951 | ;; correctly | ||
| 952 | (`inside-paren | ||
| 953 | (cond | ||
| 954 | ;; If current line closes the outermost open paren use the | ||
| 955 | ;; current indentation of the context-start line. | ||
| 956 | ((save-excursion | ||
| 957 | (skip-syntax-forward "\s" (line-end-position)) | ||
| 958 | (when (and (looking-at (regexp-opt '(")" "]" "}"))) | ||
| 959 | (progn | ||
| 960 | (forward-char 1) | ||
| 961 | (not (python-syntax-context 'paren)))) | ||
| 962 | (goto-char context-start) | ||
| 963 | (current-indentation)))) | ||
| 964 | ;; If open paren is contained on a line by itself add another | ||
| 965 | ;; indentation level, else look for the first word after the | ||
| 966 | ;; opening paren and use it's column position as indentation | ||
| 967 | ;; level. | ||
| 968 | ((let* ((content-starts-in-newline) | ||
| 969 | (indent | ||
| 970 | (save-excursion | ||
| 971 | (if (setq content-starts-in-newline | ||
| 972 | (progn | ||
| 973 | (goto-char context-start) | ||
| 974 | (forward-char) | ||
| 975 | (save-restriction | ||
| 976 | (narrow-to-region | ||
| 977 | (line-beginning-position) | ||
| 978 | (line-end-position)) | ||
| 979 | (python-util-forward-comment)) | ||
| 980 | (looking-at "$"))) | ||
| 981 | (+ (current-indentation) python-indent-offset) | ||
| 982 | (current-column))))) | ||
| 983 | ;; Adjustments | ||
| 984 | (cond | ||
| 985 | ;; If current line closes a nested open paren de-indent one | ||
| 986 | ;; level. | ||
| 987 | ((progn | ||
| 988 | (back-to-indentation) | ||
| 989 | (looking-at (regexp-opt '(")" "]" "}")))) | ||
| 990 | (- indent python-indent-offset)) | ||
| 991 | ;; If the line of the opening paren that wraps the current | ||
| 992 | ;; line starts a block add another level of indentation to | ||
| 993 | ;; follow new pep8 recommendation. See: http://ur1.ca/5rojx | ||
| 994 | ((save-excursion | ||
| 995 | (when (and content-starts-in-newline | ||
| 996 | (progn | ||
| 997 | (goto-char context-start) | ||
| 998 | (back-to-indentation) | ||
| 999 | (looking-at (python-rx block-start)))) | ||
| 1000 | (+ indent python-indent-offset)))) | ||
| 1001 | (t indent))))))))))) | ||
| 1002 | |||
| 1003 | (defun python-indent-calculate-levels () | ||
| 1004 | "Calculate `python-indent-levels' and reset `python-indent-current-level'." | ||
| 1005 | (if (or (python-info-continuation-line-p) | ||
| 1006 | (not (python-info-dedenter-statement-p))) | ||
| 1007 | ;; XXX: This asks for a refactor. Even if point is on a | ||
| 1008 | ;; dedenter statement, it could be multiline and in that case | ||
| 1009 | ;; the continuation lines should be indented with normal rules. | ||
| 1010 | (let* ((indentation (python-indent-calculate-indentation))) | ||
| 1011 | (if (not (numberp indentation)) | ||
| 1012 | (setq python-indent-levels indentation) | ||
| 1013 | (let* ((remainder (% indentation python-indent-offset)) | ||
| 1014 | (steps (/ (- indentation remainder) python-indent-offset))) | ||
| 1015 | (setq python-indent-levels (list 0)) | ||
| 1016 | (dotimes (step steps) | ||
| 1017 | (push (* python-indent-offset (1+ step)) python-indent-levels)) | ||
| 1018 | (when (not (eq 0 remainder)) | ||
| 1019 | (push (+ (* python-indent-offset steps) remainder) | ||
| 1020 | python-indent-levels))))) | ||
| 1021 | (setq python-indent-levels | ||
| 1022 | (or | ||
| 1023 | (mapcar (lambda (pos) | ||
| 1024 | (save-excursion | ||
| 1025 | (goto-char pos) | ||
| 1026 | (current-indentation))) | ||
| 1027 | (python-info-dedenter-opening-block-positions)) | ||
| 1028 | (list 0)))) | ||
| 1029 | (when (listp python-indent-levels) | ||
| 1030 | (setq python-indent-current-level (1- (length python-indent-levels)) | ||
| 1031 | python-indent-levels (nreverse python-indent-levels)))) | ||
| 1032 | |||
| 1033 | (defun python-indent-toggle-levels () | ||
| 1034 | "Toggle `python-indent-current-level' over `python-indent-levels'." | ||
| 1035 | (setq python-indent-current-level (1- python-indent-current-level)) | ||
| 1036 | (when (< python-indent-current-level 0) | ||
| 1037 | (setq python-indent-current-level (1- (length python-indent-levels))))) | ||
| 1038 | |||
| 1039 | (defun python-indent-line (&optional force-toggle) | ||
| 1040 | "Internal implementation of `python-indent-line-function'. | 1074 | "Internal implementation of `python-indent-line-function'. |
| 1041 | Uses the offset calculated in | 1075 | Use the PREVIOUS level when argument is non-nil, otherwise indent |
| 1042 | `python-indent-calculate-indentation' and available levels | 1076 | to the maxium available level. When indentation is the minimum |
| 1043 | indicated by the variable `python-indent-levels' to set the | 1077 | possible and PREVIOUS is non-nil, cycle back to the maximum |
| 1044 | current indentation. | 1078 | level." |
| 1079 | (let ((follow-indentation-p | ||
| 1080 | ;; Check if point is within indentation. | ||
| 1081 | (and (<= (line-beginning-position) (point)) | ||
| 1082 | (>= (+ (line-beginning-position) | ||
| 1083 | (current-indentation)) | ||
| 1084 | (point))))) | ||
| 1085 | (save-excursion | ||
| 1086 | (indent-line-to | ||
| 1087 | (python-indent-calculate-indentation previous)) | ||
| 1088 | (python-info-dedenter-opening-block-message)) | ||
| 1089 | (when follow-indentation-p | ||
| 1090 | (back-to-indentation)))) | ||
| 1045 | 1091 | ||
| 1046 | When the variable `last-command' is equal to one of the symbols | 1092 | (defun python-indent-calculate-levels () |
| 1047 | inside `python-indent-trigger-commands' or FORCE-TOGGLE is | 1093 | "Return possible indentation levels." |
| 1048 | non-nil it cycles levels indicated in the variable | 1094 | (python-indent--calculate-levels |
| 1049 | `python-indent-levels' by setting the current level in the | 1095 | (python-indent--calculate-indentation))) |
| 1050 | variable `python-indent-current-level'. | ||
| 1051 | |||
| 1052 | When the variable `last-command' is not equal to one of the | ||
| 1053 | symbols inside `python-indent-trigger-commands' and FORCE-TOGGLE | ||
| 1054 | is nil it calculates possible indentation levels and saves them | ||
| 1055 | in the variable `python-indent-levels'. Afterwards it sets the | ||
| 1056 | variable `python-indent-current-level' correctly so offset is | ||
| 1057 | equal to | ||
| 1058 | (nth python-indent-current-level python-indent-levels)" | ||
| 1059 | (if (and (or (and (memq this-command python-indent-trigger-commands) | ||
| 1060 | (eq last-command this-command)) | ||
| 1061 | force-toggle) | ||
| 1062 | (not (equal python-indent-levels '(0)))) | ||
| 1063 | (if (listp python-indent-levels) | ||
| 1064 | (python-indent-toggle-levels)) | ||
| 1065 | (python-indent-calculate-levels)) | ||
| 1066 | (if (eq python-indent-levels 'noindent) | ||
| 1067 | python-indent-levels | ||
| 1068 | (let* ((starting-pos (point-marker)) | ||
| 1069 | (indent-ending-position | ||
| 1070 | (+ (line-beginning-position) (current-indentation))) | ||
| 1071 | (follow-indentation-p | ||
| 1072 | (or (bolp) | ||
| 1073 | (and (<= (line-beginning-position) starting-pos) | ||
| 1074 | (>= indent-ending-position starting-pos)))) | ||
| 1075 | (next-indent (nth python-indent-current-level python-indent-levels))) | ||
| 1076 | (unless (= next-indent (current-indentation)) | ||
| 1077 | (beginning-of-line) | ||
| 1078 | (delete-horizontal-space) | ||
| 1079 | (indent-to next-indent) | ||
| 1080 | (goto-char starting-pos)) | ||
| 1081 | (and follow-indentation-p (back-to-indentation))) | ||
| 1082 | (python-info-dedenter-opening-block-message))) | ||
| 1083 | 1096 | ||
| 1084 | (defun python-indent-line-function () | 1097 | (defun python-indent-line-function () |
| 1085 | "`indent-line-function' for Python mode. | 1098 | "`indent-line-function' for Python mode. |
| 1086 | See `python-indent-line' for details." | 1099 | When the variable `last-command' is equal to one of the symbols |
| 1087 | (python-indent-line)) | 1100 | inside `python-indent-trigger-commands' it cycles possible |
| 1101 | indentation levels from right to left." | ||
| 1102 | (python-indent-line | ||
| 1103 | (and (memq this-command python-indent-trigger-commands) | ||
| 1104 | (eq last-command this-command)))) | ||
| 1088 | 1105 | ||
| 1089 | (defun python-indent-dedent-line () | 1106 | (defun python-indent-dedent-line () |
| 1090 | "De-indent current line." | 1107 | "De-indent current line." |
| 1091 | (interactive "*") | 1108 | (interactive "*") |
| 1092 | (when (and (not (python-syntax-comment-or-string-p)) | 1109 | (when (and (not (bolp)) |
| 1093 | (<= (point) (save-excursion | 1110 | (not (python-syntax-comment-or-string-p)) |
| 1094 | (back-to-indentation) | 1111 | (= (+ (line-beginning-position) |
| 1095 | (point))) | 1112 | (current-indentation)) |
| 1096 | (> (current-column) 0)) | 1113 | (point))) |
| 1097 | (python-indent-line t) | 1114 | (python-indent-line t) |
| 1098 | t)) | 1115 | t)) |
| 1099 | 1116 | ||
| 1100 | (defun python-indent-dedent-line-backspace (arg) | 1117 | (defun python-indent-dedent-line-backspace (arg) |
| 1101 | "De-indent current line. | 1118 | "De-indent current line. |
| 1102 | Argument ARG is passed to `backward-delete-char-untabify' when | 1119 | Argument ARG is passed to `backward-delete-char-untabify' when |
| 1103 | point is not in between the indentation." | 1120 | point is not in between the indentation." |
| 1104 | (interactive "*p") | 1121 | (interactive "*p") |
| 1105 | (when (not (python-indent-dedent-line)) | 1122 | (unless (python-indent-dedent-line) |
| 1106 | (backward-delete-char-untabify arg))) | 1123 | (backward-delete-char-untabify arg))) |
| 1124 | |||
| 1107 | (put 'python-indent-dedent-line-backspace 'delete-selection 'supersede) | 1125 | (put 'python-indent-dedent-line-backspace 'delete-selection 'supersede) |
| 1108 | 1126 | ||
| 1109 | (defun python-indent-region (start end) | 1127 | (defun python-indent-region (start end) |