87 lines
9.4 KiB
Plaintext
87 lines
9.4 KiB
Plaintext
<p>I don’t know about you, but I like to monitor my Emacs configuration to see if
|
||
it is growing out of control due to my penchant for experimenting with ELisp and
|
||
new packages. This led me to a simple question: why not have a command that can
|
||
produce a summary of the installed packages? Specifically, I want to know the
|
||
total number of packages installed and I’d like to list the packages for every
|
||
archive set up in <code class="language-plaintext highlighter-rouge">package-archives</code>.</p>
|
||
|
||
<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu-package-report</span> <span class="p">()</span>
|
||
<span class="s">"Report total package counts grouped by archive."</span>
|
||
<span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nv">package-refresh-contents</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nv">mu--display-package-report</span>
|
||
<span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">arch-pkgs</span> <span class="p">(</span><span class="nv">mu--archive-packages</span><span class="p">))</span>
|
||
<span class="p">(</span><span class="nv">counts</span> <span class="p">(</span><span class="nv">seq-sort-by</span> <span class="nf">#'</span><span class="nb">cdr</span> <span class="nf">#'</span><span class="nb">></span> <span class="p">(</span><span class="nv">mu--archive-counts</span> <span class="nv">arch-pkgs</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nv">by-arch</span> <span class="p">(</span><span class="nv">seq-group-by</span> <span class="nf">#'</span><span class="nb">car</span> <span class="nv">arch-pkgs</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nv">concat</span>
|
||
<span class="p">(</span><span class="nb">format</span> <span class="s">"Total packages: %s\n\n"</span> <span class="p">(</span><span class="nb">apply</span> <span class="nf">#'</span><span class="nb">+</span> <span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nb">cdr</span> <span class="nv">counts</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nv">mapconcat</span>
|
||
<span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">archive</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nv">concat</span> <span class="s">"• "</span>
|
||
<span class="p">(</span><span class="nb">format</span> <span class="s">"%s (%s)"</span> <span class="p">(</span><span class="nb">car</span> <span class="nv">archive</span><span class="p">)</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">archive</span><span class="p">))</span>
|
||
<span class="s">": "</span>
|
||
<span class="p">(</span><span class="nv">mapconcat</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">ap-pair</span><span class="p">)</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">ap-pair</span><span class="p">))</span>
|
||
<span class="p">(</span><span class="nv">alist-get</span> <span class="p">(</span><span class="nb">car</span> <span class="nv">archive</span><span class="p">)</span> <span class="nv">by-arch</span><span class="p">)</span>
|
||
<span class="s">", "</span><span class="p">)))</span>
|
||
<span class="nv">counts</span>
|
||
<span class="s">"\n\n"</span><span class="p">)))))</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Now, let’s unpack it.</p>
|
||
|
||
<p>I want my report buffer to be displayed in a new window, so this is what
|
||
<code class="language-plaintext highlighter-rouge">mu--display-package-report</code> does:</p>
|
||
|
||
<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--display-package-report</span> <span class="p">(</span><span class="nv">output</span><span class="p">)</span>
|
||
<span class="s">"Display OUTPUT in a popup buffer."</span>
|
||
<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">buffer-name</span> <span class="s">"*package-report*"</span><span class="p">))</span>
|
||
<span class="p">(</span><span class="nv">with-help-window</span> <span class="nv">buffer-name</span>
|
||
<span class="p">(</span><span class="nv">with-current-buffer</span> <span class="nv">buffer-name</span>
|
||
<span class="p">(</span><span class="nv">visual-line-mode</span> <span class="mi">1</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nv">erase-buffer</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nv">insert</span> <span class="nv">output</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nv">goto-char</span> <span class="p">(</span><span class="nv">point-min</span><span class="p">))))))</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>Next, I want to know from which archive (e.g., GNU ELPA) a package is coming to
|
||
my system:</p>
|
||
|
||
<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--archive-packages</span> <span class="p">()</span>
|
||
<span class="s">"Return a list of (archive . package) cons cells."</span>
|
||
<span class="p">(</span><span class="nv">seq-reduce</span>
|
||
<span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">res</span> <span class="nc">package</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">archive</span> <span class="p">(</span><span class="nv">package-desc-archive</span>
|
||
<span class="p">(</span><span class="nb">cadr</span> <span class="p">(</span><span class="nv">assq</span> <span class="nc">package</span> <span class="nv">package-archive-contents</span><span class="p">))))</span>
|
||
<span class="p">(</span><span class="nv">pkg</span> <span class="p">(</span><span class="nb">symbol-name</span> <span class="nc">package</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nb">push</span> <span class="p">(</span><span class="nb">cons</span> <span class="nv">archive</span> <span class="nv">pkg</span><span class="p">)</span> <span class="nv">res</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nb">car</span> <span class="nv">package-alist</span><span class="p">)</span>
|
||
<span class="no">nil</span><span class="p">))</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>This is nice because now I can also have the number of packages for every archive.</p>
|
||
|
||
<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">mu--archive-counts</span> <span class="p">(</span><span class="nv">arch-pkgs</span><span class="p">)</span>
|
||
<span class="s">"Return a list of cons cells from alist ARCH-PKGS.
|
||
The cars are package archives, the cdrs are the number of
|
||
packages installed from each archive."</span>
|
||
<span class="p">(</span><span class="nv">seq-reduce</span>
|
||
<span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">counts</span> <span class="nv">key</span><span class="p">)</span>
|
||
<span class="p">(</span><span class="nb">cons</span> <span class="p">(</span><span class="nb">cons</span> <span class="nv">key</span> <span class="p">(</span><span class="nb">+</span> <span class="mi">1</span> <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nb">cdr</span> <span class="p">(</span><span class="nb">assoc</span> <span class="nv">key</span> <span class="nv">counts</span><span class="p">))</span> <span class="mi">0</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nv">assoc-delete-all</span> <span class="nv">key</span> <span class="nv">counts</span><span class="p">)))</span>
|
||
<span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#'</span><span class="nb">car</span> <span class="nv">arch-pkgs</span><span class="p">)</span>
|
||
<span class="no">nil</span><span class="p">))</span>
|
||
</code></pre></div></div>
|
||
|
||
<p>The rest of the code in <code class="language-plaintext highlighter-rouge">mu-package-report</code> deals with formatting the output.
|
||
For example, I am using <code class="language-plaintext highlighter-rouge">seq-sort-by</code> to have the archive with the highest
|
||
number of packages on top. As for the <code class="language-plaintext highlighter-rouge">mapconcat</code> producing the actual bullet
|
||
points, the Emacs community came to the rescue on <a href="https://emacs.stackexchange.com/questions/65088/format-alist-into-bullet-points">Emacs Stack
|
||
Exchange</a>.</p>
|
||
|
||
<p>Finally, this is how <kbd>M-x mu-package-report RET</kbd> looks like:</p>
|
||
|
||
<div style="text-align: center; padding-top: 5px; padding-bottom: 5px;">
|
||
<a href="https://raw.githubusercontent.com/manuel-uberti/manuel-uberti.github.io/master/images/package-report.png" target="_blank">
|
||
<img src="https://www.manueluberti.eu/images/package-report.png" />
|
||
</a>
|
||
</div> |