From 8d64eda2d43882e1569a3d7da430e1109a5ac693 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 19 Sep 2026 03:52:41 +0700 Subject: [PATCH] end-of-defun steps over the newline, and the value was drawn on the next line lisp.el finishes end-of-defun by skipping blanks and stepping over the newline after the closing paren, so the bounds C-c C-c works from end at the start of the next line. The declaration path never cared -- a newline more or less in the text sent changes nothing -- but a value drawn at that position sits in column 0 below the form, in the gap before the next one. The fixture that missed it inserted the expression at point-max with nothing after it, which is the one shape where end-of-defun has no newline to step over. It has one now, and the check is the closing paren rather than a line number. The error-overlay check was the same kind of weak: it asserted the line was not 1, which flan--text alone would have given. It asserts the token now, which is what flan--text-at is for -- and eval-expr's replies do respect the column padding, so the switch stands. --- emacs/flan.el | 15 +++++++++++++-- emacs/test-flan.el | 28 ++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/emacs/flan.el b/emacs/flan.el index 493033a..3628b48 100644 --- a/emacs/flan.el +++ b/emacs/flan.el @@ -2156,12 +2156,23 @@ declaration for it to live in." ;; an evaluation nobody made. The same refusal `C-x C-e' gives. ((= (car b) (cdr b)) (user-error "flan: no top-level form at point to evaluate")) - (t (flan--eval-expression (car b) (cdr b) arg) + (t + ;; `end-of-defun' does not stop at the closing paren: `lisp.el' skips + ;; the blanks after it and then steps over the newline, so END is the + ;; start of the *next* line in every file that ends a line after a form + ;; — which is every file. The declaration path never noticed, because + ;; a newline more or less in the text sent changes nothing. This one + ;; draws a value at END, and at the untrimmed one it lands in column 0 + ;; of the line below, over the gap before the next form. + (let ((end (save-excursion (goto-char (cdr b)) + (skip-chars-backward " \t\n") + (point)))) + (flan--eval-expression (car b) end arg) ;; Flashed for the reason the declaration path flashes: point may be ;; nowhere near the form `beginning-of-defun' actually found, and the ;; value alone does not say which one that was. Only on success — ;; `flan--report' signals on a rejection. - (pulse-momentary-highlight-region (car b) (cdr b)))))) + (pulse-momentary-highlight-region (car b) end)))))) ;;;###autoload (defun flan-eval-buffer () diff --git a/emacs/test-flan.el b/emacs/test-flan.el index 624ab3d..99d8c18 100644 --- a/emacs/test-flan.el +++ b/emacs/test-flan.el @@ -551,7 +551,11 @@ already rely on it — so nothing here is a stand-in for the real thing." ;; had the one path. `C-M-x' and `C-c C-c' are one command and both route. (goto-char (point-max)) (let ((beg (point))) - (insert "\n(+ 1 1)") + ;; The trailing newline is the point, not tidiness: `end-of-defun' steps + ;; over it, so the bounds it hands back end at the start of the next line + ;; and a value drawn at that position appears in column 0 below the form. + ;; Without the newline here the bug is invisible. + (insert "\n(+ 1 1)\n") ;; Point *inside* the form, which is where `C-c C-c' is pressed from and ;; the difference between this and `C-x C-e': the form is the one point is ;; in, not the one behind it. @@ -560,6 +564,15 @@ already rely on it — so nothing here is a stand-in for the real thing." (progn (flan-eval-defun) (let ((r (test-flan--result))) (and r (string-match-p "=> 2" r))))) + (test-flan--check "and draws the value after the closing paren" + (let ((ovs (flan--result-overlays))) + (and (= 1 (length ovs)) + (= (char-before (overlay-start (car ovs))) ?\)) + (= (line-number-at-pos (overlay-start (car ovs))) + (line-number-at-pos + (save-excursion + (goto-char (point-min)) + (search-forward "(+ 1 1)"))))))) ;; What a keystroke would do. There are no commands under --batch, so the ;; `pre-command-hook' that takes a value down never runs and the next ;; check below would be reading this one's overlay. @@ -657,12 +670,15 @@ already rely on it — so nothing here is a stand-in for the real thing." (or (overlay-get (car ovs) 'help-echo) ""))))) ;; The padding argument, which is why the expression path sends ;; `flan--text-at': the daemon numbers from the start of what it was sent, - ;; so an unpadded snippet puts this overlay on line 1 of the file. - (test-flan--check "and marked where it is written, not at line 1" + ;; so an unpadded snippet puts this overlay on line 1 of the file. The + ;; column is the half `flan--text' alone would not have fixed, so the + ;; check is the token and not the line — a client that padded lines only + ;; would pass "not line 1" and still point at the open paren. + (test-flan--check "and marked at the word it is about, not at line 1" (let ((ovs (flan--error-overlays))) - (and ovs (> (line-number-at-pos - (overlay-start (car ovs))) - 1)))) + (and ovs (save-excursion + (goto-char (overlay-start (car ovs))) + (looking-at-p "nonsense"))))) (flan-clear-errors) (goto-char (point-max)) (delete-region beg (point-max)))