aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/headless.rs67
-rw-r--r--src/server/notifications.rs2
2 files changed, 65 insertions, 4 deletions
diff --git a/src/server/headless.rs b/src/server/headless.rs
index ed81b015..750e9250 100644
--- a/src/server/headless.rs
+++ b/src/server/headless.rs
@@ -100,7 +100,7 @@ fn non_empty_body(value: &str) -> Option<String> {
enum LoopEvent {
Timer,
Internal(AppEvent),
- Api(api::ApiRequestMessage),
+ Api(Box<api::ApiRequestMessage>),
ServerEvent(ServerEvent),
RenderRequested,
}
@@ -637,7 +637,7 @@ impl HeadlessServer {
let event = {
tokio::select! {
maybe_api = self.app.api_rx.recv() => match maybe_api {
- Some(msg) => LoopEvent::Api(msg),
+ Some(msg) => LoopEvent::Api(Box::new(msg)),
None => LoopEvent::Timer,
},
maybe_ev = self.app.event_rx.recv() => match maybe_ev {
@@ -662,7 +662,7 @@ impl HeadlessServer {
}
}
LoopEvent::Api(msg) => {
- if self.handle_api_request_with_shutdown_check(msg) {
+ if self.handle_api_request_with_shutdown_check(*msg) {
needs_render = true;
needs_full_render = true;
}
@@ -1603,6 +1603,39 @@ impl HeadlessServer {
.unwrap_or_else(|_| "{}".to_string())
}
+ fn handle_client_window_title_api(&mut self, id: String, title: Option<String>) -> String {
+ use api::schema::{ClientWindowTitleReason, ResponseResult};
+
+ let title = match title {
+ Some(title) => match sanitize_window_title_text(&title, 200) {
+ Some(title) => Some(title),
+ None => {
+ return serde_json::to_string(&api::schema::ErrorResponse {
+ id,
+ error: api::schema::ErrorBody {
+ code: "invalid_params".into(),
+ message: "window title is empty".into(),
+ },
+ })
+ .unwrap_or_else(|_| "{}".to_string());
+ }
+ },
+ None => None,
+ };
+ let set_title = title.is_some();
+ let changed = self.send_to_foreground_client(ServerMessage::WindowTitle { title });
+ let reason = match (changed, set_title) {
+ (true, true) => ClientWindowTitleReason::Set,
+ (true, false) => ClientWindowTitleReason::Cleared,
+ (false, _) => ClientWindowTitleReason::NoForegroundClient,
+ };
+ serde_json::to_string(&api::schema::SuccessResponse {
+ id,
+ result: ResponseResult::ClientWindowTitle { changed, reason },
+ })
+ .unwrap_or_else(|_| "{}".to_string())
+ }
+
fn forward_api_notification_sound(&mut self, sound: api::schema::NotificationShowSound) {
let Some(sound) = sound.to_sound() else {
return;
@@ -2511,6 +2544,23 @@ impl HeadlessServer {
return true;
}
+ match &msg.request.method {
+ api::schema::Method::ClientWindowTitleSet(params) => {
+ let response = self.handle_client_window_title_api(
+ msg.request.id.clone(),
+ Some(params.title.clone()),
+ );
+ let _ = msg.respond_to.send(response);
+ return true;
+ }
+ api::schema::Method::ClientWindowTitleClear(_) => {
+ let response = self.handle_client_window_title_api(msg.request.id.clone(), None);
+ let _ = msg.respond_to.send(response);
+ return true;
+ }
+ _ => {}
+ }
+
let mut changed = api::request_changes_ui(&msg.request);
let skip_default_workspace = matches!(
&msg.request.method,
@@ -3544,6 +3594,17 @@ fn sanitize_notification_text(value: &str, max_chars: usize) -> Option<String> {
(!sanitized.is_empty()).then_some(sanitized)
}
+fn sanitize_window_title_text(value: &str, max_chars: usize) -> Option<String> {
+ let sanitized = value
+ .chars()
+ .filter(|ch| !matches!(*ch, '\u{1b}' | '\u{7}' | '\u{9c}') && !ch.is_control())
+ .take(max_chars)
+ .collect::<String>()
+ .trim()
+ .to_string();
+ (!sanitized.is_empty()).then_some(sanitized)
+}
+
fn server_config_diagnostic_summaries(diagnostics: &[String]) -> (Option<String>, Option<String>) {
let without_keybindings = diagnostics
.iter()
diff --git a/src/server/notifications.rs b/src/server/notifications.rs
index 63bfe944..79ff63ca 100644
--- a/src/server/notifications.rs
+++ b/src/server/notifications.rs
@@ -121,10 +121,10 @@ mod tests {
0,
crate::terminal_theme::TerminalTheme::default(),
crate::pane::PaneShellConfig::new("/bin/sh", crate::config::ShellModeConfig::NonLogin),
+ &crate::pane::PaneLaunchEnv::default(),
events,
std::sync::Arc::new(tokio::sync::Notify::new()),
std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
- None,
)
.unwrap();
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2);