diff options
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r-- | lisp/progmodes/python.el | 281 |
1 files changed, 166 insertions, 115 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 8e7d9f23b0e..14b65669c4b 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -4,7 +4,7 @@ ;; Author: Fabián E. Gallina <fgallina@gnu.org> ;; URL: https://github.com/fgallina/python.el -;; Version: 0.25.2 +;; Version: 0.26.1 ;; Package-Requires: ((emacs "24.1") (cl-lib "1.0")) ;; Maintainer: emacs-devel@gnu.org ;; Created: Jul 2010 @@ -287,9 +287,20 @@ ;;; 24.x Compat -(unless (fboundp 'prog-first-column) - (defun prog-first-column () - 0)) +(eval-and-compile + (unless (fboundp 'prog-first-column) + (defun prog-first-column () + 0)) + (unless (fboundp 'file-local-name) + (defun file-local-name (file) + "Return the local name component of FILE. +It returns a file name which can be used directly as argument of +`process-file', `start-file-process', or `shell-command'." + (or (file-remote-p file 'localname) file)))) + +;; In Emacs 24.3 and earlier, `define-derived-mode' does not define +;; the hook variable, it only puts documentation on the symbol. +(defvar inferior-python-mode-hook) ;;; Bindings @@ -331,7 +342,7 @@ (substitute-key-definition 'complete-symbol 'completion-at-point map global-map) (easy-menu-define python-menu map "Python Mode menu" - `("Python" + '("Python" :help "Python-specific Features" ["Shift region left" python-indent-shift-left :active mark-active :help "Shift region left by a single indentation step"] @@ -427,7 +438,7 @@ (* ?\\ ?\\) (any ?\' ?\"))) (* ?\\ ?\\) ;; Match single or triple quotes of any kind. - (group (or "\"" "\"\"\"" "'" "'''"))))) + (group (or "\"\"\"" "\"" "'''" "'"))))) (coding-cookie . ,(rx line-start ?# (* space) (or ;; # coding=<encoding name> @@ -458,13 +469,13 @@ This variant of `rx' supports common Python named REGEXPS." (eval-and-compile (defun python-syntax--context-compiler-macro (form type &optional syntax-ppss) (pcase type - (`'comment + (''comment `(let ((ppss (or ,syntax-ppss (syntax-ppss)))) (and (nth 4 ppss) (nth 8 ppss)))) - (`'string + (''string `(let ((ppss (or ,syntax-ppss (syntax-ppss)))) (and (nth 3 ppss) (nth 8 ppss)))) - (`'paren + (''paren `(nth 1 (or ,syntax-ppss (syntax-ppss)))) (_ form)))) @@ -475,9 +486,9 @@ character address of the specified TYPE." (declare (compiler-macro python-syntax--context-compiler-macro)) (let ((ppss (or syntax-ppss (syntax-ppss)))) (pcase type - (`comment (and (nth 4 ppss) (nth 8 ppss))) - (`string (and (nth 3 ppss) (nth 8 ppss))) - (`paren (nth 1 ppss)) + ('comment (and (nth 4 ppss) (nth 8 ppss))) + ('string (and (nth 3 ppss) (nth 8 ppss))) + ('paren (nth 1 ppss)) (_ nil)))) (defun python-syntax-context-type (&optional syntax-ppss) @@ -515,9 +526,19 @@ The type returned can be `comment', `string' or `paren'." font-lock-string-face) font-lock-comment-face)) -(defvar python-font-lock-keywords - ;; Keywords - `(,(rx symbol-start +(defvar python-font-lock-keywords-level-1 + `((,(rx symbol-start "def" (1+ space) (group (1+ (or word ?_)))) + (1 font-lock-function-name-face)) + (,(rx symbol-start "class" (1+ space) (group (1+ (or word ?_)))) + (1 font-lock-type-face))) + "Font lock keywords to use in python-mode for level 1 decoration. + +This is the minimum decoration level, including function and +class declarations.") + +(defvar python-font-lock-keywords-level-2 + `(,@python-font-lock-keywords-level-1 + ,(rx symbol-start (or "and" "del" "from" "not" "while" "as" "elif" "global" "or" "with" "assert" "else" "if" "pass" "yield" "break" "except" "import" "class" @@ -537,12 +558,35 @@ The type returned can be `comment', `string' or `paren'." ;; Extra: "self") symbol-end) - ;; functions - (,(rx symbol-start "def" (1+ space) (group (1+ (or word ?_)))) - (1 font-lock-function-name-face)) - ;; classes - (,(rx symbol-start "class" (1+ space) (group (1+ (or word ?_)))) - (1 font-lock-type-face)) + ;; Builtins + (,(rx symbol-start + (or + "abs" "all" "any" "bin" "bool" "callable" "chr" "classmethod" + "compile" "complex" "delattr" "dict" "dir" "divmod" "enumerate" + "eval" "filter" "float" "format" "frozenset" "getattr" "globals" + "hasattr" "hash" "help" "hex" "id" "input" "int" "isinstance" + "issubclass" "iter" "len" "list" "locals" "map" "max" "memoryview" + "min" "next" "object" "oct" "open" "ord" "pow" "print" "property" + "range" "repr" "reversed" "round" "set" "setattr" "slice" "sorted" + "staticmethod" "str" "sum" "super" "tuple" "type" "vars" "zip" + "__import__" + ;; Python 2: + "basestring" "cmp" "execfile" "file" "long" "raw_input" "reduce" + "reload" "unichr" "unicode" "xrange" "apply" "buffer" "coerce" + "intern" + ;; Python 3: + "ascii" "breakpoint" "bytearray" "bytes" "exec" + ;; Extra: + "__all__" "__doc__" "__name__" "__package__") + symbol-end) . font-lock-builtin-face)) + "Font lock keywords to use in python-mode for level 2 decoration. + +This is the medium decoration level, including everything in +`python-font-lock-keywords-level-1', as well as keywords and +builtins.") + +(defvar python-font-lock-keywords-maximum-decoration + `(,@python-font-lock-keywords-level-2 ;; Constants (,(rx symbol-start (or @@ -585,27 +629,6 @@ The type returned can be `comment', `string' or `paren'." "VMSError" "WindowsError" ) symbol-end) . font-lock-type-face) - ;; Builtins - (,(rx symbol-start - (or - "abs" "all" "any" "bin" "bool" "callable" "chr" "classmethod" - "compile" "complex" "delattr" "dict" "dir" "divmod" "enumerate" - "eval" "filter" "float" "format" "frozenset" "getattr" "globals" - "hasattr" "hash" "help" "hex" "id" "input" "int" "isinstance" - "issubclass" "iter" "len" "list" "locals" "map" "max" "memoryview" - "min" "next" "object" "oct" "open" "ord" "pow" "print" "property" - "range" "repr" "reversed" "round" "set" "setattr" "slice" "sorted" - "staticmethod" "str" "sum" "super" "tuple" "type" "vars" "zip" - "__import__" - ;; Python 2: - "basestring" "cmp" "execfile" "file" "long" "raw_input" "reduce" - "reload" "unichr" "unicode" "xrange" "apply" "buffer" "coerce" - "intern" - ;; Python 3: - "ascii" "bytearray" "bytes" "exec" - ;; Extra: - "__all__" "__doc__" "__name__" "__package__") - symbol-end) . font-lock-builtin-face) ;; assignments ;; support for a = b = c = 5 (,(lambda (limit) @@ -629,22 +652,41 @@ The type returned can be `comment', `string' or `paren'." (goto-char (match-end 1)) (python-syntax-context 'paren))) res)) - (1 font-lock-variable-name-face nil nil)))) + (1 font-lock-variable-name-face nil nil))) + "Font lock keywords to use in python-mode for maximum decoration. + +This decoration level includes everything in +`python-font-lock-keywords-level-2', as well as constants, +decorators, exceptions, and assignments.") + +(defvar python-font-lock-keywords + '(python-font-lock-keywords-level-1 ; When `font-lock-maximum-decoration' is nil. + python-font-lock-keywords-level-1 ; When `font-lock-maximum-decoration' is 1. + python-font-lock-keywords-level-2 ; When `font-lock-maximum-decoration' is 2. + python-font-lock-keywords-maximum-decoration ; When `font-lock-maximum-decoration' + ; is more than 1, or t (which it is, + ; by default). + ) + "List of font lock keyword specifications to use in python-mode. + +Which one will be chosen depends on the value of +`font-lock-maximum-decoration'.") + (defconst python-syntax-propertize-function (syntax-propertize-rules - ((python-rx string-delimiter) + ((rx (or "\"\"\"" "'''")) (0 (ignore (python-syntax-stringify)))))) +(define-obsolete-variable-alias 'python--prettify-symbols-alist + 'python-prettify-symbols-alist "26.1") + (defvar python-prettify-symbols-alist '(("lambda" . ?λ) ("and" . ?∧) ("or" . ?∨)) "Value for `prettify-symbols-alist' in `python-mode'.") -(define-obsolete-variable-alias 'python--prettify-symbols-alist - 'python-prettify-symbols-alist "26.1") - (defsubst python-syntax-count-quotes (quote-char &optional point limit) "Count number of quotes around point (max is 3). QUOTE-CHAR is the quote char to count. Optional argument POINT is @@ -659,35 +701,27 @@ is used to limit the scan." (defun python-syntax-stringify () "Put `syntax-table' property correctly on single/triple quotes." - (let* ((num-quotes (length (match-string-no-properties 1))) - (ppss (prog2 - (backward-char num-quotes) - (syntax-ppss) - (forward-char num-quotes))) - (string-start (and (not (nth 4 ppss)) (nth 8 ppss))) - (quote-starting-pos (- (point) num-quotes)) - (quote-ending-pos (point)) - (num-closing-quotes - (and string-start - (python-syntax-count-quotes - (char-before) string-start quote-starting-pos)))) - (cond ((and string-start (= num-closing-quotes 0)) - ;; This set of quotes doesn't match the string starting - ;; kind. Do nothing. + (let* ((ppss (save-excursion (backward-char 3) (syntax-ppss))) + (string-start (and (eq t (nth 3 ppss)) (nth 8 ppss))) + (quote-starting-pos (- (point) 3)) + (quote-ending-pos (point))) + (cond ((or (nth 4 ppss) ;Inside a comment + (and string-start + ;; Inside of a string quoted with different triple quotes. + (not (eql (char-after string-start) + (char-after quote-starting-pos))))) + ;; Do nothing. nil) - ((not string-start) + ((nth 5 ppss) + ;; The first quote is escaped, so it's not part of a triple quote! + (goto-char (1+ quote-starting-pos))) + ((null string-start) ;; This set of quotes delimit the start of a string. (put-text-property quote-starting-pos (1+ quote-starting-pos) 'syntax-table (string-to-syntax "|"))) - ((= num-quotes num-closing-quotes) + (t ;; This set of quotes delimit the end of a string. (put-text-property (1- quote-ending-pos) quote-ending-pos - 'syntax-table (string-to-syntax "|"))) - ((> num-quotes num-closing-quotes) - ;; This may only happen whenever a triple quote is closing - ;; a single quoted string. Add string delimiter syntax to - ;; all three quotes. - (put-text-property quote-starting-pos quote-ending-pos 'syntax-table (string-to-syntax "|")))))) (defvar python-mode-syntax-table @@ -1036,12 +1070,18 @@ possibilities can be narrowed to specific indentation points." (`(,(or :after-line :after-comment :inside-string - :after-backslash - :inside-paren-at-closing-paren - :inside-paren-at-closing-nested-paren) . ,start) + :after-backslash) . ,start) ;; Copy previous indentation. (goto-char start) (current-indentation)) + (`(,(or :inside-paren-at-closing-paren + :inside-paren-at-closing-nested-paren) . ,start) + (goto-char (+ 1 start)) + (if (looking-at "[ \t]*\\(?:#\\|$\\)") + ;; Copy previous indentation. + (current-indentation) + ;; Align with opening paren. + (current-column))) (`(:inside-docstring . ,start) (let* ((line-indentation (current-indentation)) (base-indent (progn @@ -1292,16 +1332,17 @@ the line will be re-indented automatically if needed." (not (equal ?: (char-before (1- (point))))) (not (python-syntax-comment-or-string-p))) ;; Just re-indent dedenters - (let ((dedenter-pos (python-info-dedenter-statement-p)) - (current-pos (point))) + (let ((dedenter-pos (python-info-dedenter-statement-p))) (when dedenter-pos - (save-excursion - (goto-char dedenter-pos) - (python-indent-line) - (unless (= (line-number-at-pos dedenter-pos) - (line-number-at-pos current-pos)) - ;; Reindent region if this is a multiline statement - (python-indent-region dedenter-pos current-pos))))))))) + (let ((start (copy-marker dedenter-pos)) + (end (point-marker))) + (save-excursion + (goto-char start) + (python-indent-line) + (unless (= (line-number-at-pos start) + (line-number-at-pos end)) + ;; Reindent region if this is a multiline statement + (python-indent-region start end)))))))))) ;;; Mark @@ -1474,7 +1515,7 @@ nested definitions." (defun python-nav-beginning-of-statement () "Move to start of current statement." (interactive "^") - (back-to-indentation) + (forward-line 0) (let* ((ppss (syntax-ppss)) (context-point (or @@ -1489,6 +1530,7 @@ nested definitions." (python-info-line-ends-backslash-p)) (forward-line -1) (python-nav-beginning-of-statement)))) + (back-to-indentation) (point-marker)) (defun python-nav-end-of-statement (&optional noend) @@ -1506,9 +1548,10 @@ of the statement." ;; are somehow out of whack. This has been ;; observed when using `syntax-ppss' during ;; narrowing. - (cl-assert (> string-start last-string-end) + (cl-assert (>= string-start last-string-end) :show-args - "Overlapping strings detected") + "\ +Overlapping strings detected (start=%d, last-end=%d)") (goto-char string-start) (if (python-syntax-context 'paren) ;; Ended up inside a paren, roll again. @@ -1966,7 +2009,7 @@ position, else returns nil." It should not contain a caret (^) at the beginning." :type 'string) -(defcustom python-shell-prompt-block-regexp "\\.\\.\\. " +(defcustom python-shell-prompt-block-regexp "\\.\\.\\.:? " "Regular expression matching block input prompt of Python shell. It should not contain a caret (^) at the beginning." :type 'string) @@ -2147,7 +2190,7 @@ of `exec-path'." (defun python-shell-tramp-refresh-process-environment (vec env) "Update VEC's process environment with ENV." ;; Stolen from `tramp-open-connection-setup-interactive-shell'. - (let ((env (append (when (fboundp #'tramp-get-remote-locale) + (let ((env (append (when (fboundp 'tramp-get-remote-locale) ;; Emacs<24.4 compat. (list (tramp-get-remote-locale vec))) (copy-sequence env))) @@ -2830,10 +2873,12 @@ process buffer for a list of commands.)" (y-or-n-p "Make dedicated process? ") (= (prefix-numeric-value current-prefix-arg) 4)) (list (python-shell-calculate-command) nil t))) - (get-buffer-process - (python-shell-make-comint - (or cmd (python-shell-calculate-command)) - (python-shell-get-process-name dedicated) show))) + (let ((buffer + (python-shell-make-comint + (or cmd (python-shell-calculate-command)) + (python-shell-get-process-name dedicated) show))) + (pop-to-buffer buffer) + (get-buffer-process buffer))) (defun run-python-internal () "Run an inferior Internal Python process. @@ -2911,11 +2956,17 @@ be asked for their values." "Instead call `python-shell-get-process' and create one if returns nil." "25.1") +(define-obsolete-variable-alias + 'python-buffer 'python-shell-internal-buffer "24.3") + (defvar python-shell-internal-buffer nil "Current internal shell buffer for the current buffer. This is really not necessary at all for the code to work but it's there for compatibility with CEDET.") +(define-obsolete-variable-alias + 'python-preoutput-result 'python-shell-internal-last-output "24.3") + (defvar python-shell-internal-last-output nil "Last output captured by the internal shell. This is really not necessary at all for the code to work but it's @@ -2931,12 +2982,6 @@ there for compatibility with CEDET.") (define-obsolete-function-alias 'python-proc 'python-shell-internal-get-or-create-process "24.3") -(define-obsolete-variable-alias - 'python-buffer 'python-shell-internal-buffer "24.3") - -(define-obsolete-variable-alias - 'python-preoutput-result 'python-shell-internal-last-output "24.3") - (defun python-shell--save-temp-file (string) (let* ((temporary-file-directory (if (file-remote-p default-directory) @@ -3151,9 +3196,12 @@ t when called interactively." (beginning-of-line 1)) (> (current-indentation) 0))) (when (not arg) - (while (and (forward-line -1) - (looking-at (python-rx decorator)))) - (forward-line 1)) + (while (and + (eq (forward-line -1) 0) + (if (looking-at (python-rx decorator)) + t + (forward-line 1) + nil)))) (point-marker)) (progn (or (python-nav-end-of-defun) @@ -3184,10 +3232,10 @@ t when called interactively." (insert-file-contents (or temp-file-name file-name)) (python-info-encoding))) - (file-name (expand-file-name (file-local-name file-name))) + (file-name (file-local-name (expand-file-name file-name))) (temp-file-name (when temp-file-name - (expand-file-name - (file-local-name temp-file-name))))) + (file-local-name (expand-file-name + temp-file-name))))) (python-shell-send-string (format (concat @@ -3967,11 +4015,11 @@ JUSTIFY should be used (if applicable) as in `fill-paragraph'." ;; is NIL means to not add any newlines for start or end ;; of docstring. See `python-fill-docstring-style' for a ;; graphic idea of each style. - (`django (cons 1 1)) - (`onetwo (and multi-line-p (cons 1 2))) - (`pep-257 (and multi-line-p (cons nil 2))) - (`pep-257-nn (and multi-line-p (cons nil 1))) - (`symmetric (and multi-line-p (cons 1 1))))) + ('django (cons 1 1)) + ('onetwo (and multi-line-p (cons 1 2))) + ('pep-257 (and multi-line-p (cons nil 2))) + ('pep-257-nn (and multi-line-p (cons nil 1))) + ('symmetric (and multi-line-p (cons 1 1))))) (fill-paragraph-function)) (save-restriction (narrow-to-region str-start-pos str-end-pos) @@ -5192,9 +5240,10 @@ be used." (defcustom python-flymake-msg-alist '(("\\(^redefinition\\|.*unused.*\\|used$\\)" . :warning)) "Alist used to associate messages to their types. -Each element should be a cons-cell (REGEXP . TYPE), where TYPE must be -one defined in the variable `flymake-diagnostic-types-alist'. -For example, when using `flake8' a possible configuration could be: +Each element should be a cons-cell (REGEXP . TYPE), where TYPE +should be a diagnostic type symbol like `:error', `:warning' or +`:note'. For example, when using `flake8' a possible +configuration could be: ((\"\\(^redefinition\\|.*unused.*\\|used$\\)\" . :warning) (\"^E999\" . :error) @@ -5203,7 +5252,7 @@ For example, when using `flake8' a possible configuration could be: By default messages are considered errors." :version "26.1" :group 'python-flymake - :type `(alist :key-type (regexp) + :type '(alist :key-type (regexp) :value-type (symbol))) (defvar-local python--flymake-proc nil) @@ -5287,6 +5336,7 @@ REPORT-FN is Flymake's callback function." (save-excursion (insert (make-string 2 last-command-event))))) (defvar electric-indent-inhibit) +(defvar prettify-symbols-alist) ;;;###autoload (define-derived-mode python-mode prog-mode "Python" @@ -5306,7 +5356,7 @@ REPORT-FN is Flymake's callback function." 'python-nav-forward-sexp) (set (make-local-variable 'font-lock-defaults) - '(python-font-lock-keywords + `(,python-font-lock-keywords nil nil nil nil (font-lock-syntactic-face-function . python-font-lock-syntactic-face-function))) @@ -5329,6 +5379,7 @@ REPORT-FN is Flymake's callback function." (set (make-local-variable 'paragraph-start) "\\s-*$") (set (make-local-variable 'fill-paragraph-function) #'python-fill-paragraph) + (set (make-local-variable 'fill-indent-according-to-mode) t) ; Bug#36056. (set (make-local-variable 'beginning-of-defun-function) #'python-nav-beginning-of-defun) @@ -5364,7 +5415,7 @@ REPORT-FN is Flymake's callback function." (add-to-list 'hs-special-modes-alist - `(python-mode + '(python-mode "\\s-*\\_<\\(?:def\\|class\\)\\_>" ;; Use the empty string as end regexp so it doesn't default to ;; "\\s)". This way parens at end of defun are properly hidden. @@ -5382,7 +5433,7 @@ REPORT-FN is Flymake's callback function." (1+ (/ (current-indentation) python-indent-offset)))) (set (make-local-variable 'prettify-symbols-alist) - python--prettify-symbols-alist) + python-prettify-symbols-alist) (python-skeleton-add-menu-items) |