1
1
mirror of https://github.com/wez/wezterm.git synced 2024-10-26 23:58:28 +03:00

Add wezterm ls-fonts subcommand

At this time it just shows you the fonts that your config matches
and where they came from:

```
; wezterm -n ls-fonts
Primary font:
  wezterm.font("JetBrains Mono", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/JetBrainsMono-Regular.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/usr/share/fonts/google-noto-emoji/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Last Resort High-Efficiency", weight="Regular", stretch="Normal", italic=false)
    (<built-in>, BuiltIn)

When Italic=true:
  wezterm.font("JetBrains Mono", weight="Regular", stretch="Normal", italic=true)
    (/home/wez/.fonts/JetBrainsMono-Italic.ttf, FontConfig)

  wezterm.font("JetBrains Mono", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/JetBrainsMono-Regular.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/usr/share/fonts/google-noto-emoji/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Last Resort High-Efficiency", weight="Regular", stretch="Normal", italic=false)
    (<built-in>, BuiltIn)

When Intensity=Bold:
  wezterm.font("JetBrains Mono", weight="Bold", stretch="Normal", italic=false)
    (/home/wez/.fonts/JetBrainsMono-Bold.ttf, FontConfig)

  wezterm.font("JetBrains Mono", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/JetBrainsMono-Regular.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/usr/share/fonts/google-noto-emoji/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Last Resort High-Efficiency", weight="Regular", stretch="Normal", italic=false)
    (<built-in>, BuiltIn)

When Intensity=Bold Italic=true:
  wezterm.font("JetBrains Mono", weight="Bold", stretch="Normal", italic=true)
    (/home/wez/.fonts/JetBrainsMono-Bold-Italic.ttf, FontConfig)

  wezterm.font("JetBrains Mono", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/JetBrainsMono-Regular.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/usr/share/fonts/google-noto-emoji/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Noto Color Emoji", weight="Regular", stretch="Normal", italic=false)
    (/home/wez/.fonts/NotoColorEmoji.ttf, FontConfig)

  wezterm.font("Last Resort High-Efficiency", weight="Regular", stretch="Normal", italic=false)
    (<built-in>, BuiltIn)

```

refs: #347
This commit is contained in:
Wez Furlong 2021-04-12 09:36:56 -07:00
parent 5ced58c37b
commit 2e34f1a8dd
14 changed files with 126 additions and 12 deletions

1
Cargo.lock generated
View File

