From 23f9066f75593df25c3922c96dd9f7a1aa1d14f4 Mon Sep 17 00:00:00 2001 From: ef3d0c3e Date: Fri, 25 Oct 2024 10:05:13 +0200 Subject: [PATCH] Inlay hints --- src/elements/code.rs | 13 ++--- src/elements/comment.rs | 2 +- src/elements/customstyle.rs | 23 +++++--- src/elements/graphviz.rs | 2 +- src/elements/import.rs | 2 +- src/elements/layout.rs | 6 +-- src/elements/link.rs | 4 +- src/elements/list.rs | 2 +- src/elements/raw.rs | 2 +- src/elements/reference.rs | 6 +-- src/elements/script.rs | 37 ++++++++----- src/elements/section.rs | 2 +- src/elements/style.rs | 2 +- src/elements/tex.rs | 2 +- src/elements/variable.rs | 4 +- src/lsp/data.rs | 25 +++++++++ src/lsp/hints.rs | 102 ++++++++++++++++++++++++++++++++++++ src/lsp/mod.rs | 2 + src/lsp/semantic.rs | 52 ++++++++---------- src/lua/kernel.rs | 35 ++++++++++++- src/parser/langparser.rs | 17 +++--- src/parser/parser.rs | 8 +-- src/server.rs | 44 ++++++++++++++-- 23 files changed, 298 insertions(+), 96 deletions(-) create mode 100644 src/lsp/data.rs create mode 100644 src/lsp/hints.rs diff --git a/src/elements/code.rs b/src/elements/code.rs index 4fefa6b..65c73a1 100644 --- a/src/elements/code.rs +++ b/src/elements/code.rs @@ -369,16 +369,9 @@ impl RegexRule for CodeRule { let code_lang = match matches.get(2) { None => "Plain Text".to_string(), Some(lang) => { - let code_lang = lang.as_str().trim_start().trim_end().to_string(); + let mut code_lang = lang.as_str().trim_start().trim_end().to_string(); if code_lang.is_empty() { - report_err!( - &mut reports, - token.source(), - "Missing Code Language".into(), - span(lang.range(), "No language specified".into()) - ); - - return reports; + code_lang = "Plain Text".into(); } if Code::get_syntaxes() .find_syntax_by_name(code_lang.as_str()) @@ -511,7 +504,7 @@ impl RegexRule for CodeRule { } if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let range = matches .get(0) diff --git a/src/elements/comment.rs b/src/elements/comment.rs index ef19783..b62eba0 100644 --- a/src/elements/comment.rs +++ b/src/elements/comment.rs @@ -91,7 +91,7 @@ impl RegexRule for CommentRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let comment = matches.get(1).unwrap().range(); sems.add(comment.start - 2..comment.end, tokens.comment); diff --git a/src/elements/customstyle.rs b/src/elements/customstyle.rs index 58e184c..0772ef8 100644 --- a/src/elements/customstyle.rs +++ b/src/elements/customstyle.rs @@ -8,6 +8,7 @@ use std::rc::Rc; use std::sync::Arc; use ariadne::Fmt; +use lsp::semantic::Semantics; use mlua::Error::BadArgument; use mlua::Function; use mlua::Lua; @@ -51,14 +52,14 @@ impl CustomStyle for LuaCustomStyle { let kernel: Ref<'_, Kernel> = Ref::map(state.shared.kernels.borrow(), |b| b.get("main").unwrap()); //let kernel = RefMut::map(parser_state.shared.kernels.borrow(), |ker| ker.get("main").unwrap()); - let ctx = KernelContext { - location: location.clone(), + let mut ctx = KernelContext::new( + location.clone(), state, document, - }; + ); let mut reports = vec![]; - kernel.run_with_context(ctx, |lua| { + kernel.run_with_context(&mut ctx, |lua| { let chunk = lua.load(self.start.as_str()); if let Err(err) = chunk.eval::<()>() { report_err!( @@ -85,14 +86,14 @@ impl CustomStyle for LuaCustomStyle { ) -> Vec { let kernel: Ref<'_, Kernel> = Ref::map(state.shared.kernels.borrow(), |b| b.get("main").unwrap()); - let ctx = KernelContext { - location: location.clone(), + let mut ctx = KernelContext::new( + location.clone(), state, document, - }; + ); let mut reports = vec![]; - kernel.run_with_context(ctx, |lua| { + kernel.run_with_context(&mut ctx, |lua| { let chunk = lua.load(self.end.as_str()); if let Err(err) = chunk.eval::<()>() { report_err!( @@ -336,6 +337,12 @@ impl Rule for CustomStyleRule { style.on_start(token.clone(), state, document) }; + if let Some((sems, tokens)) = + Semantics::from_source(token.source(), &state.shared.lsp) + { + sems.add(token.range.clone(), tokens.customstyle_marker); + } + (cursor.at(token.end()), unsafe { std::mem::transmute(reports) }) diff --git a/src/elements/graphviz.rs b/src/elements/graphviz.rs index 1be9d19..81d88c1 100644 --- a/src/elements/graphviz.rs +++ b/src/elements/graphviz.rs @@ -344,7 +344,7 @@ impl RegexRule for GraphRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let range = token.range; sems.add( diff --git a/src/elements/import.rs b/src/elements/import.rs index 14fe64f..5e57cab 100644 --- a/src/elements/import.rs +++ b/src/elements/import.rs @@ -180,7 +180,7 @@ impl RegexRule for ImportRule { } if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { // @import let import = diff --git a/src/elements/layout.rs b/src/elements/layout.rs index 7bd6ca0..3920c85 100644 --- a/src/elements/layout.rs +++ b/src/elements/layout.rs @@ -497,7 +497,7 @@ impl RegexRule for LayoutRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let start = matches .get(0) @@ -581,7 +581,7 @@ impl RegexRule for LayoutRule { }; if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let start = matches .get(0) @@ -668,7 +668,7 @@ impl RegexRule for LayoutRule { layout_state.stack.pop(); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let start = matches .get(0) diff --git a/src/elements/link.rs b/src/elements/link.rs index bb73678..f2f1df1 100644 --- a/src/elements/link.rs +++ b/src/elements/link.rs @@ -145,7 +145,7 @@ impl RegexRule for LinkRule { } if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { sems.add( display.range().start - 1..display.range().start, @@ -215,7 +215,7 @@ impl RegexRule for LinkRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { sems.add( matches.get(1).unwrap().end()..matches.get(1).unwrap().end() + 1, diff --git a/src/elements/list.rs b/src/elements/list.rs index 4212c51..edc01a2 100644 --- a/src/elements/list.rs +++ b/src/elements/list.rs @@ -336,7 +336,7 @@ impl Rule for ListRule { ); if let Some((sems, tokens)) = - Semantics::from_source(cursor.source.clone(), &state.shared.semantics) + Semantics::from_source(cursor.source.clone(), &state.shared.lsp) { sems.add(captures.get(1).unwrap().range(), tokens.list_bullet); if let Some(props) = captures.get(2).map(|m| m.range()) { diff --git a/src/elements/raw.rs b/src/elements/raw.rs index 7ed9300..d1898a9 100644 --- a/src/elements/raw.rs +++ b/src/elements/raw.rs @@ -210,7 +210,7 @@ impl RegexRule for RawRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let range = matches.get(0).unwrap().range(); sems.add(range.start..range.start + 2, tokens.raw_sep); diff --git a/src/elements/reference.rs b/src/elements/reference.rs index 00881c3..648551a 100644 --- a/src/elements/reference.rs +++ b/src/elements/reference.rs @@ -327,7 +327,7 @@ impl RegexRule for ReferenceRule { } if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let link = matches.get(1).unwrap().range(); sems.add(link.start - 2..link.start - 1, tokens.reference_operator); @@ -357,7 +357,7 @@ impl RegexRule for ReferenceRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let link = matches.get(1).unwrap().range(); sems.add(link.start - 2..link.start - 1, tokens.reference_operator); @@ -368,7 +368,7 @@ impl RegexRule for ReferenceRule { } if let (Some((sems, tokens)), Some(props)) = ( - Semantics::from_source(token.source(), &state.shared.semantics), + Semantics::from_source(token.source(), &state.shared.lsp), matches.get(2).map(|m| m.range()), ) { sems.add(props.start - 1..props.start, tokens.reference_props_sep); diff --git a/src/elements/script.rs b/src/elements/script.rs index 18d43d6..8da3934 100644 --- a/src/elements/script.rs +++ b/src/elements/script.rs @@ -14,6 +14,7 @@ use crate::parser::source::VirtualSource; use crate::parser::util; use crate::parser::util::escape_source; use ariadne::Fmt; +use lsp::hints::Hints; use mlua::Lua; use regex::Captures; use regex::Regex; @@ -141,14 +142,13 @@ impl RegexRule for ScriptRule { "Invalid Kernel Code".into(), span(script_range, "Kernel code is empty".into()) ); - return reports; } let execute = |lua: &Lua| { let chunk = lua.load(source.content()).set_name(kernel_name); if index == 0 - // Exec + // Exec @<>@ { if let Err(e) = chunk.exec() { report_err!( @@ -160,10 +160,9 @@ impl RegexRule for ScriptRule { format!("Kernel execution failed:\n{}", e) ) ); - return reports; } } else - // Eval + // Eval %<>% { // Validate kind let kind = match matches.get(2) { @@ -177,7 +176,7 @@ impl RegexRule for ScriptRule { "Invalid Kernel Code Kind".into(), span(kind.range(), msg) ); - return reports; + return; } }, }; @@ -246,18 +245,18 @@ impl RegexRule for ScriptRule { } } } - - reports }; - let ctx = KernelContext { - location: Token::new(0..source.content().len(), source.clone()), + let mut ctx = KernelContext::new( + Token::new(0..source.content().len(), source.clone()), state, document, - }; + ); + + kernel.run_with_context(&mut ctx, execute); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let range = matches .get(0) @@ -288,7 +287,21 @@ impl RegexRule for ScriptRule { } sems.add(range.end - 2..range.end, tokens.script_sep); } - kernel.run_with_context(ctx, execute) + + if let Some(hints) = Hints::from_source(token.source(), &state.shared.lsp) + { + let mut label = String::new(); + ctx.redirects.iter() + .for_each(|redir| { + label += format!("{}: {} ", redir.source, redir.content).as_str(); + }); + if !label.is_empty() + { + label.pop(); + hints.add(matches.get(0).unwrap().end(), label); + } + } + reports } } diff --git a/src/elements/section.rs b/src/elements/section.rs index 8e3901e..ca6b75f 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -336,7 +336,7 @@ impl RegexRule for SectionRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { sems.add(matches.get(1).unwrap().range(), tokens.section_heading); if let Some(reference) = matches.get(2) { diff --git a/src/elements/style.rs b/src/elements/style.rs index b3bb5b7..6e6cecb 100644 --- a/src/elements/style.rs +++ b/src/elements/style.rs @@ -196,7 +196,7 @@ impl RegexRule for StyleRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { sems.add(token.start()..token.end(), tokens.style_marker); } diff --git a/src/elements/tex.rs b/src/elements/tex.rs index 0762b92..cbc3baa 100644 --- a/src/elements/tex.rs +++ b/src/elements/tex.rs @@ -425,7 +425,7 @@ impl RegexRule for TexRule { ); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let range = token.range; sems.add( diff --git a/src/elements/variable.rs b/src/elements/variable.rs index a1fbd6e..b76a261 100644 --- a/src/elements/variable.rs +++ b/src/elements/variable.rs @@ -254,7 +254,7 @@ impl RegexRule for VariableRule { } if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let name = matches.get(2).unwrap().range(); if let Some(kind) = matches.get(1).map(|m| m.range()) { @@ -426,7 +426,7 @@ impl RegexRule for VariableSubstitutionRule { variable.parse(state, token.clone(), document); if let Some((sems, tokens)) = - Semantics::from_source(token.source(), &state.shared.semantics) + Semantics::from_source(token.source(), &state.shared.lsp) { let name = matches.get(1).unwrap().range(); sems.add(name.start - 1..name.start, tokens.variable_sub_sep); diff --git a/src/lsp/data.rs b/src/lsp/data.rs new file mode 100644 index 0000000..ecbad75 --- /dev/null +++ b/src/lsp/data.rs @@ -0,0 +1,25 @@ +use std::collections::HashMap; +use std::rc::Rc; + +use crate::parser::source::Source; + +use super::hints::HintsData; +use super::semantic::SemanticsData; +use super::semantic::Tokens; + +#[derive(Debug)] +pub struct LSPData { + pub semantic_tokens: Tokens, + pub semantic_data: HashMap, SemanticsData>, + pub inlay_hints: HashMap, HintsData>, +} + +impl LSPData { + pub fn new() -> Self { + Self { + semantic_tokens: Tokens::new(), + semantic_data: HashMap::new(), + inlay_hints: HashMap::new(), + } + } +} diff --git a/src/lsp/hints.rs b/src/lsp/hints.rs new file mode 100644 index 0000000..c8168d7 --- /dev/null +++ b/src/lsp/hints.rs @@ -0,0 +1,102 @@ +use std::{cell::{Ref, RefCell}, rc::Rc}; + +use tower_lsp::lsp_types::InlayHint; + +use crate::parser::source::{LineCursor, Source, SourceFile, VirtualSource}; + +use super::data::LSPData; + +/// Per file hints +#[derive(Debug)] +pub struct HintsData +{ + /// The current cursor + cursor: RefCell, + + /// The hints + pub hints: RefCell>, +} + +impl HintsData { + pub fn new(source: Rc) -> Self { + Self { + cursor: RefCell::new(LineCursor::new(source)), + hints: RefCell::new(vec![]), + } + } +} + +#[derive(Debug)] +pub struct Hints<'a> { + pub(self) hints: Ref<'a, HintsData>, + // The source used when resolving the parent source + pub(self) original_source: Rc, + /// The resolved parent source + pub(self) source: Rc, +} + +impl<'a> Hints<'a> { + fn from_source_impl( + source: Rc, + lsp: &'a Option>, + original_source: Rc, + ) -> Option { + if source.name().starts_with(":LUA:") && source.downcast_ref::().is_some() { + return None; + } + + if let Some(location) = source + .clone() + .downcast_rc::() + .ok() + .as_ref() + .map(|parent| parent.location()) + .unwrap_or(None) + { + return Self::from_source_impl(location.source(), lsp, original_source); + } else if let Ok(source) = source.clone().downcast_rc::() { + return Ref::filter_map( + lsp.as_ref().unwrap().borrow(), + |lsp: &LSPData| { + lsp.inlay_hints.get(&(source.clone() as Rc)) + }, + ) + .ok() + .map(|hints| { + Self { + hints, + source, + original_source, + } + }); + } + None + } + + pub fn from_source( + source: Rc, + lsp: &'a Option>, + ) -> Option { + if lsp.is_none() { + return None; + } + Self::from_source_impl(source.clone(), lsp, source) + } + + pub fn add(&self, position: usize, label: String) + { + let mut cursor = self.hints.cursor.borrow_mut(); + cursor.move_to(position); + + self.hints.hints.borrow_mut().push(InlayHint { + position: tower_lsp::lsp_types::Position { line: cursor.line as u32, character: cursor.line_pos as u32 }, + label: tower_lsp::lsp_types::InlayHintLabel::String(label), + kind: Some(tower_lsp::lsp_types::InlayHintKind::PARAMETER), + text_edits: None, + tooltip: None, + padding_left: None, + padding_right: None, + data: None, + }) + } +} diff --git a/src/lsp/mod.rs b/src/lsp/mod.rs index 515416e..648ce42 100644 --- a/src/lsp/mod.rs +++ b/src/lsp/mod.rs @@ -1 +1,3 @@ pub mod semantic; +pub mod data; +pub mod hints; diff --git a/src/lsp/semantic.rs b/src/lsp/semantic.rs index cd30bf4..aff4359 100644 --- a/src/lsp/semantic.rs +++ b/src/lsp/semantic.rs @@ -1,6 +1,5 @@ use std::cell::Ref; use std::cell::RefCell; -use std::collections::HashMap; use std::ops::Range; use std::rc::Rc; @@ -14,6 +13,8 @@ use crate::parser::source::SourceFile; use crate::parser::source::SourcePosition; use crate::parser::source::VirtualSource; +use super::data::LSPData; + pub const TOKEN_TYPE: &[SemanticTokenType] = &[ SemanticTokenType::NAMESPACE, SemanticTokenType::TYPE, @@ -102,6 +103,8 @@ pub struct Tokens { pub style_marker: (u32, u32), + pub customstyle_marker: (u32, u32), + pub import_import: (u32, u32), pub import_as_sep: (u32, u32), pub import_as: (u32, u32), @@ -179,6 +182,8 @@ impl Tokens { style_marker: token!("operator"), + customstyle_marker: token!("operator"), + import_import: token!("macro"), import_as_sep: token!("operator"), import_as: token!("operator"), @@ -264,7 +269,7 @@ impl SemanticsData { #[derive(Debug)] pub struct Semantics<'a> { pub(self) sems: Ref<'a, SemanticsData>, - // TODO + // The source used when resolving the parent source pub(self) original_source: Rc, /// The resolved parent source pub(self) source: Rc, @@ -273,7 +278,7 @@ pub struct Semantics<'a> { impl<'a> Semantics<'a> { fn from_source_impl( source: Rc, - semantics: &'a Option>, + lsp: &'a Option>, original_source: Rc, ) -> Option<(Self, Ref<'a, Tokens>)> { if source.name().starts_with(":LUA:") && source.downcast_ref::().is_some() { @@ -288,12 +293,12 @@ impl<'a> Semantics<'a> { .map(|parent| parent.location()) .unwrap_or(None) { - return Self::from_source_impl(location.source(), semantics, original_source); + return Self::from_source_impl(location.source(), lsp, original_source); } else if let Ok(source) = source.clone().downcast_rc::() { return Ref::filter_map( - semantics.as_ref().unwrap().borrow(), - |semantics: &SemanticsHolder| { - semantics.sems.get(&(source.clone() as Rc)) + lsp.as_ref().unwrap().borrow(), + |lsp: &LSPData| { + lsp.semantic_data.get(&(source.clone() as Rc)) }, ) .ok() @@ -305,8 +310,8 @@ impl<'a> Semantics<'a> { original_source, }, Ref::map( - semantics.as_ref().unwrap().borrow(), - |semantics: &SemanticsHolder| &semantics.tokens, + lsp.as_ref().unwrap().borrow(), + |lsp: &LSPData| &lsp.semantic_tokens, ), ) }); @@ -316,12 +321,12 @@ impl<'a> Semantics<'a> { pub fn from_source( source: Rc, - semantics: &'a Option>, + lsp: &'a Option>, ) -> Option<(Self, Ref<'a, Tokens>)> { - if semantics.is_none() { + if lsp.is_none() { return None; } - Self::from_source_impl(source.clone(), semantics, source) + Self::from_source_impl(source.clone(), lsp, source) } pub fn add(&self, range: Range, token: (u32, u32)) { @@ -365,42 +370,27 @@ impl<'a> Semantics<'a> { } } -#[derive(Debug)] -pub struct SemanticsHolder { - pub tokens: Tokens, - pub sems: HashMap, SemanticsData>, -} - -impl SemanticsHolder { - pub fn new() -> Self { - Self { - tokens: Tokens::new(), - sems: HashMap::new(), - } - } -} - #[cfg(test)] pub mod tests { #[macro_export] macro_rules! validate_semantics { ($state:expr, $source:expr, $idx:expr,) => {}; ($state:expr, $source:expr, $idx:expr, $token_name:ident { $($field:ident == $value:expr),* }; $($tail:tt)*) => {{ - let token = $state.shared.semantics + let token = $state.shared.lsp .as_ref() .unwrap() .borrow() - .sems + .semantic_data .get(&($source as std::rc::Rc)) .unwrap() .tokens .borrow() [$idx]; - let token_type = $state.shared.semantics + let token_type = $state.shared.lsp .as_ref() .unwrap() .borrow() - .tokens + .semantic_tokens .$token_name; let found_token = (token.token_type, token.token_modifiers_bitset); diff --git a/src/lua/kernel.rs b/src/lua/kernel.rs index d2b6e8b..7712fb0 100644 --- a/src/lua/kernel.rs +++ b/src/lua/kernel.rs @@ -8,14 +8,32 @@ use crate::parser::parser::Parser; use crate::parser::parser::ParserState; use crate::parser::source::Token; + +/// Redirected data from lua execution +pub struct KernelRedirect +{ + /// Message source e.g print() + pub source: String, + /// Message content + pub content: String, +} + pub struct KernelContext<'a, 'b, 'c> { pub location: Token, pub state: &'a ParserState<'a, 'b>, pub document: &'c dyn Document<'c>, + pub redirects: Vec, } +impl<'a, 'b, 'c> KernelContext<'a, 'b, 'c> { + pub fn new(location: Token, state: &'a ParserState<'a, 'b>, document: &'c dyn Document<'c>) -> Self { + Self { location, state, document, redirects: vec![] } + } +} + + thread_local! { - pub static CTX: RefCell>> = const { RefCell::new(None) }; + pub static CTX: RefCell>> = const { RefCell::new(None) }; } #[derive(Debug)] @@ -42,6 +60,18 @@ impl Kernel { lua.globals().set("nml", nml_table).unwrap(); } + lua.globals().set("print", lua.create_function(|_, msg: String| { + CTX.with_borrow_mut(|ctx| { + ctx.as_mut().map(|ctx| { + ctx.redirects.push(KernelRedirect { + source: "print".into(), + content: msg, + }); + }); + }); + Ok(()) + }).unwrap()).unwrap(); + Self { lua } } @@ -49,10 +79,11 @@ impl Kernel { /// /// This is the only way lua code shoule be ran, because exported /// functions may require the context in order to operate - pub fn run_with_context(&self, context: KernelContext, f: F) -> T + pub fn run_with_context(&self, context: &mut KernelContext, f: F) -> T where F: FnOnce(&Lua) -> T, { + // Redirects CTX.set(Some(unsafe { std::mem::transmute(context) })); let ret = f(&self.lua); CTX.set(None); diff --git a/src/parser/langparser.rs b/src/parser/langparser.rs index 6f2e382..d7e8c7e 100644 --- a/src/parser/langparser.rs +++ b/src/parser/langparser.rs @@ -5,6 +5,7 @@ use crate::document::document::Document; use crate::document::element::DocumentEnd; use crate::document::langdocument::LangDocument; use crate::elements::text::Text; +use crate::lsp::hints::HintsData; use crate::lsp::semantic::SemanticsData; use super::parser::ParseMode; @@ -81,16 +82,20 @@ impl<'b> Parser for LangParser<'b> { ) -> (Box + 'doc>, ParserState<'p, 'a>) { let doc = LangDocument::new(source.clone(), parent); - // Insert semantics into state - if let (Some(_), Some(semantics)) = ( + // Insert lsp data into state + if let (Some(_), Some(lsp)) = ( source.clone().downcast_rc::().ok(), - state.shared.semantics.as_ref(), + state.shared.lsp.as_ref(), ) { - let mut b = semantics.borrow_mut(); - if !b.sems.contains_key(&source) { - b.sems + let mut b = lsp.borrow_mut(); + if !b.semantic_data.contains_key(&source) { + b.semantic_data .insert(source.clone(), SemanticsData::new(source.clone())); } + if !b.inlay_hints.contains_key(&source) { + b.inlay_hints + .insert(source.clone(), HintsData::new(source.clone())); + } } let content = source.content(); diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 42c71a7..159ddf4 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -17,7 +17,7 @@ use crate::document::element::ContainerElement; use crate::document::element::ElemKind; use crate::document::element::Element; use crate::elements::paragraph::Paragraph; -use crate::lsp::semantic::SemanticsHolder; +use crate::lsp::data::LSPData; use crate::lua::kernel::Kernel; use crate::lua::kernel::KernelHolder; use ariadne::Color; @@ -66,8 +66,8 @@ pub struct SharedState { /// The custom styles pub custom_styles: RefCell, - /// The semantics - pub semantics: Option>, + /// The lsp data + pub lsp: Option>, } impl SharedState { @@ -79,7 +79,7 @@ impl SharedState { styles: RefCell::new(StyleHolder::default()), layouts: RefCell::new(LayoutHolder::default()), custom_styles: RefCell::new(CustomStyleHolder::default()), - semantics: enable_semantics.then_some(RefCell::new(SemanticsHolder::new())), + lsp: enable_semantics.then_some(RefCell::new(LSPData::new())), }; // Register default kernel diff --git a/src/server.rs b/src/server.rs index f590c3f..696c5d6 100644 --- a/src/server.rs +++ b/src/server.rs @@ -27,6 +27,7 @@ struct Backend { document_map: DashMap, semantic_token_map: DashMap>, diagnostic_map: DashMap>, + hints_map: DashMap>, } #[derive(Debug)] @@ -47,10 +48,13 @@ impl Backend { params.text.clone(), None, )); + + // Diagnostics self.diagnostic_map.clear(); let parser = LangParser::new(false, Box::new( |_colors, reports| Report::reports_to_diagnostics(&self.diagnostic_map, reports) )); + // Parse let (_doc, state) = parser.parse( ParserState::new_with_semantics(&parser, None), source.clone(), @@ -58,9 +62,10 @@ impl Backend { ParseMode::default(), ); - if let Some(sems) = state.shared.semantics.as_ref() { - let borrow = sems.borrow(); - for (source, sem) in &borrow.sems { + // Semantics + if let Some(lsp) = state.shared.lsp.as_ref() { + let borrow = lsp.borrow(); + for (source, sem) in &borrow.semantic_data { if let Some(path) = source .clone() .downcast_rc::() @@ -72,6 +77,22 @@ impl Backend { } } } + + // Hints + if let Some(lsp) = state.shared.lsp.as_ref() { + let borrow = lsp.borrow(); + for (source, hints) in &borrow.inlay_hints { + if let Some(path) = source + .clone() + .downcast_rc::() + .ok() + .map(|source| source.path().to_owned()) + { + self.hints_map + .insert(path, hints.hints.replace(vec![])); + } + } + } } } @@ -127,6 +148,7 @@ impl LanguageServer for Backend { work_done_progress_options: WorkDoneProgressOptions::default(), }) ), + inlay_hint_provider: Some(OneOf::Left(true)), ..ServerCapabilities::default() }, server_info: Some(ServerInfo { @@ -181,12 +203,12 @@ impl LanguageServer for Backend { &self, params: SemanticTokensParams, ) -> tower_lsp::jsonrpc::Result> { - let uri = params.text_document.uri.to_string(); + let uri = params.text_document.uri; self.client .log_message(MessageType::LOG, "semantic_token_full") .await; - if let Some(semantic_tokens) = self.semantic_token_map.get(&uri) { + if let Some(semantic_tokens) = self.semantic_token_map.get(uri.as_str()) { let data = semantic_tokens .iter() .filter_map(|token| Some(token.clone())) @@ -218,6 +240,17 @@ impl LanguageServer for Backend { ) ) } + + async fn inlay_hint(&self, params: InlayHintParams) -> tower_lsp::jsonrpc::Result>> + { + if let Some(hints) = self.hints_map.get(params.text_document.uri.as_str()) + { + let (_, data) = hints.pair(); + + return Ok(Some(data.to_owned())); + } + Ok(None) + } } #[tokio::main] @@ -230,6 +263,7 @@ async fn main() { document_map: DashMap::new(), semantic_token_map: DashMap::new(), diagnostic_map: DashMap::new(), + hints_map: DashMap::new(), }); Server::new(stdin, stdout, socket).serve(service).await; }