Skip to content

Commit

Permalink
add wezterm.color.save_scheme for exporting color schemes
Browse files Browse the repository at this point in the history
  • Loading branch information
wez committed Jul 15, 2022
1 parent 181401a commit 8484248
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 38 deletions.
47 changes: 46 additions & 1 deletion config/src/color.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::*;
use luahelper::impl_lua_conversion_dynamic;
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};
use std::str::FromStr;
use termwiz::cell::CellAttributes;
pub use termwiz::color::{ColorSpec, RgbColor, SrgbaTuple};
Expand Down Expand Up @@ -451,6 +451,39 @@ pub struct ColorSchemeFile {
}
impl_lua_conversion_dynamic!(ColorSchemeFile);

fn dynamic_to_toml(value: Value) -> anyhow::Result<toml::Value> {
Ok(match value {
Value::Null => anyhow::bail!("cannot map Null to toml"),
Value::Bool(b) => toml::Value::Boolean(b),
Value::String(s) => toml::Value::String(s),
Value::Array(a) => {
let mut arr = vec![];
for v in a {
arr.push(dynamic_to_toml(v)?);
}
toml::Value::Array(arr)
}
Value::Object(o) => {
let mut map = toml::value::Map::new();
for (k, v) in o {
let k = match k {
Value::String(s) => s,
_ => anyhow::bail!("toml keys must be strings {k:?}"),
};
let v = match v {
Value::Null => continue,
other => dynamic_to_toml(other)?,
};
map.insert(k, v);
}
toml::Value::Table(map)
}
Value::U64(i) => toml::Value::Integer(i.try_into()?),
Value::I64(i) => toml::Value::Integer(i.try_into()?),
Value::F64(f) => toml::Value::Float(*f),
})
}

impl ColorSchemeFile {
pub fn from_toml_value(value: &toml::Value) -> anyhow::Result<Self> {
Self::from_dynamic(&crate::toml_to_dynamic(value), Default::default())
Expand All @@ -472,6 +505,18 @@ impl ColorSchemeFile {
}
Ok(scheme)
}

pub fn to_toml_value(&self) -> anyhow::Result<toml::Value> {
let value = self.to_dynamic();
Ok(dynamic_to_toml(value)?)
}

pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
let value = self.to_toml_value()?;
let text = toml::to_string_pretty(&value)?;
std::fs::write(&path, text)
.with_context(|| format!("writing toml to {}", path.as_ref().display()))
}
}

#[cfg(test)]
Expand Down
82 changes: 82 additions & 0 deletions docs/config/lua/wezterm.color/save_scheme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# `wezterm.color.save_scheme(colors, metadata, file_name)`

*Since: nightly builds only*

Saves a color scheme as a wezterm TOML file.
This is useful when sharing your custom color scheme with others.
While you could share the lua representation of the scheme, the
TOML file is recommended for sharing as it is purely declarative:
no executable logic is present in the TOML color scheme which makes
it safe to consume "random" schemes from the internet.

This example demonstrates importing a base16 scheme and exporting
it as a wezterm scheme.

Given a yaml file with these contents:

```yaml
scheme: "Cupcake"
author: "Chris Kempson (http://chriskempson.com)"
base00: "fbf1f2"
base01: "f2f1f4"
base02: "d8d5dd"
base03: "bfb9c6"
base04: "a59daf"
base05: "8b8198"
base06: "72677E"
base07: "585062"
base08: "D57E85"
base09: "EBB790"
base0A: "DCB16C"
base0B: "A3B367"
base0C: "69A9A7"
base0D: "7297B9"
base0E: "BB99B4"
base0F: "BAA58C"
```
Then:
```lua
> colors, metadata = wezterm.color.load_base16_scheme("/tmp/cupcake.yaml")
> wezterm.color.save_scheme(colors, metadata, "/tmp/cupcacke.toml")
```

produces a toml file with these contents:

