Load local sessions in the background for the Sessions popup

command_choose ran `herdr session list --json` (up to its 5 s timeout)
before the popup drew anything, contradicting the documented immediate
display. Run the listing on a worker thread and hand the selector a
Future: the popup appears at once with a "… 本机 正在查询" placeholder,
then fills in the local rows and any discovery warning when the result
arrives, mirroring how remote hosts already load.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 03:03:09 +00:00
co-authored by Claude Fable 5.1
parent 907813867a
commit 435ba91d1e
3 changed files with 98 additions and 3 deletions
+16 -3
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import argparse
from concurrent.futures import ThreadPoolExecutor
from contextlib import contextmanager
import curses
from dataclasses import dataclass, field, replace
@@ -1389,13 +1390,19 @@ def command_open(arguments: argparse.Namespace) -> int:
return 0
def local_session_listing(herdr_bin: str) -> tuple[list[str], list[str]]:
"""Background half of the Sessions popup: names and warnings only."""
report = discover_local_sessions(herdr_bin)
return [endpoint.session for endpoint in report.endpoints], report.warnings
def command_choose(arguments: argparse.Namespace) -> int:
startup_warnings: list[str] = []
hub = make_hub(arguments, warnings=startup_warnings)
if not hub.exists():
raise HubError("herdr-hub is not running")
windows = hub.managed_windows()
local_report = discover_local_sessions(resolve_herdr())
herdr_bin = resolve_herdr()
registry_warning = remember_remote_endpoints(
window.endpoint for window in windows if window.endpoint is not None
)
@@ -1403,6 +1410,11 @@ def command_choose(arguments: argparse.Namespace) -> int:
alias_registry = make_alias_registry()
remote_registry = make_registry()
ssh_bin = resolve_ssh()
# `herdr session list` can take seconds; the popup must not wait for it.
local_executor = ThreadPoolExecutor(
max_workers=1, thread_name_prefix="herdr-hub-local"
)
local_future = local_executor.submit(local_session_listing, herdr_bin)
def close_window(window_id: str) -> list[CatalogWindow]:
hub.dismiss_window(window_id)
@@ -1519,15 +1531,14 @@ def command_choose(arguments: argparse.Namespace) -> int:
catalog_windows(windows),
remote_registry,
ssh_bin,
local_sessions=(endpoint.session for endpoint in local_report.endpoints),
aliases=hub.aliases,
activate_handler=activate_selection,
rename_handler=rename_session,
close_window_handler=close_window,
delete_session_handler=delete_session,
stop_session_handler=stop_session,
pending_local_sessions=local_future,
)
startup_warnings.extend(local_report.warnings)
if registry_warning:
startup_warnings.append(registry_warning)
if startup_warnings:
@@ -1535,6 +1546,8 @@ def command_choose(arguments: argparse.Namespace) -> int:
result = selector.run()
except (RegistryError, SelectorError) as error:
raise HubError(str(error)) from error
finally:
local_executor.shutdown(wait=False, cancel_futures=True)
if result is None:
return 0
if result.kind == "rename":