unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* python: Let pdb tracking not kill buffers
@ 2019-10-04 20:32 Andrii Kolomoiets
  2019-10-05  6:40 ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Andrii Kolomoiets @ 2019-10-04 20:32 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1314 bytes --]

Hello,

Let's start from example:
1. echo "import pdb; pdb.set_trace()" > test.py
2. emacs -Q
3. M-x run-python
4. M-x python-shell-send-file <RET> test.py <RET>

Now there are two windows: one with pdb session and another one with
source code.
Now in pdb prompt: pass<RET>

The source code buffer is killed because pdb tracking comint output
filter doesn't found file name in the output and decides that tracking
session is over.

This behavior interferes with debug session. Moving frame up/down the
stack trace open new files but evaluating some code kill them when they
are still needed.

Another reason to not kill buffers is that I want the file opened during
debug session stay there when the debug session is over because I want
to change it.

My point is: it's hard to tell that debug session is over judging from
the output but it can be determined by inspecting the input.

Attached patch brings the following changes:

- New variable `python-pdbtrack-kill-buffers' that make buffers killing
  optional;

- Comint input filter which decides that the debug session is over;

- Process sentinel to finish tracking when python process is killed.

Please see attached patch. I certainly sure docstrings and naming are
not so good but they can be fine tuned later if the main idea will be
accepted.

Thanks.

[-- Attachment #2: pdb-track.patch --]
[-- Type: application/octet-stream, Size: 9135 bytes --]

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ae5aff351c..4f9dfba8b3 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2795,7 +2795,6 @@ inferior-python-mode
   (set (make-local-variable 'comint-output-filter-functions)
        '(ansi-color-process-output
          python-shell-comint-watch-for-first-prompt-output-filter
-         python-pdbtrack-comint-output-filter-function
          python-comint-postoutput-scroll-to-bottom
          comint-watch-for-password-prompt))
   (set (make-local-variable 'compilation-error-regexp-alist)
@@ -2809,7 +2808,8 @@ inferior-python-mode
   (make-local-variable 'python-shell-internal-last-output)
   (when python-shell-font-lock-enable
     (python-shell-font-lock-turn-on))
-  (compilation-shell-minor-mode 1))
+  (compilation-shell-minor-mode 1)
+  (python-pdbtrack-setup-tracking))
 
 (defun python-shell-make-comint (cmd proc-name &optional show internal)
   "Create a Python shell comint buffer.
@@ -3744,13 +3744,29 @@ python-pdbtrack-activate
   :safe 'booleanp)
 
 (defcustom python-pdbtrack-stacktrace-info-regexp
-  "> \\([^\"(<]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
+  "> \\([^\"(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
   "Regular expression matching stacktrace information.
 Used to extract the current line and module being inspected."
   :type 'string
   :group 'python
   :safe 'stringp)
 
+(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
+  "Pdb continue command."
+  :type 'list
+  :group 'python)
+
+(defcustom python-pdbtrack-untrack-commands '("c" "cont" "continue" "q" "quit" "exit")
+  "Pdb commands that finish tracking session."
+  :type 'list
+  :group 'python)
+
+(defcustom python-pdbtrack-kill-buffers t
+  "Kill buffers when tracking is finished.
+Only buffers opened during tracking will be killed."
+  :type 'boolean
+  :group 'python)
+
 (defvar python-pdbtrack-tracked-buffer nil
   "Variable containing the value of the current tracked buffer.
 Never set this variable directly, use
@@ -3759,6 +3775,9 @@ python-pdbtrack-tracked-buffer
 (defvar python-pdbtrack-buffers-to-kill nil
   "List of buffers to be deleted after tracking finishes.")
 
+(defvar python-pdbtrack-prev-command-continue nil
+  "Is t if previous pdb command was 'continue'.")
+
 (defun python-pdbtrack-set-tracked-buffer (file-name)
   "Set the buffer for FILE-NAME as the tracked buffer.
 Internally it uses the `python-pdbtrack-tracked-buffer' variable.
@@ -3766,8 +3785,7 @@ python-pdbtrack-set-tracked-buffer
   (let* ((file-name-prospect (concat (file-remote-p default-directory)
                               file-name))
          (file-buffer (get-file-buffer file-name-prospect)))
-    (if file-buffer
-        (setq python-pdbtrack-tracked-buffer file-buffer)
+    (unless file-buffer
       (cond
        ((file-exists-p file-name-prospect)
         (setq file-buffer (find-file-noselect file-name-prospect)))
@@ -3775,10 +3793,52 @@ python-pdbtrack-set-tracked-buffer
              (file-exists-p file-name))
         ;; Fallback to a locally available copy of the file.
         (setq file-buffer (find-file-noselect file-name-prospect))))
-      (when (not (member file-buffer python-pdbtrack-buffers-to-kill))
+      (when (and python-pdbtrack-kill-buffers
+                 (not (member file-buffer python-pdbtrack-buffers-to-kill)))
         (add-to-list 'python-pdbtrack-buffers-to-kill file-buffer)))
+    (setq python-pdbtrack-tracked-buffer file-buffer)
     file-buffer))
 
+(defun python-pdbtrack-unset-tracked-buffer ()
+  "Untrack currently tracked buffer."
+  (when python-pdbtrack-tracked-buffer
+    (with-current-buffer python-pdbtrack-tracked-buffer
+      (set-marker overlay-arrow-position nil))
+    (setq python-pdbtrack-tracked-buffer nil)))
+
+(defun python-pdbtrack-tracking-finish ()
+  "Finish tracking."
+  (python-pdbtrack-unset-tracked-buffer)
+  (when python-pdbtrack-kill-buffers
+      (mapc #'(lambda (buffer)
+                (ignore-errors (kill-buffer buffer)))
+            python-pdbtrack-buffers-to-kill))
+  (setq python-pdbtrack-buffers-to-kill nil))
+
+(defun python-pdbtrack-process-sentinel (process _event)
+  "Untrack buffers when PROCESS is killed."
+  (unless (process-live-p process)
+    (python-pdbtrack-tracking-finish)))
+
+(defun python-pdbtrack-comint-input-filter-function (input)
+  "Finish tracking session depending on command in INPUT.
+Commands that must finish tracking session is listed in
+`python-pdbtrack-untracking-commands'."
+  (when (and python-pdbtrack-tracked-buffer
+             ;; Empty input is sent by C-d or `comint-send-eof'
+             (or (string-empty-p input)
+                 ;; "n some text" is "n" command for pdb. Split input and get firs part
+                 (let* ((command (car (split-string (string-trim input) " "))))
+                   (setq python-pdbtrack-prev-command-continue
+                         (or (member command python-pdbtrack-continue-command)
+                             ;; if command is empty and previous command was 'continue'
+                             ;; then current command is 'continue' too.
+                             (and (string-empty-p command)
+                                  python-pdbtrack-prev-command-continue)))
+                   (or python-pdbtrack-prev-command-continue
+                       (member command python-pdbtrack-untrack-commands)))))
+    (python-pdbtrack-tracking-finish)))
+
 (defun python-pdbtrack-comint-output-filter-function (output)
   "Move overlay arrow to current pdb line in tracked buffer.
 Argument OUTPUT is a string with the output from the comint process."
@@ -3798,19 +3858,27 @@ python-pdbtrack-comint-output-filter-function
               ;; the _last_ stack frame printed in the most recent
               ;; batch of output, then jump to the corresponding
               ;; file/line number.
+              ;; Parse output only if at pdb prompt to avoid double code
+              ;; run in situation when output and pdb prompt received in
+              ;; different hunks
               (goto-char (point-max))
-              (when (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t)
+              (goto-char (line-beginning-position))
+              (when (and (looking-at python-shell-prompt-pdb-regexp)
+                         (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t))
                 (setq line-number (string-to-number
                                    (match-string-no-properties 2)))
                 (match-string-no-properties 1)))))
