parent
ac9dac0263
commit
58bcd76bfd
|
|
@ -5,6 +5,7 @@
|
|||
### Added
|
||||
- Added a session navigator at `prefix+g` with a searchable workspace/tab/pane tree, agent state filters, mouse switching, and keyboard navigation. (#157)
|
||||
- Added scrollback support to direct agent terminal attaches. Mouse wheel and plain PageUp/PageDown now scroll the attached terminal viewport, while terminal apps that request mouse or alternate-scroll input still receive those events. The client/server protocol is now version 11.
|
||||
- Added `ui.redraw_on_focus_gained` to keep the existing full redraw on outer-terminal focus gain by default while allowing users to opt out of the visible refresh. (#282)
|
||||
|
||||
## [0.6.2] - 2026-05-23
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ sidebar_width = 32
|
|||
sidebar_min_width = 18
|
||||
sidebar_max_width = 36
|
||||
mouse_capture = true
|
||||
redraw_on_focus_gained = true
|
||||
mouse_scroll_lines = 3
|
||||
confirm_close = true
|
||||
prompt_new_tab_name = true
|
||||
|
|
@ -238,6 +239,8 @@ accent = "cyan"
|
|||
|
||||
Set `mouse_capture = false` if you want your terminal to handle normal clicks, such as command-clicking URLs.
|
||||
|
||||
Set `redraw_on_focus_gained = false` to avoid the visible full-screen refresh when switching back to Herdr. The default is `true` because a full redraw recovers from rare stale or dirty host terminal surfaces.
|
||||
|
||||
Set `mouse_scroll_lines` to change how many pane scrollback lines each mouse wheel notch scrolls. The default is 3. Pane apps that request mouse reporting still receive wheel events directly.
|
||||
|
||||
Set `show_agent_labels_on_pane_borders = true` if you want detected agent labels in split pane borders when no manual pane label is set.
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ impl App {
|
|||
request_submit_worktree_open: false,
|
||||
request_submit_worktree_remove: false,
|
||||
request_reload_config: false,
|
||||
request_client_sound_config_reload: false,
|
||||
request_client_config_reload: false,
|
||||
request_clipboard_write: None,
|
||||
creating_new_tab: false,
|
||||
requested_new_tab_name: None,
|
||||
|
|
@ -458,6 +458,7 @@ impl App {
|
|||
sidebar_section_split,
|
||||
agent_panel_scope,
|
||||
mouse_capture: config.ui.mouse_capture,
|
||||
redraw_on_focus_gained: config.ui.redraw_on_focus_gained,
|
||||
mouse_scroll_lines: config.ui.mouse_scroll_lines(),
|
||||
confirm_close: config.ui.confirm_close,
|
||||
prompt_new_tab_name: config.ui.prompt_new_tab_name,
|
||||
|
|
@ -1055,6 +1056,10 @@ impl App {
|
|||
.sidebar_width
|
||||
.clamp(self.state.sidebar_min_width, self.state.sidebar_max_width);
|
||||
self.state.mouse_capture = config.ui.mouse_capture;
|
||||
if self.state.redraw_on_focus_gained != config.ui.redraw_on_focus_gained {
|
||||
self.state.request_client_config_reload = true;
|
||||
}
|
||||
self.state.redraw_on_focus_gained = config.ui.redraw_on_focus_gained;
|
||||
self.state.mouse_scroll_lines = config.ui.mouse_scroll_lines();
|
||||
self.state.confirm_close = config.ui.confirm_close;
|
||||
self.state.prompt_new_tab_name = config.ui.prompt_new_tab_name;
|
||||
|
|
@ -1065,7 +1070,7 @@ impl App {
|
|||
self.state.agent_panel_scroll = 0;
|
||||
self.state.accent = crate::config::parse_color(&config.ui.accent);
|
||||
if !self.state.local_sound_playback && self.state.sound != config.ui.sound {
|
||||
self.state.request_client_sound_config_reload = true;
|
||||
self.state.request_client_config_reload = true;
|
||||
}
|
||||
self.state.sound = config.ui.sound.clone();
|
||||
self.state.toast_config = config.ui.toast.clone();
|
||||
|
|
@ -1500,6 +1505,17 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_uses_redraw_on_focus_gained_config() {
|
||||
let mut config = Config::default();
|
||||
config.ui.redraw_on_focus_gained = false;
|
||||
let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
|
||||
let app = App::new(&config, true, None, api_rx, crate::api::EventHub::default());
|
||||
|
||||
assert!(!app.state.redraw_on_focus_gained);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_restores_preview_update_available_from_saved_notes() {
|
||||
let _guard = config_env_lock().lock().unwrap();
|
||||
|
|
@ -1610,7 +1626,7 @@ mod tests {
|
|||
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
|
||||
std::fs::write(
|
||||
&path,
|
||||
"[terminal]\ndefault_shell = \"nu\"\nnew_cwd = \"home\"\n[keys]\nnew_workspace = \"prefix+m\"\nprefix = \"ctrl+a\"\n[ui]\nagent_panel_scope = \"current\"\n[ui.toast]\ndelivery = \"herdr\"\n",
|
||||
"[terminal]\ndefault_shell = \"nu\"\nnew_cwd = \"home\"\n[keys]\nnew_workspace = \"prefix+m\"\nprefix = \"ctrl+a\"\n[ui]\nagent_panel_scope = \"current\"\nredraw_on_focus_gained = false\n[ui.toast]\ndelivery = \"herdr\"\n",
|
||||
)
|
||||
.unwrap();
|
||||
std::env::set_var(crate::config::CONFIG_PATH_ENV_VAR, &path);
|
||||
|
|
@ -1634,6 +1650,8 @@ mod tests {
|
|||
app.state.agent_panel_scope,
|
||||
state::AgentPanelScope::CurrentWorkspace
|
||||
);
|
||||
assert!(!app.state.redraw_on_focus_gained);
|
||||
assert!(app.state.request_client_config_reload);
|
||||
assert_eq!(app.state.default_shell, "nu");
|
||||
assert_eq!(
|
||||
app.state.new_terminal_cwd,
|
||||
|
|
@ -2073,6 +2091,20 @@ mod tests {
|
|||
assert!(!app.state.workspaces[0].tabs[background_tab].panes[&background_pane].seen);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn outer_focus_gained_does_not_require_full_redraw_when_disabled() {
|
||||
let mut app = test_app();
|
||||
app.state.redraw_on_focus_gained = false;
|
||||
|
||||
let handled = app
|
||||
.handle_raw_input_event(crate::raw_input::RawInputEvent::OuterFocusGained)
|
||||
.await;
|
||||
|
||||
assert!(handled);
|
||||
assert_eq!(app.state.outer_terminal_focus, Some(true));
|
||||
assert!(!app.full_redraw_pending);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn repeat_key_events_are_ignored_outside_terminal_mode() {
|
||||
let mut app = test_app();
|
||||
|
|
|
|||
|
|
@ -106,7 +106,9 @@ impl App {
|
|||
true
|
||||
}
|
||||
crate::raw_input::RawInputEvent::OuterFocusGained => {
|
||||
self.request_full_redraw();
|
||||
if self.state.redraw_on_focus_gained {
|
||||
self.request_full_redraw();
|
||||
}
|
||||
self.state.outer_terminal_focus = Some(true);
|
||||
self.state.mark_active_tab_seen();
|
||||
true
|
||||
|
|
|
|||
|
|
@ -1057,7 +1057,7 @@ pub struct AppState {
|
|||
pub request_reload_config: bool,
|
||||
/// Set when the headless server should ask attached clients to reload
|
||||
/// their client-local sound config from disk.
|
||||
pub request_client_sound_config_reload: bool,
|
||||
pub request_client_config_reload: bool,
|
||||
/// Set when UI interaction requested a clipboard write that must be
|
||||
/// handled by the outer App/event loop instead of directly from AppState.
|
||||
pub request_clipboard_write: Option<Vec<u8>>,
|
||||
|
|
@ -1115,6 +1115,7 @@ pub struct AppState {
|
|||
/// Capture mouse input for Herdr's own mouse UI. When false, Herdr only
|
||||
/// captures mouse while the focused pane app requests mouse reporting.
|
||||
pub mouse_capture: bool,
|
||||
pub redraw_on_focus_gained: bool,
|
||||
pub mouse_scroll_lines: usize,
|
||||
pub confirm_close: bool,
|
||||
pub prompt_new_tab_name: bool,
|
||||
|
|
@ -1351,7 +1352,7 @@ impl AppState {
|
|||
request_submit_worktree_open: false,
|
||||
request_submit_worktree_remove: false,
|
||||
request_reload_config: false,
|
||||
request_client_sound_config_reload: false,
|
||||
request_client_config_reload: false,
|
||||
request_clipboard_write: None,
|
||||
creating_new_tab: false,
|
||||
requested_new_tab_name: None,
|
||||
|
|
@ -1414,6 +1415,7 @@ impl AppState {
|
|||
sidebar_section_split: 0.5,
|
||||
agent_panel_scope: AgentPanelScope::AllWorkspaces,
|
||||
mouse_capture: true,
|
||||
redraw_on_focus_gained: true,
|
||||
mouse_scroll_lines: crate::config::DEFAULT_MOUSE_SCROLL_LINES,
|
||||
confirm_close: true,
|
||||
prompt_new_tab_name: true,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ struct ClientState {
|
|||
attach_escape: Option<AttachEscapeState>,
|
||||
/// Rows scrolled for one direct-attach wheel notch.
|
||||
mouse_scroll_lines: usize,
|
||||
/// Whether outer focus gain should force a full host-terminal redraw.
|
||||
redraw_on_focus_gained: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -514,6 +516,7 @@ fn run_client_with_mode(
|
|||
|
||||
let loaded_config = crate::config::Config::load();
|
||||
let mouse_scroll_lines = loaded_config.config.ui.mouse_scroll_lines();
|
||||
let redraw_on_focus_gained = loaded_config.config.ui.redraw_on_focus_gained;
|
||||
let sound_config = loaded_config.config.ui.sound;
|
||||
let direct_attach_requested = attach_request.is_some();
|
||||
let kitty_graphics_enabled =
|
||||
|
|
@ -608,6 +611,7 @@ fn run_client_with_mode(
|
|||
should_quit,
|
||||
sound_config,
|
||||
mouse_scroll_lines,
|
||||
redraw_on_focus_gained,
|
||||
kitty_graphics_enabled,
|
||||
false,
|
||||
negotiated_encoding,
|
||||
|
|
@ -655,6 +659,7 @@ async fn run_client_loop(
|
|||
should_quit: Arc<AtomicBool>,
|
||||
sound_config: crate::config::SoundConfig,
|
||||
mouse_scroll_lines: usize,
|
||||
redraw_on_focus_gained: bool,
|
||||
kitty_graphics_enabled: bool,
|
||||
mouse_capture_active: bool,
|
||||
negotiated_encoding: RenderEncoding,
|
||||
|
|
@ -668,6 +673,7 @@ async fn run_client_loop(
|
|||
kitty_graphics_enabled,
|
||||
attach_escape,
|
||||
mouse_scroll_lines,
|
||||
redraw_on_focus_gained,
|
||||
};
|
||||
debug!(?negotiated_encoding, "client render encoding active");
|
||||
|
||||
|
|
@ -763,7 +769,10 @@ async fn run_client_loop(
|
|||
}
|
||||
} else {
|
||||
let events = crate::raw_input::parse_raw_input_bytes_sync(&data);
|
||||
if crate::raw_input::events_require_host_surface_redraw(&events) {
|
||||
if crate::raw_input::events_require_host_surface_redraw(
|
||||
&events,
|
||||
state.redraw_on_focus_gained,
|
||||
) {
|
||||
state.request_full_redraw();
|
||||
}
|
||||
data
|
||||
|
|
@ -854,7 +863,10 @@ async fn run_client_loop(
|
|||
let _ = io::stdout().flush();
|
||||
}
|
||||
ServerMessage::ReloadSoundConfig => {
|
||||
reload_local_sound_config(&mut state.sound_config);
|
||||
reload_local_client_config(
|
||||
&mut state.sound_config,
|
||||
&mut state.redraw_on_focus_gained,
|
||||
);
|
||||
}
|
||||
ServerMessage::MouseCapture { enabled } => {
|
||||
let desired = enabled;
|
||||
|
|
@ -955,17 +967,21 @@ fn write_to_server(stream: &mut UnixStream, msg: &ClientMessage) -> io::Result<(
|
|||
// Notifications
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn reload_local_sound_config(sound_config: &mut crate::config::SoundConfig) {
|
||||
fn reload_local_client_config(
|
||||
sound_config: &mut crate::config::SoundConfig,
|
||||
redraw_on_focus_gained: &mut bool,
|
||||
) {
|
||||
match crate::config::load_live_config() {
|
||||
Ok(loaded) => {
|
||||
for diagnostic in loaded.config.ui.sound.diagnostics() {
|
||||
warn!(diagnostic = %diagnostic, "local sound config diagnostic");
|
||||
}
|
||||
*sound_config = loaded.config.ui.sound;
|
||||
debug!("reloaded local sound config");
|
||||
*redraw_on_focus_gained = loaded.config.ui.redraw_on_focus_gained;
|
||||
debug!("reloaded local client config");
|
||||
}
|
||||
Err(diagnostics) => {
|
||||
warn!(diagnostics = ?diagnostics, "failed to reload local sound config; keeping current sound config");
|
||||
warn!(diagnostics = ?diagnostics, "failed to reload local client config; keeping current client config");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1631,6 +1647,29 @@ mod tests {
|
|||
assert_eq!(sound_from_notify_message("toast"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reload_local_client_config_refreshes_redraw_on_focus_gained() {
|
||||
let _guard = crate::config::test_config_env_lock().lock().unwrap();
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
"herdr-client-config-reload-{}-{}.toml",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos()
|
||||
));
|
||||
std::fs::write(&path, "[ui]\nredraw_on_focus_gained = false\n").unwrap();
|
||||
let path_string = path.to_string_lossy().to_string();
|
||||
let _env = EnvVarGuard::set(crate::config::CONFIG_PATH_ENV_VAR, &path_string);
|
||||
let mut sound_config = crate::config::SoundConfig::default();
|
||||
let mut redraw_on_focus_gained = true;
|
||||
|
||||
reload_local_client_config(&mut sound_config, &mut redraw_on_focus_gained);
|
||||
|
||||
assert!(!redraw_on_focus_gained);
|
||||
let _ = std::fs::remove_file(path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn toast_notify_from_server_is_emitted_even_when_attach_config_was_off() {
|
||||
let sound_config = crate::config::SoundConfig::default();
|
||||
|
|
|
|||
|
|
@ -259,6 +259,8 @@ pub struct UiConfig {
|
|||
pub sidebar_max_width: u16,
|
||||
/// Capture mouse input for Herdr's mouse UI. Default: true.
|
||||
pub mouse_capture: bool,
|
||||
/// Force a full host-terminal redraw when the outer terminal regains focus. Default: true.
|
||||
pub redraw_on_focus_gained: bool,
|
||||
/// Lines to scroll per mouse wheel notch. Default: 3.
|
||||
pub mouse_scroll_lines: Option<NonZeroUsize>,
|
||||
/// Ask for confirmation before closing a workspace. Default: true.
|
||||
|
|
@ -416,6 +418,7 @@ impl Default for UiConfig {
|
|||
sidebar_min_width: 18,
|
||||
sidebar_max_width: 36,
|
||||
mouse_capture: true,
|
||||
redraw_on_focus_gained: true,
|
||||
mouse_scroll_lines: None,
|
||||
confirm_close: true,
|
||||
prompt_new_tab_name: true,
|
||||
|
|
@ -669,6 +672,19 @@ mouse_capture = false
|
|||
assert!(!config.ui.mouse_capture);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redraw_on_focus_gained_default_on_and_parse() {
|
||||
let default_config = Config::default();
|
||||
assert!(default_config.ui.redraw_on_focus_gained);
|
||||
|
||||
let toml = r#"
|
||||
[ui]
|
||||
redraw_on_focus_gained = false
|
||||
"#;
|
||||
let config: Config = toml::from_str(toml).unwrap();
|
||||
assert!(!config.ui.redraw_on_focus_gained);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mouse_scroll_lines_defaults_to_three_and_parses() {
|
||||
let default_config = Config::default();
|
||||
|
|
|
|||
|
|
@ -182,6 +182,11 @@ const DEFAULT_CONFIG: &str = r##"# herdr configuration
|
|||
# Pane apps like lazygit and btop can still receive mouse when they request it.
|
||||
# mouse_capture = true
|
||||
|
||||
# Force a full redraw when the outer terminal regains focus.
|
||||
# Set false to reduce visible flashing when switching back to Herdr.
|
||||
# Trade-off: rare host terminal surface corruption may persist until the next full redraw.
|
||||
# redraw_on_focus_gained = true
|
||||
|
||||
# Pane scrollback lines to scroll per mouse wheel notch.
|
||||
# mouse_scroll_lines = 3
|
||||
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ pub enum ServerMessage {
|
|||
data: String,
|
||||
},
|
||||
|
||||
/// Client-local sound config changed on disk; refresh it without reconnecting.
|
||||
/// Client-local runtime config changed on disk; refresh it without reconnecting.
|
||||
ReloadSoundConfig,
|
||||
|
||||
/// Whether the client should currently capture host mouse input.
|
||||
|
|
|
|||
|
|
@ -128,10 +128,14 @@ pub enum RawInputEvent {
|
|||
Unsupported,
|
||||
}
|
||||
|
||||
pub(crate) fn events_require_host_surface_redraw(events: &[RawInputEvent]) -> bool {
|
||||
events
|
||||
.iter()
|
||||
.any(|event| matches!(event, RawInputEvent::OuterFocusGained))
|
||||
pub(crate) fn events_require_host_surface_redraw(
|
||||
events: &[RawInputEvent],
|
||||
redraw_on_focus_gained: bool,
|
||||
) -> bool {
|
||||
redraw_on_focus_gained
|
||||
&& events
|
||||
.iter()
|
||||
.any(|event| matches!(event, RawInputEvent::OuterFocusGained))
|
||||
}
|
||||
|
||||
pub fn spawn_input_reader() -> mpsc::Receiver<RawInputEvent> {
|
||||
|
|
@ -667,10 +671,11 @@ mod tests {
|
|||
#[test]
|
||||
fn outer_focus_gained_requests_host_surface_redraw() {
|
||||
let events = parse_raw_input_bytes_sync(b"\x1b[I");
|
||||
assert!(events_require_host_surface_redraw(&events));
|
||||
assert!(events_require_host_surface_redraw(&events, true));
|
||||
assert!(!events_require_host_surface_redraw(&events, false));
|
||||
|
||||
let events = parse_raw_input_bytes_sync(b"\x1b[O");
|
||||
assert!(!events_require_host_surface_redraw(&events));
|
||||
assert!(!events_require_host_surface_redraw(&events, true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ impl HeadlessServer {
|
|||
needs_render = true;
|
||||
}
|
||||
|
||||
self.drain_client_sound_config_reload_request();
|
||||
self.drain_client_config_reload_request();
|
||||
self.stream_host_mouse_capture_mode();
|
||||
|
||||
self.app.sync_headless_animation_timer(now);
|
||||
|
|
@ -1423,11 +1423,11 @@ impl HeadlessServer {
|
|||
(had_event, changed)
|
||||
}
|
||||
|
||||
fn drain_client_sound_config_reload_request(&mut self) {
|
||||
if !self.app.state.request_client_sound_config_reload {
|
||||
fn drain_client_config_reload_request(&mut self) {
|
||||
if !self.app.state.request_client_config_reload {
|
||||
return;
|
||||
}
|
||||
self.app.state.request_client_sound_config_reload = false;
|
||||
self.app.state.request_client_config_reload = false;
|
||||
self.send_to_all_clients(ServerMessage::ReloadSoundConfig);
|
||||
}
|
||||
|
||||
|
|
@ -1726,8 +1726,10 @@ impl HeadlessServer {
|
|||
return true;
|
||||
}
|
||||
let events = crate::raw_input::parse_raw_input_bytes_sync(&data);
|
||||
let host_surface_redraw =
|
||||
crate::raw_input::events_require_host_surface_redraw(&events);
|
||||
let host_surface_redraw = crate::raw_input::events_require_host_surface_redraw(
|
||||
&events,
|
||||
self.app.state.redraw_on_focus_gained,
|
||||
);
|
||||
if let Some(client) = self.clients.get_mut(&client_id) {
|
||||
if host_surface_redraw {
|
||||
client.request_full_redraw();
|
||||
|
|
@ -4286,6 +4288,52 @@ next_tab = ""
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn outer_focus_gained_does_not_force_terminal_ansi_full_redraw_when_disabled() {
|
||||
let mut server = test_headless_server();
|
||||
server.app.state.redraw_on_focus_gained = false;
|
||||
let (client_tx, _client_control_rx, client_rx) = test_client_writer();
|
||||
|
||||
server.clients.insert(
|
||||
1,
|
||||
ClientConnection::new(
|
||||
(80, 24),
|
||||
crate::kitty_graphics::HostCellSize::default(),
|
||||
crate::terminal_theme::TerminalTheme::default(),
|
||||
None,
|
||||
1,
|
||||
RenderEncoding::TerminalAnsi,
|
||||
Some(client_tx),
|
||||
),
|
||||
);
|
||||
server.foreground_client_id = Some(1);
|
||||
|
||||
server.render_and_stream();
|
||||
let _ = client_rx
|
||||
.recv_timeout(Duration::from_millis(100))
|
||||
.expect("initial terminal frame");
|
||||
|
||||
server.handle_server_event(ServerEvent::ClientInput {
|
||||
client_id: 1,
|
||||
data: b"\x1b[I".to_vec(),
|
||||
});
|
||||
server.render_and_stream();
|
||||
|
||||
assert!(client_rx.recv_timeout(Duration::from_millis(50)).is_err());
|
||||
assert_eq!(server.clients[&1].outer_terminal_focus, Some(true));
|
||||
assert_eq!(server.app.state.outer_terminal_focus, Some(true));
|
||||
assert_eq!(
|
||||
server
|
||||
.clients
|
||||
.get(&1)
|
||||
.unwrap()
|
||||
.render_state
|
||||
.terminal_seq()
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_render_queue_does_not_advance_terminal_ansi_baseline() {
|
||||
let mut server = test_headless_server();
|
||||
|
|
@ -4420,7 +4468,7 @@ next_tab = ""
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn client_sound_reload_request_refreshes_attached_clients() {
|
||||
fn client_config_reload_request_refreshes_attached_clients() {
|
||||
let mut server = test_headless_server();
|
||||
let (client_tx, client_control_rx, _client_rx) = test_client_writer();
|
||||
|
||||
|
|
@ -4436,19 +4484,19 @@ next_tab = ""
|
|||
Some(client_tx),
|
||||
),
|
||||
);
|
||||
server.app.state.request_client_sound_config_reload = true;
|
||||
server.app.state.request_client_config_reload = true;
|
||||
|
||||
server.drain_client_sound_config_reload_request();
|
||||
server.drain_client_config_reload_request();
|
||||
|
||||
match read_server_message(
|
||||
client_control_rx
|
||||
.recv_timeout(Duration::from_millis(100))
|
||||
.expect("client sound reload message"),
|
||||
.expect("client config reload message"),
|
||||
) {
|
||||
ServerMessage::ReloadSoundConfig => {}
|
||||
other => panic!("expected ReloadSoundConfig, got {other:?}"),
|
||||
}
|
||||
assert!(!server.app.state.request_client_sound_config_reload);
|
||||
assert!(!server.app.state.request_client_config_reload);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in New Issue