1
1
mirror of https://github.com/wez/wezterm.git synced 2025-01-01 18:22:13 +03:00

lua: make it easier to write type-safe functions

implementing the `ToLua` and `FromLua` traits allows `create_function`
to automatically apply the appropriate conversions to the parameters
and return values in a callback function.

That makes it possible (and nicer!) to write properly typed callbacks.
This commit is contained in:
Wez Furlong 2020-03-01 10:55:17 -08:00
parent 72097cbfbb
commit b1b24b48ec
11 changed files with 82 additions and 46 deletions

View File

@ -2,7 +2,7 @@ use crate::config::*;
use termwiz::cell::CellAttributes; use termwiz::cell::CellAttributes;
use termwiz::color::{ColorSpec, RgbColor}; use termwiz::color::{ColorSpec, RgbColor};
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Palette { pub struct Palette {
/// The text color to use when the attributes are reset to default /// The text color to use when the attributes are reset to default
pub foreground: Option<RgbColor>, pub foreground: Option<RgbColor>,
@ -26,6 +26,7 @@ pub struct Palette {
/// represents the current viewable area /// represents the current viewable area
pub scrollbar_thumb: Option<RgbColor>, pub scrollbar_thumb: Option<RgbColor>,
} }
impl_lua_conversion!(Palette);
impl From<Palette> for term::color::ColorPalette { impl From<Palette> for term::color::ColorPalette {
fn from(cfg: Palette) -> term::color::ColorPalette { fn from(cfg: Palette) -> term::color::ColorPalette {
@ -61,7 +62,7 @@ impl From<Palette> for term::color::ColorPalette {
} }
/// Specify the text styling for a tab in the tab bar /// Specify the text styling for a tab in the tab bar
#[derive(Debug, Deserialize, Clone, Default)] #[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct TabBarColor { pub struct TabBarColor {
/// Specifies the intensity attribute for the tab title text /// Specifies the intensity attribute for the tab title text
#[serde(default)] #[serde(default)]
@ -80,6 +81,7 @@ pub struct TabBarColor {
/// The forgeground/text color for the tab /// The forgeground/text color for the tab
pub fg_color: RgbColor, pub fg_color: RgbColor,
} }
impl_lua_conversion!(TabBarColor);
impl TabBarColor { impl TabBarColor {
pub fn as_cell_attributes(&self) -> CellAttributes { pub fn as_cell_attributes(&self) -> CellAttributes {
@ -97,7 +99,7 @@ impl TabBarColor {
/// Specifies the colors to use for the tab bar portion of the UI. /// Specifies the colors to use for the tab bar portion of the UI.
/// These are not part of the terminal model and cannot be updated /// These are not part of the terminal model and cannot be updated
/// in the same way that the dynamic color schemes are. /// in the same way that the dynamic color schemes are.
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TabBarColors { pub struct TabBarColors {
/// The background color for the tab bar /// The background color for the tab bar
#[serde(default = "default_background")] #[serde(default = "default_background")]
@ -115,6 +117,7 @@ pub struct TabBarColors {
#[serde(default = "default_inactive_tab_hover")] #[serde(default = "default_inactive_tab_hover")]
pub inactive_tab_hover: TabBarColor, pub inactive_tab_hover: TabBarColor,
} }
impl_lua_conversion!(TabBarColors);
fn default_background() -> RgbColor { fn default_background() -> RgbColor {
RgbColor::new(0x0b, 0x00, 0x22) RgbColor::new(0x0b, 0x00, 0x22)
@ -154,8 +157,9 @@ impl Default for TabBarColors {
} }
} }
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ColorSchemeFile { pub struct ColorSchemeFile {
/// The color palette /// The color palette
pub colors: Palette, pub colors: Palette,
} }
impl_lua_conversion!(ColorSchemeFile);

View File

@ -2,12 +2,13 @@ use crate::config::*;
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct DaemonOptions { pub struct DaemonOptions {
pub pid_file: Option<PathBuf>, pub pid_file: Option<PathBuf>,
pub stdout: Option<PathBuf>, pub stdout: Option<PathBuf>,
pub stderr: Option<PathBuf>, pub stderr: Option<PathBuf>,
} }
impl_lua_conversion!(DaemonOptions);
fn open_log(path: PathBuf) -> anyhow::Result<File> { fn open_log(path: PathBuf) -> anyhow::Result<File> {
create_user_owned_dirs( create_user_owned_dirs(

View File

@ -8,7 +8,7 @@ const FONT_FAMILY: &str = "Consolas";
#[cfg(all(not(target_os = "macos"), not(windows)))] #[cfg(all(not(target_os = "macos"), not(windows)))]
const FONT_FAMILY: &str = "monospace"; const FONT_FAMILY: &str = "monospace";
#[derive(Debug, Copy, Deserialize, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
pub enum FontHinting { pub enum FontHinting {
/// No hinting is performed /// No hinting is performed
None, None,
@ -21,6 +21,7 @@ pub enum FontHinting {
/// Vertical and horizontal hinting is performed. /// Vertical and horizontal hinting is performed.
Full, Full,
} }
impl_lua_conversion!(FontHinting);
impl Default for FontHinting { impl Default for FontHinting {
fn default() -> Self { fn default() -> Self {
@ -28,12 +29,13 @@ impl Default for FontHinting {
} }
} }
#[derive(Debug, Copy, Deserialize, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Copy, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
pub enum FontAntiAliasing { pub enum FontAntiAliasing {
None, None,
Greyscale, Greyscale,
Subpixel, Subpixel,
} }
impl_lua_conversion!(FontAntiAliasing);
impl Default for FontAntiAliasing { impl Default for FontAntiAliasing {
fn default() -> Self { fn default() -> Self {
@ -52,6 +54,7 @@ pub struct FontAttributes {
#[serde(default)] #[serde(default)]
pub italic: bool, pub italic: bool,
} }
impl_lua_conversion!(FontAttributes);
impl FontAttributes { impl FontAttributes {
pub fn new(family: &str) -> Self { pub fn new(family: &str) -> Self {
@ -85,6 +88,7 @@ pub struct TextStyle {
/// the text color for eg: bold text. /// the text color for eg: bold text.
pub foreground: Option<RgbColor>, pub foreground: Option<RgbColor>,
} }
impl_lua_conversion!(TextStyle);
impl Default for TextStyle { impl Default for TextStyle {
fn default() -> Self { fn default() -> Self {
@ -178,7 +182,7 @@ impl TextStyle {
/// The above is translated as: "if the `CellAttributes` have the italic bit /// The above is translated as: "if the `CellAttributes` have the italic bit
/// set, then use the italic style of font rather than the default", and /// set, then use the italic style of font rather than the default", and
/// stop processing further font rules. /// stop processing further font rules.
#[derive(Debug, Default, Deserialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
pub struct StyleRule { pub struct StyleRule {
/// If present, this rule matches when CellAttributes::intensity holds /// If present, this rule matches when CellAttributes::intensity holds
/// a value that matches this rule. Valid values are "Bold", "Normal", /// a value that matches this rule. Valid values are "Bold", "Normal",
@ -207,3 +211,4 @@ pub struct StyleRule {
/// When this rule matches, `font` specifies the styling to be used. /// When this rule matches, `font` specifies the styling to be used.
pub font: TextStyle, pub font: TextStyle,
} }
impl_lua_conversion!(StyleRule);

View File

@ -1,9 +1,9 @@
use crate::keyassignment::{KeyAssignment, SpawnTabDomain}; use crate::keyassignment::{KeyAssignment, SpawnTabDomain};
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer, Serialize};
use termwiz::input::{KeyCode, Modifiers}; use termwiz::input::{KeyCode, Modifiers};
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Key { pub struct Key {
#[serde(deserialize_with = "de_keycode")] #[serde(deserialize_with = "de_keycode")]
pub key: KeyCode, pub key: KeyCode,
@ -13,6 +13,7 @@ pub struct Key {
#[serde(default)] #[serde(default)]
pub arg: Option<String>, pub arg: Option<String>,
} }
impl_lua_conversion!(Key);
impl std::convert::TryInto<KeyAssignment> for &Key { impl std::convert::TryInto<KeyAssignment> for &Key {
type Error = Error; type Error = Error;
@ -89,7 +90,7 @@ impl std::convert::TryInto<KeyAssignment> for &Key {
} }
} }
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub enum KeyAction { pub enum KeyAction {
SpawnTab, SpawnTab,
SpawnTabInCurrentTabDomain, SpawnTabInCurrentTabDomain,
@ -116,6 +117,7 @@ pub enum KeyAction {
ScrollByPage, ScrollByPage,
ShowTabNavigator, ShowTabNavigator,
} }
impl_lua_conversion!(KeyAction);
fn de_keycode<'de, D>(deserializer: D) -> Result<KeyCode, D::Error> fn de_keycode<'de, D>(deserializer: D) -> Result<KeyCode, D::Error>
where where

View File

@ -492,7 +492,7 @@ pub struct Config {
pub use_local_build_for_proxy: bool, pub use_local_build_for_proxy: bool,
} }
#[derive(Deserialize, Clone, Copy, Debug)] #[derive(Deserialize, Serialize, Clone, Copy, Debug)]
pub enum DefaultCursorStyle { pub enum DefaultCursorStyle {
BlinkingBlock, BlinkingBlock,
SteadyBlock, SteadyBlock,
@ -501,6 +501,7 @@ pub enum DefaultCursorStyle {
BlinkingBar, BlinkingBar,
SteadyBar, SteadyBar,
} }
impl_lua_conversion!(DefaultCursorStyle);
impl Default for DefaultCursorStyle { impl Default for DefaultCursorStyle {
fn default() -> Self { fn default() -> Self {
@ -524,7 +525,7 @@ impl DefaultCursorStyle {
} }
} }
#[derive(Default, Deserialize, Clone, Copy, Debug)] #[derive(Default, Deserialize, Serialize, Clone, Copy, Debug)]
pub struct WindowPadding { pub struct WindowPadding {
#[serde(default)] #[serde(default)]
pub left: u16, pub left: u16,
@ -535,6 +536,7 @@ pub struct WindowPadding {
#[serde(default)] #[serde(default)]
pub bottom: u16, pub bottom: u16,
} }
impl_lua_conversion!(WindowPadding);
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {

View File

@ -1,7 +1,6 @@
use crate::config::*; use crate::config::*;
use serde::Deserialize;
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct SshDomain { pub struct SshDomain {
/// The name of this specific domain. Must be unique amongst /// The name of this specific domain. Must be unique amongst
/// all types of domain in the configuration file. /// all types of domain in the configuration file.
@ -24,3 +23,4 @@ pub struct SshDomain {
#[serde(default = "default_read_timeout")] #[serde(default = "default_read_timeout")]
pub timeout: Duration, pub timeout: Duration,
} }
impl_lua_conversion!(SshDomain);

View File

@ -1,7 +1,7 @@
use crate::config::*; use crate::config::*;
use crate::SshParameters; use crate::SshParameters;
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct TlsDomainServer { pub struct TlsDomainServer {
/// The address:port combination on which the server will listen /// The address:port combination on which the server will listen
/// for client connections /// for client connections
@ -24,8 +24,9 @@ pub struct TlsDomainServer {
#[serde(default)] #[serde(default)]
pub pem_root_certs: Vec<PathBuf>, pub pem_root_certs: Vec<PathBuf>,
} }
impl_lua_conversion!(TlsDomainServer);
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct TlsDomainClient { pub struct TlsDomainClient {
/// The name of this specific domain. Must be unique amongst /// The name of this specific domain. Must be unique amongst
/// all types of domain in the configuration file. /// all types of domain in the configuration file.
@ -80,6 +81,7 @@ pub struct TlsDomainClient {
#[serde(default = "default_write_timeout")] #[serde(default = "default_write_timeout")]
pub write_timeout: Duration, pub write_timeout: Duration,
} }
impl_lua_conversion!(TlsDomainClient);
impl TlsDomainClient { impl TlsDomainClient {
pub fn ssh_parameters(&self) -> Option<anyhow::Result<SshParameters>> { pub fn ssh_parameters(&self) -> Option<anyhow::Result<SshParameters>> {

View File

@ -3,7 +3,7 @@ use std::path::PathBuf;
/// Configures an instance of a multiplexer that can be communicated /// Configures an instance of a multiplexer that can be communicated
/// with via a unix domain socket /// with via a unix domain socket
#[derive(Default, Debug, Clone, Deserialize)] #[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct UnixDomain { pub struct UnixDomain {
/// The name of this specific domain. Must be unique amongst /// The name of this specific domain. Must be unique amongst
/// all types of domain in the configuration file. /// all types of domain in the configuration file.
@ -44,6 +44,7 @@ pub struct UnixDomain {
#[serde(default = "default_write_timeout")] #[serde(default = "default_write_timeout")]
pub write_timeout: Duration, pub write_timeout: Duration,
} }
impl_lua_conversion!(UnixDomain);
impl UnixDomain { impl UnixDomain {
pub fn socket_path(&self) -> PathBuf { pub fn socket_path(&self) -> PathBuf {

View File

@ -3,7 +3,7 @@ use crate::mux::tab::Tab;
use crate::mux::window::WindowId; use crate::mux::window::WindowId;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use downcast_rs::{impl_downcast, Downcast}; use downcast_rs::{impl_downcast, Downcast};
use serde::Deserialize; use serde::{Deserialize, Serialize};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
@ -12,13 +12,14 @@ pub mod activity;
pub mod gui; pub mod gui;
pub mod muxserver; pub mod muxserver;
#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
pub enum FrontEndSelection { pub enum FrontEndSelection {
OpenGL, OpenGL,
Software, Software,
MuxServer, MuxServer,
Null, Null,
} }
impl_lua_conversion!(FrontEndSelection);
impl Default for FrontEndSelection { impl Default for FrontEndSelection {
fn default() -> Self { fn default() -> Self {

View File

@ -18,6 +18,9 @@ use std::sync::Arc;
use structopt::StructOpt; use structopt::StructOpt;
use tabout::{tabulate_output, Alignment, Column}; use tabout::{tabulate_output, Alignment, Column};
// This module defines a macro, so it must be referenced before any other mods
mod scripting;
mod config; mod config;
mod connui; mod connui;
mod frontend; mod frontend;
@ -25,7 +28,6 @@ mod keyassignment;
mod localtab; mod localtab;
mod mux; mod mux;
mod ratelim; mod ratelim;
mod scripting;
mod server; mod server;
mod ssh; mod ssh;
mod stats; mod stats;

View File

@ -1,5 +1,8 @@
#![macro_use]
use crate::config::{FontAttributes, TextStyle};
use anyhow::anyhow; use anyhow::anyhow;
use mlua::{Lua, Table, Value}; use mlua::{Lua, Table};
use std::path::Path; use std::path::Path;
mod serde_lua; mod serde_lua;
@ -7,6 +10,31 @@ mod serde_lua;
pub use serde_lua::from_lua_value; pub use serde_lua::from_lua_value;
pub use serde_lua::ser::to_lua_value; pub use serde_lua::ser::to_lua_value;
/// Implement lua conversion traits for a type.
/// This implementation requires that the type implement
/// serde Serialize and Deserialize.
/// Why do we need these traits? They allow `create_function` to
/// operate in terms of our internal types rather than forcing
/// the implementer to use generic Value parameter or return values.
macro_rules! impl_lua_conversion {
($struct:ident) => {
impl<'lua> mlua::ToLua<'lua> for $struct {
fn to_lua(self, lua: &'lua mlua::Lua) -> Result<mlua::Value<'lua>, mlua::Error> {
Ok(crate::scripting::to_lua_value(lua, self)?)
}
}
impl<'lua> mlua::FromLua<'lua> for $struct {
fn from_lua(
value: mlua::Value<'lua>,
_lua: &'lua mlua::Lua,
) -> Result<Self, mlua::Error> {
Ok(crate::scripting::from_lua_value(value)?)
}
}
};
}
/// Set up a lua context for executing some code. /// Set up a lua context for executing some code.
/// The path to the directory containing the configuration is /// The path to the directory containing the configuration is
/// passed in and is used to pre-set some global values in /// passed in and is used to pre-set some global values in
@ -124,24 +152,18 @@ fn hostname<'lua>(_: &'lua Lua, _: ()) -> mlua::Result<String> {
/// yields: /// yields:
/// `{ font = {{ family = "foo" }}, foreground="tomato"}` /// `{ font = {{ family = "foo" }}, foreground="tomato"}`
fn font<'lua>( fn font<'lua>(
lua: &'lua Lua, _lua: &'lua Lua,
(family, map_defaults): (String, Option<Table<'lua>>), (family, map_defaults): (String, Option<TextStyle>),
) -> mlua::Result<Value<'lua>> { ) -> mlua::Result<TextStyle> {
use crate::config::{FontAttributes, TextStyle}; let mut text_style = map_defaults.unwrap_or_else(TextStyle::default);
let mut text_style: TextStyle = match map_defaults {
Some(def) => from_lua_value(Value::Table(def))?,
None => TextStyle::default(),
};
text_style.font.clear(); text_style.font.clear();
text_style.font.push(FontAttributes { text_style.font.push(FontAttributes {
family, family,
bold: false, ..Default::default()
italic: false,
}); });
Ok(to_lua_value(lua, text_style)?) Ok(text_style)
} }
/// Given a list of font family names in order of preference, return a /// Given a list of font family names in order of preference, return a
@ -152,24 +174,18 @@ fn font<'lua>(
/// The second optional argument is a list of other TextStyle fields, /// The second optional argument is a list of other TextStyle fields,
/// as described by the `wezterm.font` documentation. /// as described by the `wezterm.font` documentation.
fn font_with_fallback<'lua>( fn font_with_fallback<'lua>(
lua: &'lua Lua, _lua: &'lua Lua,
(fallback, map_defaults): (Vec<String>, Option<Table<'lua>>), (fallback, map_defaults): (Vec<String>, Option<TextStyle>),
) -> mlua::Result<Value<'lua>> { ) -> mlua::Result<TextStyle> {
use crate::config::{FontAttributes, TextStyle}; let mut text_style = map_defaults.unwrap_or_else(TextStyle::default);
let mut text_style: TextStyle = match map_defaults {
Some(def) => from_lua_value(Value::Table(def))?,
None => TextStyle::default(),
};
text_style.font.clear(); text_style.font.clear();
for family in fallback { for family in fallback {
text_style.font.push(FontAttributes { text_style.font.push(FontAttributes {
family, family,
bold: false, ..Default::default()
italic: false,
}); });
} }
Ok(to_lua_value(lua, text_style)?) Ok(text_style)
} }