Il formato s-lex di s.el è davvero quello che vuoi, ma se vuoi davvero essere in grado di inserire il codice all'interno dei blocchi di sostituzione e non solo i nomi delle variabili, ho scritto questo come una prova del concetto.
(defmacro fmt (str)
"Elisp string interpolation for any expression."
(let ((exprs nil))
(with-temp-buffer
(insert str)
(goto-char 1)
(while (re-search-forward "#{" nil t 1)
(let ((here (point))
(emptyp (eql (char-after) ?})))
(unless emptyp (push (read (buffer-substring (point) (progn (forward-sexp 1) (point)))) exprs))
(delete-region (- here 2) (progn (search-forward "}") (point)))
(unless emptyp (insert "%s"))
(ignore-errors (forward-char 1))))
(append (list 'format (buffer-string)) (reverse exprs)))))
;; demo with variable and code substitution
(fmt "My name is #{user-full-name}, I am running Emacs #{(if (display-graphic-p) \"with a GUI\" \"in a terminal\")}.")
;; results in
"My name is Jordon Biondo, I am running Emacs with a GUI."
Puoi anche incorporare una fmt
chiamata in un'altra fmt
se sei pazzo
(fmt "#{(fmt\"#{(fmt\\\"#{user-full-name}\\\")}\")}")
;; =>
"Jordon Biondo"
Il codice si espande a una format
chiamata, quindi tutte le sostituzioni vengono eseguite in ordine e valutate in fase di esecuzione.
(cl-prettyexpand '(fmt "Hello, I'm running Emacs #{emacs-version} on a #{system-type} machine with #{(length (window-list))} open windows."))
;; expands to
(format "Hello, I'm running Emacs %s on a %s machine with %s open windows."
emacs-version
system-type
(length (window-list)))
Potrebbero essere apportati miglioramenti con quale tipo di formato viene utilizzato invece di utilizzare sempre% s, ma ciò dovrebbe essere fatto in fase di esecuzione e aggiungerebbe overhead ma potrebbe essere fatto circondando tutti gli argomenti di formattazione in una chiamata di funzione che formatta le cose in modo ben basato sul tipo, ma in realtà l'unico scenario in cui vorresti che fosse probabilmente float e potresti anche fare un (formato "% f" float) nella sostituzione è che eri disperato.
Se ci lavoro di più, ho maggiori probabilità di aggiornare questa sintesi anziché questa risposta. https://gist.github.com/jordonbiondo/c4e22b4289be130bc59b