```toml
[colors]
ansi = [
'#fbf1f2',
'#d57e85',
'#a3b367',
'#dcb16c',
'#7297b9',
'#bb99b4',
'#69a9a7',
'#8b8198',
]
background = '#fbf1f2'
brights = [
'#bfb9c6',
'#d57e85',
'#a3b367',
'#dcb16c',
'#7297b9',
'#bb99b4',
'#69a9a7',
'#585062',
]
cursor_bg = '#8b8198'
cursor_border = '#8b8198'
cursor_fg = '#8b8198'
foreground = '#8b8198'
selection_bg = '#8b8198'
selection_fg = '#fbf1f2'

[colors.indexed]

[metadata]
author = 'Chris Kempson (http://chriskempson.com)'
name = 'Cupcake'
```
15 changes: 14 additions & 1 deletion lua-api-crates/color-funcs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::schemes::base16::Base16Scheme;
use crate::schemes::sexy::Sexy;
use config::lua::mlua::{self, Lua, MetaMethod, UserData, UserDataMethods};
use config::lua::{get_or_create_module, get_or_create_sub_module};
use config::{ColorSchemeFile, Gradient, Palette, RgbaColor, SrgbaTuple};
use config::{ColorSchemeFile, ColorSchemeMetaData, Gradient, Palette, RgbaColor, SrgbaTuple};

mod image_colors;
pub mod schemes;
Expand Down Expand Up @@ -135,6 +135,19 @@ pub fn register(lua: &Lua) -> anyhow::Result<()> {
Ok((scheme.colors, scheme.metadata))
})?,
)?;

color.set(
"save_scheme",
lua.create_function(
|_, (colors, metadata, file_name): (Palette, ColorSchemeMetaData, String)| {
let scheme = ColorSchemeFile { colors, metadata };
scheme
.save_to_file(file_name)
.map_err(|err| mlua::Error::external(format!("{err:#}")))
},
)?,
)?;

color.set(
"load_terminal_sexy_scheme",
lua.create_function(|_, file_name: String| {
Expand Down
1 change: 0 additions & 1 deletion sync-color-schemes/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use sqlite_cache::Cache;
use std::collections::BTreeMap;
use std::path::Path;
use std::time::Duration;
use wezterm_dynamic::{ToDynamic, Value};

mod base16;
mod gogh;
Expand Down
36 changes: 1 addition & 35 deletions sync-color-schemes/src/scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ pub struct Scheme {

impl Scheme {
pub fn to_toml_value(&self) -> anyhow::Result<toml::Value> {
let value = self.data.to_dynamic();
Ok(dynamic_to_toml(value)?)
self.data.to_toml_value()
}

pub fn to_toml(&self) -> anyhow::Result<String> {
Expand Down Expand Up @@ -45,36 +44,3 @@ impl Scheme {
Ok(serde_json::from_str(&json)?)
}
}

fn dynamic_to_toml(value: Value) -> anyhow::Result<toml::Value> {
Ok(match value {
Value::Null => anyhow::bail!("cannot map Null to toml"),
Value::Bool(b) => toml::Value::Boolean(b),
Value::String(s) => toml::Value::String(s),
Value::Array(a) => {
let mut arr = vec![];
for v in a {
arr.push(dynamic_to_toml(v)?);
}
toml::Value::Array(arr)
}
Value::Object(o) => {
let mut map = toml::value::Map::new();
for (k, v) in o {
let k = match k {
Value::String(s) => s,
_ => anyhow::bail!("toml keys must be strings {k:?}"),
};
let v = match v {
Value::Null => continue,
other => dynamic_to_toml(other)?,
};
map.insert(k, v);
}
toml::Value::Table(map)
}
Value::U64(i) => toml::Value::Integer(i.try_into()?),
Value::I64(i) => toml::Value::Integer(i.try_into()?),
Value::F64(f) => toml::Value::Float(*f),
})
}

0 comments on commit 8484248

Please sign in to comment.