-      (if (and file-name line-number)
-          (let* ((tracked-buffer
-                  (python-pdbtrack-set-tracked-buffer file-name))
+      (when (and file-name line-number)
+        (if (string-prefix-p "<" file-name)
+            ;; Finish tracking session if stacktrace info is like
+            ;; "> <stdin>(1)<module>()->None"
+            (python-pdbtrack-tracking-finish)
+          (python-pdbtrack-unset-tracked-buffer)
+          (let* ((tracked-buffer (python-pdbtrack-set-tracked-buffer file-name))
                  (shell-buffer (current-buffer))
                  (tracked-buffer-window (get-buffer-window tracked-buffer))
                  (tracked-buffer-line-pos))
             (with-current-buffer tracked-buffer
-              (set (make-local-variable 'overlay-arrow-string) "=>")
               (set (make-local-variable 'overlay-arrow-position) (make-marker))
               (setq tracked-buffer-line-pos (progn
                                               (goto-char (point-min))
@@ -3821,17 +3889,18 @@ python-pdbtrack-comint-output-filter-function
                  tracked-buffer-window tracked-buffer-line-pos))
               (set-marker overlay-arrow-position tracked-buffer-line-pos))
             (pop-to-buffer tracked-buffer)
-            (switch-to-buffer-other-window shell-buffer))
-        (when python-pdbtrack-tracked-buffer
-          (with-current-buffer python-pdbtrack-tracked-buffer
-            (set-marker overlay-arrow-position nil))
-          (mapc #'(lambda (buffer)
-                    (ignore-errors (kill-buffer buffer)))
-                python-pdbtrack-buffers-to-kill)
-          (setq python-pdbtrack-tracked-buffer nil
-                python-pdbtrack-buffers-to-kill nil)))))
+            (switch-to-buffer-other-window shell-buffer))))))
   output)
 
