summaryrefslogtreecommitdiffstats
path: root/content/posts/emacs-buffers-to-stdout/index.org
blob: 3f9c7e2263fe0b1d0e7ab69a38ff35846919708c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#+TITLE: How to get all Emacs daemon buffers from a shell script
#+DATE: 2021-05-01T22:38:32-04:00
#+DRAFT: false
#+DESCRIPTION: A small script that will print all Emacs daemon buffers to stdout
#+TAGS[]: emacs
#+KEYWORDS[]: emacs
#+SLUG:
#+SUMMARY:

#+ATTR_HTML: :title Emacs daemon buffers
#+ATTR_HTML: :alt Emacs darmon buffers
[[file:cover.png]]

A while back I posted a response to someone's question on [[https://www.reddit.com/r/emacs/comments/ljtify/is_it_there_a_way_to_export_the_list_of_opened/gnhatdu/?context=3][reddit]] about
how to get a list of all Emacs daemon buffers from a shell script. It
was a pretty interesting problem so I thought I'd explain my answer
here.

The question was "Is it there a way to export the list of opened
buffers to STDOUT?".

In the comments I left a rather byzantine looking snippet of code that
I'd managed to produce.

#+begin_src
emacs --batch --eval "(require 'server)" --eval "(mapc #'print (read (server-eval-at \"server\" '(format \"%s\" (mapcar (lambda (buffer) (format \"\\\"%s\\\"\n\" buffer)) (buffer-list))))))" | sed '/^$/d; s/^"//g; s/"$//g'
#+end_src

I've simplified the lisp slightly since I answered that question.
Here's the updated version.

#+begin_src
emacs --batch --eval "(require 'server)" --eval "(mapc #'princ (read (server-eval-at \"server\" '(prin1-to-string (mapcar (lambda (buffer) (format \"%s\\n\" buffer)) (buffer-list))))))" 2>/dev/null
#+end_src

Here it is written in a way that's easier to read.

#+begin_src
emacs --batch \
      --eval "(require 'server)" \
      --eval "(mapc #'princ
                    (read (server-eval-at \"server\"
                             '(prin1-to-string (mapcar (lambda (buffer)
                                                           (format \"%s\\n\" buffer))
                                                       (buffer-list))))))" \
      2>/dev/null
#+end_src


Let's break it down.

- =emacs= Emacs itself!
  - =--batch= Runs Emacs in [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Batch-Mode.html][=batch=]] mode, which executes commands
    non-interactively and stops it from opening a window. This is
    usually used for running Emacs lisp as a script.
  - =--eval= Evaluates the following piece of elisp in the batch Emacs
    - =(require 'server)= Loads the built-in =server= package. This is
      used to connect to the running Emacs daemon
  - =--eval= Since the previous elisp snippet was a complete
    s-expression I evaluate the next expression as a new argument. I
    could have also wrapped them both in a =progn=, but this felt cleaner.
    - =mapc FUNCTION SEQUENCE= Apply =FUNCTION= to every object in the
      list =SEQUENCE=.
      - =princ= Outputs the printed form of an object to
        =standard-out=. It's used here because it doesn't surround the
        string in quotes like =print= does.
      - =read STREAM= Read =STREAM=, in this case a string, and turn it
        into a lisp object
        - =server-eval-at \"server\" FORM= Evaluates =FORM= on the Emacs
          daemon and returns the result. The quotes are escaped
          because it's already inside a quote because it's a command
          line argument.
          - =prin1-to-string OBJECT= Return a string containing the
            printed representation of =OBJECT=. I use this instead of
            =princ= because that outputs the result to the minibuffer of
            the Emacs daemon instead of returning it.
            - =mapcar FUNCTION SEQUENCE= Applies FUNCTION to each
              element of SEQUENCE and returns a list of the result.
              - =(lambda (buffer) (format \"%s\\n\" buffer)= An
                anonymous function that takes a buffer and returns the
                string version of its name followed by a newline. The
                quotes and newline are escaped because it's already
                inside a quote because it's a command line argument.
              - =buffer-list= Returns a list of all buffers in Emacs
  - =2>/dev/null= Send the Emacs startup text, which is outputted to
    =stderr=, to =/dev/null=. We don't want to see it.

The result is a single line command that outputs the name of every
buffer in the Emacs daemon, one per line, to =stdout=.