aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-18 20:42:29 -0500
committerCraig Jennings <c@cjennings.net>2026-06-18 20:42:29 -0500
commitcac380cf2a2960c97274c6ce3cc8b4ae3feb62d8 (patch)
treecc452ae0ba94584ea8025fa1433feda70fa39622 /scripts/theme-studio
parent61d68eae4a6184cfd241f4c25f55598843604183 (diff)
downloaddotemacs-cac380cf2a2960c97274c6ce3cc8b4ae3feb62d8.tar.gz
dotemacs-cac380cf2a2960c97274c6ce3cc8b4ae3feb62d8.zip
feat(theme-studio): bucket unrecognized faces by their defface source
A newly-loaded package (or a new built-in face) used to fall into emacs-core because grouping is by name-prefix and an unknown prefix matched nothing. Now the fallback routes by where the defface lives: an elpa face becomes its own package bucket, a built-in face a new emacs-general child. So loading a package and running make face-coverage surfaces it as a fresh TODO bucket instead of an orphan in core. Recognized faces still match their family first, and faces.el/frame.el faces stay in emacs-core.
Diffstat (limited to 'scripts/theme-studio')
-rw-r--r--scripts/theme-studio/face_coverage.py32
1 files changed, 29 insertions, 3 deletions
diff --git a/scripts/theme-studio/face_coverage.py b/scripts/theme-studio/face_coverage.py
index 99a4e01fc..ba761230b 100644
--- a/scripts/theme-studio/face_coverage.py
+++ b/scripts/theme-studio/face_coverage.py
@@ -109,7 +109,31 @@ def load_managed():
return managed, fontlock, ui, pkg, inv
-def make_group_of(families):
+# Built-in source files whose faces are core display faces, not a subsystem;
+# an unrecognized face from one of these stays in emacs-core rather than
+# spawning an odd subsystem bucket under emacs-general.
+CORE_FILES = {'faces', 'frame'}
+
+
+def bucket_from_source(path):
+ """Derive a bucket name from a face's defface file, for faces that match no
+ known family. elpa -> the package dir name (version stripped); built-in ->
+ the source file basename; otherwise emacs-core (can't tell)."""
+ if not path:
+ return 'emacs-core'
+ if '/elpa/' in path:
+ pkgdir = path.split('/elpa/', 1)[1].split('/', 1)[0]
+ return re.sub(r'-[0-9].*$', '', pkgdir) or 'emacs-core'
+ if '/.emacs.d/modules' in path:
+ return 'user-config'
+ if path.startswith('/usr/share/emacs') or path.startswith('/usr/lib/emacs'):
+ base = os.path.basename(path)
+ base = base[:-3] if base.endswith('.el') else base
+ return 'emacs-core' if base in CORE_FILES else base
+ return 'emacs-core'
+
+
+def make_group_of(families, src):
fams = sorted(families, key=len, reverse=True)
def group_of(f):
@@ -124,7 +148,9 @@ def make_group_of(families):
return p
if f.lower().startswith('info-'):
return 'info'
- return 'emacs-core'
+ # Unrecognized: route by where the defface lives so a newly-loaded
+ # package buckets itself instead of falling into emacs-core.
+ return bucket_from_source(src.get(f, ''))
return group_of
@@ -189,7 +215,7 @@ def build(data, today):
universe = sorted(set(docs.keys()) | managed)
families = set(inv.keys()) | EXTRA_FAMILIES
- group_of = make_group_of(families)
+ group_of = make_group_of(families, src)
groups = collections.defaultdict(list)
for f in universe:
groups[group_of(f)].append(f)