diff options
author | Kirill Chibisov <contact@kchibisov.com> | 2021-11-22 21:34:09 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-22 18:34:09 +0000 |
commit | 8681f71084894db6d1e258be17db1f80bb669314 (patch) | |
tree | 24d3c0ced916d2d171fd03f50cd34dcda8f0aa06 /alacritty/src/ipc.rs | |
parent | c89939b5d14e581e1aeaa940d81843192e0abc79 (diff) | |
download | r-alacritty-8681f71084894db6d1e258be17db1f80bb669314.tar.gz r-alacritty-8681f71084894db6d1e258be17db1f80bb669314.tar.bz2 r-alacritty-8681f71084894db6d1e258be17db1f80bb669314.zip |
Add parameters to `msg create-window` subcommand
Alacritty's `msg create-window` subcommand would previously inherit all
the CLI parameters from the original executable. However not only could
this lead to unexpected behavior, it also prevents multi-window users
from making use of parameters like `-e`, `--working-directory`, or
`--hold`.
This is solved by adding a JSON-based message format to the IPC socket
messages which instructs the Alacritty server on which CLI parameters
should be used to create the new window.
Fixes #5562.
Fixes #5561.
Fixes #5560.
Diffstat (limited to 'alacritty/src/ipc.rs')
-rw-r--r-- | alacritty/src/ipc.rs | 69 |
1 files changed, 43 insertions, 26 deletions
diff --git a/alacritty/src/ipc.rs b/alacritty/src/ipc.rs index 02aaf85f..6f02e757 100644 --- a/alacritty/src/ipc.rs +++ b/alacritty/src/ipc.rs @@ -1,8 +1,8 @@ //! Alacritty socket IPC. use std::ffi::OsStr; -use std::io::{Error as IoError, ErrorKind, Result as IoResult}; -use std::os::unix::net::UnixDatagram; +use std::io::{BufRead, BufReader, Error as IoError, ErrorKind, Result as IoResult, Write}; +use std::os::unix::net::{UnixListener, UnixStream}; use std::path::PathBuf; use std::{env, fs, process}; @@ -11,12 +11,9 @@ use log::warn; use alacritty_terminal::thread; -use crate::cli::Options; +use crate::cli::{Options, SocketMessage}; use crate::event::{Event, EventType}; -/// IPC socket message for creating a new window. -pub const SOCKET_MESSAGE_CREATE_WINDOW: [u8; 1] = [1]; - /// Environment variable name for the IPC socket path. const ALACRITTY_SOCKET_ENV: &str = "ALACRITTY_SOCKET"; @@ -30,8 +27,8 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) - }); env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str()); - let socket = match UnixDatagram::bind(&socket_path) { - Ok(socket) => socket, + let listener = match UnixListener::bind(&socket_path) { + Ok(listener) => listener, Err(err) => { warn!("Unable to create socket: {:?}", err); return None; @@ -40,13 +37,31 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) - // Spawn a thread to listen on the IPC socket. thread::spawn_named("socket listener", move || { - // Accept up to 2 bytes to ensure only one byte is received. - // This ensures forward-compatibility. - let mut buf = [0; 2]; - - while let Ok(received) = socket.recv(&mut buf) { - if buf[..received] == SOCKET_MESSAGE_CREATE_WINDOW { - let _ = event_proxy.send_event(Event::new(EventType::CreateWindow, None)); + let mut data = String::new(); + for stream in listener.incoming().filter_map(Result::ok) { + data.clear(); + let mut stream = BufReader::new(stream); + + match stream.read_line(&mut data) { + Ok(0) | Err(_) => continue, + Ok(_) => (), + }; + + // Read pending events on socket. + let message: SocketMessage = match serde_json::from_str(&data) { + Ok(message) => message, + Err(err) => { + warn!("Failed to convert data from socket: {}", err); + continue; + }, + }; + + // Handle IPC events. + match message { + SocketMessage::CreateWindow(terminal_options) => { + let event = Event::new(EventType::CreateWindow(Some(terminal_options)), None); + let _ = event_proxy.send_event(event); + }, } } }); @@ -55,9 +70,13 @@ pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) - } /// Send a message to the active Alacritty socket. -pub fn send_message(socket: Option<PathBuf>, message: &[u8]) -> IoResult<()> { - let socket = find_socket(socket)?; - socket.send(message)?; +pub fn send_message(socket: Option<PathBuf>, message: SocketMessage) -> IoResult<()> { + let mut socket = find_socket(socket)?; + + let message = serde_json::to_string(&message)?; + socket.write_all(message[..].as_bytes())?; + let _ = socket.flush(); + Ok(()) } @@ -78,22 +97,20 @@ fn socket_dir() -> PathBuf { } /// Find the IPC socket path. -fn find_socket(socket_path: Option<PathBuf>) -> IoResult<UnixDatagram> { - let socket = UnixDatagram::unbound()?; - +fn find_socket(socket_path: Option<PathBuf>) -> IoResult<UnixStream> { // Handle --socket CLI override. if let Some(socket_path) = socket_path { // Ensure we inform the user about an invalid path. - socket.connect(&socket_path).map_err(|err| { + return UnixStream::connect(&socket_path).map_err(|err| { let message = format!("invalid socket path {:?}", socket_path); IoError::new(err.kind(), message) - })?; + }); } // Handle environment variable. if let Ok(path) = env::var(ALACRITTY_SOCKET_ENV) { let socket_path = PathBuf::from(path); - if socket.connect(&socket_path).is_ok() { + if let Ok(socket) = UnixStream::connect(&socket_path) { return Ok(socket); } } @@ -114,8 +131,8 @@ fn find_socket(socket_path: Option<PathBuf>) -> IoResult<UnixDatagram> { } // Attempt to connect to the socket. - match socket.connect(&path) { - Ok(_) => return Ok(socket), + match UnixStream::connect(&path) { + Ok(socket) => return Ok(socket), // Delete orphan sockets. Err(error) if error.kind() == ErrorKind::ConnectionRefused => { let _ = fs::remove_file(&path); |