From 3165cb73a6326a80bcaf9093d5c48acbd27f78e1 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 19 Sep 2026 02:18:38 +0700 Subject: [PATCH] A propertized string is not a string once it reaches the daemon's reader MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit comint hands the input sender its buffer text with font-lock's properties still on it, and prin1 writes such a string as #(...) — which the daemon reads as a bare symbol followed by a stray list, so the field stops being a string without anything saying so. The wire layer strips rather than asking every caller to remember: it is the one place that knows the text is about to become bytes. --- emacs/flan-dev.el | 15 ++++++++++++++- emacs/test-flan-dev.el | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/emacs/flan-dev.el b/emacs/flan-dev.el index 0eeb13b..4898c13 100644 --- a/emacs/flan-dev.el +++ b/emacs/flan-dev.el @@ -177,9 +177,22 @@ reply that request was waiting for.") ;; a multibyte identifier would otherwise put the reply stream out of step by ;; exactly as many bytes as the payload has non-ASCII characters. +(defun flan-dev--bare (form) + "FORM with every string stripped of its text properties. +A propertized string prints as #(...) syntax, which the daemon's reader +takes as a bare symbol followed by a stray list — the field silently stops +being a string. Buffer text arrives propertized (the REPL's comint input +does, for one), so the wire layer strips rather than trusting every caller +to." + (cond ((stringp form) (substring-no-properties form)) + ((consp form) (cons (flan-dev--bare (car form)) + (flan-dev--bare (cdr form)))) + (t form))) + (defun flan-dev--send (proc form) "Send FORM to PROC as one framed message." - (let* ((payload (encode-coding-string (prin1-to-string form) 'utf-8 t))) + (let* ((payload (encode-coding-string (prin1-to-string (flan-dev--bare form)) + 'utf-8 t))) (process-send-string proc (format "%d\n%s" (length payload) payload)))) (defun flan-dev--take-reply (proc) diff --git a/emacs/test-flan-dev.el b/emacs/test-flan-dev.el index 8688fec..89e60e0 100644 --- a/emacs/test-flan-dev.el +++ b/emacs/test-flan-dev.el @@ -570,7 +570,12 @@ is written instead — the real `message' call the real command makes." (flan-repl) (with-current-buffer flan-repl-buffer (goto-char (point-max)) - (insert "(+ 20 3)") + ;; Propertized, as interactive input always is — font-lock marks what a + ;; batch `insert' would leave bare. comint hands the sender the text + ;; properties and all, and a propertized string prints as #(...), which + ;; the daemon's reader takes as a symbol and a stray list rather than a + ;; string. So this line is the regression test for `flan-dev--bare'. + (insert (propertize "(+ 20 3)" 'fontified t 'face 'default)) (flan-repl-return) (let ((deadline (+ (float-time) 15))) (while (and (not (string-match-p "23" (buffer-string)))