From a425eb5d8b6c1bd58cfd2c1cabf84b9cb01001b5 Mon Sep 17 00:00:00 2001 From: Lin Sun Date: Sat, 27 Apr 2024 06:54:27 +0000 Subject: [PATCH] New function 'python-shell-send-block' for python-mode * lisp/progmodes/python.el: Implemention of the new function. * test/lisp/progmodes/python-tests.el: Test case for the new function. * etc/NEWS: Document for the new function. --- etc/NEWS | 4 ++++ lisp/progmodes/python.el | 25 +++++++++++++++++++++++++ test/lisp/progmodes/python-tests.el | 27 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index fea27bb8a3..974e0c35dc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1319,6 +1319,10 @@ instead of: This allows the user to specify command line arguments to the non interactive Python interpreter specified by 'python-interpreter'. +*** New function 'python-shell-send-block'. +It sends the python block delimited by 'python-nav-beginning-of-block' +and 'python-nav-end-of-block' to the inferior Python process. + ** Scheme mode Scheme mode now handles regular expression literal '#/regexp/' that is available in some Scheme implementations. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 85279d3e84..bc21281334 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -350,6 +350,7 @@ python-mode-map (define-key map "\C-c\C-e" #'python-shell-send-statement) (define-key map "\C-c\C-r" #'python-shell-send-region) (define-key map "\C-\M-x" #'python-shell-send-defun) + (define-key map "\C-c\C-b" #'python-shell-send-block) (define-key map "\C-c\C-c" #'python-shell-send-buffer) (define-key map "\C-c\C-l" #'python-shell-send-file) (define-key map "\C-c\C-z" #'python-shell-switch-to-shell) @@ -390,6 +391,8 @@ python-mode-map :help "Switch to running inferior Python process"] ["Eval string" python-shell-send-string :help "Eval string in inferior Python session"] + ["Eval block" python-shell-send-block + :help "Eval block in inferior Python session"] ["Eval buffer" python-shell-send-buffer :help "Eval buffer in inferior Python session"] ["Eval statement" python-shell-send-statement @@ -4136,6 +4139,27 @@ python-shell-send-statement (save-excursion (python-nav-end-of-statement)) send-main msg t))) +(defun python-shell-send-block (&optional arg msg) + "Send the block at point to inferior Python process. +The block is delimited by `python-nav-beginning-of-block' and +`python-nav-end-of-block'. When optional argument ARG is non-nil, send +the block body without its header. 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." + (interactive (list current-prefix-arg t)) + (let ((beg (save-excursion + (when (python-nav-beginning-of-block) + (if (null arg) + (beginning-of-line) + (python-nav-end-of-statement) + (beginning-of-line 2))) + (point-marker))) + (end (save-excursion (python-nav-end-of-block))) + (python-indent-guess-indent-offset-verbose nil)) + (if (and beg end) + (python-shell-send-region beg end nil msg t) + (user-error "Can't get code block from current position.")))) + (defun python-shell-send-buffer (&optional send-main msg) "Send the entire buffer to inferior Python process. When optional argument SEND-MAIN is non-nil, allow execution of @@ -7176,6 +7200,7 @@ python-ts-mode python-nav-if-name-main python-nav-up-list python-remove-import + python-shell-send-block python-shell-send-buffer python-shell-send-defun python-shell-send-statement diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index e11440cdb5..134710abf2 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -7465,6 +7465,33 @@ python-tests--flymake-command-output-pattern "Unused import a.b.c (unused-import)" "W0611: Unused import a.b.c (unused-import)")))))) +(ert-deftest python-test--shell-send-block () + (skip-unless (executable-find python-tests-shell-interpreter)) + (python-tests-with-temp-buffer-with-shell + "print('current 0') +for x in range(1,3): + print('current %s' % x) +print('current 3')" + (goto-line 1) + (should-error (python-shell-send-block) :type 'user-error) + (goto-line 2) + (python-shell-send-block) + (python-tests-shell-wait-for-prompt) + (python-shell-with-shell-buffer + (goto-char (point-min)) + (should-not (re-search-forward "current 0" nil t)) + (should (re-search-forward "current 1" nil t)) + (should (re-search-forward "current 2" nil t)) + (should-not (re-search-forward "current 3" nil t))) + (goto-line 3) + (python-shell-send-block t) ;; send block body only + (python-tests-shell-wait-for-prompt) + (python-shell-with-shell-buffer + ;; should only 1 line output from the block body + (should (re-search-forward "current")) + (should (looking-at " 2")) + (should-not (re-search-forward "current" nil t))))) + ;;; python-ts-mode font-lock tests (defmacro python-ts-tests-with-temp-buffer (contents &rest body) -- 2.20.5