0

I am able to collect output data from a process, but I don't understand the coordination of point and process-mark. In particular, the visible cursor in a non-selected window visiting the buffer does not advance, even though point is reported at correct locations when I access the variable. Selecting the window moves point to an incorrect location.

(EDIT: in an earlier version of this question, I had some basic confusion about windows, frames, selection, and focus. I consulted the documentation here and edited this question to be coherent with emacs definitions.)

I'd be grateful for some explanations and corrections to the following MVE (minimal viable example). First, I start a process:

(start-process-shell-command
 "foo-process"
 "foo-buffer"
 "python")

I open another window to watch what's going on: C-x3, visit foo-buffer in that window C-xbfoo-buffer, and select my programming window window again C-xo. The window visiting foo-buffer is not selected at this time, but a shadowy cursor is visible in the window.

I set up a couple of global variables for debugging and for collecting output and a function to report on the state:

(defvar my-python-buffer-data '())
(defvar my-python-latest-output "")

(defun report ()
  (with-current-buffer "foo-buffer"
    `((:point-min     ,(point-min))
      (:point         ,(point))
      (:point-max     ,(point-max))
      (:process-mark  ,(process-mark (get-process "foo-process")))
      (:buffer-data   ,my-python-buffer-data)
      (:latest-output ,my-python-latest-output))))

Before sending data to the buffer, I check the state by calling report:

(report)

((:point-min 1)
 (:point 149)
 (:point-max 149)
 (:process-mark #<marker at 149 in foo-buffer>)
 (:buffer-data nil)
 (:latest-output ""))

Things seems consistent: the point and process marker are at the end of the buffer. I can also see that the shadowy cursor in the other window (which is not selected) is at the end of the buffer.

I now set up my custom "insertion filter," following the documentation in section 38.9.2 of the elisp manual at this link address. I am using the documented option of unconditionally setting point via goto-char at the end of the filter function. I want point to be always at the end of the new output.

I collect data about point and the process mark as I go along, so I need a function to do that:

(defun collect-python-buffer-data (sigil)
  (setq my-python-buffer-data
        (cons
         `(:sigil ,sigil :marker ,(process-mark proc) :point ,(point))
         my-python-buffer-data)))

and here is my filter function, copy-pasted and modded from the doc:

(defun extracting-insertion-filter (proc string)
  (setq my-python-buffer-data '())
  (setq my-python-latest-output "")
  (let ((pb (process-buffer proc)))
   (when (buffer-live-p pb)
     (with-current-buffer pb
       (save-excursion
         (collect-python-buffer-data 1)
         (goto-char (process-mark proc))
         (collect-python-buffer-data 2)
         (insert string) ; advances point
         (collect-python-buffer-data 3)
         (set-marker (process-mark proc) (point))
         (collect-python-buffer-data 4))
       (goto-char (process-mark proc))
       (collect-python-buffer-data 5)))
   ;; for reporting:
   (setq my-python-buffer-data (reverse my-python-buffer-data))
   (setq my-python-latest-output string)))

I now set the process filter for the process to my new function:

(set-process-filter
 (get-process "foo-process")
 #'extracting-insertion-filter)

and send some data to my process:

(process-send-string "foo-process" "420 / 3\n")

Now report:

(report)

((:point-min 1)
 (:point 157)
 (:point-max 157)
 (:process-mark #<marker at 157 in foo-buffer>)
 (:buffer-data ((:sigil 1 :marker #<marker at 157 in foo-buffer> :point 149)
                (:sigil 2 :marker #<marker at 157 in foo-buffer> :point 149)
                (:sigil 3 :marker #<marker at 157 in foo-buffer> :point 157)
                (:sigil 4 :marker #<marker at 157 in foo-buffer> :point 157)
                (:sigil 5 :marker #<marker at 157 in foo-buffer> :point 157)))
 (:latest-output "140
>>> "))

Things look OK, here. I get my output, and point and process-mark are at the end, where I want them.

However, the little shadowy cursor is at the wrong place in the non-selected window that shows my buffer. Before selecting that window (and spoiling the state), let me make sure that I can send more data over:

(process-send-string "foo-process" "42 / 3\n")

(report)

((:point-min 1)
 (:point 164)
 (:point-max 164)
 (:process-mark #<marker at 164 in foo-buffer>)
 (:buffer-data ((:sigil 1 :marker #<marker at 164 in foo-buffer> :point 149)
                (:sigil 2 :marker #<marker at 164 in foo-buffer> :point 157)
                (:sigil 3 :marker #<marker at 164 in foo-buffer> :point 164)
                (:sigil 4 :marker #<marker at 164 in foo-buffer> :point 164)
                (:sigil 5 :marker #<marker at 164 in foo-buffer> :point 164)))
 (:latest-output "14
>>> "))

Everything is OK in the program, but the cursor in the non-selected window has not moved. If I select that that window and un-select it, the party is spoiled, i.e., point moved from 164 (where I want it) to 149, where it should not have been after the initialization of the process buffer. C-xoC-xo

(with-current-buffer "foo-buffer" (point))

149

Again, I'd be grateful for guidance on how to fix this. I tried the moving option in the documentation, but the effect is the same.

  • 2
    Each window has its own "window point". It's intentional (and very useful) that you can have multiple windows on a buffer, each showing a different part of the buffer. Forcing all windows to track a single point by default would spoil that. I suggest you look at how comint-scroll-to-bottom-on-input is used in comint.el. – phils Sep 16 '18 at 1:53
  • That's a good hint. I had some confusion on the basics and this doc tree is helping to set me straight: gnu.org/software/emacs/manual/html_node/elisp/… – Reb.Cabin Sep 16 '18 at 12:58
1

The following solves the problem inside my process filter. It sets the window point for every window visiting the process buffer to be the process mark, which I force to be at the end.

(mapcar (lambda (w)
          (set-window-point w
           (process-mark (get-process "foo-process"))))
        (get-buffer-window-list "foo-buffer"))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.