0

I'm trying to run emacsclient -e with an expression that evaluates to a string containing newlines, and I'd like those newlines to be rendered on the console as newlines rather than \n.

Unfortunately, every attempt I've made so far prints the escaped newline:

$ emacsclient -e '(string-join (list "a" "b" "c") "\n")'
"a\nb\nc"
$ emacsclient -e '(print (string-join (list "a" "b" "c") "\n"))'
"a\nb\nc"
$ emacsclient -e '(message (string-join (list "a" "b" "c") "\n"))'
"a\nb\nc"
$ emacsclient -e '(string-join (list "a" "b" "c") "
> "))'
"a\nb\nc"

What am I missing? Bonus points if the quotation marks can also be removed from the output. Intended output:

$ emacsclient -e '(somefunction (list "a" "b" "c"))'
a
b
c
1

One way is to use other tool to interpret the string, such as echo

bash-4.4$ emacsclient --eval '"hello\nworld"' | xargs echo -e
hello
world
bash-4.4$

Another way is to change what the server will return, by default, the server will returns a pp representation of a Lisp value, with the following advice, for Strings, it use a princ representation

(define-advice server-eval-and-print (:override (expr proc) render-string)
  (let ((v (with-local-quit (eval (car (read-from-string expr))))))
    (when proc
      (with-temp-buffer
        (let ((standard-output (current-buffer)))
          (if (stringp v)
              (princ v)
            (pp v))
          (let ((text (buffer-substring-no-properties
                       (point-min) (point-max))))
            (server-reply-print (server-quote-arg text) proc)))))))

;; To uninstall (i.e., remove the advice)
;; (advice-remove 'server-eval-and-print #'server-eval-and-print@render-string)

Give it a try

bash-4.4$ emacsclient --eval '"hello\nworld"'
hello
world
bash-4.4$
0

The --batch argument can be used. From the documentation:

The command-line option ‘-batch’ causes Emacs to run noninteractively. In this mode, Emacs does not read commands from the terminal, it does not alter the terminal modes, and it does not expect to be outputting to an erasable screen.

Later, it discusses output:

Any Lisp program output that would normally go to the echo area, either using message, or using prin1, etc., with t as the stream, goes instead to Emacs's standard descriptors when in batch mode: message writes to the standard error descriptor, while prin1 and other print functions write to the standard output.

So we can call emacs with the --batch and -eval form arguments:

$ emacs --batch --eval '(progn (require (quote subr-x)) (message (string-join (list "a" "b" "c") "\n")))'
a
b
c

Note that --batch prevents your init file from being loaded. Therefore, because we're using string-join, we have to require the library containing it (subr-x) before using it. You could, alternately, use -l <file> to load your init file, before using --eval <lisp code> on the code you want to actually print.

  • Or just (message (mapconcat (quote identity) (list "a" "b" "c") "\n")). However, emacsclient does not have a --batch option. – Sam Brightman Sep 18 '17 at 21:47
  • Why do you want to use emacsclient instead of emacs? – zck Sep 18 '17 at 21:52
  • Because I want to operate on information in the server. – Sam Brightman Sep 18 '17 at 21:54
  • The emacsclient call is not showing you the messages printed, but instead the return value of the s-expression being evaled. I'm unsure how to connect to an existing server and print out things to the console. – zck Sep 18 '17 at 22:02
0

This is moderately horrible, but maybe just pipe it through something in the shell to deal with translating the \n into an actual newline?

Proof-of-concept:

% emacsclient -e '(message (string-join (list "a" "b" "c") "\n"))' | perl -e 'print eval <>'
a
b
c

(I feel like I should put some sort of "I would never normally do this, but..." disclaimer on that bit of Perl...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.