branch: externals/fontaine commit 96cece385783a9f19d3a418a8f2150ca8b5c0a58 Author: Protesilaos Stavrou <i...@protesilaos.com> Commit: Protesilaos Stavrou <i...@protesilaos.com>
Make it possible to inherit a preset in another preset --- README.org | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ fontaine.el | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/README.org b/README.org index 3a40b7f445..195f52c152 100644 --- a/README.org +++ b/README.org @@ -407,6 +407,57 @@ intend to change their values). We then have this transformation: :variable-pitch-height 1.05))) #+end_src +** Inherit the properties of another named preset +:PROPERTIES: +:CUSTOM_ID: h:9604c817-9b01-46d6-9455-58b8c393e441 +:END: + +[ Part of {{{development-version}}}. ] + +When defining multiple presets, we may need to duplicate properties +and then make tweaks to individual values. Suppose we want to have +two distinct presets for presentations: one is for coding related +demonstrations and the other for prose. Both must have some common +styles, but must define distinct font families each of which is +suitable for the given task. In this case, we do not want to fall +back to the generic =t= preset and we also do not wish to duplicate +properties manually, potentially making mistakes in the process. +Fontaine thus provides a method of inheriting a named preset's +properties. Here is the idea: + +#+begin_src emacs-lisp +(setq fontaine-presets + '((regular + :default-height 100) + (code-demo + :default-family "Source Code Pro" + :default-weight semilight + :default-height 170 + :variable-pitch-family "Sans" + :bold-weight extrabold) + (prose-demo + :inherit code-demo ; copy the `code-demo' properties + :default-family "Sans" + :variable-pitch-family "Serif" + :default-height 220) + (t + :default-family "Monospace" + ;; more generic fallback properties here... + ))) +#+end_src + +In this scenario, the =regular= preset gets all its properties from +the =t= preset. We omit them here in the interest of brevity (see the +default value of ~fontaine-presets~ and its documentation for the +details). In turn, the =code-demo= specifies more properites and +falls back to =t= for any property not explicitly referenced. +Finally, the =prose-demo= copies everything in =code-demo=, overrides +any property therein, and falls back to =t= for every other property. + +In the interest of simplicity, Fontaine does not support recursive +inheritance. If there is a compelling need for it, we can add it in +future versions. + * Installation :PROPERTIES: :CUSTOM_ID: h:031b9bea-d42b-4be0-82c7-42712cde94cc diff --git a/fontaine.el b/fontaine.el index fdbd984f39..100b8544b2 100644 --- a/fontaine.el +++ b/fontaine.el @@ -225,6 +225,18 @@ The properties in detail: - The `:line-spacing' specifies the value of the `line-spacing' variable. +- The `:inherit' contains the name of another named preset. This + tells the relevant Fontaine functions to get the properties of + that preset and blend them with those of the current one. The + properties of the current preset take precedence over those of + the inherited one, thus overriding them. In practice, this is + a way to have something like an extra-large preset copy the + large preset and then only modify its individual properties. + Remember that all named presets fall back to the preset whose + name is t: the `:inherit' is not a substitute for that generic + fallback but rather an extra method of specifying font + configuration presets. + Use the desired preset with the command `fontaine-set-preset'. For detailed configuration: Info node `(fontaine) Shared and @@ -281,12 +293,25 @@ Caveats or further notes: (const reverse-italic) (const reverse-oblique))) - ((const :tag "Line spacing" :line-spacing) ,(get 'line-spacing 'custom-type)))) + ((const :tag "Line spacing" :line-spacing) ,(get 'line-spacing 'custom-type)) + ;; FIXME 2023-01-19: Adding the (choice + ;; ,@(fontaine--inheritable-presets-widget)) instead + ;; of `symbol' does not have the desired effect + ;; because it does not re-read `fontaine-presets'. + ((const :tag "Inherit another preset" :inherit) symbol))) :key-type symbol) - :package-version '(fontaine . "0.4.0") + :package-version '(fontaine . "0.5.0") :group 'fontaine :link '(info-link "(fontaine) Shared and implicit fallback values for presets")) +;; ;; See FIXME above in `fontaine-presets' :type. +;; ;; +;; (defun fontaine--inheritable-presets-widget () +;; "Return widget with choice among named presets." +;; (mapcar (lambda (s) +;; (list 'const s)) +;; (delq t (mapcar #'car fontaine-presets)))) + (defcustom fontaine-latest-state-file (locate-user-emacs-file "fontaine-latest-state.eld") "File to save the latest value of `fontaine-set-preset'. @@ -374,14 +399,32 @@ combine the other two lists." ;;;; Apply preset configurations +(defun fontaine--preset-p (preset) + "Return non-nil if PRESET is one of the named `fontaine-presets'." + (let ((presets (delq t (mapcar #'car fontaine-presets)))) + (memq preset presets))) + +(defun fontaine--get-inherit-name (preset) + "Get the `:inherit' value of PRESET." + (when-let* ((inherit (plist-get (alist-get preset fontaine-presets) :inherit)) + (fontaine--preset-p inherit)) + inherit)) + +(defun fontaine--get-preset-properties (preset) + "Return list of properties for PRESET in `fontaine-presets'." + (let ((presets fontaine-presets)) + (append (alist-get preset presets) + (when-let ((inherit (fontaine--get-inherit-name preset))) + (alist-get inherit presets)) + (alist-get t presets)))) + (defmacro fontaine--apply-preset (fn doc args) "Produce function to apply preset. FN is the symbol of the function, DOC is its documentation, and ARGS are its routines." `(defun ,fn (preset &optional frame) ,doc - (if-let ((properties (append (alist-get preset fontaine-presets) - (alist-get t fontaine-presets)))) + (if-let ((properties (fontaine--get-preset-properties preset))) ,args ;; FIXME 2022-09-07: Because we `append' the t of ;; `fontaine-presets' this error is only relevant when the list