@ -4432,6 +4432,7 @@ dependencies = [
"core-foundation 0.9.1",
"core-text",
"dwrote",
"enum-display-derive",
"euclid",
"fontconfig",
"freetype",

View File

@ -1,5 +1,11 @@
[workspace]
members = ["wezterm-mux-server", "wezterm", "wezterm-gui", "strip-ansi-escapes", "wezterm-ssh"]
members = [
"strip-ansi-escapes",
"wezterm",
"wezterm-gui",
"wezterm-mux-server",
"wezterm-ssh"
]
resolver = "2"
[profile.release]

View File

@ -10,6 +10,7 @@ edition = "2018"
allsorts = { git = "https://github.com/yeslogic/allsorts.git", rev="3947164a201ab5e15d5f23204faaaaaad52531aa" }
anyhow = "1.0"
config = { path = "../config" }
enum-display-derive = "0.1"
euclid = "0.22"
freetype = { path = "../deps/freetype" }
harfbuzz = { path = "../deps/harfbuzz" }

View File

@ -1,6 +1,6 @@
//! A font-database to keep track of fonts that we've located
use crate::locator::FontDataSource;
use crate::locator::{FontDataSource, FontOrigin};
use crate::parser::{load_built_in_fonts, parse_and_collect_font_info, ParsedFont};
use anyhow::Context;
use config::{Config, FontAttributes};
@ -38,7 +38,7 @@ impl FontDatabase {
};
let source = FontDataSource::OnDisk(entry.path().to_path_buf());
parse_and_collect_font_info(&source, &mut font_info)
parse_and_collect_font_info(&source, &mut font_info, FontOrigin::FontDirs)
.map_err(|err| {
log::trace!("failed to read {:?}: {:#}", source, err);
err

View File

@ -149,6 +149,7 @@ impl Face {
source: self.source.source.clone(),
index: self.source.index,
variation: i,
origin: self.source.origin,
};
res.push(ParsedFont::from_face(&self, source)?);
}

View File

@ -142,6 +142,10 @@ impl LoadedFont {
result
}
}
pub fn clone_handles(&self) -> Vec<ParsedFont> {
self.handles.borrow().clone()
}
}
struct FontConfigInner {

View File

@ -1,6 +1,6 @@
#![cfg(target_os = "macos")]
use crate::locator::{FontDataSource, FontLocator};
use crate::locator::{FontDataSource, FontLocator, FontOrigin};
use crate::parser::ParsedFont;
use config::{FontAttributes, FontStretch, FontWeight};
use core_foundation::array::CFArray;
@ -66,7 +66,11 @@ fn handles_from_descriptor(descriptor: &CTFontDescriptor) -> Vec<ParsedFont> {
let mut font_info = vec![];
let source = FontDataSource::OnDisk(path);
let _ = crate::parser::parse_and_collect_font_info(&source, &mut font_info);
let _ = crate::parser::parse_and_collect_font_info(
&source,
&mut font_info,
FontOrigin::CoreText,
);
for parsed in font_info {
if parsed.names().full_name == family_name || parsed.names().family == family_name {

View File

@ -1,5 +1,5 @@
use crate::fcwrap;
use crate::locator::{FontDataHandle, FontDataSource, FontLocator};
use crate::locator::{FontDataHandle, FontDataSource, FontLocator, FontOrigin};
use crate::parser::ParsedFont;
use anyhow::Context;
use config::FontAttributes;
@ -92,6 +92,7 @@ impl FontLocator for FontConfigFontLocator {
source: FontDataSource::OnDisk(file.into()),
index,
variation,
origin: FontOrigin::FontConfig,
};
// fontconfig will give us a boatload of random fallbacks.
@ -161,6 +162,7 @@ impl FontLocator for FontConfigFontLocator {
source: FontDataSource::OnDisk(file.into()),
index: pat.get_integer("index")?.try_into()?,
variation: 0,
origin: FontOrigin::FontConfig,
};
if let Ok(parsed) = crate::parser::ParsedFont::from_locator(&handle) {
fonts.push(parsed);

View File

@ -1,6 +1,6 @@
#![cfg(windows)]
use crate::locator::{FontDataSource, FontLocator};
use crate::locator::{FontDataSource, FontLocator, FontOrigin};
use crate::parser::{best_matching_font, parse_and_collect_font_info, ParsedFont};
use config::{FontAttributes, FontStretch as WTFontStretch, FontWeight as WTFontWeight};
use dwrote::{FontDescriptor, FontStretch, FontStyle, FontWeight};
@ -63,7 +63,7 @@ fn extract_font_data(font: HFONT, attr: &FontAttributes) -> anyhow::Result<Parse
};
let mut font_info = vec![];
parse_and_collect_font_info(&source, &mut font_info)?;
parse_and_collect_font_info(&source, &mut font_info, FontOrigin::Gdi)?;
let matches = ParsedFont::best_match(attr, font_info);
for m in matches {
@ -146,7 +146,7 @@ fn handle_from_descriptor(
log::debug!("{} -> {}", family_name, path.display());
let source = FontDataSource::OnDisk(path);
match best_matching_font(&source, attr) {
match best_matching_font(&source, attr, FontOrigin::DirectWrite) {
Ok(Some(parsed)) => {
return Some(parsed);
}

View File

@ -1,8 +1,10 @@
use crate::parser::ParsedFont;
use config::FontAttributes;
use enum_display_derive::Display;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt::Display;
use std::path::PathBuf;
use std::sync::Arc;
@ -11,6 +13,16 @@ pub mod core_text;
pub mod font_config;
pub mod gdi;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Display)]
pub enum FontOrigin {
FontConfig,
CoreText,
DirectWrite,
Gdi,
FontDirs,
BuiltIn,
}
#[derive(Clone)]
pub enum FontDataSource {
OnDisk(PathBuf),
@ -101,6 +113,7 @@ pub struct FontDataHandle {
pub source: FontDataSource,
pub index: u32,
pub variation: u32,
pub origin: FontOrigin,
}
impl FontDataHandle {
@ -115,6 +128,23 @@ impl FontDataHandle {
pub fn set_index(&mut self, idx: u32) {
self.index = idx;
}
pub fn diagnostic_string(&self) -> String {
let source = match &self.source {
FontDataSource::OnDisk(path) => format!("{}", path.display()),
FontDataSource::BuiltIn { .. } => "<built-in>".to_string(),
FontDataSource::Memory { .. } => "<imported to RAM>".to_string(),
};
if self.index == 0 && self.variation == 0 {
format!("{}, {}", source, self.origin)
} else {
format!(
"{} index={} variation={}, {}",
source, self.index, self.variation, self.origin
)
}
}
}
pub trait FontLocator {

View File

@ -1,4 +1,4 @@
use crate::locator::{FontDataHandle, FontDataSource};
use crate::locator::{FontDataHandle, FontDataSource, FontOrigin};
use crate::shaper::GlyphInfo;
use config::FontAttributes;
pub use config::{FontStretch, FontWeight};
@ -368,6 +368,7 @@ pub(crate) fn load_built_in_fonts(font_info: &mut Vec<ParsedFont>) -> anyhow::Re
source: FontDataSource::BuiltIn { data, name },
index: 0,
variation: 0,
origin: FontOrigin::BuiltIn,
};
let face = lib.face_from_locator(&locator)?;
let parsed = ParsedFont::from_face(&face, locator)?;
@ -380,15 +381,17 @@ pub(crate) fn load_built_in_fonts(font_info: &mut Vec<ParsedFont>) -> anyhow::Re
pub fn best_matching_font(
source: &FontDataSource,
font_attr: &FontAttributes,
origin: FontOrigin,
) -> anyhow::Result<Option<ParsedFont>> {
let mut font_info = vec![];
parse_and_collect_font_info(source, &mut font_info)?;
parse_and_collect_font_info(source, &mut font_info, origin)?;
Ok(ParsedFont::best_match(font_attr, font_info))
}
pub(crate) fn parse_and_collect_font_info(
source: &FontDataSource,
font_info: &mut Vec<ParsedFont>,
origin: FontOrigin,
) -> anyhow::Result<()> {
let lib = crate::ftwrap::Library::new()?;
let num_faces = lib.query_num_faces(&source)?;
@ -398,11 +401,13 @@ pub(crate) fn parse_and_collect_font_info(
source: &FontDataSource,
index: u32,
font_info: &mut Vec<ParsedFont>,
origin: FontOrigin,
) -> anyhow::Result<()> {
let locator = FontDataHandle {
source: source.clone(),
index,
variation: 0,
origin,
};
let face = lib.face_from_locator(&locator)?;
@ -418,7 +423,7 @@ pub(crate) fn parse_and_collect_font_info(
}
for index in 0..num_faces {
if let Err(err) = load_one(&lib, &source, index, font_info) {
if let Err(err) = load_one(&lib, &source, index, font_info, origin) {
log::trace!("error while parsing {:?} index {}: {}", source, index, err);
}
}

View File

@ -108,3 +108,6 @@ pub struct ConnectCommand {
#[structopt(parse(from_os_str))]
pub prog: Vec<OsString>,
}
#[derive(Debug, StructOpt, Clone)]
pub struct LsFontsCommand {}

View File

@ -84,6 +84,9 @@ enum SubCommand {
#[structopt(name = "connect", about = "Connect to wezterm multiplexer")]
Connect(ConnectCommand),
#[structopt(name = "ls-fonts", about = "Display information about fonts")]
LsFonts(LsFontsCommand),
}
async fn async_run_ssh(opts: SshCommand) -> anyhow::Result<()> {
@ -410,6 +413,55 @@ fn maybe_show_configuration_error_window() {
}
}
pub fn run_ls_fonts(config: config::ConfigHandle, _cmd: &LsFontsCommand) -> anyhow::Result<()> {
let font_config = wezterm_font::FontConfiguration::new(Some(config.clone()))?;
println!("Primary font:");
let default_font = font_config.default_font()?;
for f in default_font.clone_handles() {
println!(" {}", f.lua_name());
println!(" ({})", f.handle.diagnostic_string());
println!();
}
for rule in &config.font_rules {
println!();
let mut condition = "When".to_string();
if let Some(intensity) = &rule.intensity {
condition.push_str(&format!(" Intensity={:?}", intensity));
}
if let Some(underline) = &rule.underline {
condition.push_str(&format!(" Underline={:?}", underline));
}
if let Some(italic) = &rule.italic {
condition.push_str(&format!(" Italic={:?}", italic));
}
if let Some(blink) = &rule.blink {
condition.push_str(&format!(" Blink={:?}", blink));
}
if let Some(rev) = &rule.reverse {
condition.push_str(&format!(" Reverse={:?}", rev));
}
if let Some(strikethrough) = &rule.strikethrough {
condition.push_str(&format!(" Strikethrough={:?}", strikethrough));
}
if let Some(invisible) = &rule.invisible {
condition.push_str(&format!(" Invisible={:?}", invisible));
}
println!("{}:", condition);
let font = font_config.resolve_font(&rule.font)?;
for f in font.clone_handles() {
println!(" {}", f.lua_name());
println!(" ({})", f.handle.diagnostic_string());
println!();
}
}
Ok(())
}
#[cfg(windows)]
mod win_bindings {
::windows::include_bindings!();
@ -484,5 +536,6 @@ fn run() -> anyhow::Result<()> {
SubCommand::Ssh(ssh) => run_ssh(ssh),
SubCommand::Serial(serial) => run_serial(config, &serial),
SubCommand::Connect(connect) => run_mux_client(config, &connect),
SubCommand::LsFonts(cmd) => run_ls_fonts(config, &cmd),
}
}

View File

@ -64,6 +64,9 @@ enum SubCommand {
#[structopt(name = "connect", about = "Connect to wezterm multiplexer")]
Connect(ConnectCommand),
#[structopt(name = "ls-fonts", about = "Display information about fonts")]
LsFonts(LsFontsCommand),
#[structopt(name = "cli", about = "Interact with experimental mux server")]
Cli(CliCommand),
@ -295,6 +298,7 @@ fn run() -> anyhow::Result<()> {
.unwrap_or_else(|| SubCommand::Start(StartCommand::default()))
{
SubCommand::Start(_)
| SubCommand::LsFonts(_)
| SubCommand::Ssh(_)
| SubCommand::Serial(_)
| SubCommand::Connect(_) => delegate_to_gui(saver),