emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/fontaine 00a8b41a67: Accept common fallback values for


From: ELPA Syncer
Subject: [elpa] externals/fontaine 00a8b41a67: Accept common fallback values for fontaine-presets
Date: Mon, 9 May 2022 01:57:34 -0400 (EDT)

branch: externals/fontaine
commit 00a8b41a67601a5eb4edc74a154e7e4a8d9eae69
Author: Protesilaos Stavrou <info@protesilaos.com>
Commit: Protesilaos Stavrou <info@protesilaos.com>

    Accept common fallback values for fontaine-presets
    
    Update the documentation to reflect all the user-facing changes.
    
    Thanks to Ted Reed for proposing this idea and testing my prototype in
    fontaine's official mailing list:
    
<https://lists.sr.ht/~protesilaos/fontaine/%3C87y1zcmo67.fsf@zenithia.net%3E>.
---
 README.org  | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fontaine.el | 131 +++++++++++++++++++--------------
 2 files changed, 318 insertions(+), 53 deletions(-)

diff --git a/README.org b/README.org
index aae05ec1f3..6164cbab97 100644
--- a/README.org
+++ b/README.org
@@ -101,6 +101,8 @@ The doc string of ~fontaine-presets~ explains all 
properties in detail
 and documents some important caveats or information about font settings
 in Emacs.
 
+[[#h:35bc7f51-6368-4718-ad25-b276a1f2cc08][Shared and implicit fallback values 
for presets]].
+
 #+findex: fontaine-set-preset
 The command ~fontaine-set-preset~ applies the desired preset.  If there
 is only one available, it implements it outright.  Otherwise it produces
@@ -165,6 +167,242 @@ which, in turn, is what the font or source is.  However, 
I will not
 blame you if you can only interpret it as a descriptive acronym: FONTs
 Are Irrelevant in Non-graphical Emacs (because that is actually true).
 
