mirror of
https://github.com/wez/wezterm.git
synced 2024-08-17 02:00:25 +03:00
config: split out lua functions into their own crates
This shaves off some build time and allows more parallism in the build.
This commit is contained in:
parent
42a7c1d481
commit
2f14d640e8
84
Cargo.lock
generated
84
Cargo.lock
generated
@ -334,6 +334,17 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|||||||
name = "base91"
|
name = "base91"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "battery"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"config",
|
||||||
|
"luahelper",
|
||||||
|
"starship-battery",
|
||||||
|
"wezterm-dynamic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "benchmarking"
|
name = "benchmarking"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
@ -643,13 +654,11 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bstr 0.2.17",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"colorgrad",
|
"colorgrad",
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"enum-display-derive",
|
"enum-display-derive",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"filenamegen",
|
|
||||||
"hostname",
|
"hostname",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
@ -657,7 +666,6 @@ dependencies = [
|
|||||||
"luahelper",
|
"luahelper",
|
||||||
"mlua",
|
"mlua",
|
||||||
"notify",
|
"notify",
|
||||||
"open",
|
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"portable-pty",
|
"portable-pty",
|
||||||
"promise",
|
"promise",
|
||||||
@ -665,16 +673,12 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"shlex",
|
"shlex",
|
||||||
"smol",
|
"smol",
|
||||||
"starship-battery",
|
|
||||||
"terminfo",
|
|
||||||
"termwiz",
|
"termwiz",
|
||||||
"toml",
|
"toml",
|
||||||
"umask",
|
"umask",
|
||||||
"unicode-segmentation",
|
|
||||||
"wezterm-bidi",
|
"wezterm-bidi",
|
||||||
"wezterm-dynamic",
|
"wezterm-dynamic",
|
||||||
"wezterm-input-types",
|
"wezterm-input-types",
|
||||||
"wezterm-ssh",
|
|
||||||
"wezterm-term",
|
"wezterm-term",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
@ -1070,16 +1074,22 @@ name = "env-bootstrap"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
|
"battery",
|
||||||
"chrono",
|
"chrono",
|
||||||
"cocoa",
|
"cocoa",
|
||||||
"config",
|
"config",
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"filesystem",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"logging",
|
||||||
"objc",
|
"objc",
|
||||||
|
"spawn-funcs",
|
||||||
|
"ssh-funcs",
|
||||||
"termwiz",
|
"termwiz",
|
||||||
|
"termwiz-funcs",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1173,6 +1183,17 @@ dependencies = [
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filesystem"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"config",
|
||||||
|
"filenamegen",
|
||||||
|
"luahelper",
|
||||||
|
"smol",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filetime"
|
name = "filetime"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -1996,6 +2017,16 @@ dependencies = [
|
|||||||
"value-bag",
|
"value-bag",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "logging"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"config",
|
||||||
|
"log",
|
||||||
|
"luahelper",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lru"
|
name = "lru"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@ -2280,6 +2311,7 @@ dependencies = [
|
|||||||
"smol",
|
"smol",
|
||||||
"terminfo",
|
"terminfo",
|
||||||
"termwiz",
|
"termwiz",
|
||||||
|
"termwiz-funcs",
|
||||||
"textwrap 0.15.0",
|
"textwrap 0.15.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
@ -3840,6 +3872,19 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spawn-funcs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bstr 0.2.17",
|
||||||
|
"config",
|
||||||
|
"luahelper",
|
||||||
|
"open",
|
||||||
|
"smol",
|
||||||
|
"wezterm-dynamic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@ -3855,6 +3900,16 @@ dependencies = [
|
|||||||
"lock_api 0.4.7",
|
"lock_api 0.4.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssh-funcs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"config",
|
||||||
|
"luahelper",
|
||||||
|
"wezterm-ssh",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ssh2"
|
name = "ssh2"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@ -4088,6 +4143,20 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termwiz-funcs"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"config",
|
||||||
|
"lazy_static",
|
||||||
|
"luahelper",
|
||||||
|
"terminfo",
|
||||||
|
"termwiz",
|
||||||
|
"unicode-segmentation",
|
||||||
|
"wezterm-dynamic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -4806,6 +4875,7 @@ dependencies = [
|
|||||||
"tabout",
|
"tabout",
|
||||||
"terminfo",
|
"terminfo",
|
||||||
"termwiz",
|
"termwiz",
|
||||||
|
"termwiz-funcs",
|
||||||
"textwrap 0.15.0",
|
"textwrap 0.15.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
|
@ -12,14 +12,11 @@ env_logger = "0.9"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
starship-battery = "0.7"
|
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
bstr = "0.2"
|
|
||||||
chrono = {version="0.4", features=["unstable-locales"]}
|
chrono = {version="0.4", features=["unstable-locales"]}
|
||||||
colorgrad = "0.5"
|
colorgrad = "0.5"
|
||||||
dirs-next = "2.0"
|
dirs-next = "2.0"
|
||||||
enum-display-derive = "0.1"
|
enum-display-derive = "0.1"
|
||||||
filenamegen = "0.2"
|
|
||||||
hostname = "0.3"
|
hostname = "0.3"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
@ -28,7 +25,6 @@ luahelper = { path = "../luahelper" }
|
|||||||
mlua = {version="0.8.0-beta.4", features=["vendored", "lua54", "async", "send"]}
|
mlua = {version="0.8.0-beta.4", features=["vendored", "lua54", "async", "send"]}
|
||||||
# file change notification
|
# file change notification
|
||||||
notify = "4.0"
|
notify = "4.0"
|
||||||
open = "2.0"
|
|
||||||
ordered-float = { version = "3.0", features = ["serde"] }
|
ordered-float = { version = "3.0", features = ["serde"] }
|
||||||
portable-pty = { path = "../pty", features = ["serde_support"]}
|
portable-pty = { path = "../pty", features = ["serde_support"]}
|
||||||
promise = { path = "../promise" }
|
promise = { path = "../promise" }
|
||||||
@ -36,15 +32,12 @@ serde = {version="1.0", features = ["rc", "derive"]}
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
shlex = "1.1"
|
shlex = "1.1"
|
||||||
smol = "1.2"
|
smol = "1.2"
|
||||||
terminfo = "0.7"
|
|
||||||
termwiz = { path = "../termwiz", features=["use_serde"] }
|
termwiz = { path = "../termwiz", features=["use_serde"] }
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
umask = { path = "../umask" }
|
umask = { path = "../umask" }
|
||||||
unicode-segmentation = "1.8"
|
|
||||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||||
wezterm-bidi = { path = "../bidi" }
|
wezterm-bidi = { path = "../bidi" }
|
||||||
wezterm-input-types = { path = "../wezterm-input-types" }
|
wezterm-input-types = { path = "../wezterm-input-types" }
|
||||||
wezterm-ssh = { path = "../wezterm-ssh" }
|
|
||||||
wezterm-term = { path = "../term", features=["use_serde"] }
|
wezterm-term = { path = "../term", features=["use_serde"] }
|
||||||
|
|
||||||
[target."cfg(windows)".dependencies]
|
[target."cfg(windows)".dependencies]
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::lua::{format_as_escapes, FormatItem};
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use luahelper::impl_lua_conversion_dynamic;
|
use luahelper::impl_lua_conversion_dynamic;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
@ -297,7 +296,7 @@ impl Default for TabBarStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn default_new_tab() -> String {
|
fn default_new_tab() -> String {
|
||||||
format_as_escapes(vec![FormatItem::Text(" + ".to_string())]).unwrap()
|
" + ".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||||
|
@ -4,23 +4,50 @@ use crate::{
|
|||||||
TextStyle,
|
TextStyle,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use bstr::BString;
|
use luahelper::from_lua_value_dynamic;
|
||||||
pub use luahelper::*;
|
use mlua::{FromLua, Lua, Table, ToLuaMulti, Value, Variadic};
|
||||||
use mlua::{FromLua, Lua, Table, ToLua, ToLuaMulti, Value, Variadic};
|
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
use smol::prelude::*;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use termwiz::cell::{grapheme_column_width, unicode_column_width, AttributeChange, CellAttributes};
|
use std::sync::Mutex;
|
||||||
use termwiz::color::{AnsiColor, ColorAttribute, ColorSpec, RgbColor};
|
|
||||||
use termwiz::input::Modifiers;
|
|
||||||
use termwiz::surface::change::Change;
|
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
|
||||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||||
|
|
||||||
|
pub use mlua;
|
||||||
|
|
||||||
static LUA_REGISTRY_USER_CALLBACK_COUNT: &str = "wezterm-user-callback-count";
|
static LUA_REGISTRY_USER_CALLBACK_COUNT: &str = "wezterm-user-callback-count";
|
||||||
|
|
||||||
|
pub type SetupFunc = fn(&Lua) -> anyhow::Result<()>;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref SETUP_FUNCS: Mutex<Vec<SetupFunc>> = Mutex::new(vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_context_setup_func(func: SetupFunc) {
|
||||||
|
SETUP_FUNCS.lock().unwrap().push(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_or_create_module<'lua>(lua: &'lua Lua, name: &str) -> anyhow::Result<mlua::Table<'lua>> {
|
||||||
|
let globals = lua.globals();
|
||||||
|
let package: Table = globals.get("package")?;
|
||||||
|
let loaded: Table = package.get("loaded")?;
|
||||||
|
|
||||||
|
let module = loaded.get(name)?;
|
||||||
|
match module {
|
||||||
|
Value::Nil => {
|
||||||
|
let module = lua.create_table()?;
|
||||||
|
loaded.set(name, module.clone())?;
|
||||||
|
Ok(module)
|
||||||
|
}
|
||||||
|
Value::Table(table) => Ok(table),
|
||||||
|
wat => anyhow::bail!(
|
||||||
|
"cannot register module {} as package.loaded.{} is already set to a value of type {}",
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
wat.type_name()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -54,7 +81,7 @@ pub fn make_lua_context(config_file: &Path) -> anyhow::Result<Lua> {
|
|||||||
{
|
{
|
||||||
let globals = lua.globals();
|
let globals = lua.globals();
|
||||||
// This table will be the `wezterm` module in the script
|
// This table will be the `wezterm` module in the script
|
||||||
let wezterm_mod = lua.create_table()?;
|
let wezterm_mod = get_or_create_module(&lua, "wezterm")?;
|
||||||
|
|
||||||
let package: Table = globals.get("package")?;
|
let package: Table = globals.get("package")?;
|
||||||
let package_path: String = package.get("path")?;
|
let package_path: String = package.get("path")?;
|
||||||
@ -100,7 +127,6 @@ pub fn make_lua_context(config_file: &Path) -> anyhow::Result<Lua> {
|
|||||||
|
|
||||||
wezterm_mod.set("target_triple", crate::wezterm_target_triple())?;
|
wezterm_mod.set("target_triple", crate::wezterm_target_triple())?;
|
||||||
wezterm_mod.set("version", crate::wezterm_version())?;
|
wezterm_mod.set("version", crate::wezterm_version())?;
|
||||||
wezterm_mod.set("nerdfonts", NerdFonts {})?;
|
|
||||||
wezterm_mod.set("home_dir", crate::HOME_DIR.to_str())?;
|
wezterm_mod.set("home_dir", crate::HOME_DIR.to_str())?;
|
||||||
wezterm_mod.set(
|
wezterm_mod.set(
|
||||||
"running_under_wsl",
|
"running_under_wsl",
|
||||||
@ -117,92 +143,6 @@ pub fn make_lua_context(config_file: &Path) -> anyhow::Result<Lua> {
|
|||||||
lua.create_function(|_, ()| Ok(crate::COLOR_SCHEMES.clone()))?,
|
lua.create_function(|_, ()| Ok(crate::COLOR_SCHEMES.clone()))?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
fn print_helper(args: Variadic<Value>) -> String {
|
|
||||||
let mut output = String::new();
|
|
||||||
for (idx, item) in args.into_iter().enumerate() {
|
|
||||||
if idx > 0 {
|
|
||||||
output.push(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
match item {
|
|
||||||
Value::String(s) => match s.to_str() {
|
|
||||||
Ok(s) => output.push_str(s),
|
|
||||||
Err(_) => {
|
|
||||||
let item = String::from_utf8_lossy(s.as_bytes());
|
|
||||||
output.push_str(&item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
item @ _ => {
|
|
||||||
let item = format!("{:#?}", ValuePrinter(item));
|
|
||||||
output.push_str(&item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
wezterm_mod.set(
|
|
||||||
"log_error",
|
|
||||||
lua.create_function(|_, args: Variadic<Value>| {
|
|
||||||
let output = print_helper(args);
|
|
||||||
log::error!("lua: {}", output);
|
|
||||||
Ok(())
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
wezterm_mod.set(
|
|
||||||
"log_info",
|
|
||||||
lua.create_function(|_, args: Variadic<Value>| {
|
|
||||||
let output = print_helper(args);
|
|
||||||
log::info!("lua: {}", output);
|
|
||||||
Ok(())
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
wezterm_mod.set(
|
|
||||||
"log_warn",
|
|
||||||
lua.create_function(|_, args: Variadic<Value>| {
|
|
||||||
let output = print_helper(args);
|
|
||||||
log::warn!("lua: {}", output);
|
|
||||||
Ok(())
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
globals.set(
|
|
||||||
"print",
|
|
||||||
lua.create_function(|_, args: Variadic<Value>| {
|
|
||||||
let output = print_helper(args);
|
|
||||||
log::info!("lua: {}", output);
|
|
||||||
Ok(())
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set(
|
|
||||||
"column_width",
|
|
||||||
lua.create_function(|_, s: String| Ok(unicode_column_width(&s, None)))?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set(
|
|
||||||
"pad_right",
|
|
||||||
lua.create_function(|_, (s, width): (String, usize)| Ok(pad_right(s, width)))?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set(
|
|
||||||
"pad_left",
|
|
||||||
lua.create_function(|_, (s, width): (String, usize)| Ok(pad_left(s, width)))?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set(
|
|
||||||
"truncate_right",
|
|
||||||
lua.create_function(|_, (s, max_width): (String, usize)| {
|
|
||||||
Ok(truncate_right(&s, max_width))
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set(
|
|
||||||
"truncate_left",
|
|
||||||
lua.create_function(|_, (s, max_width): (String, usize)| {
|
|
||||||
Ok(truncate_left(&s, max_width))
|
|
||||||
})?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set("font", lua.create_function(font)?)?;
|
wezterm_mod.set("font", lua.create_function(font)?)?;
|
||||||
wezterm_mod.set(
|
wezterm_mod.set(
|
||||||
"font_with_fallback",
|
"font_with_fallback",
|
||||||
@ -212,220 +152,37 @@ pub fn make_lua_context(config_file: &Path) -> anyhow::Result<Lua> {
|
|||||||
wezterm_mod.set("action", lua.create_function(action)?)?;
|
wezterm_mod.set("action", lua.create_function(action)?)?;
|
||||||
lua.set_named_registry_value(LUA_REGISTRY_USER_CALLBACK_COUNT, 0)?;
|
lua.set_named_registry_value(LUA_REGISTRY_USER_CALLBACK_COUNT, 0)?;
|
||||||
wezterm_mod.set("action_callback", lua.create_function(action_callback)?)?;
|
wezterm_mod.set("action_callback", lua.create_function(action_callback)?)?;
|
||||||
wezterm_mod.set("permute_any_mods", lua.create_function(permute_any_mods)?)?;
|
|
||||||
wezterm_mod.set(
|
|
||||||
"permute_any_or_no_mods",
|
|
||||||
lua.create_function(permute_any_or_no_mods)?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wezterm_mod.set("read_dir", lua.create_async_function(read_dir)?)?;
|
|
||||||
wezterm_mod.set("glob", lua.create_async_function(glob)?)?;
|
|
||||||
|
|
||||||
wezterm_mod.set("utf16_to_utf8", lua.create_function(utf16_to_utf8)?)?;
|
wezterm_mod.set("utf16_to_utf8", lua.create_function(utf16_to_utf8)?)?;
|
||||||
wezterm_mod.set("split_by_newlines", lua.create_function(split_by_newlines)?)?;
|
wezterm_mod.set("split_by_newlines", lua.create_function(split_by_newlines)?)?;
|
||||||
wezterm_mod.set(
|
|
||||||
"run_child_process",
|
|
||||||
lua.create_async_function(run_child_process)?,
|
|
||||||
)?;
|
|
||||||
wezterm_mod.set(
|
|
||||||
"background_child_process",
|
|
||||||
lua.create_async_function(background_child_process)?,
|
|
||||||
)?;
|
|
||||||
wezterm_mod.set("open_with", lua.create_function(open_with)?)?;
|
|
||||||
wezterm_mod.set("on", lua.create_function(register_event)?)?;
|
wezterm_mod.set("on", lua.create_function(register_event)?)?;
|
||||||
wezterm_mod.set("emit", lua.create_async_function(emit_event)?)?;
|
wezterm_mod.set("emit", lua.create_async_function(emit_event)?)?;
|
||||||
wezterm_mod.set("sleep_ms", lua.create_async_function(sleep_ms)?)?;
|
wezterm_mod.set("sleep_ms", lua.create_async_function(sleep_ms)?)?;
|
||||||
wezterm_mod.set("format", lua.create_function(format)?)?;
|
|
||||||
wezterm_mod.set("strftime", lua.create_function(strftime)?)?;
|
wezterm_mod.set("strftime", lua.create_function(strftime)?)?;
|
||||||
wezterm_mod.set("battery_info", lua.create_function(battery_info)?)?;
|
|
||||||
wezterm_mod.set("gradient_colors", lua.create_function(gradient_colors)?)?;
|
wezterm_mod.set("gradient_colors", lua.create_function(gradient_colors)?)?;
|
||||||
wezterm_mod.set(
|
|
||||||
"enumerate_ssh_hosts",
|
|
||||||
lua.create_function(enumerate_ssh_hosts)?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
package.set("path", path_array.join(";"))?;
|
package.set("path", path_array.join(";"))?;
|
||||||
|
}
|
||||||
|
|
||||||
let loaded: Table = package.get("loaded")?;
|
for func in SETUP_FUNCS.lock().unwrap().iter() {
|
||||||
loaded.set("wezterm", wezterm_mod)?;
|
func(&lua)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(lua)
|
Ok(lua)
|
||||||
}
|
}
|
||||||
|
|
||||||
use termwiz::caps::{Capabilities, ColorLevel, ProbeHints};
|
|
||||||
use termwiz::render::terminfo::TerminfoRenderer;
|
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
|
||||||
static ref CAPS: Capabilities = {
|
|
||||||
let data = include_bytes!("../../termwiz/data/xterm-256color");
|
|
||||||
let db = terminfo::Database::from_buffer(&data[..]).unwrap();
|
|
||||||
Capabilities::new_with_hints(
|
|
||||||
ProbeHints::new_from_env()
|
|
||||||
.term(Some("xterm-256color".into()))
|
|
||||||
.terminfo_db(Some(db))
|
|
||||||
.color_level(Some(ColorLevel::TrueColor))
|
|
||||||
.colorterm(None)
|
|
||||||
.colorterm_bce(None)
|
|
||||||
.term_program(Some("WezTerm".into()))
|
|
||||||
.term_program_version(Some(crate::wezterm_version().into())),
|
|
||||||
)
|
|
||||||
.expect("cannot fail to make internal Capabilities")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_wezterm_terminfo_renderer() -> TerminfoRenderer {
|
|
||||||
TerminfoRenderer::new(CAPS.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq)]
|
|
||||||
pub enum FormatColor {
|
|
||||||
AnsiColor(AnsiColor),
|
|
||||||
Color(String),
|
|
||||||
Default,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FormatColor {
|
|
||||||
fn to_attr(self) -> ColorAttribute {
|
|
||||||
let spec: ColorSpec = self.into();
|
|
||||||
let attr: ColorAttribute = spec.into();
|
|
||||||
attr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<ColorSpec> for FormatColor {
|
|
||||||
fn into(self) -> ColorSpec {
|
|
||||||
match self {
|
|
||||||
FormatColor::AnsiColor(c) => c.into(),
|
|
||||||
FormatColor::Color(s) => {
|
|
||||||
let rgb = RgbColor::from_named_or_rgb_string(&s)
|
|
||||||
.unwrap_or(RgbColor::new_8bpc(0xff, 0xff, 0xff));
|
|
||||||
rgb.into()
|
|
||||||
}
|
|
||||||
FormatColor::Default => ColorSpec::Default,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq)]
|
|
||||||
pub enum FormatItem {
|
|
||||||
Foreground(FormatColor),
|
|
||||||
Background(FormatColor),
|
|
||||||
Attribute(AttributeChange),
|
|
||||||
Text(String),
|
|
||||||
}
|
|
||||||
impl_lua_conversion_dynamic!(FormatItem);
|
|
||||||
|
|
||||||
impl Into<Change> for FormatItem {
|
|
||||||
fn into(self) -> Change {
|
|
||||||
match self {
|
|
||||||
Self::Attribute(change) => change.into(),
|
|
||||||
Self::Text(t) => t.into(),
|
|
||||||
Self::Foreground(c) => AttributeChange::Foreground(c.to_attr()).into(),
|
|
||||||
Self::Background(c) => AttributeChange::Background(c.to_attr()).into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FormatTarget {
|
|
||||||
target: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::io::Write for FormatTarget {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
||||||
std::io::Write::write(&mut self.target, buf)
|
|
||||||
}
|
|
||||||
fn flush(&mut self) -> std::io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl termwiz::render::RenderTty for FormatTarget {
|
|
||||||
fn get_size_in_cells(&mut self) -> termwiz::Result<(usize, usize)> {
|
|
||||||
Ok((80, 24))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn strftime<'lua>(_: &'lua Lua, format: String) -> mlua::Result<String> {
|
fn strftime<'lua>(_: &'lua Lua, format: String) -> mlua::Result<String> {
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
let local: DateTime<Local> = Local::now();
|
let local: DateTime<Local> = Local::now();
|
||||||
Ok(local.format(&format).to_string())
|
Ok(local.format(&format).to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_as_escapes(items: Vec<FormatItem>) -> anyhow::Result<String> {
|
|
||||||
let mut changes: Vec<Change> = items.into_iter().map(Into::into).collect();
|
|
||||||
changes.push(Change::AllAttributes(CellAttributes::default()).into());
|
|
||||||
let mut renderer = new_wezterm_terminfo_renderer();
|
|
||||||
let mut target = FormatTarget { target: vec![] };
|
|
||||||
renderer.render_to(&changes, &mut target)?;
|
|
||||||
Ok(String::from_utf8(target.target)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format<'lua>(_: &'lua Lua, items: Vec<FormatItem>) -> mlua::Result<String> {
|
|
||||||
format_as_escapes(items).map_err(|e| mlua::Error::external(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromDynamic, ToDynamic, Debug)]
|
|
||||||
struct BatteryInfo {
|
|
||||||
state_of_charge: f32,
|
|
||||||
vendor: String,
|
|
||||||
model: String,
|
|
||||||
state: String,
|
|
||||||
serial: String,
|
|
||||||
time_to_full: Option<f32>,
|
|
||||||
time_to_empty: Option<f32>,
|
|
||||||
}
|
|
||||||
impl_lua_conversion_dynamic!(BatteryInfo);
|
|
||||||
|
|
||||||
fn opt_string(s: Option<&str>) -> String {
|
|
||||||
match s {
|
|
||||||
Some(s) => s,
|
|
||||||
None => "unknown",
|
|
||||||
}
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn battery_info<'lua>(_: &'lua Lua, _: ()) -> mlua::Result<Vec<BatteryInfo>> {
|
|
||||||
use starship_battery::{Manager, State};
|
|
||||||
let manager = Manager::new().map_err(|e| mlua::Error::external(e))?;
|
|
||||||
let mut result = vec![];
|
|
||||||
for b in manager.batteries().map_err(|e| mlua::Error::external(e))? {
|
|
||||||
let bat = b.map_err(|e| mlua::Error::external(e))?;
|
|
||||||
result.push(BatteryInfo {
|
|
||||||
state_of_charge: bat.state_of_charge().value,
|
|
||||||
vendor: opt_string(bat.vendor()),
|
|
||||||
model: opt_string(bat.model()),
|
|
||||||
serial: opt_string(bat.serial_number()),
|
|
||||||
state: match bat.state() {
|
|
||||||
State::Charging => "Charging",
|
|
||||||
State::Discharging => "Discharging",
|
|
||||||
State::Empty => "Empty",
|
|
||||||
State::Full => "Full",
|
|
||||||
State::Unknown | _ => "Unknown",
|
|
||||||
}
|
|
||||||
.to_string(),
|
|
||||||
time_to_full: bat.time_to_full().map(|q| q.value),
|
|
||||||
time_to_empty: bat.time_to_empty().map(|q| q.value),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn sleep_ms<'lua>(_: &'lua Lua, milliseconds: u64) -> mlua::Result<()> {
|
async fn sleep_ms<'lua>(_: &'lua Lua, milliseconds: u64) -> mlua::Result<()> {
|
||||||
let duration = std::time::Duration::from_millis(milliseconds);
|
let duration = std::time::Duration::from_millis(milliseconds);
|
||||||
smol::Timer::after(duration).await;
|
smol::Timer::after(duration).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_with<'lua>(_: &'lua Lua, (url, app): (String, Option<String>)) -> mlua::Result<()> {
|
|
||||||
if let Some(app) = app {
|
|
||||||
open::with_in_background(url, app);
|
|
||||||
} else {
|
|
||||||
open::that_in_background(url);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the system hostname.
|
/// Returns the system hostname.
|
||||||
/// Errors may occur while retrieving the hostname from the system,
|
/// Errors may occur while retrieving the hostname from the system,
|
||||||
/// or if the hostname isn't a UTF-8 string.
|
/// or if the hostname isn't a UTF-8 string.
|
||||||
@ -669,49 +426,6 @@ fn action_callback<'lua>(lua: &'lua Lua, callback: mlua::Function) -> mlua::Resu
|
|||||||
return Ok(KeyAssignment::EmitEvent(user_event_id));
|
return Ok(KeyAssignment::EmitEvent(user_event_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_dir<'lua>(_: &'lua Lua, path: String) -> mlua::Result<Vec<String>> {
|
|
||||||
let mut dir = smol::fs::read_dir(path)
|
|
||||||
.await
|
|
||||||
.map_err(|e| mlua::Error::external(e))?;
|
|
||||||
let mut entries = vec![];
|
|
||||||
for entry in dir.next().await {
|
|
||||||
let entry = entry.map_err(|e| mlua::Error::external(e))?;
|
|
||||||
if let Some(utf8) = entry.path().to_str() {
|
|
||||||
entries.push(utf8.to_string());
|
|
||||||
} else {
|
|
||||||
return Err(mlua::Error::external(anyhow!(
|
|
||||||
"path entry {} is not representable as utf8",
|
|
||||||
entry.path().display()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(entries)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn glob<'lua>(
|
|
||||||
_: &'lua Lua,
|
|
||||||
(pattern, path): (String, Option<String>),
|
|
||||||
) -> mlua::Result<Vec<String>> {
|
|
||||||
let entries = smol::unblock(move || {
|
|
||||||
let mut entries = vec![];
|
|
||||||
let glob = filenamegen::Glob::new(&pattern)?;
|
|
||||||
for path in glob.walk(path.as_ref().map(|s| s.as_str()).unwrap_or(".")) {
|
|
||||||
if let Some(utf8) = path.to_str() {
|
|
||||||
entries.push(utf8.to_string());
|
|
||||||
} else {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"path entry {} is not representable as utf8",
|
|
||||||
path.display()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(entries)
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.map_err(|e| mlua::Error::external(e))?;
|
|
||||||
Ok(entries)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn split_by_newlines<'lua>(_: &'lua Lua, text: String) -> mlua::Result<Vec<String>> {
|
fn split_by_newlines<'lua>(_: &'lua Lua, text: String) -> mlua::Result<Vec<String>> {
|
||||||
Ok(text
|
Ok(text
|
||||||
.lines()
|
.lines()
|
||||||
@ -847,94 +561,6 @@ fn utf16_to_utf8<'lua>(_: &'lua Lua, text: mlua::String) -> mlua::Result<String>
|
|||||||
String::from_utf16(wide).map_err(|e| mlua::Error::external(e))
|
String::from_utf16(wide).map_err(|e| mlua::Error::external(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_child_process<'lua>(
|
|
||||||
_: &'lua Lua,
|
|
||||||
args: Vec<String>,
|
|
||||||
) -> mlua::Result<(bool, BString, BString)> {
|
|
||||||
let mut cmd = smol::process::Command::new(&args[0]);
|
|
||||||
|
|
||||||
if args.len() > 1 {
|
|
||||||
cmd.args(&args[1..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
use smol::process::windows::CommandExt;
|
|
||||||
cmd.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = cmd.output().await.map_err(|e| mlua::Error::external(e))?;
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
output.status.success(),
|
|
||||||
output.stdout.into(),
|
|
||||||
output.stderr.into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn background_child_process<'lua>(_: &'lua Lua, args: Vec<String>) -> mlua::Result<()> {
|
|
||||||
let mut cmd = smol::process::Command::new(&args[0]);
|
|
||||||
|
|
||||||
if args.len() > 1 {
|
|
||||||
cmd.args(&args[1..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
use smol::process::windows::CommandExt;
|
|
||||||
cmd.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.stdin(smol::process::Stdio::null())
|
|
||||||
.spawn()
|
|
||||||
.map_err(|e| mlua::Error::external(e))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn permute_any_mods<'lua>(
|
|
||||||
lua: &'lua Lua,
|
|
||||||
item: mlua::Table,
|
|
||||||
) -> mlua::Result<Vec<mlua::Value<'lua>>> {
|
|
||||||
permute_mods(lua, item, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn permute_any_or_no_mods<'lua>(
|
|
||||||
lua: &'lua Lua,
|
|
||||||
item: mlua::Table,
|
|
||||||
) -> mlua::Result<Vec<mlua::Value<'lua>>> {
|
|
||||||
permute_mods(lua, item, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn permute_mods<'lua>(
|
|
||||||
lua: &'lua Lua,
|
|
||||||
item: mlua::Table,
|
|
||||||
allow_none: bool,
|
|
||||||
) -> mlua::Result<Vec<mlua::Value<'lua>>> {
|
|
||||||
let mut result = vec![];
|
|
||||||
for ctrl in &[Modifiers::NONE, Modifiers::CTRL] {
|
|
||||||
for shift in &[Modifiers::NONE, Modifiers::SHIFT] {
|
|
||||||
for alt in &[Modifiers::NONE, Modifiers::ALT] {
|
|
||||||
for sup in &[Modifiers::NONE, Modifiers::SUPER] {
|
|
||||||
let flags = *ctrl | *shift | *alt | *sup;
|
|
||||||
if flags == Modifiers::NONE && !allow_none {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_item = lua.create_table()?;
|
|
||||||
for pair in item.clone().pairs::<mlua::Value, mlua::Value>() {
|
|
||||||
let (k, v) = pair?;
|
|
||||||
new_item.set(k, v)?;
|
|
||||||
}
|
|
||||||
new_item.set("mods", format!("{:?}", flags))?;
|
|
||||||
result.push(new_item.to_lua(lua)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gradient_colors<'lua>(
|
fn gradient_colors<'lua>(
|
||||||
_lua: &'lua Lua,
|
_lua: &'lua Lua,
|
||||||
(gradient, num_colors): (Gradient, usize),
|
(gradient, num_colors): (Gradient, usize),
|
||||||
@ -946,7 +572,7 @@ fn gradient_colors<'lua>(
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_to_config_reload_watch_list<'lua>(
|
pub fn add_to_config_reload_watch_list<'lua>(
|
||||||
lua: &'lua Lua,
|
lua: &'lua Lua,
|
||||||
args: Variadic<String>,
|
args: Variadic<String>,
|
||||||
) -> mlua::Result<()> {
|
) -> mlua::Result<()> {
|
||||||
@ -956,33 +582,6 @@ fn add_to_config_reload_watch_list<'lua>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enumerate_ssh_hosts<'lua>(
|
|
||||||
lua: &'lua Lua,
|
|
||||||
config_files: Variadic<String>,
|
|
||||||
) -> mlua::Result<HashMap<String, wezterm_ssh::ConfigMap>> {
|
|
||||||
let mut config = wezterm_ssh::Config::new();
|
|
||||||
for file in config_files {
|
|
||||||
config.add_config_file(file);
|
|
||||||
}
|
|
||||||
config.add_default_config_files();
|
|
||||||
|
|
||||||
// Trigger a config reload if any of the parsed ssh config files change
|
|
||||||
let files: Variadic<String> = config
|
|
||||||
.loaded_config_files()
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|p| p.to_str().map(|s| s.to_string()))
|
|
||||||
.collect();
|
|
||||||
add_to_config_reload_watch_list(lua, files)?;
|
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
|
||||||
for host in config.enumerate_hosts() {
|
|
||||||
let host_config = config.for_host(&host);
|
|
||||||
map.insert(host, host_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(map)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -1047,7 +646,7 @@ mod test {
|
|||||||
local wezterm = require 'wezterm';
|
local wezterm = require 'wezterm';
|
||||||
|
|
||||||
wezterm.on('foo', function (n)
|
wezterm.on('foo', function (n)
|
||||||
wezterm.log_error("lua hook recording " .. n);
|
print("lua hook recording " .. n);
|
||||||
end);
|
end);
|
||||||
|
|
||||||
-- one of the foo handlers returns false, so the emit
|
-- one of the foo handlers returns false, so the emit
|
||||||
@ -1056,7 +655,7 @@ end);
|
|||||||
assert(wezterm.emit('foo', 2) == false)
|
assert(wezterm.emit('foo', 2) == false)
|
||||||
|
|
||||||
wezterm.on('bar', function (n, str)
|
wezterm.on('bar', function (n, str)
|
||||||
wezterm.log_error("bar says " .. n .. " " .. str)
|
print("bar says " .. n .. " " .. str)
|
||||||
end);
|
end);
|
||||||
|
|
||||||
-- None of the bar handlers return anything, so the
|
-- None of the bar handlers return anything, so the
|
||||||
@ -1073,68 +672,3 @@ assert(wezterm.emit('bar', 42, 'woot') == true)
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pad_right(mut result: String, width: usize) -> String {
|
|
||||||
let mut len = unicode_column_width(&result, None);
|
|
||||||
while len < width {
|
|
||||||
result.push(' ');
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pad_left(mut result: String, width: usize) -> String {
|
|
||||||
let mut len = unicode_column_width(&result, None);
|
|
||||||
while len < width {
|
|
||||||
result.insert(0, ' ');
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn truncate_left(s: &str, max_width: usize) -> String {
|
|
||||||
let mut result = vec![];
|
|
||||||
let mut len = 0;
|
|
||||||
for g in s.graphemes(true).rev() {
|
|
||||||
let g_len = grapheme_column_width(g, None);
|
|
||||||
if g_len + len > max_width {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result.push(g);
|
|
||||||
len += g_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.reverse();
|
|
||||||
result.join("")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn truncate_right(s: &str, max_width: usize) -> String {
|
|
||||||
let mut result = String::new();
|
|
||||||
let mut len = 0;
|
|
||||||
for g in s.graphemes(true) {
|
|
||||||
let g_len = grapheme_column_width(g, None);
|
|
||||||
if g_len + len > max_width {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result.push_str(g);
|
|
||||||
len += g_len;
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NerdFonts {}
|
|
||||||
|
|
||||||
impl mlua::UserData for NerdFonts {
|
|
||||||
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
|
|
||||||
methods.add_meta_method(
|
|
||||||
mlua::MetaMethod::Index,
|
|
||||||
|_, _, key: String| -> mlua::Result<Option<String>> {
|
|
||||||
Ok(termwiz::nerdfonts::NERD_FONTS
|
|
||||||
.get(key.as_str())
|
|
||||||
.map(|c| c.to_string()))
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -16,6 +16,12 @@ libc = "0.2"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
termwiz = { path = "../termwiz" }
|
termwiz = { path = "../termwiz" }
|
||||||
|
battery = { path = "../lua-api-crates/battery" }
|
||||||
|
termwiz-funcs = { path = "../lua-api-crates/termwiz-funcs" }
|
||||||
|
logging = { path = "../lua-api-crates/logging" }
|
||||||
|
filesystem = { path = "../lua-api-crates/filesystem" }
|
||||||
|
ssh-funcs = { path = "../lua-api-crates/ssh-funcs" }
|
||||||
|
spawn-funcs = { path = "../lua-api-crates/spawn-funcs" }
|
||||||
|
|
||||||
[target."cfg(windows)".dependencies]
|
[target."cfg(windows)".dependencies]
|
||||||
winapi = "0.3"
|
winapi = "0.3"
|
||||||
|
@ -158,6 +158,19 @@ fn register_panic_hook() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_lua_modules() {
|
||||||
|
for func in [
|
||||||
|
battery::register,
|
||||||
|
termwiz_funcs::register,
|
||||||
|
logging::register,
|
||||||
|
filesystem::register,
|
||||||
|
ssh_funcs::register,
|
||||||
|
spawn_funcs::register,
|
||||||
|
] {
|
||||||
|
config::lua::add_context_setup_func(func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn bootstrap() {
|
pub fn bootstrap() {
|
||||||
setup_logger();
|
setup_logger();
|
||||||
register_panic_hook();
|
register_panic_hook();
|
||||||
@ -169,6 +182,8 @@ pub fn bootstrap() {
|
|||||||
|
|
||||||
fixup_appimage();
|
fixup_appimage();
|
||||||
|
|
||||||
|
register_lua_modules();
|
||||||
|
|
||||||
// Remove this env var to avoid weirdness with some vim configurations.
|
// Remove this env var to avoid weirdness with some vim configurations.
|
||||||
// wezterm never sets WINDOWID and we don't want to inherit it from a
|
// wezterm never sets WINDOWID and we don't want to inherit it from a
|
||||||
// parent process.
|
// parent process.
|
||||||
|
6
lua-api-crates/README.md
Normal file
6
lua-api-crates/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
The crates in this directory provide modules and functions
|
||||||
|
to wezterm's lua config file and interface.
|
||||||
|
|
||||||
|
They are registered into the lua config via env-bootstrap.
|
||||||
|
|
||||||
|
It is advantageous to build times to have multiple, smaller, crates.
|
13
lua-api-crates/battery/Cargo.toml
Normal file
13
lua-api-crates/battery/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "battery"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
starship-battery = "0.7"
|
||||||
|
config = { path = "../../config" }
|
||||||
|
wezterm-dynamic = { path = "../../wezterm-dynamic" }
|
||||||
|
luahelper = { path = "../../luahelper" }
|
56
lua-api-crates/battery/src/lib.rs
Normal file
56
lua-api-crates/battery/src/lib.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use config::lua::get_or_create_module;
|
||||||
|
use config::lua::mlua::{self, Lua};
|
||||||
|
use luahelper::impl_lua_conversion_dynamic;
|
||||||
|
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||||
|
|
||||||
|
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||||
|
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||||
|
wezterm_mod.set("battery_info", lua.create_function(battery_info)?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromDynamic, ToDynamic, Debug)]
|
||||||
|
struct BatteryInfo {
|
||||||
|
state_of_charge: f32,
|
||||||
|
vendor: String,
|
||||||
|
model: String,
|
||||||
|
state: String,
|
||||||
|
serial: String,
|
||||||
|
time_to_full: Option<f32>,
|
||||||
|
time_to_empty: Option<f32>,
|
||||||
|
}
|
||||||
|
impl_lua_conversion_dynamic!(BatteryInfo);
|
||||||
|
|
||||||
|
fn battery_info<'lua>(_: &'lua Lua, _: ()) -> mlua::Result<Vec<BatteryInfo>> {
|
||||||
|
use starship_battery::{Manager, State};
|
||||||
|
let manager = Manager::new().map_err(|e| mlua::Error::external(e))?;
|
||||||
|
let mut result = vec![];
|
||||||
|
for b in manager.batteries().map_err(|e| mlua::Error::external(e))? {
|
||||||
|
let bat = b.map_err(|e| mlua::Error::external(e))?;
|
||||||
|
result.push(BatteryInfo {
|
||||||
|
state_of_charge: bat.state_of_charge().value,
|
||||||
|
vendor: opt_string(bat.vendor()),
|
||||||
|
model: opt_string(bat.model()),
|
||||||
|
serial: opt_string(bat.serial_number()),
|
||||||
|
state: match bat.state() {
|
||||||
|
State::Charging => "Charging",
|
||||||
|
State::Discharging => "Discharging",
|
||||||
|
State::Empty => "Empty",
|
||||||
|
State::Full => "Full",
|
||||||
|
State::Unknown | _ => "Unknown",
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
time_to_full: bat.time_to_full().map(|q| q.value),
|
||||||
|
time_to_empty: bat.time_to_empty().map(|q| q.value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opt_string(s: Option<&str>) -> String {
|
||||||
|
match s {
|
||||||
|
Some(s) => s,
|
||||||
|
None => "unknown",
|
||||||
|
}
|
||||||
|
.to_string()
|
||||||
|
}
|
13
lua-api-crates/filesystem/Cargo.toml
Normal file
13
lua-api-crates/filesystem/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "filesystem"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
filenamegen = "0.2"
|
||||||
|
anyhow = "1.0"
|
||||||
|
config = { path = "../../config" }
|
||||||
|
luahelper = { path = "../../luahelper" }
|
||||||
|
smol = "1.2"
|
54
lua-api-crates/filesystem/src/lib.rs
Normal file
54
lua-api-crates/filesystem/src/lib.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use config::lua::get_or_create_module;
|
||||||
|
use config::lua::mlua::{self, Lua};
|
||||||
|
use smol::prelude::*;
|
||||||
|
|
||||||
|
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||||
|
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||||
|
wezterm_mod.set("read_dir", lua.create_async_function(read_dir)?)?;
|
||||||
|
wezterm_mod.set("glob", lua.create_async_function(glob)?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn read_dir<'lua>(_: &'lua Lua, path: String) -> mlua::Result<Vec<String>> {
|
||||||
|
let mut dir = smol::fs::read_dir(path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| mlua::Error::external(e))?;
|
||||||
|
let mut entries = vec![];
|
||||||
|
for entry in dir.next().await {
|
||||||
|
let entry = entry.map_err(|e| mlua::Error::external(e))?;
|
||||||
|
if let Some(utf8) = entry.path().to_str() {
|
||||||
|
entries.push(utf8.to_string());
|
||||||
|
} else {
|
||||||
|
return Err(mlua::Error::external(anyhow!(
|
||||||
|
"path entry {} is not representable as utf8",
|
||||||
|
entry.path().display()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn glob<'lua>(
|
||||||
|
_: &'lua Lua,
|
||||||
|
(pattern, path): (String, Option<String>),
|
||||||
|
) -> mlua::Result<Vec<String>> {
|
||||||
|
let entries = smol::unblock(move || {
|
||||||
|
let mut entries = vec![];
|
||||||
|
let glob = filenamegen::Glob::new(&pattern)?;
|
||||||
|
for path in glob.walk(path.as_ref().map(|s| s.as_str()).unwrap_or(".")) {
|
||||||
|
if let Some(utf8) = path.to_str() {
|
||||||
|
entries.push(utf8.to_string());
|
||||||
|
} else {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"path entry {} is not representable as utf8",
|
||||||
|
path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(entries)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| mlua::Error::external(e))?;
|
||||||
|
Ok(entries)
|
||||||
|
}
|
12
lua-api-crates/logging/Cargo.toml
Normal file
12
lua-api-crates/logging/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "logging"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
config = { path = "../../config" }
|
||||||
|
log = "0.4"
|
||||||
|
luahelper = { path = "../../luahelper" }
|
67
lua-api-crates/logging/src/lib.rs
Normal file
67
lua-api-crates/logging/src/lib.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use config::lua::get_or_create_module;
|
||||||
|
use config::lua::mlua::{Lua, Value, Variadic};
|
||||||
|
use luahelper::ValuePrinter;
|
||||||
|
|
||||||
|
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||||
|
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||||
|
|
||||||
|
wezterm_mod.set(
|
||||||
|
"log_error",
|
||||||
|
lua.create_function(|_, args: Variadic<Value>| {
|
||||||
|
let output = print_helper(args);
|
||||||
|
log::error!("lua: {}", output);
|
||||||
|
Ok(())
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"log_info",
|
||||||
|
lua.create_function(|_, args: Variadic<Value>| {
|
||||||
|
let output = print_helper(args);
|
||||||
|
log::info!("lua: {}", output);
|
||||||
|
Ok(())
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"log_warn",
|
||||||
|
lua.create_function(|_, args: Variadic<Value>| {
|
||||||
|
let output = print_helper(args);
|
||||||
|
log::warn!("lua: {}", output);
|
||||||
|
Ok(())
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
lua.globals().set(
|
||||||
|
"print",
|
||||||
|
lua.create_function(|_, args: Variadic<Value>| {
|
||||||
|
let output = print_helper(args);
|
||||||
|
log::info!("lua: {}", output);
|
||||||
|
Ok(())
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_helper(args: Variadic<Value>) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
for (idx, item) in args.into_iter().enumerate() {
|
||||||
|
if idx > 0 {
|
||||||
|
output.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
match item {
|
||||||
|
Value::String(s) => match s.to_str() {
|
||||||
|
Ok(s) => output.push_str(s),
|
||||||
|
Err(_) => {
|
||||||
|
let item = String::from_utf8_lossy(s.as_bytes());
|
||||||
|
output.push_str(&item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
item @ _ => {
|
||||||
|
let item = format!("{:#?}", ValuePrinter(item));
|
||||||
|
output.push_str(&item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
15
lua-api-crates/spawn-funcs/Cargo.toml
Normal file
15
lua-api-crates/spawn-funcs/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "spawn-funcs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
config = { path = "../../config" }
|
||||||
|
wezterm-dynamic = { path = "../../wezterm-dynamic" }
|
||||||
|
luahelper = { path = "../../luahelper" }
|
||||||
|
smol = "1.2"
|
||||||
|
bstr = "0.2"
|
||||||
|
open = "2.0"
|
71
lua-api-crates/spawn-funcs/src/lib.rs
Normal file
71
lua-api-crates/spawn-funcs/src/lib.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use bstr::BString;
|
||||||
|
use config::lua::get_or_create_module;
|
||||||
|
use config::lua::mlua::{self, Lua};
|
||||||
|
|
||||||
|
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||||
|
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||||
|
wezterm_mod.set("open_with", lua.create_function(open_with)?)?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"run_child_process",
|
||||||
|
lua.create_async_function(run_child_process)?,
|
||||||
|
)?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"background_child_process",
|
||||||
|
lua.create_async_function(background_child_process)?,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_with<'lua>(_: &'lua Lua, (url, app): (String, Option<String>)) -> mlua::Result<()> {
|
||||||
|
if let Some(app) = app {
|
||||||
|
open::with_in_background(url, app);
|
||||||
|
} else {
|
||||||
|
open::that_in_background(url);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_child_process<'lua>(
|
||||||
|
_: &'lua Lua,
|
||||||
|
args: Vec<String>,
|
||||||
|
) -> mlua::Result<(bool, BString, BString)> {
|
||||||
|
let mut cmd = smol::process::Command::new(&args[0]);
|
||||||
|
|
||||||
|
if args.len() > 1 {
|
||||||
|
cmd.args(&args[1..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use smol::process::windows::CommandExt;
|
||||||
|
cmd.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = cmd.output().await.map_err(|e| mlua::Error::external(e))?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
output.status.success(),
|
||||||
|
output.stdout.into(),
|
||||||
|
output.stderr.into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn background_child_process<'lua>(_: &'lua Lua, args: Vec<String>) -> mlua::Result<()> {
|
||||||
|
let mut cmd = smol::process::Command::new(&args[0]);
|
||||||
|
|
||||||
|
if args.len() > 1 {
|
||||||
|
cmd.args(&args[1..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
use smol::process::windows::CommandExt;
|
||||||
|
cmd.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.stdin(smol::process::Stdio::null())
|
||||||
|
.spawn()
|
||||||
|
.map_err(|e| mlua::Error::external(e))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
12
lua-api-crates/ssh-funcs/Cargo.toml
Normal file
12
lua-api-crates/ssh-funcs/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "ssh-funcs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
config = { path = "../../config" }
|
||||||
|
luahelper = { path = "../../luahelper" }
|
||||||
|
wezterm-ssh = { path = "../../wezterm-ssh" }
|
39
lua-api-crates/ssh-funcs/src/lib.rs
Normal file
39
lua-api-crates/ssh-funcs/src/lib.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use config::lua::get_or_create_module;
|
||||||
|
use config::lua::mlua::{self, Lua, Variadic};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||||
|
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"enumerate_ssh_hosts",
|
||||||
|
lua.create_function(enumerate_ssh_hosts)?,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate_ssh_hosts<'lua>(
|
||||||
|
lua: &'lua Lua,
|
||||||
|
config_files: Variadic<String>,
|
||||||
|
) -> mlua::Result<HashMap<String, wezterm_ssh::ConfigMap>> {
|
||||||
|
let mut config = wezterm_ssh::Config::new();
|
||||||
|
for file in config_files {
|
||||||
|
config.add_config_file(file);
|
||||||
|
}
|
||||||
|
config.add_default_config_files();
|
||||||
|
|
||||||
|
// Trigger a config reload if any of the parsed ssh config files change
|
||||||
|
let files: Variadic<String> = config
|
||||||
|
.loaded_config_files()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|p| p.to_str().map(|s| s.to_string()))
|
||||||
|
.collect();
|
||||||
|
config::lua::add_to_config_reload_watch_list(lua, files)?;
|
||||||
|
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
for host in config.enumerate_hosts() {
|
||||||
|
let host_config = config.for_host(&host);
|
||||||
|
map.insert(host, host_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(map)
|
||||||
|
}
|
16
lua-api-crates/termwiz-funcs/Cargo.toml
Normal file
16
lua-api-crates/termwiz-funcs/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[package]
|
||||||
|
name = "termwiz-funcs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0"
|
||||||
|
config = { path = "../../config" }
|
||||||
|
terminfo = "0.7"
|
||||||
|
wezterm-dynamic = { path = "../../wezterm-dynamic" }
|
||||||
|
luahelper = { path = "../../luahelper" }
|
||||||
|
termwiz = { path = "../../termwiz", features=["use_serde"] }
|
||||||
|
unicode-segmentation = "1.8"
|
||||||
|
lazy_static = "1.4"
|
261
lua-api-crates/termwiz-funcs/src/lib.rs
Normal file
261
lua-api-crates/termwiz-funcs/src/lib.rs
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
use config::lua::get_or_create_module;
|
||||||
|
use config::lua::mlua::{self, Lua, ToLua};
|
||||||
|
use luahelper::impl_lua_conversion_dynamic;
|
||||||
|
use termwiz::caps::{Capabilities, ColorLevel, ProbeHints};
|
||||||
|
use termwiz::cell::{grapheme_column_width, unicode_column_width, AttributeChange, CellAttributes};
|
||||||
|
use termwiz::color::{AnsiColor, ColorAttribute, ColorSpec, RgbColor};
|
||||||
|
use termwiz::input::Modifiers;
|
||||||
|
use termwiz::render::terminfo::TerminfoRenderer;
|
||||||
|
use termwiz::surface::change::Change;
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||||
|
|
||||||
|
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||||
|
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||||
|
wezterm_mod.set("nerdfonts", NerdFonts {})?;
|
||||||
|
wezterm_mod.set("format", lua.create_function(format)?)?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"column_width",
|
||||||
|
lua.create_function(|_, s: String| Ok(unicode_column_width(&s, None)))?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
wezterm_mod.set(
|
||||||
|
"pad_right",
|
||||||
|
lua.create_function(|_, (s, width): (String, usize)| Ok(pad_right(s, width)))?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
wezterm_mod.set(
|
||||||
|
"pad_left",
|
||||||
|
lua.create_function(|_, (s, width): (String, usize)| Ok(pad_left(s, width)))?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
wezterm_mod.set(
|
||||||
|
"truncate_right",
|
||||||
|
lua.create_function(|_, (s, max_width): (String, usize)| {
|
||||||
|
Ok(truncate_right(&s, max_width))
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
wezterm_mod.set(
|
||||||
|
"truncate_left",
|
||||||
|
lua.create_function(|_, (s, max_width): (String, usize)| Ok(truncate_left(&s, max_width)))?,
|
||||||
|
)?;
|
||||||
|
wezterm_mod.set("permute_any_mods", lua.create_function(permute_any_mods)?)?;
|
||||||
|
wezterm_mod.set(
|
||||||
|
"permute_any_or_no_mods",
|
||||||
|
lua.create_function(permute_any_or_no_mods)?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NerdFonts {}
|
||||||
|
|
||||||
|
impl mlua::UserData for NerdFonts {
|
||||||
|
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_meta_method(
|
||||||
|
mlua::MetaMethod::Index,
|
||||||
|
|_, _, key: String| -> mlua::Result<Option<String>> {
|
||||||
|
Ok(termwiz::nerdfonts::NERD_FONTS
|
||||||
|
.get(key.as_str())
|
||||||
|
.map(|c| c.to_string()))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq)]
|
||||||
|
pub enum FormatColor {
|
||||||
|
AnsiColor(AnsiColor),
|
||||||
|
Color(String),
|
||||||
|
Default,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormatColor {
|
||||||
|
fn to_attr(self) -> ColorAttribute {
|
||||||
|
let spec: ColorSpec = self.into();
|
||||||
|
let attr: ColorAttribute = spec.into();
|
||||||
|
attr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<ColorSpec> for FormatColor {
|
||||||
|
fn into(self) -> ColorSpec {
|
||||||
|
match self {
|
||||||
|
FormatColor::AnsiColor(c) => c.into(),
|
||||||
|
FormatColor::Color(s) => {
|
||||||
|
let rgb = RgbColor::from_named_or_rgb_string(&s)
|
||||||
|
.unwrap_or(RgbColor::new_8bpc(0xff, 0xff, 0xff));
|
||||||
|
rgb.into()
|
||||||
|
}
|
||||||
|
FormatColor::Default => ColorSpec::Default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq)]
|
||||||
|
pub enum FormatItem {
|
||||||
|
Foreground(FormatColor),
|
||||||
|
Background(FormatColor),
|
||||||
|
Attribute(AttributeChange),
|
||||||
|
Text(String),
|
||||||
|
}
|
||||||
|
impl_lua_conversion_dynamic!(FormatItem);
|
||||||
|
|
||||||
|
impl Into<Change> for FormatItem {
|
||||||
|
fn into(self) -> Change {
|
||||||
|
match self {
|
||||||
|
Self::Attribute(change) => change.into(),
|
||||||
|
Self::Text(t) => t.into(),
|
||||||
|
Self::Foreground(c) => AttributeChange::Foreground(c.to_attr()).into(),
|
||||||
|
Self::Background(c) => AttributeChange::Background(c.to_attr()).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FormatTarget {
|
||||||
|
target: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::io::Write for FormatTarget {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
|
std::io::Write::write(&mut self.target, buf)
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl termwiz::render::RenderTty for FormatTarget {
|
||||||
|
fn get_size_in_cells(&mut self) -> termwiz::Result<(usize, usize)> {
|
||||||
|
Ok((80, 24))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_as_escapes(items: Vec<FormatItem>) -> anyhow::Result<String> {
|
||||||
|
let mut changes: Vec<Change> = items.into_iter().map(Into::into).collect();
|
||||||
|
changes.push(Change::AllAttributes(CellAttributes::default()).into());
|
||||||
|
let mut renderer = new_wezterm_terminfo_renderer();
|
||||||
|
let mut target = FormatTarget { target: vec![] };
|
||||||
|
renderer.render_to(&changes, &mut target)?;
|
||||||
|
Ok(String::from_utf8(target.target)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format<'lua>(_: &'lua Lua, items: Vec<FormatItem>) -> mlua::Result<String> {
|
||||||
|
format_as_escapes(items).map_err(|e| mlua::Error::external(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pad_right(mut result: String, width: usize) -> String {
|
||||||
|
let mut len = unicode_column_width(&result, None);
|
||||||
|
while len < width {
|
||||||
|
result.push(' ');
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pad_left(mut result: String, width: usize) -> String {
|
||||||
|
let mut len = unicode_column_width(&result, None);
|
||||||
|
while len < width {
|
||||||
|
result.insert(0, ' ');
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn truncate_left(s: &str, max_width: usize) -> String {
|
||||||
|
let mut result = vec![];
|
||||||
|
let mut len = 0;
|
||||||
|
for g in s.graphemes(true).rev() {
|
||||||
|
let g_len = grapheme_column_width(g, None);
|
||||||
|
if g_len + len > max_width {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.push(g);
|
||||||
|
len += g_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.reverse();
|
||||||
|
result.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn truncate_right(s: &str, max_width: usize) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut len = 0;
|
||||||
|
for g in s.graphemes(true) {
|
||||||
|
let g_len = grapheme_column_width(g, None);
|
||||||
|
if g_len + len > max_width {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.push_str(g);
|
||||||
|
len += g_len;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute_mods<'lua>(
|
||||||
|
lua: &'lua Lua,
|
||||||
|
item: mlua::Table,
|
||||||
|
allow_none: bool,
|
||||||
|
) -> mlua::Result<Vec<mlua::Value<'lua>>> {
|
||||||
|
let mut result = vec![];
|
||||||
|
for ctrl in &[Modifiers::NONE, Modifiers::CTRL] {
|
||||||
|
for shift in &[Modifiers::NONE, Modifiers::SHIFT] {
|
||||||
|
for alt in &[Modifiers::NONE, Modifiers::ALT] {
|
||||||
|
for sup in &[Modifiers::NONE, Modifiers::SUPER] {
|
||||||
|
let flags = *ctrl | *shift | *alt | *sup;
|
||||||
|
if flags == Modifiers::NONE && !allow_none {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_item = lua.create_table()?;
|
||||||
|
for pair in item.clone().pairs::<mlua::Value, mlua::Value>() {
|
||||||
|
let (k, v) = pair?;
|
||||||
|
new_item.set(k, v)?;
|
||||||
|
}
|
||||||
|
new_item.set("mods", format!("{:?}", flags))?;
|
||||||
|
result.push(new_item.to_lua(lua)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute_any_mods<'lua>(
|
||||||
|
lua: &'lua Lua,
|
||||||
|
item: mlua::Table,
|
||||||
|
) -> mlua::Result<Vec<mlua::Value<'lua>>> {
|
||||||
|
permute_mods(lua, item, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute_any_or_no_mods<'lua>(
|
||||||
|
lua: &'lua Lua,
|
||||||
|
item: mlua::Table,
|
||||||
|
) -> mlua::Result<Vec<mlua::Value<'lua>>> {
|
||||||
|
permute_mods(lua, item, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref CAPS: Capabilities = {
|
||||||
|
let data = include_bytes!("../../../termwiz/data/xterm-256color");
|
||||||
|
let db = terminfo::Database::from_buffer(&data[..]).unwrap();
|
||||||
|
Capabilities::new_with_hints(
|
||||||
|
ProbeHints::new_from_env()
|
||||||
|
.term(Some("xterm-256color".into()))
|
||||||
|
.terminfo_db(Some(db))
|
||||||
|
.color_level(Some(ColorLevel::TrueColor))
|
||||||
|
.colorterm(None)
|
||||||
|
.colorterm_bce(None)
|
||||||
|
.term_program(Some("WezTerm".into()))
|
||||||
|
.term_program_version(Some(config::wezterm_version().into())),
|
||||||
|
)
|
||||||
|
.expect("cannot fail to make internal Capabilities")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_wezterm_terminfo_renderer() -> TerminfoRenderer {
|
||||||
|
TerminfoRenderer::new(CAPS.clone())
|
||||||
|
}
|
@ -36,6 +36,7 @@ shell-words = "1.1"
|
|||||||
smol = "1.2"
|
smol = "1.2"
|
||||||
terminfo = "0.7"
|
terminfo = "0.7"
|
||||||
termwiz = { path = "../termwiz" }
|
termwiz = { path = "../termwiz" }
|
||||||
|
termwiz-funcs = { path = "../lua-api-crates/termwiz-funcs" }
|
||||||
textwrap = "0.15"
|
textwrap = "0.15"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
unicode-segmentation = "1.8"
|
unicode-segmentation = "1.8"
|
||||||
|
@ -409,7 +409,7 @@ fn connect_ssh_session(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderer = config::lua::new_wezterm_terminfo_renderer();
|
let renderer = termwiz_funcs::new_wezterm_terminfo_renderer();
|
||||||
let mut shim = TerminalShim {
|
let mut shim = TerminalShim {
|
||||||
stdout: &mut StdoutShim {
|
stdout: &mut StdoutShim {
|
||||||
stdout: stdout_write,
|
stdout: stdout_write,
|
||||||
|
@ -409,7 +409,7 @@ pub fn allocate(size: PtySize) -> (TermWizTerminal, Rc<dyn Pane>) {
|
|||||||
|
|
||||||
let (input_tx, input_rx) = channel();
|
let (input_tx, input_rx) = channel();
|
||||||
|
|
||||||
let renderer = config::lua::new_wezterm_terminfo_renderer();
|
let renderer = termwiz_funcs::new_wezterm_terminfo_renderer();
|
||||||
|
|
||||||
let tw_term = TermWizTerminal {
|
let tw_term = TermWizTerminal {
|
||||||
render_tx: TermWizTerminalRenderTty {
|
render_tx: TermWizTerminalRenderTty {
|
||||||
@ -457,7 +457,7 @@ pub async fn run<
|
|||||||
let (input_tx, input_rx) = channel();
|
let (input_tx, input_rx) = channel();
|
||||||
let should_close_window = window_id.is_none();
|
let should_close_window = window_id.is_none();
|
||||||
|
|
||||||
let renderer = config::lua::new_wezterm_terminfo_renderer();
|
let renderer = termwiz_funcs::new_wezterm_terminfo_renderer();
|
||||||
|
|
||||||
let tw_term = TermWizTerminal {
|
let tw_term = TermWizTerminal {
|
||||||
render_tx: TermWizTerminalRenderTty {
|
render_tx: TermWizTerminalRenderTty {
|
||||||
|
@ -60,6 +60,7 @@ structopt = "0.3"
|
|||||||
tabout = { path = "../tabout" }
|
tabout = { path = "../tabout" }
|
||||||
terminfo = "0.7"
|
terminfo = "0.7"
|
||||||
termwiz = { path = "../termwiz" }
|
termwiz = { path = "../termwiz" }
|
||||||
|
termwiz-funcs = { path = "../lua-api-crates/termwiz-funcs" }
|
||||||
textwrap = "0.15"
|
textwrap = "0.15"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
tiny-skia = "0.6"
|
tiny-skia = "0.6"
|
||||||
|
@ -9,7 +9,6 @@ use crate::inputmap::InputMap;
|
|||||||
use crate::termwindow::TermWindowNotif;
|
use crate::termwindow::TermWindowNotif;
|
||||||
use config::configuration;
|
use config::configuration;
|
||||||
use config::keyassignment::{KeyAssignment, SpawnCommand, SpawnTabDomain};
|
use config::keyassignment::{KeyAssignment, SpawnCommand, SpawnTabDomain};
|
||||||
use config::lua::truncate_right;
|
|
||||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||||
use fuzzy_matcher::FuzzyMatcher;
|
use fuzzy_matcher::FuzzyMatcher;
|
||||||
use mux::domain::{DomainId, DomainState};
|
use mux::domain::{DomainId, DomainState};
|
||||||
@ -24,6 +23,7 @@ use termwiz::color::ColorAttribute;
|
|||||||
use termwiz::input::{InputEvent, KeyCode, KeyEvent, Modifiers, MouseButtons, MouseEvent};
|
use termwiz::input::{InputEvent, KeyCode, KeyEvent, Modifiers, MouseButtons, MouseEvent};
|
||||||
use termwiz::surface::{Change, Position};
|
use termwiz::surface::{Change, Position};
|
||||||
use termwiz::terminal::Terminal;
|
use termwiz::terminal::Terminal;
|
||||||
|
use termwiz_funcs::truncate_right;
|
||||||
use window::WindowOps;
|
use window::WindowOps;
|
||||||
|
|
||||||
pub use config::keyassignment::LauncherFlags;
|
pub use config::keyassignment::LauncherFlags;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::termwindow::{PaneInformation, TabInformation, UIItem, UIItemType};
|
use crate::termwindow::{PaneInformation, TabInformation, UIItem, UIItemType};
|
||||||
use config::lua::{format_as_escapes, FormatItem};
|
|
||||||
use config::{ConfigHandle, TabBarColors};
|
use config::{ConfigHandle, TabBarColors};
|
||||||
use mlua::FromLua;
|
use mlua::FromLua;
|
||||||
use termwiz::cell::{unicode_column_width, Cell, CellAttributes};
|
use termwiz::cell::{unicode_column_width, Cell, CellAttributes};
|
||||||
@ -8,6 +7,7 @@ use termwiz::escape::csi::Sgr;
|
|||||||
use termwiz::escape::parser::Parser;
|
use termwiz::escape::parser::Parser;
|
||||||
use termwiz::escape::{Action, ControlCode, CSI};
|
use termwiz::escape::{Action, ControlCode, CSI};
|
||||||
use termwiz::surface::SEQ_ZERO;
|
use termwiz::surface::SEQ_ZERO;
|
||||||
|
use termwiz_funcs::{format_as_escapes, FormatItem};
|
||||||
use wezterm_term::Line;
|
use wezterm_term::Line;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
Loading…
Reference in New Issue
Block a user