aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el156
1 files changed, 91 insertions, 65 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ffc6c1ac885..e99e6bda4b8 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -497,52 +497,68 @@ The type returned can be `comment', `string' or `paren'."
497 (1 font-lock-variable-name-face nil nil)))) 497 (1 font-lock-variable-name-face nil nil))))
498 498
499(defconst python-syntax-propertize-function 499(defconst python-syntax-propertize-function
500 ;; Make outer chars of matching triple-quote sequences into generic
501 ;; string delimiters. Fixme: Is there a better way?
502 ;; First avoid a sequence preceded by an odd number of backslashes.
503 (syntax-propertize-rules 500 (syntax-propertize-rules
504 (;; ¡Backrefs don't work in syntax-propertize-rules! 501 ((rx
505 (concat "\\(?:\\([RUru]\\)[Rr]?\\|^\\|[^\\]\\(?:\\\\.\\)*\\)" ;Prefix. 502 ;; Match even number of backslashes.
506 "\\(?:\\('\\)'\\('\\)\\|\\(?2:\"\\)\"\\(?3:\"\\)\\)") 503 (or (not (any ?\\ ?\' ?\")) point) (* ?\\ ?\\)
507 (3 (ignore (python-quote-syntax)))))) 504 ;; Match single or triple quotes of any kind.
508 505 (group (or "\"" "\"\"\"" "'" "'''")))
509(defun python-quote-syntax () 506 (1 (ignore (python-syntax-stringify))))
510 "Put `syntax-table' property correctly on triple quote. 507 ((rx
511Used for syntactic keywords. N is the match number (1, 2 or 3)." 508 ;; Match odd number of backslashes.
512 ;; Given a triple quote, we have to check the context to know 509 (or (not (any ?\\)) point) ?\\ (* ?\\ ?\\)
513 ;; whether this is an opening or closing triple or whether it's 510 ;; Followed by even number of equal quotes.
514 ;; quoted anyhow, and should be ignored. (For that we need to do 511 (group (or "\"\"" "\"\"\"\"" "''" "''''")))
515 ;; the same job as `syntax-ppss' to be correct and it seems to be OK 512 (1 (ignore (python-syntax-stringify))))))
516 ;; to use it here despite initial worries.) We also have to sort 513
517 ;; out a possible prefix -- well, we don't _have_ to, but I think it 514(defsubst python-syntax-count-quotes (quote-char &optional point limit)
518 ;; should be treated as part of the string. 515 "Count number of quotes around point (max is 3).
519 516QUOTE-CHAR is the quote char to count. Optional argument POINT is
520 ;; Test cases: 517the point where scan starts (defaults to current point) and LIMIT
521 ;; ur"""ar""" x='"' # """ 518is used to limit the scan."
522 ;; x = ''' """ ' a 519 (let ((i 0))
523 ;; ''' 520 (while (and (< i 3)
524 ;; x '"""' x """ \"""" x 521 (or (not limit) (< (+ point i) limit))
525 (save-excursion 522 (eq (char-after (+ point i)) quote-char))
526 (goto-char (match-beginning 0)) 523 (incf i))
527 (let ((syntax (save-match-data (syntax-ppss)))) 524 i))
528 (cond 525
529 ((eq t (nth 3 syntax)) ; after unclosed fence 526(defun python-syntax-stringify ()
530 ;; Consider property for the last char if in a fenced string. 527 "Put `syntax-table' property correctly on single/triple quotes."
531 (goto-char (nth 8 syntax)) ; fence position 528 (let* ((num-quotes
532 (skip-chars-forward "uUrR") ; skip any prefix 529 (let ((n (length (match-string-no-properties 1))))
533 ;; Is it a matching sequence? 530 ;; This corrects the quote count when matching odd number
534 (if (eq (char-after) (char-after (match-beginning 2))) 531 ;; of backslashes followed by even number of quotes.
535 (put-text-property (match-beginning 3) (match-end 3) 532 (or (and (= 1 (logand n 1)) n) (1- n))))
536 'syntax-table (string-to-syntax "|")))) 533 (ppss (prog2
537 ((match-end 1) 534 (backward-char num-quotes)
538 ;; Consider property for initial char, accounting for prefixes. 535 (syntax-ppss)
539 (put-text-property (match-beginning 1) (match-end 1) 536 (forward-char num-quotes)))
540 'syntax-table (string-to-syntax "|"))) 537 (string-start (and (not (nth 4 ppss)) (nth 8 ppss)))
541 (t 538 (quote-starting-pos (- (point) num-quotes))
542 ;; Consider property for initial char, accounting for prefixes. 539 (quote-ending-pos (point))
543 (put-text-property (match-beginning 2) (match-end 2) 540 (num-closing-quotes
544 'syntax-table (string-to-syntax "|")))) 541 (and string-start
545 ))) 542 (python-syntax-count-quotes
543 (char-before) string-start quote-starting-pos))))
544 (cond ((and string-start (= num-closing-quotes 0))
545 ;; This set of quotes doesn't match the string starting
546 ;; kind. Do nothing.
547 nil)
548 ((not string-start)
549 ;; This set of quotes delimit the start of a string.
550 (put-text-property quote-starting-pos (1+ quote-starting-pos)
551 'syntax-table (string-to-syntax "|")))
552 ((= num-quotes num-closing-quotes)
553 ;; This set of quotes delimit the end of a string.
554 (put-text-property (1- quote-ending-pos) quote-ending-pos
555 'syntax-table (string-to-syntax "|")))
556 ((> num-quotes num-closing-quotes)
557 ;; This may only happen whenever a triple quote is closing
558 ;; a single quoted string. Add string delimiter syntax to
559 ;; all three quotes.
560 (put-text-property quote-starting-pos quote-ending-pos
561 'syntax-table (string-to-syntax "|"))))))
546 562
547(defvar python-mode-syntax-table 563(defvar python-mode-syntax-table
548 (let ((table (make-syntax-table))) 564 (let ((table (make-syntax-table)))
@@ -897,16 +913,27 @@ possible indentation levels and saves it in the variable
897`python-indent-levels'. Afterwards it sets the variable 913`python-indent-levels'. Afterwards it sets the variable
898`python-indent-current-level' correctly so offset is equal 914`python-indent-current-level' correctly so offset is equal
899to (`nth' `python-indent-current-level' `python-indent-levels')" 915to (`nth' `python-indent-current-level' `python-indent-levels')"
900 (if (or (and (eq this-command 'indent-for-tab-command) 916 (or
901 (eq last-command this-command)) 917 (and (or (and (eq this-command 'indent-for-tab-command)
902 force-toggle) 918 (eq last-command this-command))
903 (if (not (equal python-indent-levels '(0))) 919 force-toggle)
904 (python-indent-toggle-levels) 920 (not (equal python-indent-levels '(0)))
905 (python-indent-calculate-levels)) 921 (or (python-indent-toggle-levels) t))
906 (python-indent-calculate-levels)) 922 (python-indent-calculate-levels))
907 (beginning-of-line) 923 (let* ((starting-pos (point-marker))
908 (delete-horizontal-space) 924 (indent-ending-position
909 (indent-to (nth python-indent-current-level python-indent-levels)) 925 (+ (line-beginning-position) (current-indentation)))
926 (follow-indentation-p
927 (or (bolp)
928 (and (<= (line-beginning-position) starting-pos)
929 (>= indent-ending-position starting-pos))))
930 (next-indent (nth python-indent-current-level python-indent-levels)))
931 (unless (= next-indent (current-indentation))
932 (beginning-of-line)
933 (delete-horizontal-space)
934 (indent-to next-indent)
935 (goto-char starting-pos))
936 (and follow-indentation-p (back-to-indentation)))
910 (python-info-closing-block-message)) 937 (python-info-closing-block-message))
911 938
912(defun python-indent-line-function () 939(defun python-indent-line-function ()
@@ -1892,19 +1919,18 @@ Returns the output. See `python-shell-send-string-no-output'."
1892 1919
1893(defun python-shell-send-buffer (&optional arg) 1920(defun python-shell-send-buffer (&optional arg)
1894 "Send the entire buffer to inferior Python process. 1921 "Send the entire buffer to inferior Python process.
1895 1922With prefix ARG allow execution of code inside blocks delimited
1896With prefix ARG include lines surrounded by \"if __name__ == '__main__':\"" 1923by \"if __name__== '__main__':\""
1897 (interactive "P") 1924 (interactive "P")
1898 (save-restriction 1925 (save-restriction
1899 (widen) 1926 (widen)
1900 (python-shell-send-region 1927 (let ((str (buffer-substring (point-min) (point-max))))
1901 (point-min) 1928 (and
1902 (or (and 1929 (not arg)
1903 (not arg) 1930 (setq str (replace-regexp-in-string
1904 (save-excursion 1931 (python-rx if-name-main)
1905 (re-search-forward (python-rx if-name-main) nil t)) 1932 "if __name__ == '__main__ ':" str)))
1906 (match-beginning 0)) 1933 (python-shell-send-string str))))
1907 (point-max)))))
1908 1934
1909(defun python-shell-send-defun (arg) 1935(defun python-shell-send-defun (arg)
1910 "Send the current defun to inferior Python process. 1936 "Send the current defun to inferior Python process.