feat: apply Pagefind attributes by selector through config rules

exclude_selectors is the only way the config can reach into a page, and it
carries the semantics of data-pagefind-ignore="index". Every other control
Pagefind has lives on an attribute, so reaching it from the config meant a
new flag per attribute.

Add a rules list that pairs a selector with the attributes to set on the
elements it matches. The attributes are applied before every other handler,
so the rest of the parser reads them exactly as if the page had carried
them, and every documented attribute is reachable without new flags.

An attribute already present on the element wins, so a rule never overrides
markup. A selector that cannot be parsed is reported and skipped.

Rules are config-file only: a list of selectors with attribute maps does not
fit a CLI flag or an environment variable.
This commit is contained in:
dualfroz committed 2026-09-23 10:26:08 +02:00
1 parent c036b250ba
commit 085385c3e4
3 files changed
+163 -3

No files matched your search

+17 -1
View File
@@ -4,7 +4,7 @@ use anyhow::{bail, Result};
use clap::Parser;
use rust_patch::Patch;
use serde::{Deserialize, Serialize};
use std::{env, path::PathBuf};
use std::{collections::BTreeMap, env, path::PathBuf};
use twelf::config;
use typed_builder::TypedBuilder;
@@ -22,6 +22,15 @@ use crate::{
// No options should be added that are required.
//
/// A selector paired with the Pagefind attributes to set on the elements it matches,
/// so a site can be configured with the same vocabulary its HTML would use.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
pub(crate) struct PagefindRule {
pub(crate) selector: String,
#[serde(default)]
pub(crate) attributes: BTreeMap<String, String>,
}
#[config]
#[derive(Parser, Debug, Clone)]
#[clap(author, version, about, long_about = None)]
@@ -74,6 +83,11 @@ pub(crate) struct PagefindInboundConfig {
#[serde(default)]
pub(crate) exclude_selectors: Vec<String>,
/// Not a CLI flag: a list of selectors with attribute maps does not fit an argument.
#[clap(skip)]
#[serde(default)]
pub(crate) rules: Vec<PagefindRule>,
#[clap(
long,
help = "The file glob Pagefind uses to find HTML files. Defaults to \"**/*.{html}\""
@@ -227,6 +241,7 @@ pub(crate) struct SearchOptions {
pub(crate) bundle_output: PathBuf,
pub(crate) root_selector: String,
pub(crate) exclude_selectors: Vec<String>,
pub(crate) rules: Vec<PagefindRule>,
pub(crate) glob: String,
pub(crate) force_language: Option<String>,
pub(crate) include_characters: Vec<char>,
@@ -308,6 +323,7 @@ impl SearchOptions {
bundle_output,
root_selector: config.root_selector,
exclude_selectors: config.exclude_selectors,
rules: config.rules,
glob: config.glob,
force_language: config.force_language,
include_characters,