technicolor

Programmatic emacs theme pallate access

Stars
8

#+title: technicolor #+subtitle: (almost) universal programmatic color palette access

  • What is this?
    =technicolor= offers a uniform API to access a specified collection of colors
    defined in your currently-enabled theme.

See this accompanying [[https://aatmunbaxi.netlify.app/comp/dyn_custom_palette_access_technicolor/][blog post]] detailing the problem, solution, and example usage.

  • The Problem
    Let's say you use DOOM themes and you use the foreground color from the doom
    theme palette somewhere in elisp. That's great! DOOM themes offer an API for that:
    =(doom-color 'fg)=.

But you also use =modus-themes= sometimes, and you want to use the modus foreground color. No problem, modus offers an API too: =(modus-themes-get-color-value 'fg-main)=. Oops, the symbol of the color is different, and the function to access the color is different. I guess you can add some branches in your elisp that determine if the current theme is a DOOM or modus theme...

..except you also sometimes use =catppuccin-theme=, and =ef-themes=, and...

What to do? Add branches /ad nauseam/ to cover every possible theme you might have active?

technicolor hopes to solve this issue by letting users define a "universal color palette" in which they can access these colors from any currently-set theme coming from a list of themes the user specifies with a /single API/.

Configured properly, the above situation would reduce to =(technicolor-get-color 'foreground)=.

  • Using =technicolor=
    technicolor comes with some limited configuration associated to a few popular
    theme packs:
  • [[https://github.com/doomemacs/themes][DOOM themes]]
  • Prot's themes (modus-, ef-, standard-)
  • [[https://github.com/catppuccin/emacs][catppuccin theme]]

These are good starting points, but the user should still peer into the color palettes and decide how they want to map colors. Here is an example:

Let's say you want to access the foreground color in elisp for the DOOM themes and modus themes. You can set this in the =technicolor-colors= list: #+begin_src emacs-lisp (setq technicolor-colors '(foreground)) #+end_src The theme's above have the following accessors we can use:

  • Doom themes :: =doom-color=
  • Prot themes :: =*-themes-get-color-value=

The DOOM themes use =fg= for the foreground color, while Prot uses =fg-main=, so we map our "universal" palette name =foreground= to these symbols in their configurations. #+begin_src emacs-lisp (setq technicolor-themes '(("^doom-." doom-color '((foreground . fg))) ("^modus-." modus-themes-get-color-value '((foreground . fg-main))) ...)) #+end_src You can now access the current foreground color with =(technicolor-get-color 'foreground)= provided your theme matches one of the above. Note we have reproduced a subset of the default config provided.

That configuration will match all doom themes and all modus themes; you can set per-theme rules on color mappings from the universal palette by refining the regex: #+begin_src emacs-lisp ' ... ("^modus-operandi" modus-themes-get-color-value '((mappings . here))) (("^modus-vivendi" modus-themes-get-color-value '((different . mappings))) ...) #+end_src Extend the value of =technicolor-colors= to any colors that you'd like to use. If you give appropriate mappings for each group of themes, technicolor will find them.

Note that if /all/ of your themes provide the same symbol for a certain color, as is common for generic colors like "red", "blue", etc, you don't need to specify the mapping from the universal palette (but they should still be in =technicolor-colors=).

** Theme accessors technicolor depends on a theme's /accessor/ to retrieve colors. An accessor for a color should take in a color symbol and return the hexadecimal color that the theme defines for that color, or =nil= or =unspecified= if no such color exists in the palette. DOOM themes and Prot's themes ship with their own accessors.

If the theme you want to include does include one, you will have to write your own. With varying degrees of munging, this is possible (e.g. the catppuccin color accessor defined in =technicolor.el=).

  • Installation
    Via =straight=:
    #+begin_src emacs-lisp
    (straight-use-package
    '(technicolor :type git :host github :repo "aatmunbaxi/technicolor"))
    #+end_src

or for DOOM emacs users in your =packages.el=: #+begin_src emacs-lisp (package! technicolor :recipe (:host github :repo "aatmunbaxi/technicolor")) #+end_src

If your package manager does not support git recipes and you use =use-package=, you can clone the repo and place the following in your configuration: #+begin_src emacs-lisp (use-package technicolor :load-path "path/to/cloned/technicolor") #+end_src along with any =use-package= configuration.

  • Color Manipulation
    technicolor can also perform basic manipulation of colors, using the same ethos
    of accessing the colors via =technicolor-get-color=. They are listed below.
    Essentially, they wrap the =color= library.
  • =technicolor-darken=
  • =technicolor-lighten=
  • =technicolor-complement=
  • =technicolor-gradient=
  • =technicolor-saturate=
  • =technicolor-desaturate=
  • =technicolor-blend=