tinymist_query/selection_range.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
use typst_shim::syntax::LinkedNodeExt;
use crate::{prelude::*, SyntaxRequest};
/// The [`textDocument/selectionRange`] request is sent from the client to the
/// server to return suggested selection ranges at an array of given positions.
/// A selection range is a range around the cursor position which the user might
/// be interested in selecting.
///
/// [`textDocument/selectionRange`]: https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange
///
/// A selection range in the return array is for the position in the provided
/// parameters at the same index. Therefore `params.positions[i]` must be
/// contained in `result[i].range`.
///
/// # Compatibility
///
/// This request was introduced in specification version 3.15.0.
#[derive(Debug, Clone)]
pub struct SelectionRangeRequest {
/// The path of the document to get selection ranges for.
pub path: PathBuf,
/// The positions to get selection ranges for.
pub positions: Vec<LspPosition>,
}
impl SyntaxRequest for SelectionRangeRequest {
type Response = Vec<SelectionRange>;
fn request(
self,
source: &Source,
position_encoding: PositionEncoding,
) -> Option<Self::Response> {
let mut ranges = Vec::new();
for position in self.positions {
let typst_offset = to_typst_position(position, position_encoding, source)?;
let tree = LinkedNode::new(source.root());
let leaf = tree.leaf_at_compat(typst_offset + 1)?;
ranges.push(range_for_node(source, position_encoding, &leaf));
}
Some(ranges)
}
}
fn range_for_node(
source: &Source,
position_encoding: PositionEncoding,
node: &LinkedNode,
) -> SelectionRange {
let range = to_lsp_range(node.range(), source, position_encoding);
SelectionRange {
range,
parent: node
.parent()
.map(|node| Box::new(range_for_node(source, position_encoding, node))),
}
}