+** Shared and implicit fallback values for presets
+:PROPERTIES:
+:CUSTOM_ID: h:35bc7f51-6368-4718-ad25-b276a1f2cc08
+:END:
+#+cindex: Concise fontaine-presets
+
+The user option ~fontaine-presets~ may look like this (its default
+value):
+
+#+begin_src emacs-lisp
+(setq fontaine-presets
+      '((regular
+         :default-family "Hack"
+         :default-weight normal
+         :default-height 100
+         :fixed-pitch-family "Fira Code"
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "Noto Sans"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.0
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight bold
+         :italic-family "Source Code Pro"
+         :italic-slant italic
+         :line-spacing 1)
+        (large
+         :default-family "Iosevka"
+         :default-weight normal
+         :default-height 150
+         :fixed-pitch-family nil ; falls back to :default-family
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.05
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight bold
+         :italic-family nil ; use whatever the underlying face has
+         :italic-slant italic
+         :line-spacing 1)))
+#+end_src
+
+Notice that not all properties need to be specified, as they have
+reasonable fallback values.  The above can be written thus (removed
+lines are left empty for didactic purposes):
+
+#+begin_src emacs-lisp
+(setq fontaine-presets
+      '((regular
+         :default-family "Hack"
+
+         :default-height 100
+         :fixed-pitch-family "Fira Code"
+
+
+         :variable-pitch-family "Noto Sans"
+
+
+
+
+         :italic-family "Source Code Pro"
+
+         :line-spacing 1)
+        (large
+         :default-family "Iosevka"
+
+         :default-height 150
+
+
+
+         :variable-pitch-family "FiraGO"
+
+
+
+
+
+
+         :line-spacing 1)))
+#+end_src
+
+Without the empty lines, we have this, which yields the same results as
+the first example:
+
+#+begin_src emacs-lisp
+(setq fontaine-presets
+      '((regular
+         :default-family "Hack"
+         :default-height 100
+         :fixed-pitch-family "Fira Code"
+         :variable-pitch-family "Noto Sans"
+         :italic-family "Source Code Pro"
+         :line-spacing 1)
+        (large
+         :default-family "Iosevka"
+         :default-height 150
+         :variable-pitch-family "FiraGO"
+         :line-spacing 1)))
+#+end_src
+
+We call the properties of the removed lines "implicit fallback values".
+
+This already shows us that the value of ~fontaine-presets~ does not need
+to be extensive.  To further improve its conciseness, it accepts a
+special preset that provides a list of "shared fallback properties": the
+=t= preset.  This one is used to define properties that are common to
+multiple presets, such as the =regular= and =large= we have illustrated
+thus far.  Here is how verbose presets can be expressed succinctly:
+
+#+begin_src emacs-lisp
+;; Notice the duplication of properties and how we will avoid it.
+(setq fontaine-presets
+      '((regular
+         :default-family "Iosevka Comfy"
+         :default-weight normal
+         :default-height 100
+         :fixed-pitch-family nil ; falls back to :default-family
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.05
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight bold
+         :italic-family nil
+         :italic-slant italic
+         :line-spacing nil)
+        (medium
+         :default-family "Iosevka Comfy"
+         :default-weight semilight
+         :default-height 140
+         :fixed-pitch-family nil ; falls back to :default-family
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.05
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight bold
+         :italic-family nil
+         :italic-slant italic
+         :line-spacing nil)
+        (large
+         :default-family "Iosevka Comfy"
+         :default-weight semilight
+         :default-height 180
+         :fixed-pitch-family nil ; falls back to :default-family
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.05
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight extrabold
+         :italic-family nil
+         :italic-slant italic
+         :line-spacing nil)))
+
+(setq fontaine-presets
+      '((regular
+         :default-height 100)
+        (medium
+         :default-weight semilight
+         :default-height 140)
+        (large
+         :default-weight semilight
+         :default-height 180
+         :bold-weight extrabold)
+        (t ; our shared fallback properties
+         :default-family "Iosevka Comfy"
+         :default-weight normal
+         ;; :default-height 100
+         :fixed-pitch-family nil ; falls back to :default-family
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.05
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight bold
+         :italic-family nil
+         :italic-slant italic
+         :line-spacing nil)))
+#+end_src
+
+The =t= preset does not need to explicitly cover all properties.  It can
+rely on the aforementioned "implicit fallback values" to further reduce
+its verbosity (though the user can always write all properties if they
+intend to change their values).  We then have this transformation:
+
+#+begin_src emacs-lisp
+;; The verbose form
+(setq fontaine-presets
+      '((regular
+         :default-height 100)
+        (medium
+         :default-weight semilight
+         :default-height 140)
+        (large
+         :default-weight semilight
+         :default-height 180
+         :bold-weight extrabold)
+        (t ; our shared fallback properties
+         :default-family "Iosevka Comfy"
+         :default-weight normal
+         ;; :default-height 100
+         :fixed-pitch-family nil ; falls back to :default-family
+         :fixed-pitch-weight nil ; falls back to :default-weight
+         :fixed-pitch-height 1.0
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-weight normal
+         :variable-pitch-height 1.05
+         :bold-family nil ; use whatever the underlying face has
+         :bold-weight bold
+         :italic-family nil
+         :italic-slant italic
+         :line-spacing nil)))
+
+;; The concise one which relies on "implicit fallback values"
+(setq fontaine-presets
+      '((regular
+         :default-height 100)
+        (medium
+         :default-weight semilight
+         :default-height 140)
+        (large
+         :default-weight semilight
+         :default-height 180
+         :bold-weight extrabold)
+        (t ; our shared fallback properties
+         :default-family "Iosevka Comfy"
+         :default-weight normal
+         :variable-pitch-family "FiraGO"
+         :variable-pitch-height 1.05)))
+#+end_src
+
 * Installation
 :PROPERTIES:
 :CUSTOM_ID: h:031b9bea-d42b-4be0-82c7-42712cde94cc