+(defun python-pdbtrack-setup-tracking ()
+  "Setup pdb tracking in current buffer."
+  (add-to-list (make-local-variable 'comint-input-filter-functions)
+               #'python-pdbtrack-comint-input-filter-function)
+  (add-to-list (make-local-variable 'comint-output-filter-functions)
+               #'python-pdbtrack-comint-output-filter-function)
+  (set-process-sentinel (get-buffer-process (current-buffer))
+                        #'python-pdbtrack-process-sentinel))
+
 \f
 ;;; Symbol completion
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-04 20:32 python: Let pdb tracking not kill buffers Andrii Kolomoiets
@ 2019-10-05  6:40 ` Eli Zaretskii
  2019-10-07  4:33   ` Lawrence Liu
  2019-10-07 12:28   ` Andrii Kolomoiets
  0 siblings, 2 replies; 12+ messages in thread
From: Eli Zaretskii @ 2019-10-05  6:40 UTC (permalink / raw)
  To: Andrii Kolomoiets; +Cc: emacs-devel

> From: Andrii Kolomoiets <andreyk.mad@gmail.com>
> Date: Fri, 4 Oct 2019 23:32:09 +0300
> 
> 1. echo "import pdb; pdb.set_trace()" > test.py
> 2. emacs -Q
> 3. M-x run-python
> 4. M-x python-shell-send-file <RET> test.py <RET>
> 
> Now there are two windows: one with pdb session and another one with
> source code.
> Now in pdb prompt: pass<RET>
> 
> The source code buffer is killed because pdb tracking comint output
> filter doesn't found file name in the output and decides that tracking
> session is over.
> 
> This behavior interferes with debug session. Moving frame up/down the
> stack trace open new files but evaluating some code kill them when they
> are still needed.

Thanks.

Aren't users supposed to use pdb via "M-x pdb" instead?  (I don't use
this, and don't debug Python programs, so maybe my question makes no
sense.)

> Attached patch brings the following changes:
> 
> - New variable `python-pdbtrack-kill-buffers' that make buffers killing
>   optional;
> 
> - Comint input filter which decides that the debug session is over;
> 
> - Process sentinel to finish tracking when python process is killed.
> 
> Please see attached patch. I certainly sure docstrings and naming are
> not so good but they can be fine tuned later if the main idea will be
> accepted.

Besides the question I asked above, your patch is too large to be
accepted without assigning copyright to the FSF.  Would you like to
start the legal paperwork rolling, so that any contributions from you
could be accepted without limitations?

> +(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
> +  "Pdb continue command."
> +  :type 'list
> +  :group 'python)

Each new defcustom should have a :version tag.  Also, if they belong
to the group of the current file, our convention is not to use :group,
as that's redundant.

In addition, please try making the doc strings explain how is the
variable used and what is its effect, including (if applicable) the
effect of special values, like nil etc.

> +(defcustom python-pdbtrack-kill-buffers t
> +  "Kill buffers when tracking is finished.
> +Only buffers opened during tracking will be killed."

The first sentence should be "If non-nil, kill buffers when tracking
is finished."  (And that is somewhat unclear, because it isn't clear
what it means "when tracking is finished".)



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-05  6:40 ` Eli Zaretskii
@ 2019-10-07  4:33   ` Lawrence Liu
  2019-10-07 16:19     ` Eli Zaretskii
  2019-10-07 12:28   ` Andrii Kolomoiets
  1 sibling, 1 reply; 12+ messages in thread
From: Lawrence Liu @ 2019-10-07  4:33 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Andrii Kolomoiets, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2895 bytes --]

Dear

I am a full time python developer and seems in my case mostly I am using
the way as below:

insert a

import pdb; pdb.set_trace();

in my code bass and trigger the break point from other place (mostly
browser) and wait for the break point been hit.

Thanks.

Eli Zaretskii <eliz@gnu.org>于2019年10月5日 周六14:41写道:

> > From: Andrii Kolomoiets <andreyk.mad@gmail.com>
> > Date: Fri, 4 Oct 2019 23:32:09 +0300
> >
> > 1. echo "import pdb; pdb.set_trace()" > test.py
> > 2. emacs -Q
> > 3. M-x run-python
> > 4. M-x python-shell-send-file <RET> test.py <RET>
> >
> > Now there are two windows: one with pdb session and another one with
> > source code.
> > Now in pdb prompt: pass<RET>
> >
> > The source code buffer is killed because pdb tracking comint output
> > filter doesn't found file name in the output and decides that tracking
> > session is over.
> >
> > This behavior interferes with debug session. Moving frame up/down the
> > stack trace open new files but evaluating some code kill them when they
> > are still needed.
>
> Thanks.
>
> Aren't users supposed to use pdb via "M-x pdb" instead?  (I don't use
> this, and don't debug Python programs, so maybe my question makes no
> sense.)
>
> > Attached patch brings the following changes:
> >
> > - New variable `python-pdbtrack-kill-buffers' that make buffers killing
> >   optional;
> >
> > - Comint input filter which decides that the debug session is over;
> >
> > - Process sentinel to finish tracking when python process is killed.
> >
> > Please see attached patch. I certainly sure docstrings and naming are
> > not so good but they can be fine tuned later if the main idea will be
> > accepted.
>
> Besides the question I asked above, your patch is too large to be
> accepted without assigning copyright to the FSF.  Would you like to
> start the legal paperwork rolling, so that any contributions from you
> could be accepted without limitations?
>
> > +(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
> > +  "Pdb continue command."
> > +  :type 'list
> > +  :group 'python)
>
> Each new defcustom should have a :version tag.  Also, if they belong
> to the group of the current file, our convention is not to use :group,
> as that's redundant.
>
> In addition, please try making the doc strings explain how is the
> variable used and what is its effect, including (if applicable) the
> effect of special values, like nil etc.
>
> > +(defcustom python-pdbtrack-kill-buffers t
> > +  "Kill buffers when tracking is finished.
> > +Only buffers opened during tracking will be killed."
>
> The first sentence should be "If non-nil, kill buffers when tracking
> is finished."  (And that is somewhat unclear, because it isn't clear
> what it means "when tracking is finished".)
>
> --
Best Regards
Lawrence

[-- Attachment #2: Type: text/html, Size: 3984 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-05  6:40 ` Eli Zaretskii
  2019-10-07  4:33   ` Lawrence Liu
@ 2019-10-07 12:28   ` Andrii Kolomoiets
  2019-10-30 19:14     ` Andrii Kolomoiets
  1 sibling, 1 reply; 12+ messages in thread
From: Andrii Kolomoiets @ 2019-10-07 12:28 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1565 bytes --]

> On Oct 5, 2019, at 09:40, Eli Zaretskii <eliz@gnu.org> wrote:
> 
> Aren't users supposed to use pdb via "M-x pdb" instead?  (I don't use
> this, and don't debug Python programs, so maybe my question makes no
> sense.)

M-x pdb requires launch program in gud-mode while pdbtrack comint output
filter can be used in any buffer and mode, like interactive python
shell.

>> Please see attached patch. I certainly sure docstrings and naming are
>> not so good but they can be fine tuned later if the main idea will be
>> accepted.
> 
> Besides the question I asked above, your patch is too large to be
> accepted without assigning copyright to the FSF.  Would you like to
> start the legal paperwork rolling, so that any contributions from you
> could be accepted without limitations?

Yes, please.

>> +(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
>> +  "Pdb continue command."
>> +  :type 'list
>> +  :group 'python)
> 
> Each new defcustom should have a :version tag.  Also, if they belong
> to the group of the current file, our convention is not to use :group,
> as that's redundant.

Would it be better to create a separate subgroup for pdbtracking related
variables?

>> +(defcustom python-pdbtrack-kill-buffers t
>> +  "Kill buffers when tracking is finished.
>> +Only buffers opened during tracking will be killed."
> 
> The first sentence should be "If non-nil, kill buffers when tracking
> is finished."  (And that is somewhat unclear, because it isn't clear
> what it means "when tracking is finished".)

Please see updated patch.


[-- Attachment #2: pdb-track.patch --]
[-- Type: application/octet-stream, Size: 11179 bytes --]

diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ae5aff351c..8a0f12550e 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2795,7 +2795,6 @@ inferior-python-mode
   (set (make-local-variable 'comint-output-filter-functions)
        '(ansi-color-process-output
          python-shell-comint-watch-for-first-prompt-output-filter
-         python-pdbtrack-comint-output-filter-function
          python-comint-postoutput-scroll-to-bottom
          comint-watch-for-password-prompt))
   (set (make-local-variable 'compilation-error-regexp-alist)
@@ -2804,12 +2803,11 @@ inferior-python-mode
             #'python-shell-completion-at-point nil 'local)
   (define-key inferior-python-mode-map "\t"
     'python-shell-completion-complete-or-indent)
-  (make-local-variable 'python-pdbtrack-buffers-to-kill)
-  (make-local-variable 'python-pdbtrack-tracked-buffer)
   (make-local-variable 'python-shell-internal-last-output)
   (when python-shell-font-lock-enable
     (python-shell-font-lock-turn-on))
-  (compilation-shell-minor-mode 1))
+  (compilation-shell-minor-mode 1)
+  (python-pdbtrack-setup-tracking))
 
 (defun python-shell-make-comint (cmd proc-name &optional show internal)
   "Create a Python shell comint buffer.
@@ -3738,19 +3736,59 @@ python-shell-completion-complete-or-indent
 ;;; PDB Track integration
 
 (defcustom python-pdbtrack-activate t
-  "Non-nil makes Python shell enable pdbtracking."
+  "Non-nil makes Python shell enable pdbtracking.
+Pdbtracking would open the file for current stack frame found in pdb output by
+`python-pdbtrack-stacktrace-info-regexp' and add overlay arrow in currently
+inspected line in that file.
+
+After command listed in `python-pdbtrack-continue-command' or
+`python-pdbtrack-exit-command' is sent to pdb, pdbtracking session is
+considered over.  Overlay arrow will be removed from currentry tracked
+buffer.  Additionally, if `python-pdbtrack-kill-buffers' is non-nil, all
+files opened by pdbtracking will be killed."
   :type 'boolean
   :group 'python
   :safe 'booleanp)
 
 (defcustom python-pdbtrack-stacktrace-info-regexp
-  "> \\([^\"(<]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
+  "> \\([^\"(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
   "Regular expression matching stacktrace information.
 Used to extract the current line and module being inspected."
   :type 'string
-  :group 'python
+  :version "27.1"
   :safe 'stringp)
 
+(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
+  "Pdb 'continue' command aliases.
+After one of this commands is sent to pdb, pdbtracking session is
+considered over.
+
+This command is remembered by pdbtracking.  If next command sent to pdb
+is empty string, it considered 'continue' command if previous command
+was 'continue'.  This behavior slightly differentiate 'continue' command
+from 'exit' commands listed in `python-pdbtrack-exit-command'.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'list
+  :version "27.1")
+
+(defcustom python-pdbtrack-exit-command '("q" "quit" "exit")
+  "Pdb 'exit' command aliases.
+After one of this commands is sent to pdb, pdbtracking session is
+considered over.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'list
+  :version "27.1")
+
+(defcustom python-pdbtrack-kill-buffers t
+  "If non-nil, kill buffers when pdbtracking session is over.
+Only buffers opened by pdbtracking will be killed.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'boolean
+  :version "27.1")
+
 (defvar python-pdbtrack-tracked-buffer nil
   "Variable containing the value of the current tracked buffer.
 Never set this variable directly, use
@@ -3759,6 +3797,9 @@ python-pdbtrack-tracked-buffer
 (defvar python-pdbtrack-buffers-to-kill nil
   "List of buffers to be deleted after tracking finishes.")
 
+(defvar python-pdbtrack-prev-command-continue nil
+  "Is t if previous pdb command was 'continue'.")
+
 (defun python-pdbtrack-set-tracked-buffer (file-name)
   "Set the buffer for FILE-NAME as the tracked buffer.
 Internally it uses the `python-pdbtrack-tracked-buffer' variable.
@@ -3766,8 +3807,7 @@ python-pdbtrack-set-tracked-buffer
   (let* ((file-name-prospect (concat (file-remote-p default-directory)
                               file-name))
          (file-buffer (get-file-buffer file-name-prospect)))
-    (if file-buffer
-        (setq python-pdbtrack-tracked-buffer file-buffer)
+    (unless file-buffer
       (cond
        ((file-exists-p file-name-prospect)
         (setq file-buffer (find-file-noselect file-name-prospect)))
@@ -3775,10 +3815,55 @@ python-pdbtrack-set-tracked-buffer
              (file-exists-p file-name))
         ;; Fallback to a locally available copy of the file.
         (setq file-buffer (find-file-noselect file-name-prospect))))
-      (when (not (member file-buffer python-pdbtrack-buffers-to-kill))
+      (when (and python-pdbtrack-kill-buffers
+                 (not (member file-buffer python-pdbtrack-buffers-to-kill)))
         (add-to-list 'python-pdbtrack-buffers-to-kill file-buffer)))
+    (setq python-pdbtrack-tracked-buffer file-buffer)
     file-buffer))
 
+(defun python-pdbtrack-unset-tracked-buffer ()
+  "Untrack currently tracked buffer."
+  (when python-pdbtrack-tracked-buffer
+    (with-current-buffer python-pdbtrack-tracked-buffer
+      (set-marker overlay-arrow-position nil))
+    (setq python-pdbtrack-tracked-buffer nil)))
+
+(defun python-pdbtrack-tracking-finish ()
+  "Finish tracking."
+  (python-pdbtrack-unset-tracked-buffer)
+  (when python-pdbtrack-kill-buffers
+      (mapc #'(lambda (buffer)
+                (ignore-errors (kill-buffer buffer)))
+            python-pdbtrack-buffers-to-kill))
+  (setq python-pdbtrack-buffers-to-kill nil))
+
+(defun python-pdbtrack-process-sentinel (process _event)
+  "Untrack buffers when PROCESS is killed."
+  (unless (process-live-p process)
+    (let ((buffer (process-buffer process)))
+      (when (buffer-live-p buffer)
+        (with-current-buffer buffer
+          (python-pdbtrack-tracking-finish))))))
+
+(defun python-pdbtrack-comint-input-filter-function (input)
+  "Finish tracking session depending on command in INPUT.
+Commands that must finish tracking session is listed in
+`python-pdbtrack-untracking-commands'."
+  (when (and python-pdbtrack-tracked-buffer
+             ;; Empty input is sent by C-d or `comint-send-eof'
+             (or (string-empty-p input)
+                 ;; "n some text" is "n" command for pdb. Split input and get firs part
+                 (let* ((command (car (split-string (string-trim input) " "))))
+                   (setq python-pdbtrack-prev-command-continue
+                         (or (member command python-pdbtrack-continue-command)
+                             ;; if command is empty and previous command was 'continue'
+                             ;; then current command is 'continue' too.
+                             (and (string-empty-p command)
+                                  python-pdbtrack-prev-command-continue)))
+                   (or python-pdbtrack-prev-command-continue
+                       (member command python-pdbtrack-exit-command)))))
+    (python-pdbtrack-tracking-finish)))
+
 (defun python-pdbtrack-comint-output-filter-function (output)
   "Move overlay arrow to current pdb line in tracked buffer.
 Argument OUTPUT is a string with the output from the comint process."
@@ -3798,19 +3883,27 @@ python-pdbtrack-comint-output-filter-function
               ;; the _last_ stack frame printed in the most recent
               ;; batch of output, then jump to the corresponding
               ;; file/line number.
+              ;; Parse output only if at pdb prompt to avoid double code
+              ;; run in situation when output and pdb prompt received in
+              ;; different hunks
               (goto-char (point-max))
-              (when (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t)
+              (goto-char (line-beginning-position))
+              (when (and (looking-at python-shell-prompt-pdb-regexp)
+                         (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t))
                 (setq line-number (string-to-number
                                    (match-string-no-properties 2)))
                 (match-string-no-properties 1)))))
-      (if (and file-name line-number)
-          (let* ((tracked-buffer
-                  (python-pdbtrack-set-tracked-buffer file-name))
+      (when (and file-name line-number)
+        (if (string-prefix-p "<" file-name)
+            ;; Finish tracking session if stacktrace info is like
+            ;; "> <stdin>(1)<module>()->None"
+            (python-pdbtrack-tracking-finish)
+          (python-pdbtrack-unset-tracked-buffer)
+          (let* ((tracked-buffer (python-pdbtrack-set-tracked-buffer file-name))
                  (shell-buffer (current-buffer))
                  (tracked-buffer-window (get-buffer-window tracked-buffer))
                  (tracked-buffer-line-pos))
             (with-current-buffer tracked-buffer
-              (set (make-local-variable 'overlay-arrow-string) "=>")
               (set (make-local-variable 'overlay-arrow-position) (make-marker))
               (setq tracked-buffer-line-pos (progn
                                               (goto-char (point-min))
@@ -3821,17 +3914,21 @@ python-pdbtrack-comint-output-filter-function
                  tracked-buffer-window tracked-buffer-line-pos))
               (set-marker overlay-arrow-position tracked-buffer-line-pos))
             (pop-to-buffer tracked-buffer)
-            (switch-to-buffer-other-window shell-buffer))
-        (when python-pdbtrack-tracked-buffer
-          (with-current-buffer python-pdbtrack-tracked-buffer
-            (set-marker overlay-arrow-position nil))
-          (mapc #'(lambda (buffer)
-                    (ignore-errors (kill-buffer buffer)))
-                python-pdbtrack-buffers-to-kill)
-          (setq python-pdbtrack-tracked-buffer nil
-                python-pdbtrack-buffers-to-kill nil)))))
+            (switch-to-buffer-other-window shell-buffer))))))
   output)
 
+(defun python-pdbtrack-setup-tracking ()
+  "Setup pdb tracking in current buffer."
+  (make-local-variable 'python-pdbtrack-buffers-to-kill)
+  (make-local-variable 'python-pdbtrack-tracked-buffer)
+  (add-to-list (make-local-variable 'comint-input-filter-functions)
+               #'python-pdbtrack-comint-input-filter-function)
+  (add-to-list (make-local-variable 'comint-output-filter-functions)
+               #'python-pdbtrack-comint-output-filter-function)
+  (add-function :before (process-sentinel (get-buffer-process (current-buffer)))
+                #'python-pdbtrack-process-sentinel)
+  (add-hook 'kill-buffer-hook #'python-pdbtrack-tracking-finish nil t))
+
 \f
 ;;; Symbol completion
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-07  4:33   ` Lawrence Liu
@ 2019-10-07 16:19     ` Eli Zaretskii
  2019-10-07 16:26       ` Lawrence Liu
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2019-10-07 16:19 UTC (permalink / raw)
  To: Lawrence Liu; +Cc: andreyk.mad, emacs-devel

> From: Lawrence Liu <smartlitchi@gmail.com>
> Date: Mon, 7 Oct 2019 12:33:17 +0800
> Cc: Andrii Kolomoiets <andreyk.mad@gmail.com>, emacs-devel@gnu.org
> 
> I am a full time python developer and seems in my case mostly I am using the way as below:
> 
> insert a 
> 
> import pdb; pdb.set_trace();
> 
> in my code bass and trigger the break point from other place (mostly browser) and wait for the break point
> been hit. 

Any reason you don't use "M-x pdb" instead?



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-07 16:19     ` Eli Zaretskii
@ 2019-10-07 16:26       ` Lawrence Liu
  0 siblings, 0 replies; 12+ messages in thread
From: Lawrence Liu @ 2019-10-07 16:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: andreyk.mad, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 932 bytes --]

I think the main reason is because sometimes,

the entires of our program is not a python file, it might be launch of a
docker image, a gunicorn application, even a background task etc. or it
might be wrapped by some 3rd launcher.

And sometimes it will coming through many steps before hit the break point.


Eli Zaretskii <eliz@gnu.org>于2019年10月8日 周二00:19写道:

> > From: Lawrence Liu <smartlitchi@gmail.com>
> > Date: Mon, 7 Oct 2019 12:33:17 +0800
> > Cc: Andrii Kolomoiets <andreyk.mad@gmail.com>, emacs-devel@gnu.org
> >
> > I am a full time python developer and seems in my case mostly I am using
> the way as below:
> >
> > insert a
> >
> > import pdb; pdb.set_trace();
> >
> > in my code bass and trigger the break point from other place (mostly
> browser) and wait for the break point
> > been hit.
>
> Any reason you don't use "M-x pdb" instead?
>
-- 
Best Regards
Lawrence

[-- Attachment #2: Type: text/html, Size: 1670 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-07 12:28   ` Andrii Kolomoiets
@ 2019-10-30 19:14     ` Andrii Kolomoiets
  2019-11-01  9:35       ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Andrii Kolomoiets @ 2019-10-30 19:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On 7 Oct 2019, at 15:28, Andrii Kolomoiets <andreyk.mad@gmail.com> wrote:
> 
>> On Oct 5, 2019, at 09:40, Eli Zaretskii <eliz@gnu.org> wrote:
>> 
>> Besides the question I asked above, your patch is too large to be
>> accepted without assigning copyright to the FSF.  Would you like to
>> start the legal paperwork rolling, so that any contributions from you
>> could be accepted without limitations?
> 
> Yes, please.

Copyright paperwork is done.




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-10-30 19:14     ` Andrii Kolomoiets
@ 2019-11-01  9:35       ` Eli Zaretskii
  2019-11-02 16:37         ` Andrii Kolomoiets
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2019-11-01  9:35 UTC (permalink / raw)
  To: Andrii Kolomoiets; +Cc: emacs-devel

> From: Andrii Kolomoiets <andreyk.mad@gmail.com>
> Date: Wed, 30 Oct 2019 21:14:38 +0200
> Cc: emacs-devel@gnu.org
> 
> Copyright paperwork is done.

Thanks.

Can you please add:

  . Commit log message formatted according to instructions in
    CONTRIBUTE
  . Suitable short entry for NEWS about the new options

Also, I don't see any rationale for changing
python-pdbtrack-stacktrace-info-regexp; can you tell why you needed
that?



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-11-01  9:35       ` Eli Zaretskii
@ 2019-11-02 16:37         ` Andrii Kolomoiets
  2019-11-02 17:29           ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Andrii Kolomoiets @ 2019-11-02 16:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 782 bytes --]

On 1 Nov 2019, at 11:35, Eli Zaretskii <eliz@gnu.org> wrote:
> Can you please add:
> 
>  . Commit log message formatted according to instructions in
>    CONTRIBUTE
>  . Suitable short entry for NEWS about the new options

Please see attached updated patch.

> Also, I don't see any rationale for changing
> python-pdbtrack-stacktrace-info-regexp; can you tell why you needed
> that?

Current python-pdbtrack-stacktrace-info-regexp match only lines with real
filenames, like:
  > /Users/mad/test.py(3)<module>()->None

Pdb command "next" can bring us to upper stack frame, like:
  > <stdin>(1)<module>()->None

At this point pdbtracking session can be considered over.  And new
python-pdbtrack-stacktrace-info-regexp can match such lines with "<stdin>"
or "<string>" as filenames.


[-- Attachment #2: 0001-python.el-Pdbtracking-improvements.patch --]
[-- Type: application/octet-stream, Size: 13004 bytes --]

From 705dd66d5e46d115cda71abb856d68cea3f8f70c Mon Sep 17 00:00:00 2001
From: Andrii Kolomoiets <andreyk.mad@gmail.com>
Date: Sat, 2 Nov 2019 18:08:13 +0200
Subject: [PATCH] python.el: Pdbtracking improvements

Allow to not kill buffers when pdbtracking session is finished.
Pdbtracking session consider finished judging from the user input.

* lisp/progmodes/python.el (python-pdbtrack-kill-buffers): New
customizable variable.
(python-pdbtrack-set-tracked-buffer): Use it.
(python-pdbtrack-unset-tracked-buffer, python-pdbtrack-tracking-finish): New
functions.
(python-pdbtrack-continue-command, python-pdbtrack-exit-command): New
customizable variables.
(python-pdbtrack-process-sentinel): New function.  Finish pdbtracking session
when process is killed.
(python-pdbtrack-prev-command-continue): New variable.
(python-pdbtrack-comint-input-filter-function): New function.  Finish
pdbtracking session based on commands sent to pdb.
(python-pdbtrack-comint-output-filter-function): Unset/set tracking buffer if
looking at pdb prompt; finish pdbtracking session if filename of current
stack frame starts with "<" e.g. "<stdin>".
(python-pdbtrack-comint-output-filter-function): Don't override
overlay-arrow-string.
(python-pdbtrack-setup-tracking): New function.
(inferior-python-mode): Use it.
; * etc/NEWS: Mention python-pdbtrack-kill-buffers

diff --git a/etc/NEWS b/etc/NEWS
index 7a76d90ed5..903a991a1f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1389,6 +1389,11 @@ unescaping text.
 The maximum level is used by default; customize
 'font-lock-maximum-decoration' to tone down the decoration.

+---
+*** New user option 'python-pdbtrack-kill-buffers'.
+If nil, buffers opened during pdbtracking session is not killed when
+pdbtracking session is finished.
+
 ** Help

 ---
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index bdc0f1cd96..b217f6cfde 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2785,7 +2785,6 @@ inferior-python-mode
   (set (make-local-variable 'comint-output-filter-functions)
        '(ansi-color-process-output
          python-shell-comint-watch-for-first-prompt-output-filter
-         python-pdbtrack-comint-output-filter-function
          python-comint-postoutput-scroll-to-bottom
          comint-watch-for-password-prompt))
   (set (make-local-variable 'compilation-error-regexp-alist)
@@ -2794,12 +2793,11 @@ inferior-python-mode
             #'python-shell-completion-at-point nil 'local)
   (define-key inferior-python-mode-map "\t"
     'python-shell-completion-complete-or-indent)
-  (make-local-variable 'python-pdbtrack-buffers-to-kill)
-  (make-local-variable 'python-pdbtrack-tracked-buffer)
   (make-local-variable 'python-shell-internal-last-output)
   (when python-shell-font-lock-enable
     (python-shell-font-lock-turn-on))
-  (compilation-shell-minor-mode 1))
+  (compilation-shell-minor-mode 1)
+  (python-pdbtrack-setup-tracking))

 (defun python-shell-make-comint (cmd proc-name &optional show internal)
   "Create a Python shell comint buffer.
@@ -3728,19 +3726,59 @@ python-shell-completion-complete-or-indent
 ;;; PDB Track integration

 (defcustom python-pdbtrack-activate t
-  "Non-nil makes Python shell enable pdbtracking."
+  "Non-nil makes Python shell enable pdbtracking.
+Pdbtracking would open the file for current stack frame found in pdb output by
+`python-pdbtrack-stacktrace-info-regexp' and add overlay arrow in currently
+inspected line in that file.
+
+After command listed in `python-pdbtrack-continue-command' or
+`python-pdbtrack-exit-command' is sent to pdb, pdbtracking session is
+considered over.  Overlay arrow will be removed from currentry tracked
+buffer.  Additionally, if `python-pdbtrack-kill-buffers' is non-nil, all
+files opened by pdbtracking will be killed."
   :type 'boolean
   :group 'python
   :safe 'booleanp)

 (defcustom python-pdbtrack-stacktrace-info-regexp
-  "> \\([^\"(<]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
+  "> \\([^\"(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
   "Regular expression matching stacktrace information.
 Used to extract the current line and module being inspected."
   :type 'string
-  :group 'python
+  :version "27.1"
   :safe 'stringp)

+(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
+  "Pdb 'continue' command aliases.
+After one of this commands is sent to pdb, pdbtracking session is
+considered over.
+
+This command is remembered by pdbtracking.  If next command sent to pdb
+is empty string, it considered 'continue' command if previous command
+was 'continue'.  This behavior slightly differentiate 'continue' command
+from 'exit' commands listed in `python-pdbtrack-exit-command'.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'list
+  :version "27.1")
+
+(defcustom python-pdbtrack-exit-command '("q" "quit" "exit")
+  "Pdb 'exit' command aliases.
+After one of this commands is sent to pdb, pdbtracking session is
+considered over.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'list
+  :version "27.1")
+
+(defcustom python-pdbtrack-kill-buffers t
+  "If non-nil, kill buffers when pdbtracking session is over.
+Only buffers opened by pdbtracking will be killed.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'boolean
+  :version "27.1")
+
 (defvar python-pdbtrack-tracked-buffer nil
   "Variable containing the value of the current tracked buffer.
 Never set this variable directly, use
@@ -3749,6 +3787,9 @@ python-pdbtrack-tracked-buffer
 (defvar python-pdbtrack-buffers-to-kill nil
   "List of buffers to be deleted after tracking finishes.")

+(defvar python-pdbtrack-prev-command-continue nil
+  "Is t if previous pdb command was 'continue'.")
+
 (defun python-pdbtrack-set-tracked-buffer (file-name)
   "Set the buffer for FILE-NAME as the tracked buffer.
 Internally it uses the `python-pdbtrack-tracked-buffer' variable.
@@ -3756,8 +3797,7 @@ python-pdbtrack-set-tracked-buffer
   (let* ((file-name-prospect (concat (file-remote-p default-directory)
                               file-name))
          (file-buffer (get-file-buffer file-name-prospect)))
-    (if file-buffer
-        (setq python-pdbtrack-tracked-buffer file-buffer)
+    (unless file-buffer
       (cond
        ((file-exists-p file-name-prospect)
         (setq file-buffer (find-file-noselect file-name-prospect)))
@@ -3765,10 +3805,55 @@ python-pdbtrack-set-tracked-buffer
              (file-exists-p file-name))
         ;; Fallback to a locally available copy of the file.
         (setq file-buffer (find-file-noselect file-name-prospect))))
-      (when (not (member file-buffer python-pdbtrack-buffers-to-kill))
+      (when (and python-pdbtrack-kill-buffers
+                 (not (member file-buffer python-pdbtrack-buffers-to-kill)))
         (add-to-list 'python-pdbtrack-buffers-to-kill file-buffer)))
+    (setq python-pdbtrack-tracked-buffer file-buffer)
     file-buffer))

+(defun python-pdbtrack-unset-tracked-buffer ()
+  "Untrack currently tracked buffer."
+  (when python-pdbtrack-tracked-buffer
+    (with-current-buffer python-pdbtrack-tracked-buffer
+      (set-marker overlay-arrow-position nil))
+    (setq python-pdbtrack-tracked-buffer nil)))
+
+(defun python-pdbtrack-tracking-finish ()
+  "Finish tracking."
+  (python-pdbtrack-unset-tracked-buffer)
+  (when python-pdbtrack-kill-buffers
+      (mapc #'(lambda (buffer)
+                (ignore-errors (kill-buffer buffer)))
+            python-pdbtrack-buffers-to-kill))
+  (setq python-pdbtrack-buffers-to-kill nil))
+
+(defun python-pdbtrack-process-sentinel (process _event)
+  "Untrack buffers when PROCESS is killed."
+  (unless (process-live-p process)
+    (let ((buffer (process-buffer process)))
+      (when (buffer-live-p buffer)
+        (with-current-buffer buffer
+          (python-pdbtrack-tracking-finish))))))
+
+(defun python-pdbtrack-comint-input-filter-function (input)
+  "Finish tracking session depending on command in INPUT.
+Commands that must finish tracking session is listed in
+`python-pdbtrack-untracking-commands'."
+  (when (and python-pdbtrack-tracked-buffer
+             ;; Empty input is sent by C-d or `comint-send-eof'
+             (or (string-empty-p input)
+                 ;; "n some text" is "n" command for pdb. Split input and get firs part
+                 (let* ((command (car (split-string (string-trim input) " "))))
+                   (setq python-pdbtrack-prev-command-continue
+                         (or (member command python-pdbtrack-continue-command)
+                             ;; if command is empty and previous command was 'continue'
+                             ;; then current command is 'continue' too.
+                             (and (string-empty-p command)
+                                  python-pdbtrack-prev-command-continue)))
+                   (or python-pdbtrack-prev-command-continue
+                       (member command python-pdbtrack-exit-command)))))
+    (python-pdbtrack-tracking-finish)))
+
 (defun python-pdbtrack-comint-output-filter-function (output)
   "Move overlay arrow to current pdb line in tracked buffer.
 Argument OUTPUT is a string with the output from the comint process."
@@ -3788,19 +3873,27 @@ python-pdbtrack-comint-output-filter-function
               ;; the _last_ stack frame printed in the most recent
               ;; batch of output, then jump to the corresponding
               ;; file/line number.
+              ;; Parse output only if at pdb prompt to avoid double code
+              ;; run in situation when output and pdb prompt received in
+              ;; different hunks
               (goto-char (point-max))
-              (when (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t)
+              (goto-char (line-beginning-position))
+              (when (and (looking-at python-shell-prompt-pdb-regexp)
+                         (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t))
                 (setq line-number (string-to-number
                                    (match-string-no-properties 2)))
                 (match-string-no-properties 1)))))
-      (if (and file-name line-number)
-          (let* ((tracked-buffer
-                  (python-pdbtrack-set-tracked-buffer file-name))
+      (when (and file-name line-number)
+        (if (string-prefix-p "<" file-name)
+            ;; Finish tracking session if stacktrace info is like
+            ;; "> <stdin>(1)<module>()->None"
+            (python-pdbtrack-tracking-finish)
+          (python-pdbtrack-unset-tracked-buffer)
+          (let* ((tracked-buffer (python-pdbtrack-set-tracked-buffer file-name))
                  (shell-buffer (current-buffer))
                  (tracked-buffer-window (get-buffer-window tracked-buffer))
                  (tracked-buffer-line-pos))
             (with-current-buffer tracked-buffer
-              (set (make-local-variable 'overlay-arrow-string) "=>")
               (set (make-local-variable 'overlay-arrow-position) (make-marker))
               (setq tracked-buffer-line-pos (progn
                                               (goto-char (point-min))
@@ -3811,17 +3904,21 @@ python-pdbtrack-comint-output-filter-function
                  tracked-buffer-window tracked-buffer-line-pos))
               (set-marker overlay-arrow-position tracked-buffer-line-pos))
             (pop-to-buffer tracked-buffer)
-            (switch-to-buffer-other-window shell-buffer))
-        (when python-pdbtrack-tracked-buffer
-          (with-current-buffer python-pdbtrack-tracked-buffer
-            (set-marker overlay-arrow-position nil))
-          (mapc #'(lambda (buffer)
-                    (ignore-errors (kill-buffer buffer)))
-                python-pdbtrack-buffers-to-kill)
-          (setq python-pdbtrack-tracked-buffer nil
-                python-pdbtrack-buffers-to-kill nil)))))
+            (switch-to-buffer-other-window shell-buffer))))))
   output)

+(defun python-pdbtrack-setup-tracking ()
+  "Setup pdb tracking in current buffer."
+  (make-local-variable 'python-pdbtrack-buffers-to-kill)
+  (make-local-variable 'python-pdbtrack-tracked-buffer)
+  (add-to-list (make-local-variable 'comint-input-filter-functions)
+               #'python-pdbtrack-comint-input-filter-function)
+  (add-to-list (make-local-variable 'comint-output-filter-functions)
+               #'python-pdbtrack-comint-output-filter-function)
+  (add-function :before (process-sentinel (get-buffer-process (current-buffer)))
+                #'python-pdbtrack-process-sentinel)
+  (add-hook 'kill-buffer-hook #'python-pdbtrack-tracking-finish nil t))
+
 \f
 ;;; Symbol completion

--
2.15.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-11-02 16:37         ` Andrii Kolomoiets
@ 2019-11-02 17:29           ` Eli Zaretskii
  2019-11-02 18:51             ` Andrii Kolomoiets
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2019-11-02 17:29 UTC (permalink / raw)
  To: Andrii Kolomoiets; +Cc: emacs-devel

> From: Andrii Kolomoiets <andreyk.mad@gmail.com>
> Date: Sat, 2 Nov 2019 18:37:26 +0200
> Cc: emacs-devel@gnu.org
> 
> On 1 Nov 2019, at 11:35, Eli Zaretskii <eliz@gnu.org> wrote:
> > Can you please add:
> > 
> >  . Commit log message formatted according to instructions in
> >    CONTRIBUTE
> >  . Suitable short entry for NEWS about the new options
> 
> Please see attached updated patch.

Thanks.

> Current python-pdbtrack-stacktrace-info-regexp match only lines with real
> filenames, like:
>   > /Users/mad/test.py(3)<module>()->None
> 
> Pdb command "next" can bring us to upper stack frame, like:
>   > <stdin>(1)<module>()->None

OK, but the change in that variable should be called out in the log
entry, so please add that, together with the explanation above.  Maybe
also add a comment before the variable to explain what it needs to
match.

> +*** New user option 'python-pdbtrack-kill-buffers'.
> +If nil, buffers opened during pdbtracking session is not killed when
                                                     ^^
"are", plural.

Thanks.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-11-02 17:29           ` Eli Zaretskii
@ 2019-11-02 18:51             ` Andrii Kolomoiets
  2019-11-07 16:57               ` Eli Zaretskii
  0 siblings, 1 reply; 12+ messages in thread
From: Andrii Kolomoiets @ 2019-11-02 18:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 822 bytes --]

On 2 Nov 2019, at 19:29, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>> Current python-pdbtrack-stacktrace-info-regexp match only lines with real
>> filenames, like:
>>> /Users/mad/test.py(3)<module>()->None
>> 
>> Pdb command "next" can bring us to upper stack frame, like:
>>> <stdin>(1)<module>()->None
> 
> OK, but the change in that variable should be called out in the log
> entry, so please add that, together with the explanation above.  Maybe
> also add a comment before the variable to explain what it needs to
> match.

Explanation is added to python-pdbtrack-stacktrace-info-regexp docstring.

>> +*** New user option 'python-pdbtrack-kill-buffers'.
>> +If nil, buffers opened during pdbtracking session is not killed when
>                                                     ^^
> "are", plural.

Fixed.

Thanks.


[-- Attachment #2: 0001-python.el-Pdbtracking-improvements.patch --]
[-- Type: application/octet-stream, Size: 13744 bytes --]

From 6a8b5db07acd7c1b61c98d71edb299d2f4f2e6ed Mon Sep 17 00:00:00 2001
From: Andrii Kolomoiets <andreyk.mad@gmail.com>
Date: Sat, 2 Nov 2019 18:08:13 +0200
Subject: [PATCH] python.el: Pdbtracking improvements

Allow to not kill buffers when pdbtracking session is finished.
Pdbtracking session consider finished judging from the user input.

* lisp/progmodes/python.el (python-pdbtrack-kill-buffers): New
customizable variable.
(python-pdbtrack-set-tracked-buffer): Use it.
(python-pdbtrack-unset-tracked-buffer, python-pdbtrack-tracking-finish): New
functions.
(python-pdbtrack-continue-command, python-pdbtrack-exit-command): New
customizable variables.
(python-pdbtrack-process-sentinel): New function.  Finish pdbtracking session
when process is killed.
(python-pdbtrack-prev-command-continue): New variable.
(python-pdbtrack-comint-input-filter-function): New function.  Finish
pdbtracking session based on commands sent to pdb.
(python-pdbtrack-comint-output-filter-function): Unset/set tracking buffer if
looking at pdb prompt; finish pdbtracking session if filename of current
stack frame starts with "<" e.g. "<stdin>".
(python-pdbtrack-comint-output-filter-function): Don't override
overlay-arrow-string.
(python-pdbtrack-setup-tracking): New function.
(inferior-python-mode): Use it.
(python-pdbtrack-stacktrace-info-regexp): Default value is changed.  Must also
match lines with filename like "<stdin>" and "<string>".
; * etc/NEWS: Mention python-pdbtrack-kill-buffers

diff --git a/etc/NEWS b/etc/NEWS
index 7a76d90ed5..eae666eff6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1389,6 +1389,11 @@ unescaping text.
 The maximum level is used by default; customize
 'font-lock-maximum-decoration' to tone down the decoration.
 
+---
+*** New user option 'python-pdbtrack-kill-buffers'.
+If nil, buffers opened during pdbtracking session are not killed when
+pdbtracking session is finished.
+
 ** Help
 
 ---
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index bdc0f1cd96..e672645c73 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2785,7 +2785,6 @@ inferior-python-mode
   (set (make-local-variable 'comint-output-filter-functions)
        '(ansi-color-process-output
          python-shell-comint-watch-for-first-prompt-output-filter
-         python-pdbtrack-comint-output-filter-function
          python-comint-postoutput-scroll-to-bottom
          comint-watch-for-password-prompt))
   (set (make-local-variable 'compilation-error-regexp-alist)
@@ -2794,12 +2793,11 @@ inferior-python-mode
             #'python-shell-completion-at-point nil 'local)
   (define-key inferior-python-mode-map "\t"
     'python-shell-completion-complete-or-indent)
-  (make-local-variable 'python-pdbtrack-buffers-to-kill)
-  (make-local-variable 'python-pdbtrack-tracked-buffer)
   (make-local-variable 'python-shell-internal-last-output)
   (when python-shell-font-lock-enable
     (python-shell-font-lock-turn-on))
-  (compilation-shell-minor-mode 1))
+  (compilation-shell-minor-mode 1)
+  (python-pdbtrack-setup-tracking))
 
 (defun python-shell-make-comint (cmd proc-name &optional show internal)
   "Create a Python shell comint buffer.
@@ -3728,19 +3726,72 @@ python-shell-completion-complete-or-indent
 ;;; PDB Track integration
 
 (defcustom python-pdbtrack-activate t
-  "Non-nil makes Python shell enable pdbtracking."
+  "Non-nil makes Python shell enable pdbtracking.
+Pdbtracking would open the file for current stack frame found in pdb output by
+`python-pdbtrack-stacktrace-info-regexp' and add overlay arrow in currently
+inspected line in that file.
+
+After command listed in `python-pdbtrack-continue-command' or
+`python-pdbtrack-exit-command' is sent to pdb, pdbtracking session is
+considered over.  Overlay arrow will be removed from currentry tracked
+buffer.  Additionally, if `python-pdbtrack-kill-buffers' is non-nil, all
+files opened by pdbtracking will be killed."
   :type 'boolean
   :group 'python
   :safe 'booleanp)
 
 (defcustom python-pdbtrack-stacktrace-info-regexp
-  "> \\([^\"(<]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
+  "> \\([^\"(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_<>]+\\)()"
   "Regular expression matching stacktrace information.
-Used to extract the current line and module being inspected."
+Used to extract the current line and module being inspected.
+
+Must match lines with real filename, like
+ > /path/to/file.py(42)<module>()->None
+and lines in which filename starts with '<', e.g.
+ > <stdin>(1)<module>()->None
+
+In the first case /path/to/file.py file will be visited and overlay icon
+will be placed in line 42.
+In the second case pdbtracking session will be considered over because
+the top stack frame has been reached.
+
+Filename is expected in the first parenthesized expression.
+Line number is expected in the second parenthesized expression."
   :type 'string
-  :group 'python
+  :version "27.1"
   :safe 'stringp)
 
+(defcustom python-pdbtrack-continue-command '("c" "cont" "continue")
+  "Pdb 'continue' command aliases.
+After one of this commands is sent to pdb, pdbtracking session is
+considered over.
+
+This command is remembered by pdbtracking.  If next command sent to pdb
+is empty string, it considered 'continue' command if previous command
+was 'continue'.  This behavior slightly differentiate 'continue' command
+from 'exit' commands listed in `python-pdbtrack-exit-command'.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'list
+  :version "27.1")
+
+(defcustom python-pdbtrack-exit-command '("q" "quit" "exit")
+  "Pdb 'exit' command aliases.
+After one of this commands is sent to pdb, pdbtracking session is
+considered over.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'list
+  :version "27.1")
+
+(defcustom python-pdbtrack-kill-buffers t
+  "If non-nil, kill buffers when pdbtracking session is over.
+Only buffers opened by pdbtracking will be killed.
+
+See `python-pdbtrack-activate' for pdbtracking session overview."
+  :type 'boolean
+  :version "27.1")
+
 (defvar python-pdbtrack-tracked-buffer nil
   "Variable containing the value of the current tracked buffer.
 Never set this variable directly, use
@@ -3749,6 +3800,9 @@ python-pdbtrack-tracked-buffer
 (defvar python-pdbtrack-buffers-to-kill nil
   "List of buffers to be deleted after tracking finishes.")
 
+(defvar python-pdbtrack-prev-command-continue nil
+  "Is t if previous pdb command was 'continue'.")
+
 (defun python-pdbtrack-set-tracked-buffer (file-name)
   "Set the buffer for FILE-NAME as the tracked buffer.
 Internally it uses the `python-pdbtrack-tracked-buffer' variable.
@@ -3756,8 +3810,7 @@ python-pdbtrack-set-tracked-buffer
   (let* ((file-name-prospect (concat (file-remote-p default-directory)
                               file-name))
          (file-buffer (get-file-buffer file-name-prospect)))
-    (if file-buffer
-        (setq python-pdbtrack-tracked-buffer file-buffer)
+    (unless file-buffer
       (cond
        ((file-exists-p file-name-prospect)
         (setq file-buffer (find-file-noselect file-name-prospect)))
@@ -3765,10 +3818,55 @@ python-pdbtrack-set-tracked-buffer
              (file-exists-p file-name))
         ;; Fallback to a locally available copy of the file.
         (setq file-buffer (find-file-noselect file-name-prospect))))
-      (when (not (member file-buffer python-pdbtrack-buffers-to-kill))
+      (when (and python-pdbtrack-kill-buffers
+                 (not (member file-buffer python-pdbtrack-buffers-to-kill)))
         (add-to-list 'python-pdbtrack-buffers-to-kill file-buffer)))
+    (setq python-pdbtrack-tracked-buffer file-buffer)
     file-buffer))
 
+(defun python-pdbtrack-unset-tracked-buffer ()
+  "Untrack currently tracked buffer."
+  (when python-pdbtrack-tracked-buffer
+    (with-current-buffer python-pdbtrack-tracked-buffer
+      (set-marker overlay-arrow-position nil))
+    (setq python-pdbtrack-tracked-buffer nil)))
+
+(defun python-pdbtrack-tracking-finish ()
+  "Finish tracking."
+  (python-pdbtrack-unset-tracked-buffer)
+  (when python-pdbtrack-kill-buffers
+      (mapc #'(lambda (buffer)
+                (ignore-errors (kill-buffer buffer)))
+            python-pdbtrack-buffers-to-kill))
+  (setq python-pdbtrack-buffers-to-kill nil))
+
+(defun python-pdbtrack-process-sentinel (process _event)
+  "Untrack buffers when PROCESS is killed."
+  (unless (process-live-p process)
+    (let ((buffer (process-buffer process)))
+      (when (buffer-live-p buffer)
+        (with-current-buffer buffer
+          (python-pdbtrack-tracking-finish))))))
+
+(defun python-pdbtrack-comint-input-filter-function (input)
+  "Finish tracking session depending on command in INPUT.
+Commands that must finish tracking session is listed in
+`python-pdbtrack-untracking-commands'."
+  (when (and python-pdbtrack-tracked-buffer
+             ;; Empty input is sent by C-d or `comint-send-eof'
+             (or (string-empty-p input)
+                 ;; "n some text" is "n" command for pdb. Split input and get firs part
+                 (let* ((command (car (split-string (string-trim input) " "))))
+                   (setq python-pdbtrack-prev-command-continue
+                         (or (member command python-pdbtrack-continue-command)
+                             ;; if command is empty and previous command was 'continue'
+                             ;; then current command is 'continue' too.
+                             (and (string-empty-p command)
+                                  python-pdbtrack-prev-command-continue)))
+                   (or python-pdbtrack-prev-command-continue
+                       (member command python-pdbtrack-exit-command)))))
+    (python-pdbtrack-tracking-finish)))
+
 (defun python-pdbtrack-comint-output-filter-function (output)
   "Move overlay arrow to current pdb line in tracked buffer.
 Argument OUTPUT is a string with the output from the comint process."
@@ -3788,19 +3886,27 @@ python-pdbtrack-comint-output-filter-function
               ;; the _last_ stack frame printed in the most recent
               ;; batch of output, then jump to the corresponding
               ;; file/line number.
+              ;; Parse output only if at pdb prompt to avoid double code
+              ;; run in situation when output and pdb prompt received in
+              ;; different hunks
               (goto-char (point-max))
-              (when (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t)
+              (goto-char (line-beginning-position))
+              (when (and (looking-at python-shell-prompt-pdb-regexp)
+                         (re-search-backward python-pdbtrack-stacktrace-info-regexp nil t))
                 (setq line-number (string-to-number
                                    (match-string-no-properties 2)))
                 (match-string-no-properties 1)))))
-      (if (and file-name line-number)
-          (let* ((tracked-buffer
-                  (python-pdbtrack-set-tracked-buffer file-name))
+      (when (and file-name line-number)
+        (if (string-prefix-p "<" file-name)
+            ;; Finish tracking session if stacktrace info is like
+            ;; "> <stdin>(1)<module>()->None"
+            (python-pdbtrack-tracking-finish)
+          (python-pdbtrack-unset-tracked-buffer)
+          (let* ((tracked-buffer (python-pdbtrack-set-tracked-buffer file-name))
                  (shell-buffer (current-buffer))
                  (tracked-buffer-window (get-buffer-window tracked-buffer))
                  (tracked-buffer-line-pos))
             (with-current-buffer tracked-buffer
-              (set (make-local-variable 'overlay-arrow-string) "=>")
               (set (make-local-variable 'overlay-arrow-position) (make-marker))
               (setq tracked-buffer-line-pos (progn
                                               (goto-char (point-min))
@@ -3811,17 +3917,21 @@ python-pdbtrack-comint-output-filter-function
                  tracked-buffer-window tracked-buffer-line-pos))
               (set-marker overlay-arrow-position tracked-buffer-line-pos))
             (pop-to-buffer tracked-buffer)
-            (switch-to-buffer-other-window shell-buffer))
-        (when python-pdbtrack-tracked-buffer
-          (with-current-buffer python-pdbtrack-tracked-buffer
-            (set-marker overlay-arrow-position nil))
-          (mapc #'(lambda (buffer)
-                    (ignore-errors (kill-buffer buffer)))
-                python-pdbtrack-buffers-to-kill)
-          (setq python-pdbtrack-tracked-buffer nil
-                python-pdbtrack-buffers-to-kill nil)))))
+            (switch-to-buffer-other-window shell-buffer))))))
   output)
 
+(defun python-pdbtrack-setup-tracking ()
+  "Setup pdb tracking in current buffer."
+  (make-local-variable 'python-pdbtrack-buffers-to-kill)
+  (make-local-variable 'python-pdbtrack-tracked-buffer)
+  (add-to-list (make-local-variable 'comint-input-filter-functions)
+               #'python-pdbtrack-comint-input-filter-function)
+  (add-to-list (make-local-variable 'comint-output-filter-functions)
+               #'python-pdbtrack-comint-output-filter-function)
+  (add-function :before (process-sentinel (get-buffer-process (current-buffer)))
+                #'python-pdbtrack-process-sentinel)
+  (add-hook 'kill-buffer-hook #'python-pdbtrack-tracking-finish nil t))
+
 \f
 ;;; Symbol completion
 
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: python: Let pdb tracking not kill buffers
  2019-11-02 18:51             ` Andrii Kolomoiets
@ 2019-11-07 16:57               ` Eli Zaretskii
  0 siblings, 0 replies; 12+ messages in thread
From: Eli Zaretskii @ 2019-11-07 16:57 UTC (permalink / raw)
  To: Andrii Kolomoiets; +Cc: emacs-devel

> From: Andrii Kolomoiets <andreyk.mad@gmail.com>
> Date: Sat, 2 Nov 2019 20:51:13 +0200
> Cc: emacs-devel@gnu.org
> 
> On 2 Nov 2019, at 19:29, Eli Zaretskii <eliz@gnu.org> wrote:
> > 
> >> Current python-pdbtrack-stacktrace-info-regexp match only lines with real
> >> filenames, like:
> >>> /Users/mad/test.py(3)<module>()->None
> >> 
> >> Pdb command "next" can bring us to upper stack frame, like:
> >>> <stdin>(1)<module>()->None
> > 
> > OK, but the change in that variable should be called out in the log
> > entry, so please add that, together with the explanation above.  Maybe
> > also add a comment before the variable to explain what it needs to
> > match.
> 
> Explanation is added to python-pdbtrack-stacktrace-info-regexp docstring.
> 
> >> +*** New user option 'python-pdbtrack-kill-buffers'.
> >> +If nil, buffers opened during pdbtracking session is not killed when
> >                                                     ^^
> > "are", plural.
> 
> Fixed.

Thanks, pushed.



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2019-11-07 16:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-04 20:32 python: Let pdb tracking not kill buffers Andrii Kolomoiets
2019-10-05  6:40 ` Eli Zaretskii
2019-10-07  4:33   ` Lawrence Liu
2019-10-07 16:19     ` Eli Zaretskii
2019-10-07 16:26       ` Lawrence Liu
2019-10-07 12:28   ` Andrii Kolomoiets
2019-10-30 19:14     ` Andrii Kolomoiets
2019-11-01  9:35       ` Eli Zaretskii
2019-11-02 16:37         ` Andrii Kolomoiets
2019-11-02 17:29           ` Eli Zaretskii
2019-11-02 18:51             ` Andrii Kolomoiets
2019-11-07 16:57               ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).