From e5afbcacfab50bb3cceb95bb778a1a4cbb90eda0 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 4 Nov 2013 14:14:58 -0500 Subject: [PATCH] * lisp/progmodes/python.el: Fix up last change. (python-shell--save-temp-file): New function. (python-shell-send-string): Use it. Remove `msg' arg. Don't assume `string' comes from the current buffer. (python-shell-send-string-no-output): Remove `msg' arg. (python--use-fake-loc): New var. (python-shell-buffer-substring): Obey it. Try to compensate for the extra coding line added by python-shell--save-temp-file. (python-shell-send-region): Use python-shell--save-temp-file and python-shell-send-file directly. Add `nomain' argument. (python-shell-send-buffer): Use python-shell-send-region. (python-electric-pair-string-delimiter): New function. (python-mode): Use it. --- lisp/ChangeLog | 20 ++++++- lisp/progmodes/python.el | 110 ++++++++++++++++++++++++--------------- 2 files changed, 87 insertions(+), 43 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 965a62668ed..f6f3a276afe 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,19 @@ +2013-11-04 Stefan Monnier + + * progmodes/python.el: Fix up last change. + (python-shell--save-temp-file): New function. + (python-shell-send-string): Use it. Remove `msg' arg. Don't assume + `string' comes from the current buffer. + (python-shell-send-string-no-output): Remove `msg' arg. + (python--use-fake-loc): New var. + (python-shell-buffer-substring): Obey it. Try to compensate for the + extra coding line added by python-shell--save-temp-file. + (python-shell-send-region): Use python-shell--save-temp-file and + python-shell-send-file directly. Add `nomain' argument. + (python-shell-send-buffer): Use python-shell-send-region. + (python-electric-pair-string-delimiter): New function. + (python-mode): Use it. + 2013-11-04 Eli Zaretskii * startup.el (normal-top-level): Move setting eol-mnemonic-unix, @@ -14,8 +30,8 @@ 2013-11-04 Teodor Zlatanov * emacs-lisp/package.el (package-menu-mode) - (package-menu--print-info, package-menu--archive-predicate): Add - Archive column to package list. + (package-menu--print-info, package-menu--archive-predicate): + Add Archive column to package list. 2013-11-04 Michael Albinus diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index e0a7feb3a72..ca9c3c6e6ef 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2036,34 +2036,31 @@ there for compatibility with CEDET.") (define-obsolete-variable-alias 'python-preoutput-result 'python-shell-internal-last-output "24.3") -(defun python-shell-send-string (string &optional process msg) +(defun python-shell--save-temp-file (string) + (let* ((temporary-file-directory + (if (file-remote-p default-directory) + (concat (file-remote-p default-directory) "/tmp") + temporary-file-directory)) + (temp-file-name (make-temp-file "py")) + (coding-system-for-write 'utf-8)) + (with-temp-file temp-file-name + (insert "# -*- coding: utf-8 -*-\n") ;Not needed for Python-3. + (insert string) + (delete-trailing-whitespace)) + temp-file-name)) + +(defun python-shell-send-string (string &optional process) "Send STRING to inferior Python PROCESS. -When MSG is non-nil messages the first line of STRING. -If a temp file is used, return its name, otherwise return nil." +When MSG is non-nil messages the first line of STRING." (interactive "sPython command: ") - (let ((process (or process (python-shell-get-or-create-process))) - (_ (string-match "\\`\n*\\(.*\\)\\(\n.\\)?" string)) - (multiline (match-beginning 2))) - (and msg (message "Sent: %s..." (match-string 1 string))) - (if multiline - (let* ((temporary-file-directory - (if (file-remote-p default-directory) - (concat (file-remote-p default-directory) "/tmp") - temporary-file-directory)) - (temp-file-name (make-temp-file "py")) - (coding-system-for-write 'utf-8) - (file-name (or (buffer-file-name) temp-file-name))) - (with-temp-file temp-file-name - (insert "# -*- coding: utf-8 -*-\n") - (insert string) - (delete-trailing-whitespace)) - (python-shell-send-file file-name process temp-file-name) - temp-file-name) + (let ((process (or process (python-shell-get-or-create-process)))) + (if (string-match ".\n+." string) ;Multiline. + (let* ((temp-file-name (python-shell--save-temp-file string))) + (python-shell-send-file temp-file-name process temp-file-name)) (comint-send-string process string) - (when (or (not (string-match "\n$" string)) - (string-match "\n[ \t].*\n?$" string)) - (comint-send-string process "\n")) - nil))) + (when (or (not (string-match "\n\\'" string)) + (string-match "\n[ \t].*\n?\\'" string)) + (comint-send-string process "\n"))))) (defvar python-shell-output-filter-in-progress nil) (defvar python-shell-output-filter-buffer nil) @@ -2101,7 +2098,7 @@ detecting a prompt at the end of the buffer." (substring python-shell-output-filter-buffer (match-end 0))))) "") -(defun python-shell-send-string-no-output (string &optional process msg) +(defun python-shell-send-string-no-output (string &optional process) "Send STRING to PROCESS and inhibit output. When MSG is non-nil messages the first line of STRING. Return the output." @@ -2112,7 +2109,7 @@ the output." (inhibit-quit t)) (or (with-local-quit - (python-shell-send-string string process msg) + (python-shell-send-string string process) (while python-shell-output-filter-in-progress ;; `python-shell-output-filter' takes care of setting ;; `python-shell-output-filter-in-progress' to NIL after it @@ -2134,7 +2131,7 @@ Returns the output. See `python-shell-send-string-no-output'." ;; Makes this function compatible with the old ;; python-send-receive. (At least for CEDET). (replace-regexp-in-string "_emacs_out +" "" string) - (python-shell-internal-get-or-create-process) nil))) + (python-shell-internal-get-or-create-process)))) (define-obsolete-function-alias 'python-send-receive 'python-shell-internal-send-string "24.3") @@ -2142,6 +2139,12 @@ Returns the output. See `python-shell-send-string-no-output'." (define-obsolete-function-alias 'python-send-string 'python-shell-internal-send-string "24.3") +(defvar python--use-fake-loc nil + "If non-nil, use `compilation-fake-loc' to trace errors back to the buffer. +If nil, regions of text are prepended by the corresponding number of empty +lines and Python is told to output error messages referring to the whole +source file.") + (defun python-shell-buffer-substring (start end &optional nomain) "Send buffer substring from START to END formatted for shell. This is a wrapper over `buffer-substring' that takes care of @@ -2154,7 +2157,8 @@ the python shell: 3. Wraps indented regions under an \"if True:\" block so the interpreter evaluates them correctly." (let ((substring (buffer-substring-no-properties start end)) - (fillstr (make-string (1- (line-number-at-pos start)) ?\n)) + (fillstr (unless python--use-fake-loc + (make-string (1- (line-number-at-pos start)) ?\n))) (toplevel-block-p (save-excursion (goto-char start) (or (zerop (line-number-at-pos start)) @@ -2163,9 +2167,14 @@ the python shell: (zerop (current-indentation))))))) (with-temp-buffer (python-mode) - (insert fillstr) + (if fillstr (insert fillstr)) (insert substring) (goto-char (point-min)) + (unless python--use-fake-loc + ;; python-shell--save-temp-file adds an extra coding line, which would + ;; throw off the line-counts, so let's try to compensate here. + (if (looking-at "[ \t]*[#\n]") + (delete-region (point) (line-beginning-position 2)))) (when (not toplevel-block-p) (insert "if True:") (delete-region (point) (line-end-position))) @@ -2192,15 +2201,23 @@ the python shell: (declare-function compilation-fake-loc "compile" (marker file &optional line col)) -(defun python-shell-send-region (start end) +(defun python-shell-send-region (start end &optional nomain) "Send the region delimited by START and END to inferior Python process." (interactive "r") - (let ((temp-file-name - (python-shell-send-string - (python-shell-buffer-substring start end) nil t))) - (when temp-file-name - (with-current-buffer (python-shell-get-buffer) - (compilation-fake-loc (copy-marker start) temp-file-name))))) + (let* ((python--use-fake-loc + (or python--use-fake-loc (not buffer-file-name))) + (string (python-shell-buffer-substring start end nomain)) + (process (python-shell-get-or-create-process)) + (_ (string-match "\\`\n*\\(.*\\)" string))) + (message "Sent: %s..." (match-string 1 string)) + (let* ((temp-file-name (python-shell--save-temp-file string)) + (file-name (or (buffer-file-name) temp-file-name))) + (python-shell-send-file file-name process temp-file-name) + (unless python--use-fake-loc + (with-current-buffer (process-buffer process) + (compilation-fake-loc (copy-marker start) temp-file-name + 2)) ;; Not 1, because of the added coding line. + )))) (defun python-shell-send-buffer (&optional arg) "Send the entire buffer to inferior Python process. @@ -2209,9 +2226,7 @@ by \"if __name__== '__main__':\"" (interactive "P") (save-restriction (widen) - (python-shell-send-string - (python-shell-buffer-substring - (point-min) (point-max) (not arg))))) + (python-shell-send-region (point-min) (point-max) (not arg)))) (defun python-shell-send-defun (arg) "Send the current defun to inferior Python process. @@ -3561,6 +3576,15 @@ list is returned as is." (reverse acc)))) +(defun python-electric-pair-string-delimiter () + (when (and electric-pair-mode + (memq last-command-event '(?\" ?\')) + (let ((count 0)) + (while (eq (char-before (- (point) count)) last-command-event) + (cl-incf count)) + (= count 3))) + (save-excursion (insert (make-string 3 last-command-event))))) + (defvar electric-indent-inhibit) ;;;###autoload @@ -3593,7 +3617,11 @@ if that value is non-nil." (set (make-local-variable 'indent-region-function) #'python-indent-region) ;; Because indentation is not redundant, we cannot safely reindent code. (setq-local electric-indent-inhibit t) - + + ;; Add """ ... """ pairing to electric-pair-mode. + (add-hook 'post-self-insert-hook + #'python-electric-pair-string-delimiter 'append t) + (set (make-local-variable 'paragraph-start) "\\s-*$") (set (make-local-variable 'fill-paragraph-function) 'python-fill-paragraph) -- 2.39.2