feat: associate request function

This commit is contained in:
Myriad-Dreamin 2024-03-07 16:31:16 +08:00
parent 0c7e67ed9a
commit 50ca444915
9 changed files with 215 additions and 206 deletions

View file

@ -7,20 +7,23 @@ pub struct CompletionRequest {
pub explicit: bool,
}
pub fn completion(
world: &TypstSystemWorld,
doc: Option<Arc<TypstDocument>>,
req: CompletionRequest,
position_encoding: PositionEncoding,
) -> Option<CompletionResponse> {
let source = get_suitable_source_in_workspace(world, &req.path).ok()?;
let typst_offset = lsp_to_typst::position_to_offset(req.position, position_encoding, &source);
impl CompletionRequest {
pub fn request(
self,
world: &TypstSystemWorld,
doc: Option<Arc<TypstDocument>>,
position_encoding: PositionEncoding,
) -> Option<CompletionResponse> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let typst_offset =
lsp_to_typst::position_to_offset(self.position, position_encoding, &source);
let (typst_start_offset, completions) =
typst_ide::autocomplete(world, doc.as_deref(), &source, typst_offset, req.explicit)?;
let (typst_start_offset, completions) =
typst_ide::autocomplete(world, doc.as_deref(), &source, typst_offset, self.explicit)?;
let lsp_start_position =
typst_to_lsp::offset_to_position(typst_start_offset, position_encoding, &source);
let replace_range = LspRawRange::new(lsp_start_position, req.position);
Some(typst_to_lsp::completions(&completions, replace_range).into())
let lsp_start_position =
typst_to_lsp::offset_to_position(typst_start_offset, position_encoding, &source);
let replace_range = LspRawRange::new(lsp_start_position, self.position);
Some(typst_to_lsp::completions(&completions, replace_range).into())
}
}

View file

@ -5,17 +5,19 @@ pub struct DocumentSymbolRequest {
pub path: PathBuf,
}
pub fn document_symbol(
world: &TypstSystemWorld,
req: DocumentSymbolRequest,
position_encoding: PositionEncoding,
) -> Option<DocumentSymbolResponse> {
let source = get_suitable_source_in_workspace(world, &req.path).ok()?;
impl DocumentSymbolRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<DocumentSymbolResponse> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let uri = Url::from_file_path(req.path).unwrap();
let symbols = get_document_symbols(source, uri, position_encoding);
let uri = Url::from_file_path(self.path).unwrap();
let symbols = get_document_symbols(source, uri, position_encoding);
symbols.map(DocumentSymbolResponse::Flat)
symbols.map(DocumentSymbolResponse::Flat)
}
}
#[comemo::memoize]

View file

@ -6,22 +6,25 @@ pub struct HoverRequest {
pub position: LspPosition,
}
pub fn hover(
world: &TypstSystemWorld,
doc: Option<Arc<TypstDocument>>,
req: HoverRequest,
position_encoding: PositionEncoding,
) -> Option<Hover> {
let source = get_suitable_source_in_workspace(world, &req.path).ok()?;
let typst_offset = lsp_to_typst::position_to_offset(req.position, position_encoding, &source);
impl HoverRequest {
pub fn request(
self,
world: &TypstSystemWorld,
doc: Option<Arc<TypstDocument>>,
position_encoding: PositionEncoding,
) -> Option<Hover> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let typst_offset =
lsp_to_typst::position_to_offset(self.position, position_encoding, &source);
let typst_tooltip = typst_ide::tooltip(world, doc.as_deref(), &source, typst_offset)?;
let typst_tooltip = typst_ide::tooltip(world, doc.as_deref(), &source, typst_offset)?;
let ast_node = LinkedNode::new(source.root()).leaf_at(typst_offset)?;
let range = typst_to_lsp::range(ast_node.range(), &source, position_encoding);
let ast_node = LinkedNode::new(source.root()).leaf_at(typst_offset)?;
let range = typst_to_lsp::range(ast_node.range(), &source, position_encoding);
Some(Hover {
contents: typst_to_lsp::tooltip(&typst_tooltip),
range: Some(range.raw_range),
})
Some(Hover {
contents: typst_to_lsp::tooltip(&typst_tooltip),
range: Some(range.raw_range),
})
}
}

View file

