简体   繁体   中英

emacs elisp send line if no region active python-mode

I want to create a command where the region is sent if active, and if not, the current line/statement is evaluated and point is taken further to the next statement.

I started with This solution. Now I can't get the (python-shell-send-region) to work though as I don't know how to pass the beginning and end of the region to it.

So far I have this:

 (defun my-python-send-region (&optional beg end)   
   (interactive)   
    (if (use-region-p)
      (python-shell-send-region)    (let ((beg (cond (beg beg)
                    ((region-active-p)
                     (region-beginning))
                    (t (line-beginning-position))))
         (end (cond (end end)
                    ((region-active-p)
                     (copy-marker (region-end)))
                    (t (line-end-position)))))
     (python-shell-send-region beg end)
     (python-nav-forward-statement))))

 (add-hook 'python-mode-hook
       (lambda ()
     (define-key python-mode-map "\C-cn" 'my-python-send-region)))

UPDATE: With Andreas' and Legoscia's suggestions I changed the structure a bit.

Now I get an error (Invalid function: (setq beg (point)) for:

 (defun my-python-send-region (&optional beg end)
  (interactive)
  (if (use-region-p)
    (python-shell-send-region (region-beginning) (region-end))
   ((setq beg (point))
    (python-nav-end-of-statement)
    (setq end (point))
    (python-shell-send-region (beg) (end)))
    (python-nav-forward-statement))))

However, this works:

 (defun my-python-send-region (&optional beg end)
 (interactive)
 (setq beg (point))
 (python-nav-end-of-statement)
 (setq end (point))
 (python-shell-send-region beg end))

An alternative approach which might work is to try the whole-line-or-region package from melpa. This package sets up things so that if you call a command which expects a region, but no region is defined, it will basically set a region which is equal to the current line. Essentially, this causes commands which expect a region to work when no region is defined on the current line. I have this in my init.org file

Allow region oriented commands to work on the current line if no region is defined.

   #+BEGIN_SRC emacs-lisp
     (use-package whole-line-or-region
       :ensure t
       :diminish whole-line-or-region-mode
       :config
       (whole-line-or-region-mode t)
       (make-variable-buffer-local 'whole-line-or-region-mode))

In this part:

(if (use-region-p)
  (python-shell-send-region)

you need to pass the beginning and end of the region to python-shell-send-region . It only gets those values automatically when called interactively. When you call it from Lisp code, you need to pass the values explicitly:

(python-shell-send-region (region-beginning) (region-end))

Updated answer: the python-shell-send-defun does not always send the current statement/line ( it is not meant to do that ), so I replaced it with a function from elpy

(defun python-shell-send-region-or-line nil
  "Sends from python-mode buffer to a python shell, intelligently."
  (interactive)
  (cond ((region-active-p)
     (setq deactivate-mark t)
     (python-shell-send-region (region-beginning) (region-end))
 ) (t (python-shell-send-current-statement))))

(defun python-shell-send-current-statement ()
"Send current statement to Python shell.
Taken from elpy-shell-send-current-statement"
(interactive)
(let ((beg (python-nav-beginning-of-statement))
    (end (python-nav-end-of-statement)))
(python-shell-send-string (buffer-substring beg end)))
(python-nav-forward-statement))

I use cond for if in case I want to add cases. Setting deactivate-mark is to deselect the region if selected. If no region is selected, I also navigate forward a python statement.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM