aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/ipc.rs
diff options
context:
space:
mode:
authorKirill Chibisov <contact@kchibisov.com>2021-11-22 21:34:09 +0300
committerGitHub <noreply@github.com>2021-11-22 18:34:09 +0000
commit8681f71084894db6d1e258be17db1f80bb669314 (patch)
tree24d3c0ced916d2d171fd03f50cd34dcda8f0aa06 /alacritty/src/ipc.rs
parentc89939b5d14e581e1aeaa940d81843192e0abc79 (diff)
downloadr-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.rs69
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);