1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-29 16:42: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::color::{ColorSpec, RgbColor};
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Palette {
/// The text color to use when the attributes are reset to default
pub foreground: Option<RgbColor>,
@ -26,6 +26,7 @@ pub struct Palette {
/// represents the current viewable area
pub scrollbar_thumb: Option<RgbColor>,
}
impl_lua_conversion!(Palette);
impl From<Palette> for 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
#[derive(Debug, Deserialize, Clone, Default)]
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
pub struct TabBarColor {
/// Specifies the intensity attribute for the tab title text
#[serde(default)]
@ -80,6 +81,7 @@ pub struct TabBarColor {
/// The forgeground/text color for the tab
pub fg_color: RgbColor,
}
impl_lua_conversion!(TabBarColor);
impl TabBarColor {
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.
/// These are not part of the terminal model and cannot be updated
/// in the same way that the dynamic color schemes are.
#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TabBarColors {
/// The background color for the tab bar
#[serde(default = "default_background")]
@ -115,6 +117,7 @@ pub struct TabBarColors {
#[serde(default = "default_inactive_tab_hover")]
pub inactive_tab_hover: TabBarColor,
}
impl_lua_conversion!(TabBarColors);
fn default_background() -> RgbColor {
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 {
/// The color palette
pub colors: Palette,
}
impl_lua_conversion!(ColorSchemeFile);

View File

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

View File

@ -8,7 +8,7 @@ const FONT_FAMILY: &str = "Consolas";
#[cfg(all(not(target_os = "macos"), not(windows)))]
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 {
/// No hinting is performed
None,
@ -21,6 +21,7 @@ pub enum FontHinting {
/// Vertical and horizontal hinting is performed.
Full,
}
impl_lua_conversion!(FontHinting);
impl Default for FontHinting {
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 {
None,
Greyscale,
Subpixel,
}
impl_lua_conversion!(FontAntiAliasing);
impl Default for FontAntiAliasing {
fn default() -> Self {
@ -52,6 +54,7 @@ pub struct FontAttributes {
#[serde(default)]
pub italic: bool,
}
impl_lua_conversion!(FontAttributes);
impl FontAttributes {
pub fn new(family: &str) -> Self {
@ -85,6 +88,7 @@ pub struct TextStyle {
/// the text color for eg: bold text.
pub foreground: Option<RgbColor>,
}
impl_lua_conversion!(TextStyle);
impl Default for TextStyle {
fn default() -> Self {
@ -178,7 +182,7 @@ impl TextStyle {
/// 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
/// stop processing further font rules.
#[derive(Debug, Default, Deserialize, Clone)]
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
pub struct StyleRule {
/// If present, this rule matches when CellAttributes::intensity holds
/// 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.
pub font: TextStyle,
}
impl_lua_conversion!(StyleRule);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,9 @@ use std::sync::Arc;
use structopt::StructOpt;
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 connui;
mod frontend;
@ -25,7 +28,6 @@ mod keyassignment;
mod localtab;
mod mux;
mod ratelim;
mod scripting;
mod server;
mod ssh;
mod stats;

View File

@ -1,5 +1,8 @@
#![macro_use]
use crate::config::{FontAttributes, TextStyle};
use anyhow::anyhow;
use mlua::{Lua, Table, Value};
use mlua::{Lua, Table};
use std::path::Path;
mod serde_lua;
@ -7,6 +10,31 @@ mod serde_lua;
pub use serde_lua::from_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.
/// The path to the directory containing the configuration is
/// 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:
/// `{ font = {{ family = "foo" }}, foreground="tomato"}`
fn font<'lua>(
lua: &'lua Lua,
(family, map_defaults): (String, Option<Table<'lua>>),
) -> mlua::Result<Value<'lua>> {
use crate::config::{FontAttributes, TextStyle};
let mut text_style: TextStyle = match map_defaults {
Some(def) => from_lua_value(Value::Table(def))?,
None => TextStyle::default(),
};
_lua: &'lua Lua,
(family, map_defaults): (String, Option<TextStyle>),
) -> mlua::Result<TextStyle> {
let mut text_style = map_defaults.unwrap_or_else(TextStyle::default);
text_style.font.clear();
text_style.font.push(FontAttributes {
family,
bold: false,
italic: false,
..Default::default()
});
Ok(to_lua_value(lua, text_style)?)
Ok(text_style)
}
/// 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,
/// as described by the `wezterm.font` documentation.
fn font_with_fallback<'lua>(
lua: &'lua Lua,
(fallback, map_defaults): (Vec<String>, Option<Table<'lua>>),
) -> mlua::Result<Value<'lua>> {
use crate::config::{FontAttributes, TextStyle};
let mut text_style: TextStyle = match map_defaults {
Some(def) => from_lua_value(Value::Table(def))?,
None => TextStyle::default(),
};
_lua: &'lua Lua,
(fallback, map_defaults): (Vec<String>, Option<TextStyle>),
) -> mlua::Result<TextStyle> {
let mut text_style = map_defaults.unwrap_or_else(TextStyle::default);
text_style.font.clear();
for family in fallback {
text_style.font.push(FontAttributes {
family,
bold: false,
italic: false,
..Default::default()
});
}
Ok(to_lua_value(lua, text_style)?)
Ok(text_style)
}