mirror of
https://github.com/SqrtMinusOne/sqrtminusone.github.io.git
synced 2025-12-10 15:53:03 +03:00
tree: add 1.5 draft
This commit is contained in:
parent
133849bc01
commit
91d7185480
1 changed files with 60 additions and 9 deletions
|
|
@ -6,11 +6,11 @@
|
|||
#+HUGO_DRAFT: true
|
||||
|
||||
#+begin_abstract
|
||||
The post describes how to determine package dependency tree, using the built-in =load-history= and =use-package=. This is helpful for configuring lazy loading in configs as large as mine.
|
||||
The post describes how to determine package dependency tree, using the built-in =load-history= and =use-package=. This is helpful for configuring lazy loading in large configs, such as mine.
|
||||
#+end_abstract
|
||||
|
||||
* Intro
|
||||
Hmm?
|
||||
- This document is an awkward middle between a blog post and a package: there's a bit too much code for the former, but too little for the latter, and I don't feel it's general enough anyway. So, for now it's a blog post.
|
||||
|
||||
* Prior work
|
||||
Somehow it has been particularly hard to find anything on that topic.
|
||||
|
|
@ -21,7 +21,7 @@ I started with advising =require= (yes, Emacs allows to do that), but then I had
|
|||
#+end_example
|
||||
This is all the information needed to restore the dependency graph.
|
||||
|
||||
There are packages using this variable, namely the built-in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/loadhist.el][loadhist]] providing =file-requires= and =file-dependents=. Unfortunately, these functions are neither recursive nor interactive.
|
||||
There are already packages using this variable, including the built-in [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/loadhist.el][loadhist]] providing =file-requires= and =file-dependents=. Unfortunately, these functions are neither recursive nor interactive.
|
||||
|
||||
The [[https://www.emacswiki.org/emacs/LibraryDependencies][LibraryDependencies]] page on EmacsWiki also has some ideas, of which [[https://www.emacswiki.org/emacs/lib-requires.el][lib-requires.el]] by Drew Adams looks is the closest to what I want, but it seems to require providing filenames for libraries to inspect.
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ and the cdr being a list cons cell of the same kind."
|
|||
(remhash feature-name found-features)))
|
||||
#+end_src
|
||||
|
||||
The resulting feature tree is interesting enough, but I also want to see the subset of tree managed by [[https://github.com/jwiegley/use-package][use-package]].
|
||||
This feature tree is already interesting, but for me it's also helpful to find the subset of the tree managed by [[https://github.com/jwiegley/use-package][use-package]]. For instance, I used this to figure out why opening an elisp buffer loads =org-mode= (spolier: [[https://github.com/abo-abo/lispy/blob/fe44efd21573868638ca86fc8313241148fabbe3/lispy.el#L143][lispy]] -> [[https://github.com/abo-abo/zoutline/blob/32857c6c4b9b0bcbed14d825a10b91a98d5fed0a/zoutline.el#L26][zoutline]] -> org).
|
||||
|
||||
Fortunately, =use-package= has built-in [[https://github.com/jwiegley/use-package?tab=readme-ov-file#gathering-statistics][statistics functionality]]. To turn it on, set the following variable:
|
||||
#+begin_src emacs-lisp
|
||||
|
|
@ -128,9 +128,9 @@ This can be used to narrow the tree:
|
|||
(eq (car a) (car b))))))))
|
||||
#+end_src
|
||||
|
||||
Now, the only remaining thing is to render these results. I've tried Damien Cassou's [[https://github.com/DamienCassou/hierarchy][hierarchy.el]] (now [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/emacs-lisp/hierarchy.el][part of Emacs]]), but [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html][outline-mode]] seems to be more straightforward.
|
||||
Now, the only remaining thing is to render these results. I've also tried Damien Cassou's [[https://github.com/DamienCassou/hierarchy][hierarchy.el]] (now [[https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/emacs-lisp/hierarchy.el][part of Emacs]]), but I find [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html][outline-mode]] more straightforward.
|
||||
|
||||
So, render the tree with that in mind:
|
||||
To make a header for =outline-mode=, just prepend the string with the required number of "*":
|
||||
#+begin_src emacs-lisp
|
||||
(defun my/load-history--render-feature-tree-recur (tree &optional level)
|
||||
"Render the feature tree recursively.
|
||||
|
|
@ -146,7 +146,7 @@ the recursion level."
|
|||
(my/load-history--render-feature-tree-recur feature (1+ level)))))
|
||||
#+end_src
|
||||
|
||||
I'll also make a derived mode from =outline-mode= to redefine =q= and =TAB=:
|
||||
I'll also make a derived mode from =outline-mode= to redefine =q= and =TAB= and make the buffer read-only:
|
||||
#+begin_src emacs-lisp
|
||||
(defvar my/load-history-tree-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
|
|
@ -163,14 +163,28 @@ I'll also make a derived mode from =outline-mode= to redefine =q= and =TAB=:
|
|||
(setq-local buffer-read-only t))
|
||||
#+end_src
|
||||
|
||||
Finally, an interactive function that puts all of that together:
|
||||
Now, putting all of this together.
|
||||
|
||||
The completing-read function prompts the user either with a [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Named-Features.html#index-features-1][list of features]] or with the list of use-package packages.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defun my/completing-read-features-or-packages ()
|
||||
"Read a feature name or a `use-package'-package from the minibuffer.
|
||||
|
||||
The choice depends on the value of the prefix argument."
|
||||
(intern
|
||||
(if (equal current-prefix-arg '(4))
|
||||
(completing-read "Package: " (cl-loop for p being the hash-keys of
|
||||
use-package-statistics
|
||||
collect p))
|
||||
(completing-read "Feature: " features))))
|
||||
|
||||
(defun my/load-history-feature-dependents (feature-name &optional narrow-use-package)
|
||||
"Display the tree of features that depend on FEATURE-NAME.
|
||||
|
||||
If NARROW-USE-PACKAGE is non-nil, only show the features that are
|
||||
managed by `use-package'."
|
||||
(interactive (list (intern (completing-read "Feature: " features))
|
||||
(interactive (list (my/completing-read-features-or-packages)
|
||||
(equal current-prefix-arg '(4))))
|
||||
(let* ((feature-required-by (my/load-history--get-feature-required-by))
|
||||
(tree (my/load-history--get-feature-tree feature-name feature-required-by))
|
||||
|
|
@ -184,4 +198,41 @@ managed by `use-package'."
|
|||
(switch-to-buffer buffer)))
|
||||
#+end_src
|
||||
|
||||
Having that, we can also reverse the function and build a dependency tree, i.e. find out which features are required by the one in question (rather than vice versa).
|
||||
|
||||
To change this, it only takes to swap keys and values in the packages hashmap construction, i.e. reverse all edges in the dependency graph:
|
||||
#+begin_src emacs-lisp
|
||||
(defun my/load-history--get-feature-requires ()
|
||||
"Get the hashmap of which features require which.
|
||||
|
||||
The key is the feature name; the value is the list of features it
|
||||
requires."
|
||||
(let ((feature-requires (make-hash-table)))
|
||||
(my/load-history--iter-load-history
|
||||
(dolist (require-symbol requires)
|
||||
(puthash provide-symbol
|
||||
(cons require-symbol
|
||||
(gethash provide-symbol feature-requires))
|
||||
feature-requires)))
|
||||
feature-requires))
|
||||
|
||||
(defun my/load-history-feature-dependencies (feature-name &optional narrow-use-package)
|
||||
"Display the tree of features that FEATURE-NAME depends on.
|
||||
|
||||
If NARROW-USE-PACKAGE is non-nil, only show the features that are
|
||||
managed by `use-package'."
|
||||
(interactive (list (my/completing-read-features-or-packages)
|
||||
(equal current-prefix-arg '(4))))
|
||||
(let* ((feature-requires (my/load-history--get-feature-requires))
|
||||
(tree (my/load-history--get-feature-tree feature-name feature-requires))
|
||||
(buffer (generate-new-buffer (format "*feature-dependencies-%s*" feature-name))))
|
||||
(when narrow-use-package
|
||||
(setq tree (my/load-history--narrow-tree-by-use-package tree)))
|
||||
(with-current-buffer buffer
|
||||
(my/load-history--render-feature-tree-recur tree)
|
||||
(my/load-history-tree-mode)
|
||||
(goto-char (point-min)))
|
||||
(switch-to-buffer buffer)))
|
||||
#+end_src
|
||||
|
||||
* Usage and results
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue