3232(defvar-local port-repl-prompt-marker nil
3333 " Marker just past the most recently inserted prompt." )
3434
35+ (defvar-local port-repl-prompt-active-p nil
36+ " Non-nil when a live prompt is currently displayed at the end of the buffer.
37+ When nil, output is appended at point-max; when non-nil, it's
38+ inserted above the prompt (preserving any typed-but-unsent input)." )
39+
3540(defvar-local port-repl-history nil
3641 " Ring of previously sent inputs (most recent first)." )
3742
130135 field port-repl-prompt))
131136 (set-marker port-repl-prompt-marker (point )))
132137 (set-marker port-repl-input-start-marker (point ))
133- (set-marker-insertion-type port-repl-input-start-marker nil )))
138+ (set-marker-insertion-type port-repl-input-start-marker nil )
139+ (setq port-repl-prompt-active-p t )))
134140
135141(defun port-repl-handle-message (msg )
136142 " Render a single prepl MSG into the current REPL buffer.
@@ -156,42 +162,44 @@ MSG is an alist as produced by `port-client--parse-messages'."
156162 (format " %s \n " val)))
157163
158164(defun port-repl--insert-output (text+face )
159- " Insert TEXT+FACE (a (TEXT . FACE) pair) into the buffer above the prompt."
165+ " Insert TEXT+FACE (a (TEXT . FACE) pair) into the REPL buffer.
166+ If a prompt is currently displayed (`port-repl-prompt-active-p' ),
167+ insert above it -- preserving any typed-but-unsent input -- so the
168+ prompt and the user's typing stay at the bottom. Otherwise (e.g.
169+ between sending a form and receiving its first response message)
170+ just append at point-max."
160171 (let* ((text (car text+face))
161172 (face (cdr text+face))
162- (inhibit-read-only t )
163- (insert-pos (marker-position port-repl-prompt-marker))
164- (input-active (< insert-pos (point-max )))
165- (saved-input (when input-active
166- (buffer-substring-no-properties
167- port-repl-input-start-marker (point-max )))))
168- (when input-active
169- (delete-region port-repl-input-start-marker (point-max ))
170- (delete-region (- insert-pos (port-repl--prompt-length)) insert-pos))
171- (goto-char (if input-active
172- (- insert-pos (port-repl--prompt-length))
173- insert-pos))
174- (let ((start (point )))
175- (insert text)
176- (add-text-properties start (point )
177- `(read-only t
178- rear-nonsticky (read-only)
179- front-sticky (read-only)
180- face ,face )))
173+ (inhibit-read-only t ))
181174 (cond
182- (input-active
183- (port-repl--insert-prompt)
184- (insert saved-input))
175+ (port-repl-prompt-active-p
176+ (let* ((insert-pos (marker-position port-repl-prompt-marker))
177+ (saved-input (buffer-substring-no-properties
178+ port-repl-input-start-marker (point-max ))))
179+ (delete-region port-repl-input-start-marker (point-max ))
180+ (delete-region (- insert-pos (port-repl--prompt-length)) insert-pos)
181+ (goto-char (- insert-pos (port-repl--prompt-length)))
182+ (port-repl--insert-output-text text face)
183+ (port-repl--insert-prompt)
184+ (insert saved-input)))
185185 (t
186- ; ; No prompt currently on screen: keep the markers at the new
187- ; ; point so subsequent messages of the same response append
188- ; ; after this output instead of treating it as input that
189- ; ; needs preserving.
186+ (goto-char (point-max ))
187+ (port-repl--insert-output-text text face)
190188 (set-marker port-repl-prompt-marker (point ))
191189 (set-marker port-repl-input-start-marker (point ))))
192190 (set-window-point (get-buffer-window (current-buffer ) 'visible )
193191 (point-max ))))
194192
193+ (defun port-repl--insert-output-text (text face )
194+ " Insert TEXT at point with FACE and read-only properties."
195+ (let ((start (point )))
196+ (insert text)
197+ (add-text-properties start (point )
198+ `(read-only t
199+ rear-nonsticky (read-only)
200+ front-sticky (read-only)
201+ face ,face ))))
202+
195203(defun port-repl--prompt-length ()
196204 " Return the character length of the current prompt string."
197205 (length (format " %s => "
@@ -257,11 +265,13 @@ MSG is an alist as produced by `port-client--parse-messages'."
257265 (add-text-properties port-repl-input-start-marker (point )
258266 '(read-only t
259267 rear-nonsticky (read-only)))
260- ; ; Commit the just-sent text: advance the prompt and input-start
261- ; ; markers past it so response messages append after the form
262- ; ; rather than getting inserted "above the prompt".
268+ ; ; Commit the just-sent text: advance the markers past it and
269+ ; ; mark the prompt as no longer "live", so response messages
270+ ; ; append after the form rather than getting inserted "above
271+ ; ; the prompt".
263272 (set-marker port-repl-prompt-marker (point ))
264- (set-marker port-repl-input-start-marker (point )))
273+ (set-marker port-repl-input-start-marker (point ))
274+ (setq port-repl-prompt-active-p nil ))
265275 (push input port-repl-history)
266276 (setq port-repl-history-index -1 )
267277 (port-client-send port--connection input))
0 commit comments