@ -6,22 +6,25 @@ pub struct SelectionRangeRequest {
pub positions: Vec<LspPosition>,
}
pub fn selection_range(
world: &TypstSystemWorld,
req: SelectionRangeRequest,
position_encoding: PositionEncoding,
) -> Option<Vec<SelectionRange>> {
let source = get_suitable_source_in_workspace(world, &req.path).ok()?;
impl SelectionRangeRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<Vec<SelectionRange>> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let mut ranges = Vec::new();
for position in req.positions {
let typst_offset = lsp_to_typst::position_to_offset(position, position_encoding, &source);
let tree = LinkedNode::new(source.root());
let leaf = tree.leaf_at(typst_offset)?;
ranges.push(range_for_node(&source, position_encoding, &leaf));
let mut ranges = Vec::new();
for position in self.positions {
let typst_offset =
lsp_to_typst::position_to_offset(position, position_encoding, &source);
let tree = LinkedNode::new(source.root());
let leaf = tree.leaf_at(typst_offset)?;
ranges.push(range_for_node(&source, position_encoding, &leaf));
}
Some(ranges)
}
Some(ranges)
}
fn range_for_node(

View file

@ -6,32 +6,34 @@ pub struct SemanticTokensDeltaRequest {
pub previous_result_id: String,
}
pub fn semantic_tokens_delta(
cache: &SemanticTokenCache,
source: Source,
req: SemanticTokensDeltaRequest,
position_encoding: PositionEncoding,
) -> Option<SemanticTokensFullDeltaResult> {
let (tokens, result_id) = cache.try_semantic_tokens_delta_from_result_id(
&source,
&req.previous_result_id,
position_encoding,
);
impl SemanticTokensDeltaRequest {
pub fn request(
self,
cache: &SemanticTokenCache,
source: Source,
position_encoding: PositionEncoding,
) -> Option<SemanticTokensFullDeltaResult> {
let (tokens, result_id) = cache.try_semantic_tokens_delta_from_result_id(
&source,
&self.previous_result_id,
position_encoding,
);
match tokens {
Ok(edits) => Some(
SemanticTokensDelta {
result_id: Some(result_id),
edits,
}
.into(),
),
Err(tokens) => Some(
SemanticTokens {
result_id: Some(result_id),
data: tokens,
}
.into(),
),
match tokens {
Ok(edits) => Some(
SemanticTokensDelta {
result_id: Some(result_id),
edits,
}
.into(),
),
Err(tokens) => Some(
SemanticTokens {
result_id: Some(result_id),
data: tokens,
}
.into(),
),
}
}
}

View file

@ -5,19 +5,21 @@ pub struct SemanticTokensFullRequest {
pub path: PathBuf,
}
pub fn semantic_tokens_full(
cache: &SemanticTokenCache,
source: Source,
_req: SemanticTokensFullRequest,
position_encoding: PositionEncoding,
) -> Option<SemanticTokensResult> {
let (tokens, result_id) = cache.get_semantic_tokens_full(&source, position_encoding);
impl SemanticTokensFullRequest {
pub fn request(
self,
cache: &SemanticTokenCache,
source: Source,
position_encoding: PositionEncoding,
) -> Option<SemanticTokensResult> {
let (tokens, result_id) = cache.get_semantic_tokens_full(&source, position_encoding);
Some(
SemanticTokens {
result_id: Some(result_id),
data: tokens,
}
.into(),
)
Some(
SemanticTokens {
result_id: Some(result_id),
data: tokens,
}
.into(),
)
}
}

View file

@ -6,73 +6,76 @@ pub struct SignatureHelpRequest {
pub position: LspPosition,
}
pub fn signature_help(
world: &TypstSystemWorld,
SignatureHelpRequest { path, position }: SignatureHelpRequest,
position_encoding: PositionEncoding,
) -> Option<SignatureHelp> {
let source = get_suitable_source_in_workspace(world, &path).ok()?;
let typst_offset = lsp_to_typst::position_to_offset(position, position_encoding, &source);
impl SignatureHelpRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<SignatureHelp> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let typst_offset =
lsp_to_typst::position_to_offset(self.position, position_encoding, &source);
let ast_node = LinkedNode::new(source.root()).leaf_at(typst_offset)?;
let (callee, callee_node, args) = surrounding_function_syntax(&ast_node)?;
let ast_node = LinkedNode::new(source.root()).leaf_at(typst_offset)?;
let (callee, callee_node, args) = surrounding_function_syntax(&ast_node)?;
let mut ancestor = &ast_node;
while !ancestor.is::<ast::Expr>() {
ancestor = ancestor.parent()?;
}
if !callee.hash() && !matches!(callee, ast::Expr::MathIdent(_)) {
return None;
}
let values = analyze_expr(world, &callee_node);
let function = values.into_iter().find_map(|v| match v {
Value::Func(f) => Some(f),
_ => None,
})?;
trace!("got function {function:?}");
let param_index = param_index_at_leaf(&ast_node, &function, args);
let label = format!(
"{}({}){}",
function.name().unwrap_or("<anonymous closure>"),
match function.params() {
Some(params) => params
.iter()
.map(typst_to_lsp::param_info_to_label)
.join(", "),
None => "".to_owned(),
},
match function.returns() {
Some(returns) => format!("-> {}", typst_to_lsp::cast_info_to_label(returns)),
None => "".to_owned(),
let mut ancestor = &ast_node;
while !ancestor.is::<ast::Expr>() {
ancestor = ancestor.parent()?;
}
);
let params = function
.params()
.unwrap_or_default()
.iter()
.map(typst_to_lsp::param_info)
.collect();
trace!("got signature info {label} {params:?}");
let documentation = function.docs().map(markdown_docs);
if !callee.hash() && !matches!(callee, ast::Expr::MathIdent(_)) {
return None;
}
let active_parameter = param_index.map(|i| i as u32);
let values = analyze_expr(world, &callee_node);
Some(SignatureHelp {
signatures: vec![SignatureInformation {
label,
documentation,
parameters: Some(params),
active_parameter,
}],
active_signature: Some(0),
active_parameter: None,
})
let function = values.into_iter().find_map(|v| match v {
Value::Func(f) => Some(f),
_ => None,
})?;
trace!("got function {function:?}");
let param_index = param_index_at_leaf(&ast_node, &function, args);
let label = format!(
"{}({}){}",
function.name().unwrap_or("<anonymous closure>"),
match function.params() {
Some(params) => params
.iter()
.map(typst_to_lsp::param_info_to_label)
.join(", "),
None => "".to_owned(),
},
match function.returns() {
Some(returns) => format!("-> {}", typst_to_lsp::cast_info_to_label(returns)),
None => "".to_owned(),
}
);
let params = function
.params()
.unwrap_or_default()
.iter()
.map(typst_to_lsp::param_info)
.collect();
trace!("got signature info {label} {params:?}");
let documentation = function.docs().map(markdown_docs);
let active_parameter = param_index.map(|i| i as u32);
Some(SignatureHelp {
signatures: vec![SignatureInformation {
label,
documentation,
parameters: Some(params),
active_parameter,
}],
active_signature: Some(0),
active_parameter: None,
})
}
}
fn surrounding_function_syntax<'b>(

View file

@ -8,32 +8,34 @@ pub struct SymbolRequest {
pub pattern: Option<String>,
}
pub fn symbol(
world: &TypstSystemWorld,
SymbolRequest { pattern }: SymbolRequest,
position_encoding: PositionEncoding,
) -> Option<Vec<SymbolInformation>> {
// todo: expose source
impl SymbolRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<Vec<SymbolInformation>> {
// todo: expose source
let mut symbols = vec![];
let mut symbols = vec![];
world.iter_dependencies(&mut |path, _| {
let Ok(source) = get_suitable_source_in_workspace(world, path) else {
return;
};
let uri = Url::from_file_path(path).unwrap();
let res = get_document_symbols(source, uri, position_encoding).and_then(|symbols| {
pattern
.as_ref()
.map(|pattern| filter_document_symbols(symbols, pattern))
world.iter_dependencies(&mut |path, _| {
let Ok(source) = get_suitable_source_in_workspace(world, path) else {
return;
};
let uri = Url::from_file_path(path).unwrap();
let res = get_document_symbols(source, uri, position_encoding).and_then(|symbols| {
self.pattern
.as_ref()
.map(|pattern| filter_document_symbols(symbols, pattern))
});
if let Some(mut res) = res {
symbols.append(&mut res)
}
});
if let Some(mut res) = res {
symbols.append(&mut res)
}
});
Some(symbols)
Some(symbols)
}
}
fn filter_document_symbols(