## title: Fun visualization of Emacs dependencies
       ## date: "2026-03-02"
       
       ## Introduction
       
       One day, I was using my favorite application, GNU Emacs. I
       wanted to have a simple visual representation of the
       relationships between certain Emacs dependencies. I just
       wanted to be able to create a simple image with a graph on
       it. However, I couldn't find anything that matched what I
       was looking for, i.e., an Emacs package that exposes
       commands with the dependency to be analyzed as a parameter.
       
       To meet this need, I decided to write my own Emacs package,
       called dv.
       
       ## My goal
       
       The goal is to create an ELisp project that provides code
       that makes it easy to visualize the dependencies of other
       dependencies. For example, I would like to see which
       packages are dependencies of the fj package, which are
       dependencies of certain ELisp files, etc.
       
       ## How it works
       
       During execution, there are several main steps. First, we
       retrieve the metadata for all the dependencies involved and
       establish the relationships between them. Next, we generate
       the dot code that expresses these relationships. Finally, we
       create a dot process asynchronously and pass it the dot code
       as standard input, specifying a destination path as a
       parameter. We can choose to automatically open the image
       generated by the process with Emacs when it finishes.
       
       ### Package metadata
       
       Emacs package metadata retrieval is similar to the describe-
       package function, in that the package cache is first
       consulted before automatically installing the package from
       the package archive if it isn't there. In practical terms,
       Emacs package metadata, at runtime, is represented through
       package-desc objects.
       
       Below is the code responsible for retrieving this metadata.
       
       (defun dv--get-package-desc (pkg)
         "Returns `package-desc' object if PKG is available.
       Otherwise it returns
       nil."
         (or
          (if (package-desc-p pkg) pkg)
          (cadr (assq pkg package-alist))
          (let ((built-in (assq pkg package--builtins)))
            (if built-in
                (package--from-builtin built-in)
              (cadr (assq pkg package-archive-contents))))
          ;; If the package was not in cache,
          ;; we can try to install it using `package-install'
          ;;
          ;; And then we should be able to get it from cache by
       calling the
          ;; `dv--get-package-desc' function again
          (unless (package-installed-p pkg)
            ;; Can signal an error
            (package-install pkg)
            (dv--get-package-desc pkg))))
       
       (defun dv-get-package-desc (pkg)
         "Wrapping `dv--get-package-desc'."
         (unless package--initialized
           (package-initialize t))
         (dv--get-package-desc pkg))
       
       ### Node relationships
       
       Several node relationships are possible with the current
       implementation.
       
       - package nodes can only have package child nodes.
       - filepath nodes can have both filepath and package child
       nodes.
       - dirpath nodes cannot have parent nodes and can only have
       filepath child nodes.
       
       ### The main data structure
       
       The data structure chosen to represent the relationships
       between Emacs dependencies is a hash table, which allowed me
       to implement a directed graph. I find this more suited to my
       needs and easier to implement than a tree with only root
       access. It allows me to easily access any analyzed
       dependency with a time complexity of O(1). This is quite
       advantageous for handling circular imports and other edge
       cases.
       
       ### Exposed commands
       
       The main interactive functions exposed are dv-package, dv-
       filepath, and dv-dirpath. They have the following signatures,
       respectively.
       
       (dv-package DEST-FILE &optional OPEN-FILE &rest SEQ)
       (dv-filepath DEST-FILE &optional OPEN-FILE &rest SEQ)
       (dv-dirpath DEST-FILE &optional OPEN-FILE &rest SEQ)
       
       Knowing that these functions, if called non-interactively,
       can manage multiple dependencies through the SEQ parameter.
       We can imagine the following call.
       
       ;; The same package can be passed multiple times as an
       argument.
       (dv-package "/tmp/abc.jpg" t 'fj 'magit 'elfeed 'pq 'pq 'pq
       'magit)
       
       ### Customizations
       
       The package offers customizations, some of which are useful
       for customizing the output image, such as dv-node-properties,
       which defaults to the following expression.
       
       `((,dv-type-package :color "red")
         (,dv-type-filepath :color "blue")
         (,dv-type-dirpath :color "green"))
       
       It may seem complex, but it is very easy to edit using the
       Emacs user interface.
       
       ## Results
       
       I am happy with the result; it fully meets the requirements
       set out at the beginning. Below is an SVG image of the
       dependencies of the Emacs transient package.
       
           /abc.svg
 (IMG) /abc.svg
       
       Below is a more complex SVG image involving all types of
       nodes and circular imports, produced using the Emacs command
       dv-dirpath.
       
           /dirpath.svg
 (IMG) /dirpath.svg
       
       ## Conclusion
       
       This project was a lot of fun to implement, and now I can
       easily get an overview of all the dependencies of an Emacs
       package.