@@ -286,6 +524,8 @@ Fontaine is meant to be a collective effort.  Every bit of 
help matters.
 
 + Contributions to the code or manual :: Christopher League, Eli Zaretskii.
 
++ Ideas and user feedback :: Ted Reed.
+
 * GNU Free Documentation License
 :PROPERTIES:
 :APPENDIX: t
diff --git a/fontaine.el b/fontaine.el
index 8533587273..7a9f24c92f 100644
--- a/fontaine.el
+++ b/fontaine.el
@@ -170,6 +170,12 @@
 The car of each cell is an arbitrary symbol that identifies
 and/or describes the set of properties (e.g. 'small', 'reading').
 
+A preset whose car is t is treated as the default option.  This
+makes it easier to specify multiple presets without duplicating
+their properties.  The other presets beside t act as overrides of
+the defaults and, as such, need only consist of the properties
+that change from the default.
+
 The cdr is a plist that specifies the typographic properties of
 the faces `default', `fixed-pitch', `variable-pitch', `bold', and
 `italic'.  It also covers the `line-spacing' variable.
@@ -216,6 +222,9 @@ The properties in detail:
 
 Use the desired preset with the command `fontaine-set-preset'.
 
+For detailed configuration: Info node `(fontaine) Shared and
+implicit fallback values for presets'.
+
 Caveats or further notes:
 
 - On a Windows system, setting a `default' weight other than
@@ -265,7 +274,8 @@ Caveats or further notes:
                     (const reverse-oblique)))
 
                   ((const :tag "Line spacing" :line-spacing) ,(get 
'line-spacing 'custom-type))))
-          :key-type symbol))
+          :key-type symbol)
+  :link '(info-link "(fontaine) Shared and implicit fallback values for 
presets"))
 
 (defcustom fontaine-latest-state-file
   (locate-user-emacs-file "fontaine-latest-state.eld")
@@ -352,63 +362,78 @@ combine the other two lists."
 
 ;;;; Apply preset configurations
 
-(defun fontaine--apply-default-preset (preset &optional frame)
-  "Set `default' face attributes based on PRESET for optional FRAME."
-  (if-let ((properties (alist-get preset fontaine-presets)))
-      (progn
-        (fontaine--set-face-attributes
-         'default
-         (plist-get properties :default-family)
-         (plist-get properties :default-weight)
-         (plist-get properties :default-height)
-         frame)
-        (setq-default line-spacing (plist-get properties :line-spacing)))
-    (user-error "%s is not in `fontaine-presets'" preset)))
-
-(defun fontaine--apply-fixed-pitch-preset (preset &optional frame)
-  "Set `fixed-pitch' face attributes based on PRESET for optional FRAME."
-  (if-let ((properties (alist-get preset fontaine-presets)))
-      (fontaine--set-face-attributes
-       'fixed-pitch
-       (or (plist-get properties :fixed-pitch-family) (plist-get properties 
:default-family))
-       (or (plist-get properties :fixed-pitch-weight) (plist-get properties 
:default-weight))
-       (or (plist-get properties :fixed-pitch-height) 1.0)
-       frame)
-    (user-error "%s is not in `fontaine-presets'" preset)))
-
-(defun fontaine--apply-variable-pitch-preset (preset &optional frame)
-  "Set `variable-pitch' face attributes based on PRESET for optional FRAME."
-  (if-let ((properties (alist-get preset fontaine-presets)))
-      (fontaine--set-face-attributes
-       'variable-pitch
-       (or (plist-get properties :variable-pitch-family) (plist-get properties 
:default-family))
-       (or (plist-get properties :variable-pitch-weight) (plist-get properties 
:default-weight))
-       (or (plist-get properties :variable-pitch-height) 1.0)
-       frame)
-    (user-error "%s is not in `fontaine-presets'" preset)))
-
-(defun fontaine--apply-bold-preset (preset &optional frame)
+(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))))
+         ,args
+       (user-error "%s is not in `fontaine-presets' or is empty" preset))))
+
+(fontaine--apply-preset
+ fontaine--apply-default-preset
+ "Set `default' face attributes based on PRESET for optional FRAME."
+ (progn
+   (fontaine--set-face-attributes
+    'default
+    (plist-get properties :default-family)
+    (plist-get properties :default-weight)
+    (plist-get properties :default-height)
+    frame)
+   (setq-default line-spacing (plist-get properties :line-spacing))))
+
+(fontaine--apply-preset
+ fontaine--apply-fixed-pitch-preset
+ "Set `fixed-pitch' face attributes based on PRESET for optional FRAME."
+ (fontaine--set-face-attributes
+  'fixed-pitch
+  (or (plist-get properties :fixed-pitch-family) (plist-get properties 
:default-family))
+  (or (plist-get properties :fixed-pitch-weight) (plist-get properties 
:default-weight))
+  (or (plist-get properties :fixed-pitch-height) 1.0)
+  frame))
+
+(fontaine--apply-preset
+ fontaine--apply-variable-pitch-preset
+ "Set `variable-pitch' face attributes based on PRESET for optional FRAME."
+ (fontaine--set-face-attributes
+  'variable-pitch
+  (or (plist-get properties :variable-pitch-family) (plist-get properties 
:default-family))
+  (or (plist-get properties :variable-pitch-weight) (plist-get properties 
:default-weight))
+  (or (plist-get properties :variable-pitch-height) 1.0)
+  frame))
+
+(fontaine--apply-preset
+ fontaine--apply-bold-preset
   "Set `bold' face attributes based on PRESET for optional FRAME."
-  (if-let ((properties (alist-get preset fontaine-presets)))
-      (fontaine--set-face-attributes
-       'bold
-       (or (plist-get properties :bold-family) 'unspecified)
-       (or (plist-get properties :bold-weight) 'bold)
-       frame)
-    (user-error "%s is not in `fontaine-presets'" preset)))
-
-(defun fontaine--apply-italic-preset (preset &optional frame)
+  (fontaine--set-face-attributes
+   'bold
+   (or (plist-get properties :bold-family) 'unspecified)
+   (or (plist-get properties :bold-weight) 'bold)
+   frame))
+
+(fontaine--apply-preset
+ fontaine--apply-italic-preset
   "Set `italic' face attributes based on PRESET for optional FRAME."
-  (if-let ((properties (alist-get preset fontaine-presets)))
-      (fontaine--set-italic-slant
-       (or (plist-get properties :italic-family) 'unspecified)
-       (or (plist-get properties :italic-slant) 'italic)
-       frame)
-    (user-error "%s is not in `fontaine-presets'" preset)))
+  (fontaine--set-italic-slant
+   (or (plist-get properties :italic-family) 'unspecified)
+   (or (plist-get properties :italic-slant) 'italic)
+   frame))
 
 (defvar fontaine--font-display-hist '()
   "History of inputs for display-related font associations.")
 
+(defun fontaine--presets-no-fallback ()
+  "Return list of `fontaine-presets', minus the fallback value."
+  (delete
+   nil
+   (mapcar (lambda (symbol)
+             (unless (eq (car symbol) t)
+               symbol))
+           fontaine-presets)))
+
 (defun fontaine--set-fonts-prompt ()
   "Prompt for font set (used by `fontaine-set-fonts')."
   (let* ((def (nth 1 fontaine--font-display-hist))
@@ -418,7 +443,7 @@ combine the other two lists."
     (intern
      (completing-read
       prompt
-      fontaine-presets
+      (fontaine--presets-no-fallback)
       nil t nil 'fontaine--font-display-hist def))))
 
 (defvar fontaine-set-preset-hook nil



reply via email to

[Prev in Thread] Current Thread [Next in Thread]