1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 05:12:40 +03:00

Add serial_ports config

This commit teaches the config about SerialDomains, and the mux
layer about constructing a SerialDomain, then changes the GUI
layer to use those pieces to set up `wezterm serial`.

A new `serial_ports` config is added, and the GUI layer knows how
to apply it to the set of domains in the mux.

The result of this is that you can now define a domain for each
serial port and spawn a serial connection into a new tab or window
in your running wezterm gui instance.
This commit is contained in:
Wez Furlong 2023-03-29 19:05:13 -07:00
parent e38a06d640
commit 1e688a5128
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
11 changed files with 112 additions and 13 deletions

2
Cargo.lock generated
View File

@ -3075,6 +3075,7 @@ dependencies = [
"rangeset",
"regex",
"serde",
"serial",
"shell-words",
"smol",
"terminfo",
@ -6029,7 +6030,6 @@ dependencies = [
"regex",
"serde",
"serde_json",
"serial",
"shared_library",
"shlex",
"smol",

View File

@ -23,8 +23,8 @@ use crate::wsl::WslDomain;
use crate::{
default_config_with_overrides_applied, default_one_point_oh, default_one_point_oh_f64,
default_true, GpuInfo, KeyMapPreference, LoadedConfig, MouseEventTriggerMods, RgbaColor,
WebGpuPowerPreference, CONFIG_DIRS, CONFIG_FILE_OVERRIDE, CONFIG_OVERRIDES, CONFIG_SKIP,
HOME_DIR,
SerialDomain, WebGpuPowerPreference, CONFIG_DIRS, CONFIG_FILE_OVERRIDE, CONFIG_OVERRIDES,
CONFIG_SKIP, HOME_DIR,
};
use anyhow::Context;
use luahelper::impl_lua_conversion_dynamic;
@ -301,6 +301,9 @@ pub struct Config {
#[dynamic(default)]
pub exec_domains: Vec<ExecDomain>,
#[dynamic(default)]
pub serial_ports: Vec<SerialDomain>,
/// The set of unix domains
#[dynamic(default = "UnixDomain::default_unix_domains")]
pub unix_domains: Vec<UnixDomain>,

View File

@ -32,6 +32,7 @@ mod keys;
pub mod lua;
pub mod meta;
mod scheme_data;
mod serial;
mod ssh;
mod terminal;
mod tls;
@ -49,6 +50,7 @@ pub use exec_domain::*;
pub use font::*;
pub use frontend::*;
pub use keys::*;
pub use serial::*;
pub use ssh::*;
pub use terminal::*;
pub use tls::*;

19
config/src/serial.rs Normal file
View File

@ -0,0 +1,19 @@
use crate::config::validate_domain_name;
use wezterm_dynamic::{FromDynamic, ToDynamic};
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
pub struct SerialDomain {
/// The name of this specific domain. Must be unique amongst
/// all types of domain in the configuration file.
#[dynamic(validate = "validate_domain_name")]
pub name: String,
/// Specifies the serial device name.
/// On Windows systems this can be a name like `COM0`.
/// On posix systems this will be something like `/dev/ttyUSB0`.
/// If omitted, the name will be interpreted as the port.
pub port: Option<String>,
/// Set the baud rate. The default is 9600 baud.
pub baud: Option<usize>,
}

View File

@ -24,6 +24,7 @@ As features stabilize some brief notes about them will accumulate here.
#### New
* [pane:activate()](config/lua/pane/activate.md) and [tab:activate()](config/lua/MuxTab/activate.md). #3217
* [ulimit_nofile](config/lua/config/ulimit_nofile.md) and [ulimint_nproc](config/lua/config/ulimit_nproc.md) options. ?3353
* [serial_ports](config/lua/config/serial_ports.md) for more convenient access to serial ports
#### Fixed
* mux: Stale remote window mapping could prevent spawning new tabs in remote domain. #2759

View File

@ -0,0 +1,54 @@
# `serial_ports = {}`
{{since('nightly')}}
Define a list of serial port(s) that you use regularly.
Each entry defines a `SerialDomain` with the following fields:
* `name` - the name to use for the serial domain. Must be unique across
all multiplexer domains in your configuration.
* `port` - the name of the serial device. On Windows systems this can be
a name like `COM0`. On Posix systems this will be a device path something
like `/dev/ttyUSB0`. If omitted, the `name` field be be interpreted as
the port name.
* `baud` - the communication speed to assign to the port. If omitted,
the default baud rate will be 9600.
This configuration defines a single port:
```lua
config.serial_ports = {
{
name = '/dev/tty.usbserial-10',
baud = 115200,
},
}
```
You can then use the port in one of the following ways:
* `wezterm connect /dev/tty.usbserial-10` - this behaves similarly to `wezterm
serial /dev/tty.usbserial-10 --baud 115200`.
* Start wezterm normally, then use the Command Palette or Launcher Menu to
spawn a new tab in the `/dev/tty.usbserial-10` domain to connect to the
serial device
* You can reference the serial domain by its name `/dev/tty.usbserial-10` in
the various tab/window spawning key assignments that include a
[SpawnCommand](../SpawnCommand.md)
You can define multiple ports if you require, and use friendly name for them:
```lua
config.serial_ports = {
{
name = 'Sensor 1',
port = '/dev/tty.usbserial-10',
baud = 115200,
},
{
name = 'Sensor 2',
port = '/dev/tty.usbserial-11',
baud = 115200,
},
}
```

View File

@ -35,6 +35,7 @@ promise = { path = "../promise" }
rangeset = { path = "../rangeset" }
regex = "1"
serde = {version="1.0", features = ["rc", "derive"]}
serial = "0.4"
shell-words = "1.1"
smol = "1.2"
terminfo = "0.8"

View File

@ -13,7 +13,7 @@ use crate::Mux;
use anyhow::{bail, Context, Error};
use async_trait::async_trait;
use config::keyassignment::{SpawnCommand, SpawnTabDomain};
use config::{configuration, ExecDomain, ValueOrFunc, WslDomain};
use config::{configuration, ExecDomain, SerialDomain, ValueOrFunc, WslDomain};
use downcast_rs::{impl_downcast, Downcast};
use parking_lot::Mutex;
use portable_pty::{native_pty_system, CommandBuilder, PtySystem};
@ -229,6 +229,16 @@ impl LocalDomain {
Self::new(&exec_domain.name)
}
pub fn new_serial_domain(serial_domain: SerialDomain) -> anyhow::Result<Self> {
let port = serial_domain.port.as_ref().unwrap_or(&serial_domain.name);
let mut serial = portable_pty::serial::SerialTty::new(&port);
if let Some(baud) = serial_domain.baud {
serial.set_baud_rate(serial::BaudRate::from_speed(baud));
}
let pty_system = Box::new(serial);
Ok(Self::with_pty_system(&serial_domain.name, pty_system))
}
#[cfg(unix)]
fn is_conpty(&self) -> bool {
false

View File

@ -193,7 +193,7 @@ pub struct SerialCommand {
/// On Windows systems this can be a name like `COM0`.
/// On posix systems this will be something like `/dev/ttyUSB0`
#[arg(value_parser)]
pub port: OsString,
pub port: String,
}
#[derive(Debug, Parser, Clone)]

View File

@ -77,7 +77,6 @@ ratelim= { path = "../ratelim" }
regex = "1"
serde = {version="1.0", features = ["rc", "derive"]}
serde_json = "1.0"
serial = "0.4"
shlex = "1.1"
smol = "1.2"
tabout = { path = "../tabout" }

View File

@ -8,7 +8,7 @@ use anyhow::{anyhow, Context};
use clap::builder::ValueParser;
use clap::{Parser, ValueHint};
use config::keyassignment::{SpawnCommand, SpawnTabDomain};
use config::{ConfigHandle, SshDomain, SshMultiplexing};
use config::{ConfigHandle, SerialDomain, SshDomain, SshMultiplexing};
use mux::activity::Activity;
use mux::domain::{Domain, LocalDomain};
use mux::ssh::RemoteSshDomain;
@ -201,13 +201,14 @@ fn run_serial(config: config::ConfigHandle, opts: &SerialCommand) -> anyhow::Res
set_window_position(pos.clone());
}
let mut serial = portable_pty::serial::SerialTty::new(&opts.port);
if let Some(baud) = opts.baud {
serial.set_baud_rate(serial::BaudRate::from_speed(baud));
}
let serial_domain = SerialDomain {
name: "local".into(),
port: Some(opts.port.clone()),
baud: opts.baud,
};
let domain: Arc<dyn Domain> = Arc::new(LocalDomain::new_serial_domain(serial_domain)?);
let pty_system = Box::new(serial);
let domain: Arc<dyn Domain> = Arc::new(LocalDomain::with_pty_system("local", pty_system));
let mux = setup_mux(domain.clone(), &config, Some("local"), None)?;
let gui = crate::frontend::try_new()?;
@ -354,6 +355,15 @@ fn update_mux_domains(config: &ConfigHandle) -> anyhow::Result<()> {
mux.add_domain(&domain);
}
for serial in &config.serial_ports {
if mux.get_domain_by_name(&serial.name).is_some() {
continue;
}
let domain: Arc<dyn Domain> = Arc::new(LocalDomain::new_serial_domain(serial.clone())?);
mux.add_domain(&domain);
}
if let Some(name) = &config.default_domain {
if let Some(dom) = mux.get_domain_by_name(name) {
mux.set_default_domain(&dom);