dev: convert all syntax-level request and check main state before requesting (#67)

This commit is contained in:
Myriad-Dreamin 2024-03-18 17:36:43 +08:00 committed by GitHub
parent 5d123221db
commit 2fe992e933
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 78 additions and 85 deletions

View file

@ -1,6 +1,6 @@
use lsp_types::Command;
use crate::prelude::*;
use crate::{prelude::*, SyntaxRequest};
/// The [`textDocument/codeLens`] request is sent from the client to the server
/// to compute code lenses for a given text document.
@ -12,15 +12,13 @@ pub struct CodeLensRequest {
pub path: PathBuf,
}
impl CodeLensRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<Vec<CodeLens>> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
impl SyntaxRequest for CodeLensRequest {
type Response = Vec<CodeLens>;
let doc_start = typst_to_lsp::range(0..0, &source, position_encoding);
fn request(self, ctx: &mut AnalysisContext) -> Option<Self::Response> {
let source = ctx.source_by_path(&self.path).ok()?;
let doc_start = ctx.to_lsp_range(0..0, &source);
let mut res = vec![];

View file

@ -6,6 +6,7 @@ use lsp_types::LocationLink;
use crate::{
prelude::*,
syntax::{get_deref_target, DerefTarget},
SyntaxRequest,
};
#[derive(Debug, Clone)]
@ -14,36 +15,31 @@ pub struct GotoDeclarationRequest {
pub position: LspPosition,
}
impl GotoDeclarationRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<GotoDeclarationResponse> {
let mut ctx = AnalysisContext::new(world, position_encoding);
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let offset = lsp_to_typst::position(self.position, position_encoding, &source)?;
impl SyntaxRequest for GotoDeclarationRequest {
type Response = GotoDeclarationResponse;
fn request(self, ctx: &mut AnalysisContext) -> Option<Self::Response> {
let source = ctx.source_by_path(&self.path).ok()?;
let offset = ctx.to_typst_pos(self.position, &source)?;
let cursor = offset + 1;
let w: &dyn World = world;
let ast_node = LinkedNode::new(source.root()).leaf_at(cursor)?;
debug!("ast_node: {ast_node:?}", ast_node = ast_node);
let deref_target = get_deref_target(ast_node)?;
let use_site = deref_target.node();
let origin_selection_range =
typst_to_lsp::range(use_site.range(), &source, position_encoding);
let origin_selection_range = ctx.to_lsp_range(use_site.range(), &source);
let def_use = ctx.def_use(source.clone())?;
let ref_spans = find_declarations(w, def_use, deref_target)?;
let ref_spans = find_declarations(ctx, def_use, deref_target)?;
let mut links = vec![];
for ref_range in ref_spans {
let ref_id = source.id();
let ref_source = &source;
let span_path = world.path_for_id(ref_id).ok()?;
let range = typst_to_lsp::range(ref_range, ref_source, position_encoding);
let span_path = ctx.world.path_for_id(ref_id).ok()?;
let range = ctx.to_lsp_range(ref_range, ref_source);
let uri = Url::from_file_path(span_path).ok()?;
@ -61,7 +57,7 @@ impl GotoDeclarationRequest {
}
fn find_declarations(
_w: &dyn World,
_ctx: &AnalysisContext,
_def_use: Arc<crate::analysis::DefUseInfo>,
_deref_target: DerefTarget<'_>,
) -> Option<Vec<Range<usize>>> {

View file

@ -9,7 +9,7 @@ use typst::{
};
use typst_ts_core::typst::prelude::eco_vec;
use crate::prelude::*;
use crate::{prelude::*, SyntaxRequest};
pub struct InlayHintConfig {
// positional arguments group
@ -45,16 +45,14 @@ pub struct InlayHintRequest {
pub range: LspRange,
}
impl InlayHintRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<Vec<InlayHint>> {
let source = get_suitable_source_in_workspace(world, &self.path).ok()?;
let range = lsp_to_typst::range(self.range, position_encoding, &source)?;
impl SyntaxRequest for InlayHintRequest {
type Response = Vec<InlayHint>;
let hints = inlay_hint(world, &source, range, position_encoding).ok()?;
fn request(self, ctx: &mut AnalysisContext) -> Option<Self::Response> {
let source = ctx.source_by_path(&self.path).ok()?;
let range = ctx.to_typst_range(self.range, &source)?;
let hints = inlay_hint(ctx.world, &source, range, ctx.position_encoding()).ok()?;
debug!(
"got inlay hints on {source:?} => {hints:?}",
source = source.id(),
@ -663,8 +661,8 @@ mod tests {
#[test]
fn smart() {
snapshot_testing("inlay_hints", &|world, path| {
let source = get_suitable_source_in_workspace(world, &path).unwrap();
snapshot_testing2("inlay_hints", &|ctx, path| {
let source = ctx.source_by_path(&path).unwrap();
let request = InlayHintRequest {
path: path.clone(),
@ -675,7 +673,7 @@ mod tests {
),
};
let result = request.request(world, PositionEncoding::Utf16);
let result = request.request(ctx);
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
});
}

View file

@ -1,4 +1,4 @@
use crate::prelude::*;
use crate::{prelude::*, SyntaxRequest};
#[derive(Debug, Clone)]
pub struct SignatureHelpRequest {
@ -6,14 +6,12 @@ pub struct SignatureHelpRequest {
pub position: LspPosition,
}
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(self.position, position_encoding, &source)?;
impl SyntaxRequest for SignatureHelpRequest {
type Response = SignatureHelp;
fn request(self, ctx: &mut AnalysisContext) -> Option<Self::Response> {
let source = ctx.source_by_path(&self.path).ok()?;
let typst_offset = ctx.to_typst_pos(self.position, &source)?;
let ast_node = LinkedNode::new(source.root()).leaf_at(typst_offset + 1)?;
let (callee, callee_node, args) = surrounding_function_syntax(&ast_node)?;
@ -22,7 +20,7 @@ impl SignatureHelpRequest {
return None;
}
let values = analyze_expr(world, &callee_node);
let values = analyze_expr(ctx.world, &callee_node);
let function = values.into_iter().find_map(|v| match v.0 {
Value::Func(f) => Some(f),

View file

@ -3,6 +3,7 @@ use typst_ts_compiler::NotifyApi;
use crate::{
prelude::*,
syntax::{get_lexical_hierarchy, LexicalHierarchy, LexicalScopeKind},
SyntaxRequest,
};
#[derive(Debug, Clone)]
@ -10,25 +11,29 @@ pub struct SymbolRequest {
pub pattern: Option<String>,
}
impl SymbolRequest {
pub fn request(
self,
world: &TypstSystemWorld,
position_encoding: PositionEncoding,
) -> Option<Vec<SymbolInformation>> {
impl SyntaxRequest for SymbolRequest {
type Response = Vec<SymbolInformation>;
fn request(self, ctx: &mut AnalysisContext) -> Option<Self::Response> {
// todo: expose source
let mut symbols = vec![];
world.iter_dependencies(&mut |path, _| {
let Ok(source) = get_suitable_source_in_workspace(world, path) else {
ctx.world.iter_dependencies(&mut |path, _| {
let Ok(source) = ctx.source_by_path(path) else {
return;
};
let uri = Url::from_file_path(path).unwrap();
let res = get_lexical_hierarchy(source.clone(), LexicalScopeKind::Symbol).and_then(
|symbols| {
self.pattern.as_ref().map(|pattern| {
filter_document_symbols(&symbols, pattern, &source, &uri, position_encoding)
filter_document_symbols(
&symbols,
pattern,
&source,
&uri,
ctx.position_encoding(),
)
})
},
);

View file

@ -6,6 +6,7 @@ use std::{
sync::Arc,
};
use anyhow::anyhow;
use log::{debug, error, info, trace, warn};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
@ -25,7 +26,7 @@ use typst_preview::{CompilationHandle, CompilationHandleImpl, CompileStatus};
use typst_ts_compiler::{
service::{
CompileDriver as CompileDriverInner, CompileExporter, CompileMiddleware, Compiler,
WorkspaceProvider, WorldExporter,
EnvWorld, WorkspaceProvider, WorldExporter,
},
vfs::notify::{FileChangeSet, MemoryEvent},
TypstSystemWorld,
@ -211,15 +212,7 @@ macro_rules! query_state {
macro_rules! query_world {
($self:ident, $method:ident, $req:expr) => {{
let enc = $self.position_encoding;
let res = $self.steal_world(move |w| $req.request(w, enc));
res.map(CompilerQueryResponse::$method)
}};
}
macro_rules! query_world2 {
($self:ident, $method:ident, $req:expr) => {{
let res = $self.steal_world2(move |w| $req.request(w));
let res = $self.steal_world(move |w| $req.request(w));
res.map(CompilerQueryResponse::$method)
}};
}
@ -626,15 +619,15 @@ impl CompileActor {
Ok(CompilerQueryResponse::OnSaveExport(()))
}
Hover(req) => query_state!(self, Hover, req),
GotoDefinition(req) => query_world2!(self, GotoDefinition, req),
GotoDefinition(req) => query_world!(self, GotoDefinition, req),
GotoDeclaration(req) => query_world!(self, GotoDeclaration, req),
References(req) => query_world2!(self, References, req),
References(req) => query_world!(self, References, req),
InlayHint(req) => query_world!(self, InlayHint, req),
CodeLens(req) => query_world!(self, CodeLens, req),
Completion(req) => query_state!(self, Completion, req),
SignatureHelp(req) => query_world!(self, SignatureHelp, req),
Rename(req) => query_world2!(self, Rename, req),
PrepareRename(req) => query_world2!(self, PrepareRename, req),
Rename(req) => query_world!(self, Rename, req),
PrepareRename(req) => query_world!(self, PrepareRename, req),
Symbol(req) => query_world!(self, Symbol, req),
FoldingRange(..)
| SelectionRange(..)
@ -679,25 +672,30 @@ impl CompileActor {
}
fn steal_world<T: Send + Sync + 'static>(
&self,
f: impl FnOnce(&TypstSystemWorld) -> T + Send + Sync + 'static,
) -> anyhow::Result<T> {
let fut = self.steal(move |compiler| f(compiler.compiler.world()));
Ok(fut?)
}
fn steal_world2<T: Send + Sync + 'static>(
&self,
f: impl FnOnce(&mut AnalysisContext) -> T + Send + Sync + 'static,
) -> anyhow::Result<T> {
let enc = self.position_encoding;
let fut = self.steal(move |compiler| {
// todo: record analysis
f(&mut AnalysisContext::new(compiler.compiler.world(), enc))
});
Ok(fut?)
self.steal(move |compiler| {
// todo: record analysis
let w = compiler.compiler.world_mut();
let Some(main) = w.main else {
log::error!("TypstActor: main file is not set");
return Err(anyhow!("main file is not set"));
};
w.source(main).map_err(|err| {
log::info!("TypstActor: failed to prepare main file: {:?}", err);
anyhow!("failed to get source: {err}")
})?;
w.prepare_env(&mut Default::default()).map_err(|err| {
log::error!("TypstActor: failed to prepare env: {:?}", err);
anyhow!("failed to prepare env")
})?;
Ok(f(&mut AnalysisContext::new(compiler.compiler.world(), enc)))
})?
}
}