diff --git a/crates/tinymist-query/src/completion.rs b/crates/tinymist-query/src/completion.rs index d9a07eaf..20e67098 100644 --- a/crates/tinymist-query/src/completion.rs +++ b/crates/tinymist-query/src/completion.rs @@ -7,20 +7,23 @@ pub struct CompletionRequest { pub explicit: bool, } -pub fn completion( - world: &TypstSystemWorld, - doc: Option>, - req: CompletionRequest, - position_encoding: PositionEncoding, -) -> Option { - 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>, + position_encoding: PositionEncoding, + ) -> Option { + 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()) + } } diff --git a/crates/tinymist-query/src/document_symbol.rs b/crates/tinymist-query/src/document_symbol.rs index ae3e9c3c..4bb90aa0 100644 --- a/crates/tinymist-query/src/document_symbol.rs +++ b/crates/tinymist-query/src/document_symbol.rs @@ -5,17 +5,19 @@ pub struct DocumentSymbolRequest { pub path: PathBuf, } -pub fn document_symbol( - world: &TypstSystemWorld, - req: DocumentSymbolRequest, - position_encoding: PositionEncoding, -) -> Option { - let source = get_suitable_source_in_workspace(world, &req.path).ok()?; +impl DocumentSymbolRequest { + pub fn request( + self, + world: &TypstSystemWorld, + position_encoding: PositionEncoding, + ) -> Option { + 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] diff --git a/crates/tinymist-query/src/hover.rs b/crates/tinymist-query/src/hover.rs index 327fe859..1f2bd2f1 100644 --- a/crates/tinymist-query/src/hover.rs +++ b/crates/tinymist-query/src/hover.rs @@ -6,22 +6,25 @@ pub struct HoverRequest { pub position: LspPosition, } -pub fn hover( - world: &TypstSystemWorld, - doc: Option>, - req: HoverRequest, - position_encoding: PositionEncoding, -) -> Option { - 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>, + position_encoding: PositionEncoding, + ) -> Option { + 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), + }) + } } diff --git a/crates/tinymist-query/src/selection_range.rs b/crates/tinymist-query/src/selection_range.rs index 12148994..bd8a60fb 100644 --- a/crates/tinymist-query/src/selection_range.rs +++ b/crates/tinymist-query/src/selection_range.rs @@ -6,22 +6,25 @@ pub struct SelectionRangeRequest { pub positions: Vec, } -pub fn selection_range( - world: &TypstSystemWorld, - req: SelectionRangeRequest, - position_encoding: PositionEncoding, -) -> Option> { - let source = get_suitable_source_in_workspace(world, &req.path).ok()?; +impl SelectionRangeRequest { + pub fn request( + self, + world: &TypstSystemWorld, + position_encoding: PositionEncoding, + ) -> Option> { + 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( diff --git a/crates/tinymist-query/src/semantic_tokens_delta.rs b/crates/tinymist-query/src/semantic_tokens_delta.rs index 8bc6d818..8b8c6fc2 100644 --- a/crates/tinymist-query/src/semantic_tokens_delta.rs +++ b/crates/tinymist-query/src/semantic_tokens_delta.rs @@ -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 { - 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 { + 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(), + ), + } } } diff --git a/crates/tinymist-query/src/semantic_tokens_full.rs b/crates/tinymist-query/src/semantic_tokens_full.rs index 69e5e660..dee2cde4 100644 --- a/crates/tinymist-query/src/semantic_tokens_full.rs +++ b/crates/tinymist-query/src/semantic_tokens_full.rs @@ -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 { - 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 { + 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(), + ) + } } diff --git a/crates/tinymist-query/src/signature_help.rs b/crates/tinymist-query/src/signature_help.rs index 3fdf64a9..b494f4e9 100644 --- a/crates/tinymist-query/src/signature_help.rs +++ b/crates/tinymist-query/src/signature_help.rs @@ -6,73 +6,76 @@ pub struct SignatureHelpRequest { pub position: LspPosition, } -pub fn signature_help( - world: &TypstSystemWorld, - SignatureHelpRequest { path, position }: SignatureHelpRequest, - position_encoding: PositionEncoding, -) -> Option { - 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 { + 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::() { - 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(""), - 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::() { + 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(""), + 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>( diff --git a/crates/tinymist-query/src/symbol.rs b/crates/tinymist-query/src/symbol.rs index f3ebb52b..8a55d69d 100644 --- a/crates/tinymist-query/src/symbol.rs +++ b/crates/tinymist-query/src/symbol.rs @@ -8,32 +8,34 @@ pub struct SymbolRequest { pub pattern: Option, } -pub fn symbol( - world: &TypstSystemWorld, - SymbolRequest { pattern }: SymbolRequest, - position_encoding: PositionEncoding, -) -> Option> { - // todo: expose source +impl SymbolRequest { + pub fn request( + self, + world: &TypstSystemWorld, + position_encoding: PositionEncoding, + ) -> Option> { + // 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( diff --git a/crates/tinymist/src/actor/typst.rs b/crates/tinymist/src/actor/typst.rs index c55aa78d..08c27c44 100644 --- a/crates/tinymist/src/actor/typst.rs +++ b/crates/tinymist/src/actor/typst.rs @@ -7,7 +7,9 @@ use std::{ use anyhow::anyhow; use futures::future::join_all; use log::{error, trace, warn}; -use tinymist_query::{LspDiagnostic, LspRange, PositionEncoding, SemanticTokenCache}; +use tinymist_query::{ + DiagnosticsMap, LspDiagnostic, LspRange, PositionEncoding, SemanticTokenCache, +}; use tokio::sync::{broadcast, mpsc, watch, Mutex, RwLock}; use tower_lsp::lsp_types::{ CompletionResponse, DocumentSymbolResponse, Hover, SelectionRange, @@ -42,9 +44,6 @@ type CompileService = CompileActor, H type CompileClient = TsCompileClient>; type DiagnosticsSender = mpsc::UnboundedSender<(String, DiagnosticsMap)>; -type DiagnosticsMap = HashMap>; - -// type Client = TypstClient; pub struct CompileCluster { position_encoding: PositionEncoding, @@ -65,7 +64,7 @@ pub fn create_cluster( let primary = create_server( "primary".to_owned(), cfg, - create_compiler(roots.clone(), opts.clone()), + CompileDriver::new(roots.clone(), opts.clone()), diag_tx, ); @@ -83,11 +82,6 @@ pub fn create_cluster( } } -fn create_compiler(roots: Vec, opts: CompileOpts) -> CompileDriver { - let world = TypstSystemWorld::new(opts).expect("incorrect options"); - CompileDriver::new(world, roots) -} - fn create_server( diag_group: String, cfg: &ConstConfig, @@ -323,31 +317,31 @@ pub enum CompilerQueryResponse { } macro_rules! query_state { - ($self:ident, $method:ident, $query:expr, $req:expr) => {{ + ($self:ident, $method:ident, $req:expr) => {{ let doc = $self.handler.result.lock().unwrap().clone().ok(); let enc = $self.position_encoding; - let res = $self.steal_world(move |w| $query(w, doc, $req, enc)).await; + let res = $self.steal_world(move |w| $req.request(w, doc, enc)).await; res.map(CompilerQueryResponse::$method) }}; } macro_rules! query_world { - ($self:ident, $method:ident, $query:expr, $req:expr) => {{ + ($self:ident, $method:ident, $req:expr) => {{ let enc = $self.position_encoding; - let res = $self.steal_world(move |w| $query(w, $req, enc)).await; + let res = $self.steal_world(move |w| $req.request(w, enc)).await; res.map(CompilerQueryResponse::$method) }}; } macro_rules! query_tokens_cache { - ($self:ident, $method:ident, $query:expr, $req:expr) => {{ + ($self:ident, $method:ident, $req:expr) => {{ let path: ImmutPath = $req.path.clone().into(); let vfs = $self.memory_changes.read().await; let snapshot = vfs.get(&path).ok_or_else(|| anyhow!("file missing"))?; let source = snapshot.content.clone(); let enc = $self.position_encoding; - let res = $query(&$self.tokens_cache, source, $req, enc); + let res = $req.request(&$self.tokens_cache, source, enc); Ok(CompilerQueryResponse::$method(res)) }}; } @@ -357,16 +351,11 @@ impl CompileCluster { &self, query: CompilerQueryRequest, ) -> anyhow::Result { - use tinymist_query::*; use CompilerQueryRequest::*; match query { - SemanticTokensFull(req) => { - query_tokens_cache!(self, SemanticTokensFull, semantic_tokens_full, req) - } - SemanticTokensDelta(req) => { - query_tokens_cache!(self, SemanticTokensDelta, semantic_tokens_delta, req) - } + SemanticTokensFull(req) => query_tokens_cache!(self, SemanticTokensFull, req), + SemanticTokensDelta(req) => query_tokens_cache!(self, SemanticTokensDelta, req), _ => self.primary.query(query).await, } } @@ -415,7 +404,8 @@ impl CompileMiddleware for CompileDriver { } impl CompileDriver { - fn new(world: TypstSystemWorld, roots: Vec) -> Self { + fn new(roots: Vec, opts: CompileOpts) -> Self { + let world = TypstSystemWorld::new(opts).expect("incorrect options"); let driver = CompileDriverInner::new(world); Self { @@ -679,7 +669,6 @@ impl CompileNode { &self, query: CompilerQueryRequest, ) -> anyhow::Result { - use tinymist_query::*; use CompilerQueryRequest::*; match query { @@ -687,12 +676,12 @@ impl CompileNode { self.on_save_export(path).await?; Ok(CompilerQueryResponse::OnSaveExport(())) } - Hover(req) => query_state!(self, Hover, hover, req), - Completion(req) => query_state!(self, Completion, completion, req), - SignatureHelp(req) => query_world!(self, SignatureHelp, signature_help, req), - DocumentSymbol(req) => query_world!(self, DocumentSymbol, document_symbol, req), - Symbol(req) => query_world!(self, Symbol, symbol, req), - SelectionRange(req) => query_world!(self, SelectionRange, selection_range, req), + Hover(req) => query_state!(self, Hover, req), + Completion(req) => query_state!(self, Completion, req), + SignatureHelp(req) => query_world!(self, SignatureHelp, req), + DocumentSymbol(req) => query_world!(self, DocumentSymbol, req), + Symbol(req) => query_world!(self, Symbol, req), + SelectionRange(req) => query_world!(self, SelectionRange, req), CompilerQueryRequest::SemanticTokensDelta(..) | CompilerQueryRequest::SemanticTokensFull(..) => unreachable!(), }