From eee2aeca251a6fb3db09cfeeb3ae3aaf48db02fc Mon Sep 17 00:00:00 2001 From: kobarity Date: Thu, 22 Dec 2022 23:08:40 +0900 Subject: [PATCH] Fix python-shell-buffer-substring when retrieving a single statement * lisp/progmodes/python.el (python-shell-buffer-substring): Do not add "if True:" line when retrieving a single statement. (python-shell-send-region): Add a reference to `python-shell-buffer-substring' in docstring. * test/lisp/progmodes/python-tests.el (python-shell-buffer-substring-13) (python-shell-buffer-substring-14, python-shell-buffer-substring-15) (python-shell-buffer-substring-16, python-shell-buffer-substring-17): New tests. (Bug#60142) --- lisp/progmodes/python.el | 45 +++++++++++++------- test/lisp/progmodes/python-tests.el | 64 +++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 14 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 07f86d31551..641b4ccff23 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -3736,19 +3736,35 @@ the python shell: appending extra empty lines so tracebacks are correct. 3. When the region sent is a substring of the current buffer, a coding cookie is added. - 4. Wraps indented regions under an \"if True:\" block so the - interpreter evaluates them correctly." - (let* ((start (save-excursion - ;; If we're at the start of the expression, and - ;; there's just blank space ahead of it, then expand - ;; the region to include the start of the line. - ;; This makes things work better with the rest of - ;; the data we're sending over. + 4. When the region consists of a single statement, leading + whitespaces will be removed. Otherwise, wraps indented + regions under an \"if True:\" block so the interpreter + evaluates them correctly." + (let* ((single-p (save-restriction + (narrow-to-region start end) + (= (progn + (goto-char start) + (python-nav-beginning-of-statement)) + (progn + (goto-char end) + (python-nav-beginning-of-statement))))) + (start (save-excursion + ;; If we're at the start of the expression, and if + ;; the region consists of a single statement, then + ;; remove leading whitespaces, else if there's just + ;; blank space ahead of it, then expand the region + ;; to include the start of the line. This makes + ;; things work better with the rest of the data + ;; we're sending over. (goto-char start) - (if (string-blank-p - (buffer-substring (line-beginning-position) start)) - (line-beginning-position) - start))) + (if single-p + (progn + (skip-chars-forward "[:space:]" end) + (point)) + (if (string-blank-p + (buffer-substring (line-beginning-position) start)) + (line-beginning-position) + start)))) (substring (buffer-substring-no-properties start end)) (starts-at-point-min-p (save-restriction (widen) @@ -3772,7 +3788,7 @@ the python shell: (python-mode) (when fillstr (insert fillstr)) - (when (not toplevel-p) + (when (and (not single-p) (not toplevel-p)) (forward-line -1) (insert "if True:\n") (delete-region (point) (line-end-position))) @@ -3816,7 +3832,8 @@ code inside blocks delimited by \"if __name__== \\='__main__\\=':\". When called interactively SEND-MAIN defaults to nil, unless it's called with prefix argument. When optional argument MSG is non-nil, forces display of a user-friendly message if there's no -process running; defaults to t when called interactively." +process running; defaults to t when called interactively. The +substring to be sent is retrieved using `python-shell-buffer-substring'." (interactive (list (region-beginning) (region-end) current-prefix-arg t)) (let* ((string (python-shell-buffer-substring start end (not send-main) diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index 17d6d8aa706..930234a12f2 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -4456,6 +4456,70 @@ def foo(): (point-max)) "# -*- coding: utf-8 -*-\n\nif True:\n # Whitespace\n\n print ('a')\n\n")))) +(ert-deftest python-shell-buffer-substring-13 () + "Check substring from indented single statement." + (python-tests-with-temp-buffer + " +def foo(): + a = 1 +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "a = 1") + (pos-eol)) + "# -*- coding: utf-8 -*-\n\na = 1")))) + +(ert-deftest python-shell-buffer-substring-14 () + "Check substring from indented single statement spanning multiple lines." + (python-tests-with-temp-buffer + " +def foo(): + a = \"\"\"Some + string\"\"\" +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "a = \"\"\"Some") + (pos-eol 2)) + "# -*- coding: utf-8 -*-\n\na = \"\"\"Some\n string\"\"\"")))) + +(ert-deftest python-shell-buffer-substring-15 () + "Check substring from partial statement." + (python-tests-with-temp-buffer + " +def foo(): + a = 1 +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at " a = 1") + (python-tests-look-at " = 1")) + "# -*- coding: utf-8 -*-\n\na")))) + +(ert-deftest python-shell-buffer-substring-16 () + "Check substring from partial statement." + (python-tests-with-temp-buffer + " +def foo(): + a = 1 +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "1") + (1+ (point))) + "# -*- coding: utf-8 -*-\n\n1")))) + +(ert-deftest python-shell-buffer-substring-17 () + "Check substring from multiline string." + (python-tests-with-temp-buffer + " +def foo(): + s = \"\"\" + a = 1 + b = 2 +\"\"\" +" + (should (string= (python-shell-buffer-substring + (python-tests-look-at "a = 1") + (python-tests-look-at "\"\"\"")) + "# -*- coding: utf-8 -*-\n\nif True:\n a = 1\n b = 2\n\n")))) + ;;; Shell completion -- 2.39.5