2024-10-16 23:42:49 +02:00
|
|
|
mod cache;
|
2024-07-19 11:52:12 +02:00
|
|
|
mod compiler;
|
2024-10-16 23:42:49 +02:00
|
|
|
mod document;
|
2024-07-19 11:52:12 +02:00
|
|
|
mod elements;
|
|
|
|
mod lsp;
|
2024-10-16 23:42:49 +02:00
|
|
|
mod lua;
|
|
|
|
mod parser;
|
2024-07-19 11:52:12 +02:00
|
|
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
use dashmap::DashMap;
|
2024-07-21 15:56:56 +02:00
|
|
|
use parser::langparser::LangParser;
|
2024-10-20 19:38:15 +02:00
|
|
|
use parser::parser::ParseMode;
|
2024-07-21 15:56:56 +02:00
|
|
|
use parser::parser::Parser;
|
2024-10-16 23:42:49 +02:00
|
|
|
use parser::parser::ParserState;
|
2024-10-24 14:04:04 +02:00
|
|
|
use parser::reports::Report;
|
2024-07-21 15:56:56 +02:00
|
|
|
use parser::source::SourceFile;
|
2024-07-19 11:52:12 +02:00
|
|
|
use tower_lsp::lsp_types::*;
|
2024-10-16 23:42:49 +02:00
|
|
|
use tower_lsp::Client;
|
|
|
|
use tower_lsp::LanguageServer;
|
|
|
|
use tower_lsp::LspService;
|
|
|
|
use tower_lsp::Server;
|
2024-07-19 11:52:12 +02:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct Backend {
|
2024-10-16 23:42:49 +02:00
|
|
|
client: Client,
|
2024-07-19 11:52:12 +02:00
|
|
|
document_map: DashMap<String, String>,
|
2024-10-16 23:42:49 +02:00
|
|
|
semantic_token_map: DashMap<String, Vec<SemanticToken>>,
|
2024-10-24 14:04:04 +02:00
|
|
|
diagnostic_map: DashMap<String, Vec<Diagnostic>>,
|
2024-07-19 11:52:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct TextDocumentItem {
|
|
|
|
uri: Url,
|
|
|
|
text: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Backend {
|
|
|
|
async fn on_change(&self, params: TextDocumentItem) {
|
|
|
|
self.document_map
|
|
|
|
.insert(params.uri.to_string(), params.text.clone());
|
|
|
|
|
2024-07-21 15:56:56 +02:00
|
|
|
// TODO: Create a custom parser for the lsp
|
|
|
|
// Which will require a dyn Document to work
|
2024-10-24 10:18:49 +02:00
|
|
|
let source = Rc::new(SourceFile::with_content(
|
|
|
|
params.uri.to_string(),
|
|
|
|
params.text.clone(),
|
|
|
|
None,
|
|
|
|
));
|
2024-10-24 14:04:04 +02:00
|
|
|
self.diagnostic_map.clear();
|
|
|
|
let parser = LangParser::new(false, Box::new(
|
|
|
|
|_colors, reports| Report::reports_to_diagnostics(&self.diagnostic_map, reports)
|
|
|
|
));
|
2024-10-24 10:18:49 +02:00
|
|
|
let (_doc, state) = parser.parse(
|
|
|
|
ParserState::new_with_semantics(&parser, None),
|
|
|
|
source.clone(),
|
|
|
|
None,
|
|
|
|
ParseMode::default(),
|
|
|
|
);
|
2024-10-16 23:42:49 +02:00
|
|
|
|
2024-10-24 10:18:49 +02:00
|
|
|
if let Some(sems) = state.shared.semantics.as_ref() {
|
2024-10-19 21:35:18 +02:00
|
|
|
let borrow = sems.borrow();
|
2024-10-24 10:18:49 +02:00
|
|
|
for (source, sem) in &borrow.sems {
|
|
|
|
if let Some(path) = source
|
|
|
|
.clone()
|
|
|
|
.downcast_rc::<SourceFile>()
|
2024-10-19 21:35:18 +02:00
|
|
|
.ok()
|
|
|
|
.map(|source| source.path().to_owned())
|
|
|
|
{
|
|
|
|
self.semantic_token_map
|
|
|
|
.insert(path, sem.tokens.replace(vec![]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-21 15:56:56 +02:00
|
|
|
}
|
2024-07-19 11:52:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tower_lsp::async_trait]
|
|
|
|
impl LanguageServer for Backend {
|
2024-10-24 10:18:49 +02:00
|
|
|
async fn initialize(
|
|
|
|
&self,
|
|
|
|
_params: InitializeParams,
|
|
|
|
) -> tower_lsp::jsonrpc::Result<InitializeResult> {
|
2024-07-19 11:52:12 +02:00
|
|
|
Ok(InitializeResult {
|
|
|
|
capabilities: ServerCapabilities {
|
|
|
|
text_document_sync: Some(TextDocumentSyncCapability::Kind(
|
2024-10-16 23:42:49 +02:00
|
|
|
TextDocumentSyncKind::FULL,
|
2024-07-19 11:52:12 +02:00
|
|
|
)),
|
|
|
|
completion_provider: Some(CompletionOptions {
|
|
|
|
resolve_provider: Some(false),
|
|
|
|
trigger_characters: Some(vec!["%".to_string()]),
|
|
|
|
work_done_progress_options: Default::default(),
|
|
|
|
all_commit_characters: None,
|
|
|
|
completion_item: None,
|
|
|
|
}),
|
|
|
|
semantic_tokens_provider: Some(
|
2024-10-16 23:42:49 +02:00
|
|
|
SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
|
|
|
|
SemanticTokensRegistrationOptions {
|
|
|
|
text_document_registration_options: {
|
|
|
|
TextDocumentRegistrationOptions {
|
|
|
|
document_selector: Some(vec![DocumentFilter {
|
2024-10-18 12:43:51 +02:00
|
|
|
language: Some("nml".into()),
|
|
|
|
scheme: Some("file".into()),
|
|
|
|
pattern: Some("*.nml".into()),
|
2024-10-16 23:42:49 +02:00
|
|
|
}]),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
semantic_tokens_options: SemanticTokensOptions {
|
|
|
|
work_done_progress_options: WorkDoneProgressOptions::default(),
|
|
|
|
legend: SemanticTokensLegend {
|
2024-10-18 12:43:51 +02:00
|
|
|
token_types: lsp::semantic::TOKEN_TYPE.into(),
|
|
|
|
token_modifiers: lsp::semantic::TOKEN_MODIFIERS.into(),
|
2024-10-16 23:42:49 +02:00
|
|
|
},
|
|
|
|
range: None, //Some(true),
|
|
|
|
full: Some(SemanticTokensFullOptions::Bool(true)),
|
|
|
|
},
|
|
|
|
static_registration_options: StaticRegistrationOptions::default(),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
2024-10-24 14:04:04 +02:00
|
|
|
diagnostic_provider: Some(
|
|
|
|
DiagnosticServerCapabilities::Options(
|
|
|
|
DiagnosticOptions {
|
|
|
|
identifier: None,
|
|
|
|
inter_file_dependencies: true,
|
|
|
|
workspace_diagnostics: true,
|
|
|
|
work_done_progress_options: WorkDoneProgressOptions::default(),
|
|
|
|
})
|
|
|
|
),
|
2024-07-19 11:52:12 +02:00
|
|
|
..ServerCapabilities::default()
|
|
|
|
},
|
2024-10-19 21:35:18 +02:00
|
|
|
server_info: Some(ServerInfo {
|
|
|
|
name: "nmlls".into(),
|
2024-10-24 10:18:49 +02:00
|
|
|
version: Some("0.1".into()),
|
2024-10-19 21:35:18 +02:00
|
|
|
}),
|
2024-07-19 11:52:12 +02:00
|
|
|
})
|
2024-10-16 23:42:49 +02:00
|
|
|
}
|
2024-07-19 11:52:12 +02:00
|
|
|
|
2024-10-16 23:42:49 +02:00
|
|
|
async fn initialized(&self, _: InitializedParams) {
|
|
|
|
self.client
|
|
|
|
.log_message(MessageType::INFO, "server initialized!")
|
|
|
|
.await;
|
|
|
|
}
|
2024-07-19 11:52:12 +02:00
|
|
|
|
2024-10-24 09:54:52 +02:00
|
|
|
async fn shutdown(&self) -> tower_lsp::jsonrpc::Result<()> { Ok(()) }
|
2024-07-19 11:52:12 +02:00
|
|
|
|
|
|
|
async fn did_open(&self, params: DidOpenTextDocumentParams) {
|
|
|
|
self.client
|
|
|
|
.log_message(MessageType::INFO, "file opened!")
|
|
|
|
.await;
|
|
|
|
self.on_change(TextDocumentItem {
|
|
|
|
uri: params.text_document.uri,
|
|
|
|
text: params.text_document.text,
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn did_change(&self, mut params: DidChangeTextDocumentParams) {
|
|
|
|
self.on_change(TextDocumentItem {
|
|
|
|
uri: params.text_document.uri,
|
|
|
|
text: std::mem::take(&mut params.content_changes[0].text),
|
|
|
|
})
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2024-10-24 10:18:49 +02:00
|
|
|
async fn completion(
|
|
|
|
&self,
|
|
|
|
_params: CompletionParams,
|
|
|
|
) -> tower_lsp::jsonrpc::Result<Option<CompletionResponse>> {
|
2024-10-22 21:40:00 +02:00
|
|
|
//let uri = params.text_document_position.text_document.uri;
|
|
|
|
//let position = params.text_document_position.position;
|
2024-10-16 23:42:49 +02:00
|
|
|
let completions = || -> Option<Vec<CompletionItem>> {
|
|
|
|
let mut ret = Vec::with_capacity(0);
|
2024-07-19 11:52:12 +02:00
|
|
|
|
2024-10-16 23:42:49 +02:00
|
|
|
Some(ret)
|
|
|
|
}();
|
|
|
|
Ok(completions.map(CompletionResponse::Array))
|
|
|
|
}
|
2024-07-19 11:52:12 +02:00
|
|
|
|
|
|
|
async fn semantic_tokens_full(
|
|
|
|
&self,
|
|
|
|
params: SemanticTokensParams,
|
2024-10-24 09:54:52 +02:00
|
|
|
) -> tower_lsp::jsonrpc::Result<Option<SemanticTokensResult>> {
|
2024-07-19 11:52:12 +02:00
|
|
|
let uri = params.text_document.uri.to_string();
|
|
|
|
self.client
|
|
|
|
.log_message(MessageType::LOG, "semantic_token_full")
|
|
|
|
.await;
|
2024-07-21 15:56:56 +02:00
|
|
|
|
|
|
|
if let Some(semantic_tokens) = self.semantic_token_map.get(&uri) {
|
2024-10-16 23:42:49 +02:00
|
|
|
let data = semantic_tokens
|
|
|
|
.iter()
|
|
|
|
.filter_map(|token| Some(token.clone()))
|
2024-07-21 15:56:56 +02:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2024-07-19 11:52:12 +02:00
|
|
|
return Ok(Some(SemanticTokensResult::Tokens(SemanticTokens {
|
|
|
|
result_id: None,
|
2024-07-21 15:56:56 +02:00
|
|
|
data: data,
|
2024-07-19 11:52:12 +02:00
|
|
|
})));
|
|
|
|
}
|
|
|
|
Ok(None)
|
|
|
|
}
|
2024-10-24 14:04:04 +02:00
|
|
|
|
|
|
|
async fn diagnostic(
|
|
|
|
&self,
|
|
|
|
params: DocumentDiagnosticParams,
|
|
|
|
) -> tower_lsp::jsonrpc::Result<DocumentDiagnosticReportResult> {
|
|
|
|
Ok(
|
|
|
|
DocumentDiagnosticReportResult::Report(
|
|
|
|
DocumentDiagnosticReport::Full(
|
|
|
|
RelatedFullDocumentDiagnosticReport {
|
|
|
|
related_documents: None,
|
|
|
|
full_document_diagnostic_report: FullDocumentDiagnosticReport {
|
|
|
|
result_id: None,
|
|
|
|
items: self.diagnostic_map.get(params.text_document.uri.as_str()).map_or(vec![], |v| v.to_owned())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
2024-07-19 11:52:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
2024-10-16 23:42:49 +02:00
|
|
|
let stdin = tokio::io::stdin();
|
|
|
|
let stdout = tokio::io::stdout();
|
|
|
|
|
|
|
|
let (service, socket) = LspService::new(|client| Backend {
|
|
|
|
client,
|
|
|
|
document_map: DashMap::new(),
|
|
|
|
semantic_token_map: DashMap::new(),
|
2024-10-24 14:04:04 +02:00
|
|
|
diagnostic_map: DashMap::new(),
|
2024-10-16 23:42:49 +02:00
|
|
|
});
|
|
|
|
Server::new(stdin, stdout, socket).serve(service).await;
|
2024-07-19 11:52:12 +02:00
|
|
|
}
|