scrive_core/intel/hover.rs
1//! Hover — the [`Hover`] trait the app satisfies plus the plain data it
2//! returns. Like the other language services it is **synchronous by contract**:
3//! a hover query is an in-memory lookup keyed by the word under the pointer,
4//! so the widget calls it on the mouse-idle tick and renders the reply the same
5//! frame. Because the answer is produced synchronously there is no reply
6//! envelope and nothing in flight, so a reply can never arrive stale.
7
8use core::ops::Range;
9
10use crate::{DocId, Point};
11
12/// Mouse-idle delay before a hover query fires, in milliseconds. Tuned to the
13/// ~300 ms mainstream editors use, so the popup feels neither jumpy nor
14/// sluggish. The widget arms one query when the pointer rests over a word this
15/// long without moving.
16pub const HOVER_IDLE_DELAY_MS: u64 = 300;
17
18/// The provider seam the integrating app implements to answer hover queries.
19pub trait Hover {
20 /// The doc for the word under the pointer, or `None` when there is none (or
21 /// the pointer is not over a word) — the hover popup stays closed.
22 fn hover(&mut self, cx: &HoverCx) -> Option<HoverInfo>;
23}
24
25/// A revision-stamped hover request — everything the provider may read.
26#[derive(Clone, Debug)]
27pub struct HoverCx {
28 /// Which document the request is for.
29 pub doc: DocId,
30 /// The document revision the request was snapshotted at.
31 pub revision: u64,
32 /// The point under the pointer, clipped to a valid char boundary.
33 pub position: Point,
34 /// Absolute byte range of the word under the pointer, computed with
35 /// `is_completion_word_char` — empty ⇒ the query is skipped.
36 pub word: Range<u32>,
37 /// The preceding source text, back the same number of lines as
38 /// `CompletionCx`, giving the classifier the context the spec lookup needs
39 /// (dotted receiver, in-call position).
40 pub lookback: String,
41}
42
43/// A resolved hover: the markdown to render and the word it describes.
44#[derive(Clone, Debug)]
45pub struct HoverInfo {
46 /// Markdown body (a minimal block/inline subset; richer degrades to plain
47 /// text at render).
48 pub markdown: String,
49 /// The word range the doc describes — the popup anchors here and the widget
50 /// re-tests pointer containment against it for dismissal.
51 pub range: Range<u32>,
52}