Use loaded fonts if no configured font works (#1171)

macos-click-through
Keith Simmons 3 years ago committed by GitHub
parent 49224f8008
commit db53e94db9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,7 +31,7 @@ fn struct_stream(name: Ident, prefix: String, data: &DataStruct) -> TokenStream
quote! {{ quote! {{
fn update_func(value: rmpv::Value) { fn update_func(value: rmpv::Value) {
let mut s = crate::settings::SETTINGS.get::<#name>(); let mut s = crate::settings::SETTINGS.get::<#name>();
s.#ident.from_value(value); s.#ident.parse_from_value(value);
crate::settings::SETTINGS.set(&s); crate::settings::SETTINGS.set(&s);
} }

@ -7,17 +7,17 @@ use clipboard::ClipboardProvider;
pub fn get_remote_clipboard(format: Option<&str>) -> Result<Value, Box<dyn Error>> { pub fn get_remote_clipboard(format: Option<&str>) -> Result<Value, Box<dyn Error>> {
let mut ctx: ClipboardContext = ClipboardProvider::new()?; let mut ctx: ClipboardContext = ClipboardProvider::new()?;
let clipboard_raw = ctx.get_contents()?.replace("\r", ""); let clipboard_raw = ctx.get_contents()?.replace('\r', "");
let lines = if let Some("dos") = format { let lines = if let Some("dos") = format {
// add \r to lines of current file format is dos // add \r to lines of current file format is dos
clipboard_raw.replace("\n", "\r\n") clipboard_raw.replace('\n', "\r\n")
} else { } else {
// else, \r is stripped, leaving only \n // else, \r is stripped, leaving only \n
clipboard_raw clipboard_raw
} }
.split("\n") .split('\n')
.map(|line| Value::from(line)) .map(Value::from)
.collect::<Vec<Value>>(); .collect::<Vec<Value>>();
let lines = Value::from(lines); let lines = Value::from(lines);
@ -45,7 +45,7 @@ pub fn set_remote_clipboard(arguments: Vec<Value>) -> Result<(), Box<dyn Error>>
.map(|arr| { .map(|arr| {
arr.iter() arr.iter()
.filter_map(|x| x.as_str().map(String::from)) .filter_map(|x| x.as_str().map(String::from))
.map(|s| s.replace("\r", "")) // strip \r .map(|s| s.replace('\r', "")) // strip \r
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(endline) .join(endline)
}) })

@ -49,7 +49,7 @@ impl Handler for NeovimHandler {
}); });
get_remote_clipboard(endline_type.as_deref()) get_remote_clipboard(endline_type.as_deref())
.or(Err(Value::from("cannot get remote clipboard content"))) .map_err(|_| Value::from("cannot get remote clipboard content"))
} }
_ => Ok(Value::from("rpcrequest not handled")), _ => Ok(Value::from("rpcrequest not handled")),
} }

@ -42,7 +42,7 @@ pub async fn setup_neovide_remote_clipboard(nvim: &Neovim<TxWrapper>, neovide_ch
'cache_enabled': 0 'cache_enabled': 0
} }
"# "#
.replace("\n", "") // make one-liner, because multiline is not accepted (?) .replace('\n', "") // make one-liner, because multiline is not accepted (?)
.replace("neovide_channel", &neovide_channel.to_string()); .replace("neovide_channel", &neovide_channel.to_string());
nvim.command(&custom_clipboard).await.ok(); nvim.command(&custom_clipboard).await.ok();
} }

