mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 17:58:17 +00:00
feat: support goto_definition api
This commit is contained in:
parent
edd3ad260f
commit
c19197178c
5 changed files with 126 additions and 10 deletions
94
crates/tinymist-query/src/goto_definition.rs
Normal file
94
crates/tinymist-query/src/goto_definition.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GotoDefinitionRequest {
|
||||
pub path: PathBuf,
|
||||
pub position: LspPosition,
|
||||
}
|
||||
|
||||
impl GotoDefinitionRequest {
|
||||
pub fn request(
|
||||
self,
|
||||
world: &TypstSystemWorld,
|
||||
position_encoding: PositionEncoding,
|
||||
) -> Option<GotoDefinitionResponse> {
|
||||
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 mut ancestor = &ast_node;
|
||||
while !ancestor.is::<ast::Expr>() {
|
||||
ancestor = ancestor.parent()?;
|
||||
}
|
||||
|
||||
let may_ident = ancestor.cast::<ast::Expr>()?;
|
||||
if !may_ident.hash() && !matches!(may_ident, ast::Expr::MathIdent(_)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut is_ident_only = false;
|
||||
trace!("got ast_node kind {kind:?}", kind = ancestor.kind());
|
||||
let callee_node = match may_ident {
|
||||
// todo: label, reference
|
||||
// todo: import
|
||||
// todo: include
|
||||
ast::Expr::FuncCall(call) => call.callee(),
|
||||
ast::Expr::Set(set) => set.target(),
|
||||
ast::Expr::Ident(..) | ast::Expr::MathIdent(..) | ast::Expr::FieldAccess(..) => {
|
||||
is_ident_only = true;
|
||||
may_ident
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
trace!("got callee_node {callee_node:?} {is_ident_only:?}");
|
||||
|
||||
let callee_link = if is_ident_only {
|
||||
ancestor.clone()
|
||||
} else {
|
||||
ancestor.find(callee_node.span())?
|
||||
};
|
||||
|
||||
let values = analyze_expr(world, &callee_link);
|
||||
|
||||
let func_or_module = values.into_iter().find_map(|v| match &v {
|
||||
Value::Args(a) => {
|
||||
trace!("got args {a:?}");
|
||||
None
|
||||
}
|
||||
Value::Func(..) | Value::Module(..) => Some(v),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let span = match func_or_module {
|
||||
Some(Value::Func(f)) => f.span(),
|
||||
Some(Value::Module(m)) => {
|
||||
trace!("find module. {m:?}");
|
||||
// todo
|
||||
return None;
|
||||
}
|
||||
_ => {
|
||||
trace!("find value by lexical result. {callee_link:?}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
if span.is_detached() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let Some(id) = span.id() else {
|
||||
return None;
|
||||
};
|
||||
let span_path = world.path_for_id(id).ok()?;
|
||||
let span_source = world.source(id).ok()?;
|
||||
let offset = span_source.find(span)?;
|
||||
let typst_range = offset.range();
|
||||
let range = typst_to_lsp::range(typst_range, &span_source, position_encoding).raw_range;
|
||||
|
||||
let uri = Url::from_file_path(span_path).ok()?;
|
||||
|
||||
Some(GotoDefinitionResponse::Scalar(LspLocation { uri, range }))
|
||||
}
|
||||
}
|
|
@ -22,6 +22,8 @@ pub(crate) mod folding_range;
|
|||
pub use folding_range::*;
|
||||
pub(crate) mod selection_range;
|
||||
pub use selection_range::*;
|
||||
pub(crate) mod goto_definition;
|
||||
pub use goto_definition::*;
|
||||
|
||||
pub mod lsp_typst_boundary;
|
||||
pub use lsp_typst_boundary::*;
|
||||
|
|
|
@ -9,10 +9,10 @@ pub use itertools::{Format, Itertools};
|
|||
pub use log::{error, trace};
|
||||
pub use tower_lsp::lsp_types::{
|
||||
CompletionResponse, DiagnosticRelatedInformation, DocumentSymbol, DocumentSymbolResponse,
|
||||
Documentation, FoldingRange, Hover, Location as LspLocation, MarkupContent, MarkupKind,
|
||||
Position as LspPosition, SelectionRange, SemanticTokens, SemanticTokensDelta,
|
||||
SemanticTokensFullDeltaResult, SemanticTokensResult, SignatureHelp, SignatureInformation,
|
||||
SymbolInformation, Url,
|
||||
Documentation, FoldingRange, GotoDefinitionResponse, Hover, Location as LspLocation,
|
||||
MarkupContent, MarkupKind, Position as LspPosition, SelectionRange, SemanticTokens,
|
||||
SemanticTokensDelta, SemanticTokensFullDeltaResult, SemanticTokensResult, SignatureHelp,
|
||||
SignatureInformation, SymbolInformation, Url,
|
||||
};
|
||||
pub use typst::diag::{EcoString, FileError, FileResult, Tracepoint};
|
||||
pub use typst::foundations::{Func, ParamInfo, Value};
|
||||
|
|
|
@ -12,9 +12,9 @@ use tinymist_query::{
|
|||
};
|
||||
use tokio::sync::{broadcast, mpsc, watch, Mutex, RwLock};
|
||||
use tower_lsp::lsp_types::{
|
||||
CompletionResponse, DocumentSymbolResponse, FoldingRange, Hover, SelectionRange,
|
||||
SemanticTokensFullDeltaResult, SemanticTokensResult, SignatureHelp, SymbolInformation,
|
||||
TextDocumentContentChangeEvent, Url,
|
||||
CompletionResponse, DocumentSymbolResponse, FoldingRange, GotoDefinitionResponse, Hover,
|
||||
SelectionRange, SemanticTokensFullDeltaResult, SemanticTokensResult, SignatureHelp,
|
||||
SymbolInformation, TextDocumentContentChangeEvent, Url,
|
||||
};
|
||||
use typst::diag::{FileResult, SourceDiagnostic, SourceResult};
|
||||
use typst::layout::Position;
|
||||
|
@ -294,6 +294,7 @@ pub struct OnSaveExportRequest {
|
|||
pub enum CompilerQueryRequest {
|
||||
OnSaveExport(OnSaveExportRequest),
|
||||
Hover(tinymist_query::HoverRequest),
|
||||
GotoDefinition(tinymist_query::GotoDefinitionRequest),
|
||||
Completion(tinymist_query::CompletionRequest),
|
||||
SignatureHelp(tinymist_query::SignatureHelpRequest),
|
||||
DocumentSymbol(tinymist_query::DocumentSymbolRequest),
|
||||
|
@ -308,6 +309,7 @@ pub enum CompilerQueryRequest {
|
|||
pub enum CompilerQueryResponse {
|
||||
OnSaveExport(()),
|
||||
Hover(Option<Hover>),
|
||||
GotoDefinition(Option<GotoDefinitionResponse>),
|
||||
Completion(Option<CompletionResponse>),
|
||||
SignatureHelp(Option<SignatureHelp>),
|
||||
DocumentSymbol(Option<DocumentSymbolResponse>),
|
||||
|
@ -679,6 +681,7 @@ impl<H: CompilationHandle> CompileNode<H> {
|
|||
Ok(CompilerQueryResponse::OnSaveExport(()))
|
||||
}
|
||||
Hover(req) => query_state!(self, Hover, req),
|
||||
GotoDefinition(req) => query_world!(self, GotoDefinition, req),
|
||||
Completion(req) => query_state!(self, Completion, req),
|
||||
SignatureHelp(req) => query_world!(self, SignatureHelp, req),
|
||||
DocumentSymbol(req) => query_world!(self, DocumentSymbol, req),
|
||||
|
|
|
@ -17,8 +17,9 @@ use serde_json::Value as JsonValue;
|
|||
use tinymist_query::{
|
||||
get_semantic_tokens_options, get_semantic_tokens_registration,
|
||||
get_semantic_tokens_unregistration, CompletionRequest, DocumentSymbolRequest,
|
||||
FoldingRangeRequest, HoverRequest, PositionEncoding, SelectionRangeRequest,
|
||||
SemanticTokensDeltaRequest, SemanticTokensFullRequest, SignatureHelpRequest, SymbolRequest,
|
||||
FoldingRangeRequest, GotoDefinitionRequest, HoverRequest, PositionEncoding,
|
||||
SelectionRangeRequest, SemanticTokensDeltaRequest, SemanticTokensFullRequest,
|
||||
SignatureHelpRequest, SymbolRequest,
|
||||
};
|
||||
|
||||
use anyhow::bail;
|
||||
|
@ -315,6 +316,7 @@ impl LanguageServer for TypstServer {
|
|||
|
||||
Ok(InitializeResult {
|
||||
capabilities: ServerCapabilities {
|
||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||
signature_help_provider: Some(SignatureHelpOptions {
|
||||
trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
|
||||
retrigger_characters: None,
|
||||
|
@ -322,7 +324,7 @@ impl LanguageServer for TypstServer {
|
|||
work_done_progress: None,
|
||||
},
|
||||
}),
|
||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
completion_provider: Some(CompletionOptions {
|
||||
trigger_characters: Some(vec![
|
||||
String::from("#"),
|
||||
|
@ -505,6 +507,21 @@ impl LanguageServer for TypstServer {
|
|||
run_query!(self, Hover, HoverRequest { path, position })
|
||||
}
|
||||
|
||||
async fn goto_definition(
|
||||
&self,
|
||||
params: GotoDefinitionParams,
|
||||
) -> jsonrpc::Result<Option<GotoDefinitionResponse>> {
|
||||
let uri = params.text_document_position_params.text_document.uri;
|
||||
let path = uri.to_file_path().unwrap();
|
||||
let position = params.text_document_position_params.position;
|
||||
|
||||
run_query!(
|
||||
self,
|
||||
GotoDefinition,
|
||||
GotoDefinitionRequest { path, position }
|
||||
)
|
||||
}
|
||||
|
||||
async fn completion(
|
||||
&self,
|
||||
params: CompletionParams,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue