mirror of
https://github.com/wez/wezterm.git
synced 2024-12-22 12:51:31 +03:00
add window:set_config_overrides lua method
This commit expands on the prior commits to introduce the concept of per-window configuration overrides. Each TermWindow maintains json compatible object value holding a map of config key -> config value overrides. When the window notices that the config has changed, the config file is loaded, the CLI overrides (if any) are applied, and then finally the per-window overrides, before attempting to coerce the resultant lua value into a Config object. This mechanism has some important constraints: * Only data can be assigned to the overrides. Closures or special lua userdata object handles are not permitted. This is because the lifetime of those objects is tied to the lua context in which they were parsed, which doesn't really exist in the context of the window. * Only simple keys are supported for the per-window overrides. That means that trying to override a very specific field of a deeply structured value (eg: something like `font_rules[1].italic = false` isn't able to be expressed in this scheme. Instead, you would need to assign the entire `font_rules` key. I don't anticipate this being a common desire at this time; if more advance manipulations are required, then I have some thoughts on an event where arbitrary lua modifications can be applied. The implementation details are fairly straight-forward, but in testing the two examplary use cases I noticed that some hangovers from supporting overrides for a couple of font related options meant that the window-specific config wasn't being honored. I've removed the code that handled those overrides in favor of the newer more general CLI option override support, and threaded the config through to the font code. closes: #469 closes: #329
This commit is contained in:
parent
60be1a98a0
commit
db08b8c1dc
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -687,6 +687,7 @@ dependencies = [
|
||||
"pretty_env_logger",
|
||||
"promise",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smol",
|
||||
"termwiz",
|
||||
"toml",
|
||||
@ -1929,6 +1930,7 @@ dependencies = [
|
||||
"log",
|
||||
"mlua",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strsim 0.10.0",
|
||||
"thiserror",
|
||||
]
|
||||
|
@ -30,6 +30,7 @@ notify = "4.0"
|
||||
portable-pty = { path = "../pty", features = ["serde_support"]}
|
||||
promise = { path = "../promise" }
|
||||
serde = {version="1.0", features = ["rc", "derive"]}
|
||||
serde_json = "1.0"
|
||||
smol = "1.2"
|
||||
termwiz = { path = "../termwiz" }
|
||||
toml = "0.5"
|
||||
|
@ -369,10 +369,6 @@ pub enum FontLocatorSelection {
|
||||
ConfigDirsOnly,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_LOCATOR: Mutex<FontLocatorSelection> = Mutex::new(Default::default());
|
||||
}
|
||||
|
||||
impl Default for FontLocatorSelection {
|
||||
fn default() -> Self {
|
||||
if cfg!(windows) {
|
||||
@ -386,16 +382,6 @@ impl Default for FontLocatorSelection {
|
||||
}
|
||||
|
||||
impl FontLocatorSelection {
|
||||
pub fn set_default(self) {
|
||||
let mut def = DEFAULT_LOCATOR.lock().unwrap();
|
||||
*def = self;
|
||||
}
|
||||
|
||||
pub fn get_default() -> Self {
|
||||
let def = DEFAULT_LOCATOR.lock().unwrap();
|
||||
*def
|
||||
}
|
||||
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["FontConfig", "CoreText", "ConfigDirsOnly", "Gdi"]
|
||||
}
|
||||
@ -423,10 +409,6 @@ pub enum FontRasterizerSelection {
|
||||
FreeType,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_RASTER: Mutex<FontRasterizerSelection> = Mutex::new(Default::default());
|
||||
}
|
||||
|
||||
impl Default for FontRasterizerSelection {
|
||||
fn default() -> Self {
|
||||
FontRasterizerSelection::FreeType
|
||||
@ -434,16 +416,6 @@ impl Default for FontRasterizerSelection {
|
||||
}
|
||||
|
||||
impl FontRasterizerSelection {
|
||||
pub fn set_default(self) {
|
||||
let mut def = DEFAULT_RASTER.lock().unwrap();
|
||||
*def = self;
|
||||
}
|
||||
|
||||
pub fn get_default() -> Self {
|
||||
let def = DEFAULT_RASTER.lock().unwrap();
|
||||
*def
|
||||
}
|
||||
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["FreeType"]
|
||||
}
|
||||
@ -469,10 +441,6 @@ pub enum FontShaperSelection {
|
||||
Harfbuzz,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref DEFAULT_SHAPER: Mutex<FontShaperSelection> = Mutex::new(Default::default());
|
||||
}
|
||||
|
||||
impl Default for FontShaperSelection {
|
||||
fn default() -> Self {
|
||||
FontShaperSelection::Harfbuzz
|
||||
@ -480,16 +448,6 @@ impl Default for FontShaperSelection {
|
||||
}
|
||||
|
||||
impl FontShaperSelection {
|
||||
pub fn set_default(self) {
|
||||
let mut def = DEFAULT_SHAPER.lock().unwrap();
|
||||
*def = self;
|
||||
}
|
||||
|
||||
pub fn get_default() -> Self {
|
||||
let def = DEFAULT_SHAPER.lock().unwrap();
|
||||
*def
|
||||
}
|
||||
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["Harfbuzz", "AllSorts"]
|
||||
}
|
||||
|
@ -310,6 +310,12 @@ pub fn configuration() -> ConfigHandle {
|
||||
CONFIG.get()
|
||||
}
|
||||
|
||||
/// Returns a version of the config (loaded from the config file)
|
||||
/// with some field overridden based on the supplied overrides object.
|
||||
pub fn overridden_config(overrides: &serde_json::Value) -> Result<ConfigHandle, Error> {
|
||||
CONFIG.overridden(overrides)
|
||||
}
|
||||
|
||||
pub fn reload() {
|
||||
CONFIG.reload();
|
||||
}
|
||||
@ -447,9 +453,17 @@ impl ConfigInner {
|
||||
self.generation += 1;
|
||||
}
|
||||
|
||||
fn overridden(&mut self, overrides: &serde_json::Value) -> Result<ConfigHandle, Error> {
|
||||
let config = Config::load_with_overrides(overrides)?;
|
||||
Ok(ConfigHandle {
|
||||
config: Arc::new(config.config),
|
||||
generation: self.generation,
|
||||
})
|
||||
}
|
||||
|
||||
fn use_test(&mut self) {
|
||||
FontLocatorSelection::ConfigDirsOnly.set_default();
|
||||
let mut config = Config::default_config();
|
||||
config.font_locator = FontLocatorSelection::ConfigDirsOnly;
|
||||
// Specify the same DPI used on non-mac systems so
|
||||
// that we have consistent values regardless of the
|
||||
// operating system that we're running tests on
|
||||
@ -491,6 +505,11 @@ impl Configuration {
|
||||
inner.use_this_config(cfg);
|
||||
}
|
||||
|
||||
fn overridden(&self, overrides: &serde_json::Value) -> Result<ConfigHandle, Error> {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.overridden(overrides)
|
||||
}
|
||||
|
||||
/// Use a config that doesn't depend on the user's
|
||||
/// environment and is suitable for unit testing
|
||||
pub fn use_test(&self) {
|
||||
@ -1136,6 +1155,10 @@ impl PathPossibility {
|
||||
|
||||
impl Config {
|
||||
pub fn load() -> Result<LoadedConfig, Error> {
|
||||
Self::load_with_overrides(&serde_json::Value::default())
|
||||
}
|
||||
|
||||
pub fn load_with_overrides(overrides: &serde_json::Value) -> Result<LoadedConfig, Error> {
|
||||
// Note that the directories crate has methods for locating project
|
||||
// specific config directories, but only returns one of them, not
|
||||
// multiple. In addition, it spawns a lot of subprocesses,
|
||||
@ -1193,6 +1216,7 @@ impl Config {
|
||||
.eval_async(),
|
||||
)?;
|
||||
let config = Self::apply_overrides_to(&lua, config)?;
|
||||
let config = Self::apply_overrides_obj_to(config, overrides)?;
|
||||
cfg = luahelper::from_lua_value(config).with_context(|| {
|
||||
format!(
|
||||
"Error converting lua value returned by script {} to Config struct",
|
||||
@ -1222,6 +1246,24 @@ impl Config {
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_overrides_obj_to<'l>(
|
||||
mut config: mlua::Value<'l>,
|
||||
overrides: &serde_json::Value,
|
||||
) -> anyhow::Result<mlua::Value<'l>> {
|
||||
match overrides {
|
||||
serde_json::Value::Object(obj) => {
|
||||
if let mlua::Value::Table(tbl) = &mut config {
|
||||
for (key, value) in obj {
|
||||
let value = luahelper::JsonLua(value.clone());
|
||||
tbl.set(key.as_str(), value)?;
|
||||
}
|
||||
}
|
||||
Ok(config)
|
||||
}
|
||||
_ => Ok(config),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_overrides_to<'l>(
|
||||
lua: &'l mlua::Lua,
|
||||
mut config: mlua::Value<'l>,
|
||||
|
@ -33,7 +33,8 @@ brief notes about them may accumulate here.
|
||||
* Windows: Fixed [ToggleFullScreen](config/lua/keyassignment/ToggleFullScreen.md) so that it once again toggles between full screen and normal placement. [#177](https://github.com/wez/wezterm/issues/177)
|
||||
* New: [exit_behavior](config/lua/config/exit_behavior.md) config option to keep panes open after the program has completed. [#499](https://github.com/wez/wezterm/issues/499)
|
||||
* Closing the configuration error window no longer requires confirmation
|
||||
* New: added `--config name=value` options to `wezterm`, `wezterm-gui` and `wezterm-mux-server`
|
||||
* New: added `--config name=value` options to `wezterm`, `wezterm-gui` and `wezterm-mux-server`. The `--font-locator`, `--font-rasterizer` and `--font-shaper` CLI options have been removed in favor of this new mechanism.
|
||||
* New: [window:set_config_overrides](config/lua/window/set_config_overrides.md) method that can be used to override GUI related configuration options on a per-window basis. Click through to see examples of dynamically toggling ligatures and window opacity. [#469](https://github.com/wez/wezterm/issues/469) [#329](https://github.com/wez/wezterm/issues/329)
|
||||
|
||||
### 20210203-095643-70a364eb
|
||||
|
||||
|
@ -10,6 +10,8 @@ configuration, including any CLI or per-window configuration overrides.
|
||||
Note: changing the config table will NOT change the effective window config;
|
||||
it is just a copy of that information.
|
||||
|
||||
If you want to change the configuration in a window, look at [set_config_overrides](set_config_overrides.md).
|
||||
|
||||
This example will log the configured font size when `CTRL-SHIFT-E` is pressed:
|
||||
|
||||
```lua
|
||||
|
9
docs/config/lua/window/get_config_overrides.md
Normal file
9
docs/config/lua/window/get_config_overrides.md
Normal file
@ -0,0 +1,9 @@
|
||||
# `window:get_config_overrides()`
|
||||
|
||||
*Since: nightly*
|
||||
|
||||
Returns a copy of the current set of configuration overrides that is in effect
|
||||
for the window.
|
||||
|
||||
See [set_config_overrides](set_config_overrides.md) for examples!
|
||||
|
61
docs/config/lua/window/set_config_overrides.md
Normal file
61
docs/config/lua/window/set_config_overrides.md
Normal file
@ -0,0 +1,61 @@
|
||||
# `window:set_config_overrides(overrides)`
|
||||
|
||||
*Since: nightly*
|
||||
|
||||
Changes the set of configuration overrides for the window.
|
||||
The config file is re-evaluated and any CLI overrides are
|
||||
applied, followed by the keys and values from the `overrides`
|
||||
parameter.
|
||||
|
||||
This can be used to override configuration on a per-window basis;
|
||||
this is only useful for options that apply to the GUI window, such
|
||||
as rendering the GUI.
|
||||
|
||||
In this example, a key assignment (`CTRL-SHIFT-E`) is used to toggle the use of
|
||||
ligatures in the current window:
|
||||
|
||||
```lua
|
||||
local wezterm = require 'wezterm'
|
||||
|
||||
wezterm.on("toggle-ligature", function(window, pane)
|
||||
local overrides = window:get_config_overrides() or {}
|
||||
if not overrides.harfbuzz_features then
|
||||
-- If we haven't overriden it yet, then override with ligatures disabled
|
||||
overrides.harfbuzz_features = {"calt=0", "clig=0", "liga=0"}
|
||||
else
|
||||
-- else we did already, and we should disable out override now
|
||||
overrides.harfbuzz_features = nil
|
||||
end
|
||||
window:set_config_overrides(overrides)
|
||||
end)
|
||||
|
||||
return {
|
||||
keys = {
|
||||
{key="E", mods="CTRL", action=wezterm.action{EmitEvent="toggle-ligature"}},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
In this example, a key assignment (`CTRL-SHIFT-B`) is used to toggle opacity
|
||||
for the window:
|
||||
|
||||
```lua
|
||||
local wezterm = require 'wezterm'
|
||||
|
||||
wezterm.on("toggle-opacity", function(window, pane)
|
||||
local overrides = window:get_config_overrides() or {}
|
||||
if not overrides.window_background_opacity then
|
||||
overrides.window_background_opacity = 0.5;
|
||||
else
|
||||
overrides.window_background_opacity = nil
|
||||
end
|
||||
window:set_config_overrides(overrides)
|
||||
end)
|
||||
|
||||
return {
|
||||
keys = {
|
||||
{key="B", mods="CTRL", action=wezterm.action{EmitEvent="toggle-opacity"}},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
@ -11,5 +11,6 @@ bstr = "0.2"
|
||||
log = "0.4"
|
||||
mlua = "0.5"
|
||||
serde = {version="1.0", features = ["rc", "derive"]}
|
||||
serde_json = "1.0"
|
||||
strsim = "0.10"
|
||||
thiserror = "1.0"
|
||||
|
@ -1,5 +1,7 @@
|
||||
#![macro_use]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod serde_lua;
|
||||
pub use mlua;
|
||||
pub use serde_lua::from_lua_value;
|
||||
@ -19,7 +21,7 @@ macro_rules! impl_lua_conversion {
|
||||
self,
|
||||
lua: &'lua $crate::mlua::Lua,
|
||||
) -> Result<$crate::mlua::Value<'lua>, $crate::mlua::Error> {
|
||||
Ok(luahelper::to_lua_value(lua, self)?)
|
||||
Ok($crate::to_lua_value(lua, self)?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,8 +30,13 @@ macro_rules! impl_lua_conversion {
|
||||
value: $crate::mlua::Value<'lua>,
|
||||
_lua: &'lua $crate::mlua::Lua,
|
||||
) -> Result<Self, $crate::mlua::Error> {
|
||||
Ok(luahelper::from_lua_value(value)?)
|
||||
Ok($crate::from_lua_value(value)?)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct JsonLua(pub serde_json::Value);
|
||||
impl_lua_conversion!(JsonLua);
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::db::FontDatabase;
|
||||
use crate::locator::{new_locator, FontDataHandle, FontLocator, FontLocatorSelection};
|
||||
use crate::locator::{new_locator, FontDataHandle, FontLocator};
|
||||
use crate::rasterizer::{new_rasterizer, FontRasterizer};
|
||||
use crate::shaper::{new_shaper, FontShaper, FontShaperSelection};
|
||||
use crate::shaper::{new_shaper, FontShaper};
|
||||
use anyhow::{Context, Error};
|
||||
use config::{configuration, ConfigHandle, FontRasterizerSelection, TextStyle};
|
||||
use std::cell::RefCell;
|
||||
@ -60,8 +60,10 @@ impl LoadedFont {
|
||||
}
|
||||
}
|
||||
if loaded {
|
||||
if let Some(font_config) = self.font_config.upgrade() {
|
||||
*self.shaper.borrow_mut() =
|
||||
new_shaper(FontShaperSelection::get_default(), &self.handles.borrow())?;
|
||||
new_shaper(&*font_config.config.borrow(), &self.handles.borrow())?;
|
||||
}
|
||||
}
|
||||
Ok(loaded)
|
||||
}
|
||||
@ -152,10 +154,13 @@ impl LoadedFont {
|
||||
if let Some(raster) = rasterizers.get(&fallback) {
|
||||
raster.rasterize_glyph(glyph_pos, self.font_size, self.dpi)
|
||||
} else {
|
||||
let raster = new_rasterizer(
|
||||
FontRasterizerSelection::get_default(),
|
||||
&(self.handles.borrow())[fallback],
|
||||
)?;
|
||||
let raster_selection = self
|
||||
.font_config
|
||||
.upgrade()
|
||||
.map_or(FontRasterizerSelection::default(), |c| {
|
||||
c.config.borrow().font_rasterizer
|
||||
});
|
||||
let raster = new_rasterizer(raster_selection, &(self.handles.borrow())[fallback])?;
|
||||
let result = raster.rasterize_glyph(glyph_pos, self.font_size, self.dpi);
|
||||
rasterizers.insert(fallback, raster);
|
||||
result
|
||||
@ -168,7 +173,7 @@ struct FontConfigInner {
|
||||
metrics: RefCell<Option<FontMetrics>>,
|
||||
dpi_scale: RefCell<f64>,
|
||||
font_scale: RefCell<f64>,
|
||||
config_generation: RefCell<usize>,
|
||||
config: RefCell<ConfigHandle>,
|
||||
locator: Box<dyn FontLocator>,
|
||||
font_dirs: RefCell<FontDatabase>,
|
||||
built_in: RefCell<FontDatabase>,
|
||||
@ -181,36 +186,43 @@ pub struct FontConfiguration {
|
||||
|
||||
impl FontConfigInner {
|
||||
/// Create a new empty configuration
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let locator = new_locator(FontLocatorSelection::get_default());
|
||||
let config = configuration();
|
||||
pub fn new(config: Option<ConfigHandle>) -> anyhow::Result<Self> {
|
||||
let config = config.unwrap_or_else(|| configuration());
|
||||
let locator = new_locator(config.font_locator);
|
||||
Ok(Self {
|
||||
fonts: RefCell::new(HashMap::new()),
|
||||
locator,
|
||||
metrics: RefCell::new(None),
|
||||
font_scale: RefCell::new(1.0),
|
||||
dpi_scale: RefCell::new(1.0),
|
||||
config_generation: RefCell::new(config.generation()),
|
||||
config: RefCell::new(config.clone()),
|
||||
font_dirs: RefCell::new(FontDatabase::with_font_dirs(&config)?),
|
||||
built_in: RefCell::new(FontDatabase::with_built_in()?),
|
||||
})
|
||||
}
|
||||
|
||||
/// Given a text style, load (with caching) the font that best
|
||||
/// matches according to the fontconfig pattern.
|
||||
fn resolve_font(&self, myself: &Rc<Self>, style: &TextStyle) -> anyhow::Result<Rc<LoadedFont>> {
|
||||
fn config_changed(&self, config: &ConfigHandle) -> anyhow::Result<()> {
|
||||
let mut fonts = self.fonts.borrow_mut();
|
||||
|
||||
let config = configuration();
|
||||
let current_generation = config.generation();
|
||||
if current_generation != *self.config_generation.borrow() {
|
||||
*self.config.borrow_mut() = config.clone();
|
||||
// Config was reloaded, invalidate our caches
|
||||
fonts.clear();
|
||||
self.metrics.borrow_mut().take();
|
||||
*self.font_dirs.borrow_mut() = FontDatabase::with_font_dirs(&config)?;
|
||||
*self.config_generation.borrow_mut() = current_generation;
|
||||
*self.font_dirs.borrow_mut() = FontDatabase::with_font_dirs(config)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Given a text style, load (with caching) the font that best
|
||||
/// matches according to the fontconfig pattern.
|
||||
fn resolve_font(&self, myself: &Rc<Self>, style: &TextStyle) -> anyhow::Result<Rc<LoadedFont>> {
|
||||
let global_config = configuration();
|
||||
let current_generation = global_config.generation();
|
||||
if current_generation != self.config.borrow().generation() {
|
||||
self.config_changed(&global_config)?;
|
||||
}
|
||||
let config = self.config.borrow();
|
||||
|
||||
let mut fonts = self.fonts.borrow_mut();
|
||||
|
||||
if let Some(entry) = fonts.get(style) {
|
||||
return Ok(Rc::clone(entry));
|
||||
}
|
||||
@ -284,9 +296,8 @@ impl FontConfigInner {
|
||||
}
|
||||
}
|
||||
|
||||
let shaper = new_shaper(FontShaperSelection::get_default(), &handles)?;
|
||||
let shaper = new_shaper(&*config, &handles)?;
|
||||
|
||||
let config = configuration();
|
||||
let font_size = config.font_size * *self.font_scale.borrow();
|
||||
let dpi =
|
||||
*self.dpi_scale.borrow() as u32 * config.dpi.unwrap_or(::window::DEFAULT_DPI) as u32;
|
||||
@ -326,7 +337,7 @@ impl FontConfigInner {
|
||||
|
||||
/// Returns the baseline font specified in the configuration
|
||||
pub fn default_font(&self, myself: &Rc<Self>) -> anyhow::Result<Rc<LoadedFont>> {
|
||||
self.resolve_font(myself, &configuration().font)
|
||||
self.resolve_font(myself, &self.config.borrow().font)
|
||||
}
|
||||
|
||||
pub fn get_font_scale(&self) -> f64 {
|
||||
@ -392,11 +403,15 @@ impl FontConfigInner {
|
||||
|
||||
impl FontConfiguration {
|
||||
/// Create a new empty configuration
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
let inner = Rc::new(FontConfigInner::new()?);
|
||||
pub fn new(config: Option<ConfigHandle>) -> anyhow::Result<Self> {
|
||||
let inner = Rc::new(FontConfigInner::new(config)?);
|
||||
Ok(Self { inner })
|
||||
}
|
||||
|
||||
pub fn config_changed(&self, config: &ConfigHandle) -> anyhow::Result<()> {
|
||||
self.inner.config_changed(config)
|
||||
}
|
||||
|
||||
/// Given a text style, load (with caching) the font that best
|
||||
/// matches according to the fontconfig pattern.
|
||||
pub fn resolve_font(&self, style: &TextStyle) -> anyhow::Result<Rc<LoadedFont>> {
|
||||
|
@ -452,7 +452,7 @@ pub struct AllsortsShaper {
|
||||
}
|
||||
|
||||
impl AllsortsShaper {
|
||||
pub fn new(handles: &[FontDataHandle]) -> anyhow::Result<Self> {
|
||||
pub fn new(_: &config::ConfigHandle, handles: &[FontDataHandle]) -> anyhow::Result<Self> {
|
||||
let mut fonts = vec![];
|
||||
let mut success = false;
|
||||
for handle in handles {
|
||||
|
@ -4,7 +4,7 @@ use crate::locator::FontDataHandle;
|
||||
use crate::shaper::{FallbackIdx, FontMetrics, FontShaper, GlyphInfo};
|
||||
use crate::units::*;
|
||||
use anyhow::anyhow;
|
||||
use config::configuration;
|
||||
use config::ConfigHandle;
|
||||
use log::error;
|
||||
use ordered_float::NotNan;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
@ -66,6 +66,7 @@ pub struct HarfbuzzShaper {
|
||||
fonts: Vec<RefCell<Option<FontPair>>>,
|
||||
lib: ftwrap::Library,
|
||||
metrics: RefCell<HashMap<MetricsKey, FontMetrics>>,
|
||||
config: ConfigHandle,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@ -102,7 +103,7 @@ fn is_question_string(s: &str) -> bool {
|
||||
}
|
||||
|
||||
impl HarfbuzzShaper {
|
||||
pub fn new(handles: &[FontDataHandle]) -> anyhow::Result<Self> {
|
||||
pub fn new(config: &ConfigHandle, handles: &[FontDataHandle]) -> anyhow::Result<Self> {
|
||||
let lib = ftwrap::Library::new()?;
|
||||
let handles = handles.to_vec();
|
||||
let mut fonts = vec![];
|
||||
@ -114,6 +115,7 @@ impl HarfbuzzShaper {
|
||||
handles,
|
||||
lib,
|
||||
metrics: RefCell::new(HashMap::new()),
|
||||
config: config.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -149,7 +151,7 @@ impl HarfbuzzShaper {
|
||||
dpi: u32,
|
||||
no_glyphs: &mut Vec<char>,
|
||||
) -> anyhow::Result<Vec<GlyphInfo>> {
|
||||
let config = configuration();
|
||||
let config = &self.config;
|
||||
let features: Vec<harfbuzz::hb_feature_t> = config
|
||||
.harfbuzz_features
|
||||
.iter()
|
||||
@ -451,7 +453,9 @@ mod test {
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
let shaper = HarfbuzzShaper::new(&[handle]).unwrap();
|
||||
let config = config::configuration();
|
||||
|
||||
let shaper = HarfbuzzShaper::new(&config, &[handle]).unwrap();
|
||||
{
|
||||
let mut no_glyphs = vec![];
|
||||
let info = shaper.shape("abc", 10., 72, &mut no_glyphs).unwrap();
|
||||
|
@ -74,11 +74,15 @@ pub trait FontShaper {
|
||||
pub use config::FontShaperSelection;
|
||||
|
||||
pub fn new_shaper(
|
||||
shaper: FontShaperSelection,
|
||||
config: &config::ConfigHandle,
|
||||
handles: &[FontDataHandle],
|
||||
) -> anyhow::Result<Box<dyn FontShaper>> {
|
||||
match shaper {
|
||||
FontShaperSelection::Harfbuzz => Ok(Box::new(harfbuzz::HarfbuzzShaper::new(handles)?)),
|
||||
FontShaperSelection::Allsorts => Ok(Box::new(allsorts::AllsortsShaper::new(handles)?)),
|
||||
match config.font_shaper {
|
||||
FontShaperSelection::Harfbuzz => {
|
||||
Ok(Box::new(harfbuzz::HarfbuzzShaper::new(config, handles)?))
|
||||
}
|
||||
FontShaperSelection::Allsorts => {
|
||||
Ok(Box::new(allsorts::AllsortsShaper::new(config, handles)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
use config::FontLocatorSelection;
|
||||
use config::FontRasterizerSelection;
|
||||
use config::FontShaperSelection;
|
||||
use config::{FrontEndSelection, SshParameters};
|
||||
use std::ffi::OsString;
|
||||
use structopt::StructOpt;
|
||||
@ -32,27 +29,6 @@ pub struct StartCommand {
|
||||
)]
|
||||
pub front_end: Option<FrontEndSelection>,
|
||||
|
||||
#[structopt(
|
||||
long = "font-locator",
|
||||
possible_values = &FontLocatorSelection::variants(),
|
||||
case_insensitive = true
|
||||
)]
|
||||
pub font_locator: Option<FontLocatorSelection>,
|
||||
|
||||
#[structopt(
|
||||
long = "font-rasterizer",
|
||||
possible_values = &FontRasterizerSelection::variants(),
|
||||
case_insensitive = true
|
||||
)]
|
||||
pub font_rasterizer: Option<FontRasterizerSelection>,
|
||||
|
||||
#[structopt(
|
||||
long = "font-shaper",
|
||||
possible_values = &FontShaperSelection::variants(),
|
||||
case_insensitive = true
|
||||
)]
|
||||
pub font_shaper: Option<FontShaperSelection>,
|
||||
|
||||
/// If true, do not connect to domains marked as connect_automatically
|
||||
/// in your wezterm.toml configuration file.
|
||||
#[structopt(long = "no-auto-connect")]
|
||||
|
@ -270,7 +270,7 @@ mod test {
|
||||
.filter_level(log::LevelFilter::Trace)
|
||||
.try_init();
|
||||
|
||||
let fonts = Rc::new(FontConfiguration::new().unwrap());
|
||||
let fonts = Rc::new(FontConfiguration::new(None).unwrap());
|
||||
let render_metrics = RenderMetrics::new(&fonts).unwrap();
|
||||
let mut glyph_cache = GlyphCache::new_in_memory(&fonts, 128, &render_metrics).unwrap();
|
||||
|
||||
|
@ -222,6 +222,7 @@ pub struct TabState {
|
||||
pub struct TermWindow {
|
||||
pub window: Option<Window>,
|
||||
pub config: ConfigHandle,
|
||||
pub config_overrides: serde_json::Value,
|
||||
/// When we most recently received keyboard focus
|
||||
focused: Option<Instant>,
|
||||
fonts: Rc<FontConfiguration>,
|
||||
@ -720,6 +721,7 @@ impl WindowCallbacks for TermWindow {
|
||||
let guts = Box::new(Self {
|
||||
window: None,
|
||||
config: self.config.clone(),
|
||||
config_overrides: self.config_overrides.clone(),
|
||||
window_background: self.window_background.clone(),
|
||||
palette: None,
|
||||
focused: None,
|
||||
@ -935,7 +937,7 @@ impl TermWindow {
|
||||
|
||||
let window_background = load_background_image(&config);
|
||||
|
||||
let fontconfig = Rc::new(FontConfiguration::new()?);
|
||||
let fontconfig = Rc::new(FontConfiguration::new(Some(config.clone()))?);
|
||||
let mux = Mux::get().expect("to be main thread with mux running");
|
||||
let size = match mux.get_active_tab_for_window(mux_window_id) {
|
||||
Some(tab) => tab.get_size(),
|
||||
@ -994,6 +996,7 @@ impl TermWindow {
|
||||
window: None,
|
||||
window_background,
|
||||
config: config.clone(),
|
||||
config_overrides: serde_json::Value::default(),
|
||||
palette: None,
|
||||
focused: None,
|
||||
mux_window_id,
|
||||
@ -1304,8 +1307,22 @@ impl TermWindow {
|
||||
self.palette.as_ref().unwrap()
|
||||
}
|
||||
|
||||
fn config_was_reloaded(&mut self) {
|
||||
let config = configuration();
|
||||
pub fn config_was_reloaded(&mut self) {
|
||||
log::debug!(
|
||||
"config was reloaded, overrides: {:?}",
|
||||
self.config_overrides
|
||||
);
|
||||
let config = match config::overridden_config(&self.config_overrides) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
log::error!(
|
||||
"Failed to apply config overrides to window: {:#}: {:?}",
|
||||
err,
|
||||
self.config_overrides
|
||||
);
|
||||
configuration()
|
||||
}
|
||||
};
|
||||
self.config = config.clone();
|
||||
self.palette.take();
|
||||
|
||||
@ -1328,6 +1345,10 @@ impl TermWindow {
|
||||
self.leader_is_down = None;
|
||||
let dimensions = self.dimensions;
|
||||
let cell_dims = self.current_cell_dimensions();
|
||||
|
||||
if let Err(err) = self.fonts.config_changed(&config) {
|
||||
log::error!("Failed to load font configuration: {:#}", err);
|
||||
}
|
||||
self.apply_scale_change(&dimensions, self.fonts.get_font_scale());
|
||||
self.apply_dimensions(&dimensions, Some(cell_dims));
|
||||
if let Some(window) = self.window.as_ref() {
|
||||
@ -2412,7 +2433,7 @@ impl TermWindow {
|
||||
fn reset_font_and_window_size(&mut self) -> anyhow::Result<()> {
|
||||
let config = &self.config;
|
||||
let size = config.initial_size();
|
||||
let fontconfig = Rc::new(FontConfiguration::new()?);
|
||||
let fontconfig = Rc::new(FontConfiguration::new(Some(config.clone()))?);
|
||||
let render_metrics = RenderMetrics::new(&fontconfig)?;
|
||||
|
||||
let terminal_size = PtySize {
|
||||
|
@ -289,14 +289,6 @@ fn run_terminal_gui(config: config::ConfigHandle, opts: StartCommand) -> anyhow:
|
||||
}
|
||||
|
||||
let run = move || -> anyhow::Result<()> {
|
||||
opts.font_locator
|
||||
.unwrap_or(config.font_locator)
|
||||
.set_default();
|
||||
opts.font_shaper.unwrap_or(config.font_shaper).set_default();
|
||||
opts.font_rasterizer
|
||||
.unwrap_or(config.font_rasterizer)
|
||||
.set_default();
|
||||
|
||||
let need_builder = !opts.prog.is_empty() || opts.cwd.is_some();
|
||||
|
||||
let cmd = if need_builder {
|
||||
|
@ -4,6 +4,7 @@ use super::pane::PaneObject;
|
||||
use crate::gui::TermWindow;
|
||||
use anyhow::anyhow;
|
||||
use config::keyassignment::KeyAssignment;
|
||||
use luahelper::JsonLua;
|
||||
use mlua::{UserData, UserDataMethods};
|
||||
use mux::window::WindowId as MuxWindowId;
|
||||
use window::WindowOps;
|
||||
@ -59,5 +60,23 @@ impl UserData for GuiWin {
|
||||
this.with_term_window(move |term_window, _ops| Ok((*term_window.config).clone()))
|
||||
.await
|
||||
});
|
||||
methods.add_async_method("get_config_overrides", |_, this, _: ()| async move {
|
||||
this.with_term_window(move |term_window, _ops| {
|
||||
let wrap = JsonLua(term_window.config_overrides.clone());
|
||||
Ok(wrap)
|
||||
})
|
||||
.await
|
||||
});
|
||||
methods.add_async_method(
|
||||
"set_config_overrides",
|
||||
|_, this, value: JsonLua| async move {
|
||||
this.with_term_window(move |term_window, _ops| {
|
||||
term_window.config_overrides = value.0.clone();
|
||||
term_window.config_was_reloaded();
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user