Add styles support

This commit is contained in:
ef3d0c3e 2024-12-05 11:05:45 +01:00
parent 0fddb56b03
commit f99a51e73a
6 changed files with 188 additions and 19 deletions

View file

@ -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::<StyleState>() {
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);

View file

@ -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;

View file

@ -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<Rc<dyn Source>, HintsData>,
pub definitions: HashMap<Rc<dyn Source>, DefinitionData>,
pub conceals: HashMap<Rc<dyn Source>, ConcealsData>,
pub styles: HashMap<Rc<dyn Source>, 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()));
}
}
}

View file

@ -3,3 +3,4 @@ pub mod definition;
pub mod hints;
pub mod semantic;
pub mod conceal;
pub mod styles;

126
src/lsp/styles.rs Normal file
View file

@ -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<Vec<StyleInfo>>,
}
impl StylesData {
pub fn new(source: Rc<dyn Source>) -> 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<dyn Source>,
/// The resolved parent source
pub(self) source: Rc<dyn Source>,
}
impl<'a> Styles<'a> {
fn from_source_impl(
source: Rc<dyn Source>,
lsp: &'a Option<RefCell<LSPData>>,
original_source: Rc<dyn Source>,
) -> Option<Self> {
if (source.name().starts_with(":LUA:") || source.name().starts_with(":VAR:"))
&& source.downcast_ref::<VirtualSource>().is_some()
{
return None;
}
if let Some(location) = source
.clone()
.downcast_rc::<VirtualSource>()
.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::<SourceFile>() {
return Ref::filter_map(lsp.as_ref().unwrap().borrow(), |lsp: &LSPData| {
lsp.styles.get(&(source.clone() as Rc<dyn Source>))
})
.ok()
.map(|styles| Self {
styles,
source,
original_source,
});
}
None
}
pub fn from_source(source: Rc<dyn Source>, lsp: &'a Option<RefCell<LSPData>>) -> Option<Self> {
if lsp.is_none() {
return None;
}
Self::from_source_impl(source.clone(), lsp, source)
}
pub fn add(&self, range: Range<usize>, 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,
})
}
}

View file

@ -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<String, Vec<Diagnostic>>,
hints_map: DashMap<String, Vec<InlayHint>>,
conceals_map: DashMap<String, Vec<ConcealInfo>>,
styles_map: DashMap<String, Vec<StyleInfo>>,
}
#[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::<SourceFile>()
.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<Vec<ConcealInfo>> {
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<Vec<StyleInfo>> {
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;