Skip to main content

lattice_lsp/
show_message_request.rs

1//! Server-initiated `window/showMessageRequest` plumbing
2//! (4.4.b; BC.8e reshape).
3//!
4//! Spec (LSP §3.16): the server emits a message at a severity
5//! level (`Error` / `Warning` / `Info` / `Log`) accompanied by a
6//! list of `MessageActionItem` action labels. The client
7//! displays a modal picker; the user selects one (or dismisses);
8//! the client replies with the selected `MessageActionItem`, or
9//! `null` if the user dismissed without choosing.
10//!
11//! The user-side action set is server-defined -- e.g.
12//! rust-analyzer: `[{ "title": "Reload Workspace" }]` after a
13//! `Cargo.toml` edit. Picker UI uses the existing modal picker
14//! infrastructure (P.1+) but with a synthetic source built from
15//! the action list.
16//!
17//! **BC.8e (2026-06-24): reshaped onto the generic inbound primitive
18//! (host-drained variant).** `ShowMessageRequestBus` is now a type alias for the
19//! generic [`InboundBus`](lattice_mode::inbound::InboundBus) built via
20//! [`make_inbound_raw`](lattice_mode::inbound::make_inbound_raw): its `send`
21//! **wakes the editor**, so a server-initiated request raises the picker
22//! off-keystroke (was: no wake — it only appeared on the next keypress). Like
23//! apply-edit (BC.8d), this is the *host-drained* variant: the request is a
24//! **deferred user choice** routed through the host picker primitive (the host
25//! `drain_inbound_show_message_requests` registers the request — holding the
26//! oneshot in `lsp_pending_show_message_requests` — opens the picker, and
27//! resolves the oneshot from the accept / dismiss routing). That machinery is
28//! irreducibly `&mut Editor` + the host picker, so the host keeps the receiver
29//! (`Editor::pending_show_message_request_rx`) and the drain; the bus
30//! contributes only the structural wake. No mode-owned handler, no `Effect`.
31
32use std::sync::Arc;
33
34use tokio::sync::oneshot;
35
36/// The bus the supervisor fans out to each actor -- the generic inbound
37/// primitive specialised to the show-message-request payload, built
38/// host-drained via [`make_inbound_raw`](lattice_mode::inbound::make_inbound_raw).
39/// `send` wakes the editor; the host owns the matching receiver and drains it.
40/// (Was the bespoke `ShowMessageRequestBus` struct before BC.8e.)
41pub type ShowMessageRequestBus = lattice_mode::inbound::InboundBus<InboundShowMessageRequest>;
42
43/// One server-initiated `window/showMessageRequest` request,
44/// ferried from the LSP actor to the host's drain.
45#[derive(Debug)]
46pub struct InboundShowMessageRequest {
47    /// Server that sent the request.
48    pub server_id: Arc<str>,
49    /// Workspace root the originating actor was spawned against
50    /// (B'.2). Pairs with `server_id` to form the canonical
51    /// `(server_id, workspace)` instance key.
52    pub workspace: Arc<std::path::Path>,
53    /// Severity. Used to colour the picker prompt + bias placement.
54    pub level: lsp_types::MessageType,
55    /// The message text -- displayed as the picker prompt.
56    pub message: String,
57    /// Action labels the user picks between. Empty when the
58    /// server attached no actions (degenerate -- effectively
59    /// `showMessage` with a forced acknowledgement). The host
60    /// auto-replies `None` for the actionless case.
61    pub actions: Vec<lsp_types::MessageActionItem>,
62    /// Oneshot the host fills after the user picks (or
63    /// dismisses) -- held in `lsp_pending_show_message_requests`
64    /// until the picker resolves.
65    pub response: oneshot::Sender<ShowMessageRequestOutcome>,
66}
67
68/// Result the host reports back. `None` = user dismissed. `Some`
69/// = user selected the carried action; the actor forwards this
70/// verbatim to the server.
71#[derive(Debug, Clone)]
72pub struct ShowMessageRequestOutcome {
73    pub selected: Option<lsp_types::MessageActionItem>,
74}
75
76// BC.8e: the bespoke `ShowMessageRequestBus::new()`/`dispatch()` round-trip test
77// is retired — the bus is now the generic `InboundBus`, whose send/wake/dropped-
78// receiver behaviour is pinned in `lattice-mode`'s inbound tests. The host-side
79// drain + picker routing + deferred reply stay exercised by `lattice-ui-tui`'s
80// `inject_show_message_request`-based tests against
81// `Editor::drain_inbound_show_message_requests` + `finalize_show_message_request`.