diff options
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 288 |
1 files changed, 165 insertions, 123 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index d340550a017..303c36c3932 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -1068,7 +1068,9 @@ minimum." | |||
| 1068 | (levels (python-indent--calculate-levels indentation))) | 1068 | (levels (python-indent--calculate-levels indentation))) |
| 1069 | (if previous | 1069 | (if previous |
| 1070 | (python-indent--previous-level levels (current-indentation)) | 1070 | (python-indent--previous-level levels (current-indentation)) |
| 1071 | (apply #'max levels)))) | 1071 | (if levels |
| 1072 | (apply #'max levels) | ||
| 1073 | 0)))) | ||
| 1072 | 1074 | ||
| 1073 | (defun python-indent-line (&optional previous) | 1075 | (defun python-indent-line (&optional previous) |
| 1074 | "Internal implementation of `python-indent-line-function'. | 1076 | "Internal implementation of `python-indent-line-function'. |
| @@ -2331,57 +2333,57 @@ goes wrong and syntax highlighting in the shell gets messed up." | |||
| 2331 | (interactive) | 2333 | (interactive) |
| 2332 | (python-shell-with-shell-buffer | 2334 | (python-shell-with-shell-buffer |
| 2333 | (python-shell-font-lock-with-font-lock-buffer | 2335 | (python-shell-font-lock-with-font-lock-buffer |
| 2334 | (delete-region (point-min) (point-max))))) | 2336 | (erase-buffer)))) |
| 2335 | 2337 | ||
| 2336 | (defun python-shell-font-lock-comint-output-filter-function (output) | 2338 | (defun python-shell-font-lock-comint-output-filter-function (output) |
| 2337 | "Clean up the font-lock buffer after any OUTPUT." | 2339 | "Clean up the font-lock buffer after any OUTPUT." |
| 2338 | (when (and (not (string= "" output)) | 2340 | (if (and (not (string= "" output)) |
| 2339 | ;; Is end of output and is not just a prompt. | 2341 | ;; Is end of output and is not just a prompt. |
| 2340 | (not (member | 2342 | (not (member |
| 2341 | (python-shell-comint-end-of-output-p | 2343 | (python-shell-comint-end-of-output-p |
| 2342 | (ansi-color-filter-apply output)) | 2344 | (ansi-color-filter-apply output)) |
| 2343 | '(nil 0)))) | 2345 | '(nil 0)))) |
| 2344 | ;; If output is other than an input prompt then "real" output has | 2346 | ;; If output is other than an input prompt then "real" output has |
| 2345 | ;; been received and the font-lock buffer must be cleaned up. | 2347 | ;; been received and the font-lock buffer must be cleaned up. |
| 2346 | (python-shell-font-lock-cleanup-buffer)) | 2348 | (python-shell-font-lock-cleanup-buffer) |
| 2349 | ;; Otherwise just add a newline. | ||
| 2350 | (python-shell-font-lock-with-font-lock-buffer | ||
| 2351 | (goto-char (point-max)) | ||
| 2352 | (newline))) | ||
| 2347 | output) | 2353 | output) |
| 2348 | 2354 | ||
| 2349 | (defun python-shell-font-lock-post-command-hook () | 2355 | (defun python-shell-font-lock-post-command-hook () |
| 2350 | "Fontifies current line in shell buffer." | 2356 | "Fontifies current line in shell buffer." |
| 2351 | (if (eq this-command 'comint-send-input) | 2357 | (when (and (python-util-comint-last-prompt) |
| 2352 | ;; Add a newline when user sends input as this may be a block. | 2358 | (> (point) (cdr (python-util-comint-last-prompt)))) |
| 2353 | (python-shell-font-lock-with-font-lock-buffer | 2359 | (let ((input (buffer-substring-no-properties |
| 2354 | (goto-char (line-end-position)) | 2360 | (cdr (python-util-comint-last-prompt)) (point-max))) |
| 2355 | (newline)) | 2361 | (pos (point)) |
| 2356 | (when (and (python-util-comint-last-prompt) | 2362 | (buffer-undo-list t) |
| 2357 | (> (point) (cdr (python-util-comint-last-prompt)))) | 2363 | (font-lock-buffer-pos nil)) |
| 2358 | (let ((input (buffer-substring-no-properties | 2364 | ;; Keep all markers untouched, this prevents `hippie-expand' and |
| 2359 | (cdr (python-util-comint-last-prompt)) (point-max))) | 2365 | ;; others from getting confused. Bug#19650. |
| 2360 | (old-input (python-shell-font-lock-with-font-lock-buffer | 2366 | (insert-before-markers |
| 2361 | (buffer-substring-no-properties | 2367 | (python-shell-font-lock-with-font-lock-buffer |
| 2362 | (line-beginning-position) (point-max)))) | 2368 | (delete-region (line-beginning-position) |
| 2363 | (current-point (point)) | 2369 | (point-max)) |
| 2364 | (buffer-undo-list t)) | 2370 | (setq font-lock-buffer-pos (point)) |
| 2365 | ;; When input hasn't changed, do nothing. | 2371 | (insert input) |
| 2366 | (when (not (string= input old-input)) | 2372 | ;; Ensure buffer is fontified, keeping it |
| 2367 | (delete-region (cdr (python-util-comint-last-prompt)) (point-max)) | 2373 | ;; compatible with Emacs < 24.4. |
| 2368 | (insert | 2374 | (if (fboundp 'font-lock-ensure) |
| 2369 | (python-shell-font-lock-with-font-lock-buffer | 2375 | (funcall 'font-lock-ensure) |
| 2370 | (delete-region (line-beginning-position) | 2376 | (font-lock-default-fontify-buffer)) |
| 2371 | (line-end-position)) | 2377 | ;; Replace FACE text properties with FONT-LOCK-FACE so |
| 2372 | (insert input) | 2378 | ;; they are not overwritten by comint buffer's font lock. |
| 2373 | ;; Ensure buffer is fontified, keeping it | 2379 | (python-util-text-properties-replace-name |
| 2374 | ;; compatible with Emacs < 24.4. | 2380 | 'face 'font-lock-face) |
| 2375 | (if (fboundp 'font-lock-ensure) | 2381 | (buffer-substring font-lock-buffer-pos |
| 2376 | (funcall 'font-lock-ensure) | 2382 | (point-max)))) |
| 2377 | (font-lock-default-fontify-buffer)) | 2383 | ;; Remove non-fontified original text. |
| 2378 | ;; Replace FACE text properties with FONT-LOCK-FACE so | 2384 | (delete-region pos (cdr (python-util-comint-last-prompt))) |
| 2379 | ;; they are not overwritten by comint buffer's font lock. | 2385 | ;; Point should be already at pos, this is for extra safety. |
| 2380 | (python-util-text-properties-replace-name | 2386 | (goto-char pos)))) |
| 2381 | 'face 'font-lock-face) | ||
| 2382 | (buffer-substring (line-beginning-position) | ||
| 2383 | (line-end-position)))) | ||
| 2384 | (goto-char current-point)))))) | ||
| 2385 | 2387 | ||
| 2386 | (defun python-shell-font-lock-turn-on (&optional msg) | 2388 | (defun python-shell-font-lock-turn-on (&optional msg) |
| 2387 | "Turn on shell font-lock. | 2389 | "Turn on shell font-lock. |
| @@ -3148,67 +3150,68 @@ With argument MSG show activation/deactivation message." | |||
| 3148 | "Get completions using native readline for PROCESS. | 3150 | "Get completions using native readline for PROCESS. |
| 3149 | When IMPORT is non-nil takes precedence over INPUT for | 3151 | When IMPORT is non-nil takes precedence over INPUT for |
| 3150 | completion." | 3152 | completion." |
| 3151 | (when (and python-shell-completion-native-enable | 3153 | (with-current-buffer (process-buffer process) |
| 3152 | (python-util-comint-last-prompt) | 3154 | (when (and python-shell-completion-native-enable |
| 3153 | (>= (point) (cdr (python-util-comint-last-prompt)))) | 3155 | (python-util-comint-last-prompt) |
| 3154 | (let* ((input (or import input)) | 3156 | (>= (point) (cdr (python-util-comint-last-prompt)))) |
| 3155 | (original-filter-fn (process-filter process)) | 3157 | (let* ((input (or import input)) |
| 3156 | (redirect-buffer (get-buffer-create | 3158 | (original-filter-fn (process-filter process)) |
| 3157 | python-shell-completion-native-redirect-buffer)) | 3159 | (redirect-buffer (get-buffer-create |
| 3158 | (separators (python-rx | 3160 | python-shell-completion-native-redirect-buffer)) |
| 3159 | (or whitespace open-paren close-paren))) | 3161 | (separators (python-rx |
| 3160 | (trigger "\t\t\t") | 3162 | (or whitespace open-paren close-paren))) |
| 3161 | (new-input (concat input trigger)) | 3163 | (trigger "\t\t\t") |
| 3162 | (input-length | 3164 | (new-input (concat input trigger)) |
| 3163 | (save-excursion | 3165 | (input-length |
| 3164 | (+ (- (point-max) (comint-bol)) (length new-input)))) | 3166 | (save-excursion |
| 3165 | (delete-line-command (make-string input-length ?\b)) | 3167 | (+ (- (point-max) (comint-bol)) (length new-input)))) |
| 3166 | (input-to-send (concat new-input delete-line-command))) | 3168 | (delete-line-command (make-string input-length ?\b)) |
| 3167 | ;; Ensure restoring the process filter, even if the user quits | 3169 | (input-to-send (concat new-input delete-line-command))) |
| 3168 | ;; or there's some other error. | 3170 | ;; Ensure restoring the process filter, even if the user quits |
| 3169 | (unwind-protect | 3171 | ;; or there's some other error. |
| 3170 | (with-current-buffer redirect-buffer | 3172 | (unwind-protect |
| 3171 | ;; Cleanup the redirect buffer | 3173 | (with-current-buffer redirect-buffer |
| 3172 | (delete-region (point-min) (point-max)) | 3174 | ;; Cleanup the redirect buffer |
| 3173 | ;; Mimic `comint-redirect-send-command', unfortunately it | 3175 | (delete-region (point-min) (point-max)) |
| 3174 | ;; can't be used here because it expects a newline in the | 3176 | ;; Mimic `comint-redirect-send-command', unfortunately it |
| 3175 | ;; command and that's exactly what we are trying to avoid. | 3177 | ;; can't be used here because it expects a newline in the |
| 3176 | (let ((comint-redirect-echo-input nil) | 3178 | ;; command and that's exactly what we are trying to avoid. |
| 3177 | (comint-redirect-verbose nil) | 3179 | (let ((comint-redirect-echo-input nil) |
| 3178 | (comint-redirect-perform-sanity-check nil) | 3180 | (comint-redirect-verbose nil) |
| 3179 | (comint-redirect-insert-matching-regexp nil) | 3181 | (comint-redirect-perform-sanity-check nil) |
| 3180 | ;; Feed it some regex that will never match. | 3182 | (comint-redirect-insert-matching-regexp nil) |
| 3181 | (comint-redirect-finished-regexp "^\\'$") | 3183 | ;; Feed it some regex that will never match. |
| 3182 | (comint-redirect-output-buffer redirect-buffer)) | 3184 | (comint-redirect-finished-regexp "^\\'$") |
| 3183 | ;; Compatibility with Emacs 24.x. Comint changed and | 3185 | (comint-redirect-output-buffer redirect-buffer)) |
| 3184 | ;; now `comint-redirect-filter' gets 3 args. This | 3186 | ;; Compatibility with Emacs 24.x. Comint changed and |
| 3185 | ;; checks which version of `comint-redirect-filter' is | 3187 | ;; now `comint-redirect-filter' gets 3 args. This |
| 3186 | ;; in use based on its args and uses `apply-partially' | 3188 | ;; checks which version of `comint-redirect-filter' is |
| 3187 | ;; to make it up for the 3 args case. | 3189 | ;; in use based on its args and uses `apply-partially' |
| 3188 | (if (= (length | 3190 | ;; to make it up for the 3 args case. |
| 3189 | (help-function-arglist 'comint-redirect-filter)) 3) | 3191 | (if (= (length |
| 3190 | (set-process-filter | 3192 | (help-function-arglist 'comint-redirect-filter)) 3) |
| 3191 | process (apply-partially | 3193 | (set-process-filter |
| 3192 | #'comint-redirect-filter original-filter-fn)) | 3194 | process (apply-partially |
| 3193 | (set-process-filter process #'comint-redirect-filter)) | 3195 | #'comint-redirect-filter original-filter-fn)) |
| 3194 | (process-send-string process input-to-send) | 3196 | (set-process-filter process #'comint-redirect-filter)) |
| 3195 | (accept-process-output | 3197 | (process-send-string process input-to-send) |
| 3196 | process | 3198 | (accept-process-output |
| 3197 | python-shell-completion-native-output-timeout) | 3199 | process |
| 3198 | ;; XXX: can't use `python-shell-accept-process-output' | 3200 | python-shell-completion-native-output-timeout) |
| 3199 | ;; here because there are no guarantees on how output | 3201 | ;; XXX: can't use `python-shell-accept-process-output' |
| 3200 | ;; ends. The workaround here is to call | 3202 | ;; here because there are no guarantees on how output |
| 3201 | ;; `accept-process-output' until we don't find anything | 3203 | ;; ends. The workaround here is to call |
| 3202 | ;; else to accept. | 3204 | ;; `accept-process-output' until we don't find anything |
| 3203 | (while (accept-process-output | 3205 | ;; else to accept. |
| 3204 | process | 3206 | (while (accept-process-output |
| 3205 | python-shell-completion-native-output-timeout)) | 3207 | process |
| 3206 | (cl-remove-duplicates | 3208 | python-shell-completion-native-output-timeout)) |
| 3207 | (split-string | 3209 | (cl-remove-duplicates |
| 3208 | (buffer-substring-no-properties | 3210 | (split-string |
| 3209 | (point-min) (point-max)) | 3211 | (buffer-substring-no-properties |
| 3210 | separators t)))) | 3212 | (point-min) (point-max)) |
| 3211 | (set-process-filter process original-filter-fn))))) | 3213 | separators t)))) |
| 3214 | (set-process-filter process original-filter-fn)))))) | ||
| 3212 | 3215 | ||
| 3213 | (defun python-shell-completion-get-completions (process import input) | 3216 | (defun python-shell-completion-get-completions (process import input) |
| 3214 | "Do completion at point using PROCESS for IMPORT or INPUT. | 3217 | "Do completion at point using PROCESS for IMPORT or INPUT. |
| @@ -3251,20 +3254,23 @@ completion." | |||
| 3251 | Optional argument PROCESS forces completions to be retrieved | 3254 | Optional argument PROCESS forces completions to be retrieved |
| 3252 | using that one instead of current buffer's process." | 3255 | using that one instead of current buffer's process." |
| 3253 | (setq process (or process (get-buffer-process (current-buffer)))) | 3256 | (setq process (or process (get-buffer-process (current-buffer)))) |
| 3254 | (let* ((last-prompt-end (cdr (python-util-comint-last-prompt))) | 3257 | (let* ((line-start (if (derived-mode-p 'inferior-python-mode) |
| 3258 | ;; Working on a shell buffer: use prompt end. | ||
| 3259 | (cdr (python-util-comint-last-prompt)) | ||
| 3260 | (line-beginning-position))) | ||
| 3255 | (import-statement | 3261 | (import-statement |
| 3256 | (when (string-match-p | 3262 | (when (string-match-p |
| 3257 | (rx (* space) word-start (or "from" "import") word-end space) | 3263 | (rx (* space) word-start (or "from" "import") word-end space) |
| 3258 | (buffer-substring-no-properties last-prompt-end (point))) | 3264 | (buffer-substring-no-properties line-start (point))) |
| 3259 | (buffer-substring-no-properties last-prompt-end (point)))) | 3265 | (buffer-substring-no-properties line-start (point)))) |
| 3260 | (start | 3266 | (start |
| 3261 | (save-excursion | 3267 | (save-excursion |
| 3262 | (if (not (re-search-backward | 3268 | (if (not (re-search-backward |
| 3263 | (python-rx | 3269 | (python-rx |
| 3264 | (or whitespace open-paren close-paren string-delimiter)) | 3270 | (or whitespace open-paren close-paren string-delimiter)) |
| 3265 | last-prompt-end | 3271 | line-start |
| 3266 | t 1)) | 3272 | t 1)) |
| 3267 | last-prompt-end | 3273 | line-start |
| 3268 | (forward-char (length (match-string-no-properties 0))) | 3274 | (forward-char (length (match-string-no-properties 0))) |
| 3269 | (point)))) | 3275 | (point)))) |
| 3270 | (end (point)) | 3276 | (end (point)) |
| @@ -3847,8 +3853,10 @@ The skeleton will be bound to python-skeleton-NAME." | |||
| 3847 | :type 'string | 3853 | :type 'string |
| 3848 | :group 'python) | 3854 | :group 'python) |
| 3849 | 3855 | ||
| 3850 | (defvar-local python-check-custom-command nil | 3856 | (defvar python-check-custom-command nil |
| 3851 | "Internal use.") | 3857 | "Internal use.") |
| 3858 | ;; XXX: Avoid `defvar-local' for compat with Emacs<24.3 | ||
| 3859 | (make-variable-buffer-local 'python-check-custom-command) | ||
| 3852 | 3860 | ||
| 3853 | (defun python-check (command) | 3861 | (defun python-check (command) |
| 3854 | "Check a Python file (default current buffer's file). | 3862 | "Check a Python file (default current buffer's file). |
| @@ -3917,15 +3925,29 @@ See `python-check-command' for the default." | |||
| 3917 | :type 'string | 3925 | :type 'string |
| 3918 | :group 'python) | 3926 | :group 'python) |
| 3919 | 3927 | ||
| 3928 | (defun python-eldoc--get-symbol-at-point () | ||
| 3929 | "Get the current symbol for eldoc. | ||
| 3930 | Returns the current symbol handling point within arguments." | ||
| 3931 | (save-excursion | ||
| 3932 | (let ((start (python-syntax-context 'paren))) | ||
| 3933 | (when start | ||
| 3934 | (goto-char start)) | ||
| 3935 | (when (or start | ||
| 3936 | (eobp) | ||
| 3937 | (memq (char-syntax (char-after)) '(?\ ?-))) | ||
| 3938 | ;; Try to adjust to closest symbol if not in one. | ||
| 3939 | (python-util-forward-comment -1))) | ||
| 3940 | (python-info-current-symbol t))) | ||
| 3941 | |||
| 3920 | (defun python-eldoc--get-doc-at-point (&optional force-input force-process) | 3942 | (defun python-eldoc--get-doc-at-point (&optional force-input force-process) |
| 3921 | "Internal implementation to get documentation at point. | 3943 | "Internal implementation to get documentation at point. |
| 3922 | If not FORCE-INPUT is passed then what `python-info-current-symbol' | 3944 | If not FORCE-INPUT is passed then what `python-eldoc--get-symbol-at-point' |
| 3923 | returns will be used. If not FORCE-PROCESS is passed what | 3945 | returns will be used. If not FORCE-PROCESS is passed what |
| 3924 | `python-shell-get-process' returns is used." | 3946 | `python-shell-get-process' returns is used." |
| 3925 | (let ((process (or force-process (python-shell-get-process)))) | 3947 | (let ((process (or force-process (python-shell-get-process)))) |
| 3926 | (when process | 3948 | (when process |
| 3927 | (let ((input (or force-input | 3949 | (let ((input (or force-input |
| 3928 | (python-info-current-symbol t)))) | 3950 | (python-eldoc--get-symbol-at-point)))) |
| 3929 | (and input | 3951 | (and input |
| 3930 | ;; Prevent resizing the echo area when iPython is | 3952 | ;; Prevent resizing the echo area when iPython is |
| 3931 | ;; enabled. Bug#18794. | 3953 | ;; enabled. Bug#18794. |
| @@ -3945,7 +3967,7 @@ inferior Python process is updated properly." | |||
| 3945 | "Get help on SYMBOL using `help'. | 3967 | "Get help on SYMBOL using `help'. |
| 3946 | Interactively, prompt for symbol." | 3968 | Interactively, prompt for symbol." |
| 3947 | (interactive | 3969 | (interactive |
| 3948 | (let ((symbol (python-info-current-symbol t)) | 3970 | (let ((symbol (python-eldoc--get-symbol-at-point)) |
| 3949 | (enable-recursive-minibuffers t)) | 3971 | (enable-recursive-minibuffers t)) |
| 3950 | (list (read-string (if symbol | 3972 | (list (read-string (if symbol |
| 3951 | (format "Describe symbol (default %s): " symbol) | 3973 | (format "Describe symbol (default %s): " symbol) |
| @@ -3954,6 +3976,17 @@ Interactively, prompt for symbol." | |||
| 3954 | (message (python-eldoc--get-doc-at-point symbol))) | 3976 | (message (python-eldoc--get-doc-at-point symbol))) |
| 3955 | 3977 | ||
| 3956 | 3978 | ||
| 3979 | ;;; Hideshow | ||
| 3980 | |||
| 3981 | (defun python-hideshow-forward-sexp-function (arg) | ||
| 3982 | "Python specific `forward-sexp' function for `hs-minor-mode'. | ||
| 3983 | Argument ARG is ignored." | ||
| 3984 | arg ; Shut up, byte compiler. | ||
| 3985 | (python-nav-end-of-defun) | ||
| 3986 | (unless (python-info-current-line-empty-p) | ||
| 3987 | (backward-char))) | ||
| 3988 | |||
| 3989 | |||
| 3957 | ;;; Imenu | 3990 | ;;; Imenu |
| 3958 | 3991 | ||
| 3959 | (defvar python-imenu-format-item-label-function | 3992 | (defvar python-imenu-format-item-label-function |
| @@ -4682,14 +4715,23 @@ Arguments START and END narrow the buffer region to work on." | |||
| 4682 | (current-column)))) | 4715 | (current-column)))) |
| 4683 | (^ '(- (1+ (current-indentation)))))) | 4716 | (^ '(- (1+ (current-indentation)))))) |
| 4684 | 4717 | ||
| 4685 | (add-function :before-until (local 'eldoc-documentation-function) | 4718 | (if (null eldoc-documentation-function) |
| 4686 | #'python-eldoc-function) | 4719 | ;; Emacs<25 |
| 4687 | 4720 | (setq (make-local-variable 'eldoc-documentation-function) | |
| 4688 | (add-to-list 'hs-special-modes-alist | 4721 | #'python-eldoc-function) |
| 4689 | `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#" | 4722 | (add-function :before-until (local 'eldoc-documentation-function) |
| 4690 | ,(lambda (_arg) | 4723 | #'python-eldoc-function)) |
| 4691 | (python-nav-end-of-defun)) | 4724 | |
| 4692 | nil)) | 4725 | (add-to-list |
| 4726 | 'hs-special-modes-alist | ||
| 4727 | `(python-mode | ||
| 4728 | "\\s-*\\(?:def\\|class\\)\\>" | ||
| 4729 | ;; Use the empty string as end regexp so it doesn't default to | ||
| 4730 | ;; "\\s)". This way parens at end of defun are properly hidden. | ||
| 4731 | "" | ||
| 4732 | "#" | ||
| 4733 | python-hideshow-forward-sexp-function | ||
| 4734 | nil)) | ||
| 4693 | 4735 | ||
| 4694 | (set (make-local-variable 'outline-regexp) | 4736 | (set (make-local-variable 'outline-regexp) |
| 4695 | (python-rx (* space) block-start)) | 4737 | (python-rx (* space) block-start)) |