Subject: python.el first prompt missing field=output

From: JD Smith <[email-masked]>
Date: Tue, 14 Feb 2023 21:34:52 -0500

The first >>> python prompt in an inferior-python-mode comint buffer is incorrectly missing its field=output text property.  This causes a few problems:
C-c C-a at the first prompt moves back to before the prompt.
Mouse-2 clicking on the first input brings the first prompt along with it forward to the current prompt.
If you recall history at the first prompt, then change your mind and “restore”(missing)  input, comint’s history mechanism mistakenly identifies the prompt text (and sometimes text before the first prompt like python version information) as input, copying it to the prompt line.  
If the prompt is read-only, that will now be stuck on the input line.  Only Return and adding it to history is possible from here, which is not ideal.
The reason for the missing field property is subtle:

python.el sets up `python-shell-comint-watch-for-first-prompt-output-filter' among the `comint-output-filter-functions’.  These filter functions are run just after the prompt string is inserted by `comint-output-filter'.
That function arranges to send setup code to define __PYTHON_EL_eval and perform other setup, with no output.  This process interaction recursively calls `comint-output-filter’ several times.
The setup code places a function on `comint-preoutput-filter-functions’ to accumulate the hidden output, and search for the next prompt.  It finally returns the empty string to avoid placing any output in the comint buffer.
Even though no output is placed in the buffer in these recursive calls, `comint-last-output-start’ gets moved forward to the end of the first prompt (which again, is already in the buffer):  
(set-marker comint-last-output-start (point)).
When the recursive process filter calls finally finish and control returns to the “outer” filter function invocation — the one which has originally inserted the prompt text — the application of the field=output property to the original prompt is now erroneously made over a zero character range at the very end of the buffer:

		(add-text-properties comint-last-output-start (point)
                                     `(rear-nonsticky
				       ,comint--prompt-rear-nonsticky
				       front-sticky
				       (field inhibit-line-move-field-capture)
				       field output
				       inhibit-line-move-field-capture t))

A simple fix (in python.el) would be to run the python setup from the main event loop instead of in place, i.e. to avoid recursively calling the process filter.  A more defensive fix (in comint) would be to store the value of `comint-last-output-start' (or use some other “starting marker”) to guard against filter-function disturbance.  This is already done for the process mark.