mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 05:12:40 +03:00
color schemes: add alias concept
Various color schemes have been duplicated as they have been added to different scheme collections. They don't always have identical names (eg: some remove spaces) and sometimes they have very different names (eg: _bash vs. nightfox, or Miu vs. Blazer). We already detected duplicates from different collections but previously we would omit those dupes. This commit allows us to track those duplicates by recording their aliases. When we write out our data, we only include "interesting" alias names; those where the name isn't trivially identical. Some scheme collections (eg: iterm2 color schemes) have duplicates (eg: zenbones and zenbones_light are identical) and we have previously shipped with both of those names, so we special case to emit dupes for which we have prior version information in order to avoid breaking backwards compatibility for our users. In the doc generation we can generate links to the aliases if we included them, but also note about the other names and how we don't include them. That is so that someone searching the docs for say "_bash" can discover that it is actually a duplicate of "nightfox" and use nightfox instead.
This commit is contained in:
parent
ffb6ea76cd
commit
50d5f94ab0
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -4272,9 +4272,11 @@ dependencies = [
|
||||
"anyhow",
|
||||
"color-funcs",
|
||||
"config",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"libflate",
|
||||
"log",
|
||||
"reqwest",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
|
@ -185,12 +185,23 @@ class GenColorScheme(object):
|
||||
with open("colorschemes/data.json") as f:
|
||||
scheme_data = json.load(f)
|
||||
by_prefix = {}
|
||||
by_name = {}
|
||||
for scheme in scheme_data:
|
||||
scheme = load_scheme(scheme)
|
||||
prefix = scheme["prefix"]
|
||||
if prefix not in by_prefix:
|
||||
by_prefix[prefix] = []
|
||||
by_prefix[prefix].append(scheme)
|
||||
by_name[scheme["name"]] = scheme
|
||||
|
||||
def scheme_link(name):
|
||||
if name in by_name:
|
||||
scheme = by_name[name]
|
||||
prefix = scheme["prefix"]
|
||||
ident = scheme["ident"]
|
||||
return f"../{prefix}/index.md#{ident}"
|
||||
else:
|
||||
return None
|
||||
|
||||
children = []
|
||||
for scheme_prefix in sorted(by_prefix.keys()):
|
||||
@ -239,6 +250,25 @@ window.addEventListener('load', function () {{
|
||||
if version and version != "Always":
|
||||
idx.write(f"Since: *{version}*<br/>\n")
|
||||
|
||||
aliases = scheme["metadata"]["aliases"]
|
||||
if len(aliases) > 1:
|
||||
canon_name = aliases[0]
|
||||
am_canon = title == canon_name
|
||||
if am_canon:
|
||||
alias_list = []
|
||||
for a in aliases[1:]:
|
||||
alias_link = scheme_link(a)
|
||||
if alias_link:
|
||||
alias_list.append(f"[{a}]({alias_link})")
|
||||
else:
|
||||
alias_list.append(f"`{a}` (but that name isn't used here)")
|
||||
aliases = ', '.join(alias_list)
|
||||
idx.write(f"This scheme is also known as {aliases}.<br/>\n")
|
||||
else:
|
||||
canon_link = scheme_link(canon_name)
|
||||
idx.write(f"This scheme is the same as [{canon_name}]({canon_link}).<br/>\n")
|
||||
|
||||
|
||||
idx.write("\nTo use this scheme, add this to your config:\n")
|
||||
idx.write(
|
||||
f"""
|
||||
|
@ -438,6 +438,8 @@ pub struct ColorSchemeMetaData {
|
||||
pub author: Option<String>,
|
||||
pub origin_url: Option<String>,
|
||||
pub wezterm_version: Option<String>,
|
||||
#[dynamic(default)]
|
||||
pub aliases: Vec<String>,
|
||||
}
|
||||
impl_lua_conversion_dynamic!(ColorSchemeMetaData);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -74,6 +74,7 @@ impl Base16Scheme {
|
||||
author: Some(scheme.author.clone()),
|
||||
origin_url: None,
|
||||
wezterm_version: None,
|
||||
aliases: vec![],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ impl GoghTheme {
|
||||
author: None,
|
||||
origin_url: None,
|
||||
wezterm_version: None,
|
||||
aliases: vec![],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -137,6 +137,7 @@ impl ITerm2 {
|
||||
author,
|
||||
origin_url,
|
||||
wezterm_version: None,
|
||||
aliases: vec![],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ impl Sexy {
|
||||
author: Some(sexy.author),
|
||||
origin_url: None,
|
||||
wezterm_version: None,
|
||||
aliases: vec![],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -9,9 +9,11 @@ edition = "2021"
|
||||
anyhow = "1.0"
|
||||
color-funcs = { path = "../lua-api-crates/color-funcs" }
|
||||
config = { path = "../config" }
|
||||
env_logger = "0.9"
|
||||
futures = "0.3"
|
||||
lazy_static = "1.4"
|
||||
libflate = "1"
|
||||
log = "0.4"
|
||||
reqwest = "0.11"
|
||||
rusqlite = {version="0.27", features=["bundled", "blob"]}
|
||||
serde = {version="1.0", features=["derive"]}
|
||||
|
@ -94,6 +94,26 @@ fn make_prefix(key: &str) -> (char, String) {
|
||||
panic!("no good prefix");
|
||||
}
|
||||
|
||||
const KNOWN_NAMESPACES: &[&str] = &[" (base16)", " (terminal.sexy)", " (Gogh)"];
|
||||
|
||||
fn known_namespace(name: &str) -> bool {
|
||||
for ns in KNOWN_NAMESPACES {
|
||||
if name.ends_with(ns) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn suffixed_alias_matches_name(alias: &str, name: &str) -> bool {
|
||||
for ns in KNOWN_NAMESPACES {
|
||||
if let Some(stripped) = alias.strip_suffix(ns) {
|
||||
return stripped == name;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn bake_for_config(mut schemeses: Vec<Scheme>) -> anyhow::Result<()> {
|
||||
let json_file_name = "docs/colorschemes/data.json";
|
||||
|
||||
@ -112,7 +132,7 @@ fn bake_for_config(mut schemeses: Vec<Scheme>) -> anyhow::Result<()> {
|
||||
let existing: Vec<MetaOnly> = serde_json::from_str(&data)?;
|
||||
for item in &existing {
|
||||
if let Some(version) = &item.metadata.wezterm_version {
|
||||
version_by_name.insert(&item.metadata.name, version.as_str());
|
||||
version_by_name.insert(item.metadata.name.to_string(), version.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,13 +140,10 @@ fn bake_for_config(mut schemeses: Vec<Scheme>) -> anyhow::Result<()> {
|
||||
// We're bootstrapping the version info
|
||||
for item in &existing {
|
||||
let name = &item.metadata.name;
|
||||
if name.ends_with("(base16)")
|
||||
|| name.ends_with("(terminal.sexy)")
|
||||
|| name.ends_with("(Gogh)")
|
||||
{
|
||||
if known_namespace(name) {
|
||||
continue;
|
||||
}
|
||||
version_by_name.insert(name, "Always");
|
||||
version_by_name.insert(name.to_string(), "Always".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,8 +159,38 @@ fn bake_for_config(mut schemeses: Vec<Scheme>) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
let mut all = vec![];
|
||||
for s in &schemeses {
|
||||
// Only interested in aliases with different-enough names
|
||||
let mut aliases = s.data.metadata.aliases.clone();
|
||||
aliases.retain(|name| !suffixed_alias_matches_name(&name, &s.name));
|
||||
|
||||
let count = schemeses.len();
|
||||
// Normalize the list of aliases so that the canonical
|
||||
// name is included in the list at the start.
|
||||
let mut s = s.clone();
|
||||
s.data.metadata.aliases = aliases.clone();
|
||||
if !aliases.is_empty() {
|
||||
s.data.metadata.aliases.insert(0, s.name.clone());
|
||||
}
|
||||
|
||||
all.push(s.clone());
|
||||
|
||||
// Only instantiate aliases in our scheme data if
|
||||
// we had previously shipped a version with that
|
||||
// name in use
|
||||
for name in aliases {
|
||||
if version_by_name.get(&name).is_some() {
|
||||
let mut alias = Scheme {
|
||||
name: name.clone(),
|
||||
..s.clone()
|
||||
};
|
||||
alias.data.metadata.name.replace(name.clone());
|
||||
all.push(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
all.sort_by_key(|s| make_prefix(&s.name));
|
||||
|
||||
let count = all.len();
|
||||
let mut code = String::new();
|
||||
code.push_str(&format!(
|
||||
"//! This file was generated by sync-color-schemes\n
|
||||
@ -151,10 +198,6 @@ pub const SCHEMES: [(&'static str, &'static str); {count}] = [\n
|
||||
// Start here
|
||||
",
|
||||
));
|
||||
for s in &schemeses {
|
||||
all.push(s);
|
||||
}
|
||||
all.sort_by_key(|s| make_prefix(&s.name));
|
||||
|
||||
for s in &all {
|
||||
let name = s.name.escape_default();
|
||||
@ -172,7 +215,7 @@ pub const SCHEMES: [(&'static str, &'static str); {count}] = [\n
|
||||
};
|
||||
|
||||
if update {
|
||||
eprintln!("Updating {file_name}");
|
||||
println!("Updating {file_name}");
|
||||
std::fs::write(file_name, code)?;
|
||||
}
|
||||
}
|
||||
@ -192,34 +235,37 @@ pub const SCHEMES: [(&'static str, &'static str); {count}] = [\n
|
||||
};
|
||||
|
||||
if update {
|
||||
eprintln!("Updating {json_file_name}");
|
||||
println!("Updating {json_file_name}");
|
||||
std::fs::write(json_file_name, json)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn scheme_exists<'a>(schemeses: &'a [Scheme], candidate: &Scheme) -> Option<&'a str> {
|
||||
for existing in schemeses {
|
||||
fn push_or_alias(schemeses: &mut Vec<Scheme>, candidate: Scheme) -> bool {
|
||||
let mut aliased = false;
|
||||
for existing in schemeses.iter_mut() {
|
||||
if candidate.data.colors.ansi == existing.data.colors.ansi
|
||||
&& candidate.data.colors.brights == existing.data.colors.brights
|
||||
&& candidate.data.colors.foreground == existing.data.colors.foreground
|
||||
&& candidate.data.colors.background == existing.data.colors.background
|
||||
{
|
||||
return Some(&existing.name);
|
||||
log::info!("Adding {} as alias of {}", candidate.name, existing.name);
|
||||
existing.data.metadata.aliases.push(candidate.name.clone());
|
||||
aliased = true;
|
||||
}
|
||||
}
|
||||
None
|
||||
if !aliased {
|
||||
log::info!("Adding {}", candidate.name);
|
||||
schemeses.push(candidate);
|
||||
}
|
||||
aliased
|
||||
}
|
||||
|
||||
fn accumulate(schemeses: &mut Vec<Scheme>, to_add: Vec<Scheme>) {
|
||||
// Only accumulate if the scheme looks different enough
|
||||
for candidate in to_add {
|
||||
if let Some(existing) = scheme_exists(schemeses, &candidate) {
|
||||
println!("{} is same as {}", candidate.name, existing);
|
||||
continue;
|
||||
}
|
||||
schemeses.push(candidate);
|
||||
push_or_alias(schemeses, candidate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,37 +294,34 @@ async fn sync_toml(
|
||||
|
||||
let data = std::fs::read_to_string(dest_file.path())?;
|
||||
|
||||
if let Ok(mut scheme) = ColorSchemeFile::from_toml_str(&data) {
|
||||
let name = match scheme.metadata.name {
|
||||
Some(name) => name,
|
||||
None => entry
|
||||
.path()?
|
||||
.file_stem()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
};
|
||||
let name = format!("{name}{suffix}");
|
||||
scheme.metadata.name = Some(name.clone());
|
||||
scheme.metadata.origin_url = Some(repo_url.to_string());
|
||||
apply_nightly_version(&mut scheme.metadata);
|
||||
match ColorSchemeFile::from_toml_str(&data) {
|
||||
Ok(mut scheme) => {
|
||||
let name = match scheme.metadata.name {
|
||||
Some(name) => name,
|
||||
None => entry
|
||||
.path()?
|
||||
.file_stem()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
};
|
||||
let name = format!("{name}{suffix}");
|
||||
scheme.metadata.name = Some(name.clone());
|
||||
scheme.metadata.origin_url = Some(repo_url.to_string());
|
||||
apply_nightly_version(&mut scheme.metadata);
|
||||
|
||||
let scheme = Scheme {
|
||||
name: name.clone(),
|
||||
file_name: None,
|
||||
data: scheme,
|
||||
};
|
||||
let scheme = Scheme {
|
||||
name: name.clone(),
|
||||
file_name: None,
|
||||
data: scheme,
|
||||
};
|
||||
|
||||
if !suffix.is_empty() {
|
||||
// A pre-existing entry is considered canonical
|
||||
if let Some(existing) = scheme_exists(schemeses, &scheme) {
|
||||
println!("{} is same as {}", name, existing);
|
||||
continue;
|
||||
}
|
||||
push_or_alias(schemeses, scheme);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("{tarball_url}/{}: {err:#}", entry.path().unwrap().display());
|
||||
}
|
||||
|
||||
schemeses.push(scheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -287,8 +330,14 @@ async fn sync_toml(
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
// They color us! my precious!
|
||||
let mut schemeses = iterm2::sync_iterm2().await.context("sync iterm2")?;
|
||||
let mut schemeses = vec![];
|
||||
accumulate(
|
||||
&mut schemeses,
|
||||
iterm2::sync_iterm2().await.context("sync iterm2")?,
|
||||
);
|
||||
sync_toml(
|
||||
"https://github.com/catppuccin/wezterm",
|
||||
"main",
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Scheme {
|
||||
pub name: String,
|
||||
pub file_name: Option<String>,
|
||||
|
Loading…
Reference in New Issue
Block a user