C-x C-e at the top of a file has nothing behind it, and says so
`backward-sexp' does not signal when there is no form before point; it goes to the beginning of the buffer and stays there. At point-min that is no movement, so the form the dispatch then looked at was the one *after* point -- whose head is very often a declaration -- and the region between start and end was empty. The key installed the file's first declaration by name with no body, which the daemon accepts, and the echo area reported it as a change. Both paths check for movement now: the predicate refuses, and the expression arm refuses in words rather than asking the daemon to evaluate the empty string. The same predicate asked only for the depth at the open delimiter, and a form written at column 1 inside a comment or a string is at depth 0 like any other. A `defvar' in a comment is prose; it is not offered as a declaration any more. Depth in a narrowed buffer still means depth within the narrowing, which is noted where it is read rather than changed.
This commit is contained in:
parent
acf38ac064
commit
eed0cfa950
@ -1794,14 +1794,37 @@ Requiring both rather than the head alone is the more conservative of the two
|
||||
readings, and the one the user asked for: a `defn' written inside a `let' is
|
||||
not a definition of anything, and installing it as one would quietly accept
|
||||
code the compiler is right to refuse. Sent as an expression it gets the
|
||||
parser's own message, which says exactly that."
|
||||
parser's own message, which says exactly that.
|
||||
|
||||
Three things have to be true before either question is worth asking, and the
|
||||
first of them is that there *is* a form before point. `backward-sexp' does
|
||||
not signal when there is nothing behind it — it goes to the beginning of the
|
||||
buffer and stays there, which at point-min is no movement at all — and the
|
||||
form it then looks at is the one *after* point, whose head is very likely a
|
||||
declaration and whose text is empty. `C-x C-e' at the top of a file used to
|
||||
install that: a `defn' by name, with no body, out of a region zero characters
|
||||
wide. So START must have moved. The other two are that the form is not
|
||||
inside a string or a comment, where a `defn' is prose and not a definition.
|
||||
|
||||
One known limit, left as one: `syntax-ppss' reports depth from the accessible
|
||||
portion of the buffer, so in a narrowed buffer a form that is nested in the
|
||||
file reads as top-level here. Widening to ask would be a different decision
|
||||
about what `C-x C-e' means in a narrowed buffer, and it is not this one's to
|
||||
make."
|
||||
(save-excursion
|
||||
(let ((end (point)))
|
||||
(condition-case nil
|
||||
(progn
|
||||
(backward-sexp)
|
||||
(let ((start (point)))
|
||||
(and (zerop (car (syntax-ppss start)))
|
||||
(let* ((start (point))
|
||||
;; Every `syntax-ppss' call before the `looking-at' below:
|
||||
;; it moves point and clobbers the match data, and the head
|
||||
;; is read back out of that match.
|
||||
(state (syntax-ppss start)))
|
||||
(and (> end start)
|
||||
(zerop (car state))
|
||||
(not (nth 3 state)) ; inside a string
|
||||
(not (nth 4 state)) ; inside a comment
|
||||
(looking-at "([ \t\n]*\\(\\(?:\\sw\\|\\s_\\)+\\)")
|
||||
(member (match-string-no-properties 1)
|
||||
flan-dev--declaration-heads)
|
||||
@ -1846,9 +1869,20 @@ does, until the same form is evaluated again without a prefix."
|
||||
;; daemon installed no bodies and declared no names.
|
||||
(flan-dev--eval (flan-dev--text start end) head start end
|
||||
(and arg (cons start end))))
|
||||
(let ((code (buffer-substring-no-properties
|
||||
(save-excursion (backward-sexp) (point))
|
||||
(point))))
|
||||
(let* ((start (save-excursion
|
||||
(condition-case nil (backward-sexp) (scan-error nil))
|
||||
(point)))
|
||||
(code (buffer-substring-no-properties start (point))))
|
||||
;; Nothing behind point is nothing to send. `backward-sexp' does not
|
||||
;; signal at the beginning of a buffer, it simply stays there, so the
|
||||
;; region measured out is empty and the daemon is asked to evaluate
|
||||
;; the empty string — which it answers, since an empty program is a
|
||||
;; valid one, and the echo area then reports a success for an
|
||||
;; evaluation nobody made. Saying so is the honest answer, and it is
|
||||
;; also the answer to the likelier reading: point is at the top of the
|
||||
;; file and the form meant was the one *after* it.
|
||||
(when (= start (point))
|
||||
(user-error "flan: no form before point to evaluate"))
|
||||
(flan-dev--report
|
||||
(flan-dev--request
|
||||
(append
|
||||
|
||||
@ -486,6 +486,41 @@ is written instead — the real `message' call the real command makes."
|
||||
(string-match-p "=>" said))))
|
||||
(delete-region beg (point-max)))
|
||||
|
||||
;; A declaration can be written where it is prose and not a declaration, and
|
||||
;; the depth at its open delimiter says nothing about that: a form at column
|
||||
;; 1 inside a comment or a string is at depth 0 like any other, so the head
|
||||
;; was the only thing being asked and a sentence would have been compiled.
|
||||
(goto-char (point-max))
|
||||
(let ((beg (point)))
|
||||
(insert "\n;; (defvar commented i64 1)\n\"(defvar inside i64 1)\"")
|
||||
;; Point after the form's own closing paren rather than at the end of the
|
||||
;; line: `backward-sexp' walks over a whole comment, so from the end of
|
||||
;; one it never reaches the paren inside it and the guard is never asked.
|
||||
(goto-char beg)
|
||||
(search-forward "commented i64 1)")
|
||||
(test-flan--check "a declaration written in a comment is not one"
|
||||
(null (flan-dev--declaration-before-point)))
|
||||
(goto-char beg)
|
||||
(search-forward "inside i64 1)")
|
||||
(test-flan--check "and neither is one written in a string"
|
||||
(null (flan-dev--declaration-before-point)))
|
||||
(delete-region beg (point-max)))
|
||||
|
||||
;; And the top of the buffer, where there is nothing behind point at all.
|
||||
;; `backward-sexp' does not signal there — it stays where it is — so the
|
||||
;; form the predicate looked at was the one *after* point and the region it
|
||||
;; measured out was empty: C-x C-e at point-min sent the first declaration
|
||||
;; in the file by name with no body at all, and the daemon installed it.
|
||||
;; Nothing is sent now, from either path, and the refusal says why.
|
||||
(goto-char (point-min))
|
||||
(test-flan--check "the form after point is not the form before it"
|
||||
(null (flan-dev--declaration-before-point)))
|
||||
(test-flan--check "and C-x C-e at the top of a buffer refuses rather than sending nothing"
|
||||
(let ((raised nil))
|
||||
(condition-case err (flan-eval-last-sexp)
|
||||
(user-error (setq raised (error-message-string err))))
|
||||
(and raised (string-match-p "no form before point" raised))))
|
||||
|
||||
;; The bug this key had: a `defvar' typed at the top of a file could only be
|
||||
;; evaluated with C-c C-c, because C-x C-e sent it to the expression
|
||||
;; evaluator and the parser refused it as a declaration. One round trip, on
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user