@ -48,8 +48,8 @@ pub enum VfxMode {
Disabled, Disabled,
} }
impl FromValue for VfxMode { impl ParseFromValue for VfxMode {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_str() { if value.is_str() {
*self = match value.as_str().unwrap() { *self = match value.as_str().unwrap() {
"sonicboom" => VfxMode::Highlight(HighlightMode::SonicBoom), "sonicboom" => VfxMode::Highlight(HighlightMode::SonicBoom),

@ -11,7 +11,7 @@ use crate::{
redraw_scheduler::REDRAW_SCHEDULER, redraw_scheduler::REDRAW_SCHEDULER,
renderer::animation_utils::*, renderer::animation_utils::*,
renderer::{GridRenderer, RenderedWindow}, renderer::{GridRenderer, RenderedWindow},
settings::{FromValue, SETTINGS}, settings::{ParseFromValue, SETTINGS},
}; };
use blink::*; use blink::*;

@ -3,13 +3,8 @@ use std::sync::Arc;
use log::{trace, warn}; use log::{trace, warn};
use lru::LruCache; use lru::LruCache;
use skia_safe::{ use skia_safe::{
graphics::{ graphics::{font_cache_limit, font_cache_used, set_font_cache_limit},
font_cache_used, TextBlob, TextBlobBuilder,
font_cache_limit,
set_font_cache_limit,
},
TextBlob,
TextBlobBuilder,
}; };
use swash::{ use swash::{
shape::ShapeContext, shape::ShapeContext,
@ -56,16 +51,17 @@ impl CachingShaper {
} }
fn current_font_pair(&mut self) -> Arc<FontPair> { fn current_font_pair(&mut self) -> Arc<FontPair> {
let default_key = FontKey::default();
let font_key = FontKey::from(&self.options);
if let Some(font_pair) = self.font_loader.get_or_load(&font_key) {
return font_pair;
}
self.font_loader self.font_loader
.get_or_load(&default_key) .get_or_load(&FontKey {
.expect("Could not load font") bold: false,
italic: false,
family_name: self.options.primary_font(),
})
.unwrap_or_else(|| {
self.font_loader
.get_or_load(&FontKey::default())
.expect("Could not load default font")
})
} }
pub fn current_size(&self) -> f32 { pub fn current_size(&self) -> f32 {
@ -82,7 +78,11 @@ impl CachingShaper {
trace!("Updating font: {}", guifont_setting); trace!("Updating font: {}", guifont_setting);
let options = FontOptions::parse(guifont_setting); let options = FontOptions::parse(guifont_setting);
let font_key = FontKey::from(&options); let font_key = FontKey {
bold: false,
italic: false,
family_name: options.primary_font(),
};
if self.font_loader.get_or_load(&font_key).is_some() { if self.font_loader.get_or_load(&font_key).is_some() {
trace!("Font updated to: {}", guifont_setting); trace!("Font updated to: {}", guifont_setting);
@ -202,32 +202,20 @@ impl CachingShaper {
font_fallback_keys.extend(self.options.font_list.iter().map(|font_name| FontKey { font_fallback_keys.extend(self.options.font_list.iter().map(|font_name| FontKey {
italic: self.options.italic || italic, italic: self.options.italic || italic,
bold: self.options.bold || bold, bold: self.options.bold || bold,
font_selection: font_name.into(), family_name: Some(font_name.clone()),
})); }));
// Add default font // Add default font
font_fallback_keys.push(FontKey { font_fallback_keys.push(FontKey {
italic: self.options.italic || italic, italic: self.options.italic || italic,
bold: self.options.bold || bold, bold: self.options.bold || bold,
font_selection: FontSelection::Default, family_name: None,
}); });
// Add skia fallback // Use the cluster.map function to select a viable font from the fallback list and loaded fonts
font_fallback_keys.push(FontKey {
italic,
bold,
font_selection: cluster.chars()[0].ch.into(),
});
// Add last resort
font_fallback_keys.push(FontKey {
italic: false,
bold: false,
font_selection: FontSelection::LastResort,
});
let mut best = None; let mut best = None;
// Use the cluster.map function to select a viable font from the fallback list // Search through the configured and default fonts for a match
for fallback_key in font_fallback_keys.iter() { for fallback_key in font_fallback_keys.iter() {
if let Some(font_pair) = self.font_loader.get_or_load(fallback_key) { if let Some(font_pair) = self.font_loader.get_or_load(fallback_key) {
let charmap = font_pair.swash_font.as_ref().charmap(); let charmap = font_pair.swash_font.as_ref().charmap();
@ -242,9 +230,36 @@ impl CachingShaper {
} }
} }
// Configured font/default didn't work. Search through currently loaded ones
for loaded_font in self.font_loader.loaded_fonts() {
let charmap = loaded_font.swash_font.as_ref().charmap();
match cluster.map(|ch| charmap.map(ch)) {
Status::Complete => {
results.push((cluster.to_owned(), loaded_font.clone()));
self.font_loader.refresh(loaded_font.as_ref());
continue 'cluster;
}
Status::Keep => best = Some(loaded_font),
Status::Discard => {}
}
}
if let Some(best) = best { if let Some(best) = best {
// Last Resort covers all of the unicode space so we will always have a fallback
results.push((cluster.to_owned(), best.clone())); results.push((cluster.to_owned(), best.clone()));
} else {
let fallback_character = cluster.chars()[0].ch;
if let Some(fallback_font) =
self.font_loader
.load_font_for_character(bold, italic, fallback_character)
{
results.push((cluster.to_owned(), fallback_font));
} else {
// Last Resort covers all of the unicode space so we will always have a fallback
results.push((
cluster.to_owned(),
self.font_loader.get_or_load_last_resort(),
));
}
} }
} }

@ -1,28 +1,32 @@
use std::sync::Arc; use std::sync::Arc;
use log::trace;
use lru::LruCache; use lru::LruCache;
use skia_safe::{font::Edging, Data, Font, FontHinting, FontMgr, FontStyle, Typeface}; use skia_safe::{font::Edging, Data, Font, FontHinting, FontMgr, FontStyle, Typeface};
use crate::renderer::fonts::{font_options::FontOptions, swash_font::SwashFont}; use crate::renderer::fonts::swash_font::SwashFont;
static DEFAULT_FONT: &[u8] = include_bytes!("../../../assets/fonts/FiraCode-Regular.ttf"); static DEFAULT_FONT: &[u8] = include_bytes!("../../../assets/fonts/FiraCode-Regular.ttf");
static LAST_RESORT_FONT: &[u8] = include_bytes!("../../../assets/fonts/LastResort-Regular.ttf"); static LAST_RESORT_FONT: &[u8] = include_bytes!("../../../assets/fonts/LastResort-Regular.ttf");
pub struct FontPair { pub struct FontPair {
pub key: FontKey,
pub skia_font: Font, pub skia_font: Font,
pub swash_font: SwashFont, pub swash_font: SwashFont,
} }
impl FontPair { impl FontPair {
fn new(mut skia_font: Font) -> Option<FontPair> { fn new(key: FontKey, mut skia_font: Font) -> Option<FontPair> {
skia_font.set_subpixel(true); skia_font.set_subpixel(true);
skia_font.set_hinting(FontHinting::Full); skia_font.set_hinting(FontHinting::Full);
skia_font.set_edging(Edging::AntiAlias); skia_font.set_edging(Edging::AntiAlias);
let (font_data, index) = skia_font.typeface().unwrap().to_font_data().unwrap(); let typeface = skia_font.typeface().unwrap();
let (font_data, index) = typeface.to_font_data().unwrap();
let swash_font = SwashFont::from_data(font_data, index)?; let swash_font = SwashFont::from_data(font_data, index)?;
Some(Self { Some(Self {
key,
skia_font, skia_font,
swash_font, swash_font,
}) })
@ -35,116 +39,43 @@ impl PartialEq for FontPair {
} }
} }
pub struct FontLoader { #[derive(Debug, Default, Hash, PartialEq, Eq, Clone)]
font_mgr: FontMgr,
cache: LruCache<FontKey, Arc<FontPair>>,
font_size: f32,
}
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub struct FontKey { pub struct FontKey {
// TODO(smolck): Could make these private and add constructor method(s)? // TODO(smolck): Could make these private and add constructor method(s)?
// Would theoretically make things safer I guess, but not sure . . . // Would theoretically make things safer I guess, but not sure . . .
pub bold: bool, pub bold: bool,
pub italic: bool, pub italic: bool,
pub font_selection: FontSelection, pub family_name: Option<String>,
}
impl Default for FontKey {
fn default() -> Self {
FontKey {
italic: false,
bold: false,
font_selection: FontSelection::Default,
}
}
}
impl From<&FontOptions> for FontKey {
fn from(options: &FontOptions) -> FontKey {
FontKey {
italic: options.italic,
bold: options.bold,
font_selection: options.primary_font(),
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, Clone)]
pub enum FontSelection {
Name(String),
Character(char),
Default,
LastResort,
} }
impl From<&str> for FontSelection { pub struct FontLoader {
fn from(string: &str) -> FontSelection { font_mgr: FontMgr,
let string = string.to_string(); cache: LruCache<FontKey, Arc<FontPair>>,
FontSelection::Name(string) font_size: f32,
} last_resort: Option<Arc<FontPair>>,
}
impl From<&String> for FontSelection {
fn from(string: &String) -> FontSelection {
let string = string.to_owned();
FontSelection::Name(string)
}
}
impl From<String> for FontSelection {
fn from(string: String) -> FontSelection {
FontSelection::Name(string)
}
}
impl From<char> for FontSelection {
fn from(character: char) -> FontSelection {
FontSelection::Character(character)
}
} }
impl FontLoader { impl FontLoader {
pub fn new(font_size: f32) -> FontLoader { pub fn new(font_size: f32) -> FontLoader {
FontLoader { FontLoader {
font_mgr: FontMgr::new(), font_mgr: FontMgr::new(),
cache: LruCache::new(10), cache: LruCache::new(20),
font_size, font_size,
last_resort: None,
} }
} }
fn load(&mut self, font_key: FontKey) -> Option<FontPair> { fn load(&mut self, font_key: FontKey) -> Option<FontPair> {
let font_style = match (font_key.bold, font_key.italic) { let font_style = font_style(font_key.bold, font_key.italic);
(true, true) => FontStyle::bold_italic(),
(false, true) => FontStyle::italic(),
(true, false) => FontStyle::bold(),
(false, false) => FontStyle::normal(),
};
match font_key.font_selection { trace!("Loading font {:?}", font_key);
FontSelection::Name(name) => { if let Some(family_name) = &font_key.family_name {
let typeface = self.font_mgr.match_family_style(name, font_style)?; let typeface = self.font_mgr.match_family_style(family_name, font_style)?;
FontPair::new(Font::from_typeface(typeface, self.font_size)) FontPair::new(font_key, Font::from_typeface(typeface, self.font_size))
} } else {
FontSelection::Character(character) => {
let typeface = self.font_mgr.match_family_style_character(
"",
font_style,
&[],
character as i32,
)?;
FontPair::new(Font::from_typeface(typeface, self.font_size))
}
FontSelection::Default => {
let data = Data::new_copy(DEFAULT_FONT); let data = Data::new_copy(DEFAULT_FONT);
let typeface = Typeface::from_data(data, 0).unwrap(); let typeface = Typeface::from_data(data, 0).unwrap();
FontPair::new(Font::from_typeface(typeface, self.font_size)) FontPair::new(font_key, Font::from_typeface(typeface, self.font_size))
}
FontSelection::LastResort => {
let data = Data::new_copy(LAST_RESORT_FONT);
let typeface = Typeface::from_data(data, 0).unwrap();
FontPair::new(Font::from_typeface(typeface, self.font_size))
}
} }
} }
@ -162,7 +93,68 @@ impl FontLoader {
Some(font_arc) Some(font_arc)
} }
pub fn load_font_for_character(
&mut self,
bold: bool,
italic: bool,
character: char,
) -> Option<Arc<FontPair>> {
let font_style = font_style(bold, italic);
let typeface =
self.font_mgr
.match_family_style_character("", font_style, &[], character as i32)?;
let font_key = FontKey {
bold,
italic,
family_name: Some(typeface.family_name()),
};
let font_pair = Arc::new(FontPair::new(
font_key.clone(),
Font::from_typeface(typeface, self.font_size),
)?);
self.cache.put(font_key, font_pair.clone());
Some(font_pair)
}
pub fn get_or_load_last_resort(&mut self) -> Arc<FontPair> {
if let Some(last_resort) = self.last_resort.clone() {
last_resort
} else {
let font_key = FontKey::default();
let data = Data::new_copy(LAST_RESORT_FONT);
let typeface = Typeface::from_data(data, 0).unwrap();
let font_pair =
FontPair::new(font_key, Font::from_typeface(typeface, self.font_size)).unwrap();
let font_pair = Arc::new(font_pair);
self.last_resort = Some(font_pair.clone());
font_pair
}
}
pub fn loaded_fonts(&self) -> Vec<Arc<FontPair>> {
self.cache.iter().map(|(_, v)| v.clone()).collect()
}
pub fn refresh(&mut self, font_pair: &FontPair) {
self.cache.get(&font_pair.key);
}
pub fn font_names(&self) -> Vec<String> { pub fn font_names(&self) -> Vec<String> {
self.font_mgr.family_names().collect() self.font_mgr.family_names().collect()
} }
} }
fn font_style(bold: bool, italic: bool) -> FontStyle {
match (bold, italic) {
(true, true) => FontStyle::bold_italic(),
(false, true) => FontStyle::italic(),
(true, false) => FontStyle::bold(),
(false, false) => FontStyle::normal(),
}
}

@ -1,5 +1,3 @@
use super::font_loader::FontSelection;
const DEFAULT_FONT_SIZE: f32 = 14.0; const DEFAULT_FONT_SIZE: f32 = 14.0;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -51,11 +49,8 @@ impl FontOptions {
} }
} }
pub fn primary_font(&self) -> FontSelection { pub fn primary_font(&self) -> Option<String> {
self.font_list self.font_list.first().cloned()
.first()
.map(FontSelection::from)
.unwrap_or(FontSelection::Default)
} }
} }

@ -4,13 +4,13 @@ use log::error;
// Trait to allow for conversion from rmpv::Value to any other data type. // Trait to allow for conversion from rmpv::Value to any other data type.
// Note: Feel free to implement this trait for custom types in each subsystem. // Note: Feel free to implement this trait for custom types in each subsystem.
// The reverse conversion (MyType->Value) can be performed by implementing `From<MyType> for Value` // The reverse conversion (MyType->Value) can be performed by implementing `From<MyType> for Value`
pub trait FromValue { pub trait ParseFromValue {
fn from_value(&mut self, value: Value); fn parse_from_value(&mut self, value: Value);
} }
// FromValue implementations for most typical types // FromValue implementations for most typical types
impl FromValue for f32 { impl ParseFromValue for f32 {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_f64() { if value.is_f64() {
*self = value.as_f64().unwrap() as f32; *self = value.as_f64().unwrap() as f32;
} else if value.is_i64() { } else if value.is_i64() {
@ -23,8 +23,8 @@ impl FromValue for f32 {
} }
} }
impl FromValue for u64 { impl ParseFromValue for u64 {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_u64() { if value.is_u64() {
*self = value.as_u64().unwrap(); *self = value.as_u64().unwrap();
} else { } else {
@ -33,8 +33,8 @@ impl FromValue for u64 {
} }
} }
impl FromValue for u32 { impl ParseFromValue for u32 {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_u64() { if value.is_u64() {
*self = value.as_u64().unwrap() as u32; *self = value.as_u64().unwrap() as u32;
} else { } else {
@ -43,8 +43,8 @@ impl FromValue for u32 {
} }
} }
impl FromValue for i32 { impl ParseFromValue for i32 {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_i64() { if value.is_i64() {
*self = value.as_i64().unwrap() as i32; *self = value.as_i64().unwrap() as i32;
} else { } else {
@ -53,8 +53,8 @@ impl FromValue for i32 {
} }
} }
impl FromValue for String { impl ParseFromValue for String {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_str() { if value.is_str() {
*self = String::from(value.as_str().unwrap()); *self = String::from(value.as_str().unwrap());
} else { } else {
@ -63,8 +63,8 @@ impl FromValue for String {
} }
} }
impl FromValue for bool { impl ParseFromValue for bool {
fn from_value(&mut self, value: Value) { fn parse_from_value(&mut self, value: Value) {
if value.is_bool() { if value.is_bool() {
*self = value.as_bool().unwrap(); *self = value.as_bool().unwrap();
} else if value.is_u64() { } else if value.is_u64() {
@ -81,7 +81,7 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_from_value_f32() { fn test_parse_from_value_f32() {
let mut v0: f32 = 0.0; let mut v0: f32 = 0.0;
let v1 = Value::from(1.0); let v1 = Value::from(1.0);
let v2 = Value::from(-1); let v2 = Value::from(-1);
@ -90,76 +90,76 @@ mod tests {
let v2p = -1.0; let v2p = -1.0;
let v3p = std::u64::MAX as f32; let v3p = std::u64::MAX as f32;
v0.from_value(v1); v0.parse_from_value(v1);
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
v0.from_value(v2); v0.parse_from_value(v2);
assert_eq!(v0, v2p, "v0 should equal {} but is actually {}", v2p, v0); assert_eq!(v0, v2p, "v0 should equal {} but is actually {}", v2p, v0);
v0.from_value(v3); v0.parse_from_value(v3);
assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0); assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0);
// This is a noop and prints an error // This is a noop and prints an error
v0.from_value(Value::from("asd")); v0.parse_from_value(Value::from("asd"));
assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0); assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0);
} }
#[test] #[test]
fn test_from_value_u64() { fn test_parse_from_value_u64() {
let mut v0: u64 = 0; let mut v0: u64 = 0;
let v1 = Value::from(std::u64::MAX); let v1 = Value::from(std::u64::MAX);
let v1p = std::u64::MAX; let v1p = std::u64::MAX;
v0.from_value(v1); v0.parse_from_value(v1);
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
// This is a noop and prints an error // This is a noop and prints an error
v0.from_value(Value::from(-1)); v0.parse_from_value(Value::from(-1));
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
} }
#[test] #[test]
fn test_from_value_u32() { fn test_parse_from_value_u32() {
let mut v0: u32 = 0; let mut v0: u32 = 0;
let v1 = Value::from(std::u64::MAX); let v1 = Value::from(std::u64::MAX);
let v1p = std::u64::MAX as u32; let v1p = std::u64::MAX as u32;
v0.from_value(v1); v0.parse_from_value(v1);
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
// This is a noop and prints an error // This is a noop and prints an error
v0.from_value(Value::from(-1)); v0.parse_from_value(Value::from(-1));
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
} }
#[test] #[test]
fn test_from_value_i32() { fn test_parse_from_value_i32() {
let mut v0: i32 = 0; let mut v0: i32 = 0;
let v1 = Value::from(std::i64::MAX); let v1 = Value::from(std::i64::MAX);
let v1p = std::i64::MAX as i32; let v1p = std::i64::MAX as i32;
v0.from_value(v1); v0.parse_from_value(v1);
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
// This is a noop and prints an error // This is a noop and prints an error
v0.from_value(Value::from(-1)); v0.parse_from_value(Value::from(-1));
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
} }
#[test] #[test]
fn test_from_value_string() { fn test_parse_from_value_string() {
let mut v0: String = "foo".to_string(); let mut v0: String = "foo".to_string();
let v1 = Value::from("bar"); let v1 = Value::from("bar");
let v1p = "bar"; let v1p = "bar";
v0.from_value(v1); v0.parse_from_value(v1);
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
// This is a noop and prints an error // This is a noop and prints an error
v0.from_value(Value::from(-1)); v0.parse_from_value(Value::from(-1));
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
} }
#[test] #[test]
fn test_from_value_bool() { fn test_parse_from_value_bool() {
let mut v0: bool = false; let mut v0: bool = false;
let v1 = Value::from(true); let v1 = Value::from(true);
let v1p = true; let v1p = true;
@ -168,15 +168,15 @@ mod tests {
let v3 = Value::from(1); let v3 = Value::from(1);
let v3p = true; let v3p = true;
v0.from_value(v1); v0.parse_from_value(v1);
assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0); assert_eq!(v0, v1p, "v0 should equal {} but is actually {}", v1p, v0);
v0.from_value(v2); v0.parse_from_value(v2);
assert_eq!(v0, v2p, "v0 should equal {} but is actually {}", v2p, v0); assert_eq!(v0, v2p, "v0 should equal {} but is actually {}", v2p, v0);
v0.from_value(v3); v0.parse_from_value(v3);
assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0); assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0);
// This is a noop and prints an error // This is a noop and prints an error
v0.from_value(Value::from(-1)); v0.parse_from_value(Value::from(-1));
assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0); assert_eq!(v0, v3p, "v0 should equal {} but is actually {}", v3p, v0);
} }
} }

@ -12,7 +12,7 @@ use std::{
}; };
use crate::{bridge::TxWrapper, error_handling::ResultPanicExplanation}; use crate::{bridge::TxWrapper, error_handling::ResultPanicExplanation};
pub use from_value::FromValue; pub use from_value::ParseFromValue;
pub use window_geometry::{ pub use window_geometry::{
load_last_window_settings, parse_window_geometry, save_window_geometry, load_last_window_settings, parse_window_geometry, save_window_geometry,
PersistentWindowSettings, DEFAULT_WINDOW_GEOMETRY, PersistentWindowSettings, DEFAULT_WINDOW_GEOMETRY,

Loading…
Cancel
Save