diff --git a/src/elements/style.rs b/src/elements/style.rs index da21a5f..723125e 100644 --- a/src/elements/style.rs +++ b/src/elements/style.rs @@ -14,6 +14,7 @@ use crate::parser::source::Token; use crate::parser::state::RuleState; use crate::parser::state::Scope; use ariadne::Fmt; +use lsp::styles::Styles; use mlua::Function; use regex::Captures; use regex::Regex; @@ -188,6 +189,8 @@ impl RegexRule for StyleRule { }; if let Some(style_state) = style_state.borrow_mut().downcast_mut::() { + let start = style_state.toggled[index].clone(); + style_state.toggled[index] = style_state.toggled[index] .clone() .map_or(Some(token.clone()), |_| None); @@ -200,6 +203,22 @@ impl RegexRule for StyleRule { )), ); + if let Some(start) = start + { + if let Some(styles) = + Styles::from_source(token.source(), &state.shared.lsp) + { + match index + { + 0 => styles.add(start.start()..token.end(), crate::lsp::styles::Style::Style("bold".into())), + 1 => styles.add(start.start()..token.end(), crate::lsp::styles::Style::Style("italic".into())), + 2 => styles.add(start.start()..token.end(), crate::lsp::styles::Style::Style("underlined".into())), + _ => {}, + } + } + } + + // Style if let Some((sems, tokens)) = Semantics::from_source(token.source(), &state.shared.lsp) { sems.add(token.start()..token.end(), tokens.style_marker); diff --git a/src/lsp/conceal.rs b/src/lsp/conceal.rs index 2ae0363..5aecf5b 100644 --- a/src/lsp/conceal.rs +++ b/src/lsp/conceal.rs @@ -5,8 +5,6 @@ use std::rc::Rc; use serde::Deserialize; use serde::Serialize; -use tower_lsp::jsonrpc::Request; -use tower_lsp::jsonrpc::{self}; use tower_lsp::lsp_types::Position; use crate::parser::source::LineCursor; diff --git a/src/lsp/data.rs b/src/lsp/data.rs index c933620..a52b486 100644 --- a/src/lsp/data.rs +++ b/src/lsp/data.rs @@ -8,6 +8,7 @@ use super::definition::DefinitionData; use super::hints::HintsData; use super::semantic::SemanticsData; use super::semantic::Tokens; +use super::styles::StylesData; #[derive(Debug)] pub struct LSPData { @@ -16,6 +17,7 @@ pub struct LSPData { pub inlay_hints: HashMap, HintsData>, pub definitions: HashMap, DefinitionData>, pub conceals: HashMap, ConcealsData>, + pub styles: HashMap, StylesData>, } impl LSPData { @@ -26,6 +28,7 @@ impl LSPData { inlay_hints: HashMap::new(), definitions: HashMap::new(), conceals: HashMap::new(), + styles: HashMap::new(), } } @@ -47,5 +50,9 @@ impl LSPData { self.conceals .insert(source.clone(), ConcealsData::new(source.clone())); } + if !self.styles.contains_key(&source) { + self.styles + .insert(source.clone(), StylesData::new(source.clone())); + } } } diff --git a/src/lsp/mod.rs b/src/lsp/mod.rs index 082719d..55fe775 100644 --- a/src/lsp/mod.rs +++ b/src/lsp/mod.rs @@ -3,3 +3,4 @@ pub mod definition; pub mod hints; pub mod semantic; pub mod conceal; +pub mod styles; diff --git a/src/lsp/styles.rs b/src/lsp/styles.rs new file mode 100644 index 0000000..99d3752 --- /dev/null +++ b/src/lsp/styles.rs @@ -0,0 +1,126 @@ +use std::{cell::{Ref, RefCell}, ops::Range, rc::Rc}; + +use serde::{Deserialize, Serialize}; +use tower_lsp::lsp_types::Position; + +use crate::parser::source::{LineCursor, Source, SourceFile, SourcePosition, VirtualSource}; + +use super::data::LSPData; + + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct StyleParams { + pub text_document: tower_lsp::lsp_types::TextDocumentIdentifier, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct StyleInfo { + pub range: tower_lsp::lsp_types::Range, + pub style: Style, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum Style { + Color(u32), + Style(String), + Full { + color: u32, + style: String, + } +} + +/// Per file styles +#[derive(Debug)] +pub struct StylesData { + /// The styles + pub styles: RefCell>, +} + +impl StylesData { + pub fn new(source: Rc) -> Self { + Self { + styles: RefCell::new(vec![]), + } + } +} + +/// Temporary data returned by [`Self::from_source_impl`] +#[derive(Debug)] +pub struct Styles<'a> { + pub(self) styles: Ref<'a, StylesData>, + // The source used when resolving the parent source + pub(self) original_source: Rc, + /// The resolved parent source + pub(self) source: Rc, +} + +impl<'a> Styles<'a> { + fn from_source_impl( + source: Rc, + lsp: &'a Option>, + original_source: Rc, + ) -> Option { + if (source.name().starts_with(":LUA:") || source.name().starts_with(":VAR:")) + && 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.styles.get(&(source.clone() as Rc)) + }) + .ok() + .map(|styles| Self { + styles, + 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, range: Range, style: Style) { + let range = self.original_source.original_range(range).1; + let mut cursor = LineCursor::new(self.original_source.clone()); + cursor.move_to(range.start); + + let line = cursor.line; + let start_char = cursor.line_pos; + + cursor.move_to(range.end); + assert_eq!(line, cursor.line); + let end_char = cursor.line_pos; + + self.styles.styles.borrow_mut().push(StyleInfo { + range: tower_lsp::lsp_types::Range { + start: Position { + line: line as u32, + character: start_char as u32, + }, + end: Position { + line: line as u32, + character: end_char as u32, + }, + }, + style, + }) + } +} diff --git a/src/server.rs b/src/server.rs index 1dea4c6..3f364bf 100644 --- a/src/server.rs +++ b/src/server.rs @@ -9,10 +9,10 @@ mod parser; use std::rc::Rc; use dashmap::DashMap; -use downcast_rs::Downcast; use lsp::conceal::ConcealInfo; use lsp::conceal::ConcealParams; -use lsp::conceal::ConcealTarget; +use lsp::styles::StyleInfo; +use lsp::styles::StyleParams; use parser::langparser::LangParser; use parser::parser::ParseMode; use parser::parser::Parser; @@ -35,6 +35,7 @@ struct Backend { diagnostic_map: DashMap>, hints_map: DashMap>, conceals_map: DashMap>, + styles_map: DashMap>, } #[derive(Debug)] @@ -72,9 +73,10 @@ impl Backend { ParseMode::default(), ); - // Semantics if let Some(lsp) = state.shared.lsp.as_ref() { let borrow = lsp.borrow(); + + // Semantics for (source, sem) in &borrow.semantic_data { if let Some(path) = source .clone() @@ -86,11 +88,8 @@ impl Backend { .insert(path, sem.tokens.replace(vec![])); } } - } - // Hints - if let Some(lsp) = state.shared.lsp.as_ref() { - let borrow = lsp.borrow(); + // Inlay hints for (source, hints) in &borrow.inlay_hints { if let Some(path) = source .clone() @@ -101,11 +100,8 @@ impl Backend { self.hints_map.insert(path, hints.hints.replace(vec![])); } } - } - // Definitions - if let Some(lsp) = state.shared.lsp.as_ref() { - let borrow = lsp.borrow(); + // Definitions for (source, definitions) in &borrow.definitions { if let Some(path) = source .clone() @@ -117,11 +113,8 @@ impl Backend { .insert(path, definitions.definitions.replace(vec![])); } } - } - // Conceals - if let Some(lsp) = state.shared.lsp.as_ref() { - let borrow = lsp.borrow(); + // Conceals for (source, conceals) in &borrow.conceals { if let Some(path) = source .clone() @@ -133,6 +126,19 @@ impl Backend { .insert(path, conceals.conceals.replace(vec![])); } } + + // Styles + for (source, styles) in &borrow.styles { + if let Some(path) = source + .clone() + .downcast_rc::() + .ok() + .map(|source| source.path().to_owned()) + { + self.styles_map + .insert(path, styles.styles.replace(vec![])); + } + } } } @@ -140,11 +146,21 @@ impl Backend { &self, params: ConcealParams, ) -> jsonrpc::Result> { - eprintln!("HERE {:#?}", self.conceals_map); if let Some(conceals) = self.conceals_map.get(params.text_document.uri.as_str()) { let (_, data) = conceals.pair(); - eprintln!("HERE2"); + return Ok(data.to_vec()); + } + Ok(vec![]) + } + + async fn handle_style_request( + &self, + params: StyleParams, + ) -> jsonrpc::Result> { + if let Some(styles) = self.styles_map.get(params.text_document.uri.as_str()) { + let (_, data) = styles.pair(); + return Ok(data.to_vec()); } Ok(vec![]) @@ -357,8 +373,10 @@ async fn main() { diagnostic_map: DashMap::new(), hints_map: DashMap::new(), conceals_map: DashMap::new(), + styles_map: DashMap::new(), }) .custom_method("textDocument/conceal", Backend::handle_conceal_request) + .custom_method("textDocument/style", Backend::handle_style_request) .finish(); Server::new(stdin, stdout, socket).serve(service).await;