use tower_lsp and start on caching
This commit is contained in:
parent
5b12d75c47
commit
c04db217e1
|
@ -0,0 +1,73 @@
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
struct Position {
|
||||||
|
line: u32,
|
||||||
|
character: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
struct Range {
|
||||||
|
from: Position,
|
||||||
|
to: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
struct CachedScope {
|
||||||
|
range: Range,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
pub struct CachedItems {
|
||||||
|
global_tokens: Vec<String>,
|
||||||
|
scopes: Vec<CachedScope>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DocumentCache {
|
||||||
|
pub documents: DashMap<PathBuf, CachedItems>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct FileNotInCache;
|
||||||
|
|
||||||
|
impl DocumentCache {
|
||||||
|
pub fn new() -> DocumentCache {
|
||||||
|
DocumentCache {
|
||||||
|
documents: DashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_document(&self, path: PathBuf, items: CachedItems) {
|
||||||
|
self.documents.insert(path, items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::cache::{CachedItems, DocumentCache};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert() {
|
||||||
|
let mut d = DocumentCache::new(Path::new("/example/workdir").to_path_buf());
|
||||||
|
d.update_document(
|
||||||
|
Path::new("example_file.ext").to_path_buf(),
|
||||||
|
CachedItems {
|
||||||
|
global_tokens: vec![],
|
||||||
|
scopes: vec![],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let mut comp = HashMap::new();
|
||||||
|
comp.insert(
|
||||||
|
Path::new("example_file.ext").to_path_buf(),
|
||||||
|
CachedItems {
|
||||||
|
global_tokens: vec![],
|
||||||
|
scopes: vec![],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert_eq!(d.documents, comp)
|
||||||
|
}
|
||||||
|
}
|
173
src/main.rs
173
src/main.rs
|
@ -1,21 +1,172 @@
|
||||||
use std::{env, fs};
|
mod cache;
|
||||||
|
use cache::DocumentCache;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use tower_lsp::jsonrpc::{Error, ErrorCode, Result};
|
||||||
|
use tower_lsp::lsp_types::notification::Notification;
|
||||||
|
use tower_lsp::lsp_types::*;
|
||||||
|
use tower_lsp::{Client, LanguageServer, LspService, Server};
|
||||||
|
|
||||||
|
use crate::pest::Parser;
|
||||||
|
|
||||||
|
extern crate glob;
|
||||||
extern crate pest;
|
extern crate pest;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate pest_derive;
|
extern crate pest_derive;
|
||||||
|
|
||||||
use pest::Parser;
|
#[derive(Debug)]
|
||||||
|
struct Backend {
|
||||||
|
client: Client,
|
||||||
|
cache: DocumentCache,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[grammar = "skill.pest"]
|
#[grammar = "./skill.pest"]
|
||||||
pub struct SkillParser;
|
struct SkillParser;
|
||||||
|
|
||||||
fn main() {
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
let mut args: Vec<String> = env::args().collect();
|
struct CustomNotificationParams {
|
||||||
let data = fs::read_to_string(args[1].as_mut_str()).expect("could not read from file");
|
title: String,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomNotificationParams {
|
||||||
let parse = SkillParser::parse(Rule::skill, data.as_str()).expect("ha").next().unwrap();
|
fn new(title: impl Into<String>, message: impl Into<String>) -> Self {
|
||||||
for inner in parse.into_inner() {
|
CustomNotificationParams {
|
||||||
println!("{:?}: {:?}", inner.as_rule(), inner);
|
title: title.into(),
|
||||||
|
message: message.into(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CustomNotification {}
|
||||||
|
|
||||||
|
impl Notification for CustomNotification {
|
||||||
|
type Params = CustomNotificationParams;
|
||||||
|
|
||||||
|
const METHOD: &'static str = "custom/notification";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tower_lsp::async_trait]
|
||||||
|
impl LanguageServer for Backend {
|
||||||
|
async fn initialize(&self, init_params: InitializeParams) -> Result<InitializeResult> {
|
||||||
|
let root = init_params
|
||||||
|
.root_uri
|
||||||
|
.ok_or(Error::new(ErrorCode::InvalidParams))?;
|
||||||
|
self.client
|
||||||
|
.log_message(
|
||||||
|
MessageType::INFO,
|
||||||
|
format!("server initializing! ({:?})", root.path()),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let pattern = root.path().to_string() + "/**/*.il";
|
||||||
|
self.client
|
||||||
|
.log_message(MessageType::INFO, format!("pattern used: {:?}", pattern))
|
||||||
|
.await;
|
||||||
|
for entry in glob::glob(pattern.as_str()).expect("no file to cache in root_dir") {
|
||||||
|
match entry {
|
||||||
|
Ok(path) => {
|
||||||
|
self.client
|
||||||
|
.log_message(MessageType::INFO, format!("caching {:?}", path.display()))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(InitializeResult {
|
||||||
|
server_info: None,
|
||||||
|
capabilities: ServerCapabilities {
|
||||||
|
execute_command_provider: Some(ExecuteCommandOptions {
|
||||||
|
commands: vec!["custom/notification".to_string()],
|
||||||
|
work_done_progress_options: Default::default(),
|
||||||
|
}),
|
||||||
|
completion_provider: Some(CompletionOptions {
|
||||||
|
resolve_provider: Some(false),
|
||||||
|
trigger_characters: Some(vec!["(".to_string()]),
|
||||||
|
work_done_progress_options: Default::default(),
|
||||||
|
all_commit_characters: None,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..ServerCapabilities::default()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn initialized(&self, _: InitializedParams) {
|
||||||
|
self.client
|
||||||
|
.log_message(MessageType::INFO, "server initialized!")
|
||||||
|
.await;
|
||||||
|
self.client
|
||||||
|
.send_notification::<CustomNotification>(CustomNotificationParams::new(
|
||||||
|
"title", "message",
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn shutdown(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute_command(&self, params: ExecuteCommandParams) -> Result<Option<Value>> {
|
||||||
|
if params.command == "custom.notification" {
|
||||||
|
self.client
|
||||||
|
.send_notification::<CustomNotification>(CustomNotificationParams::new(
|
||||||
|
"Hello", "Message",
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
self.client
|
||||||
|
.log_message(
|
||||||
|
MessageType::INFO,
|
||||||
|
format!("Command executed with params: {params:?}"),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(Error::invalid_request())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn completion(&self, cparams: CompletionParams) -> Result<Option<CompletionResponse>> {
|
||||||
|
let doc = cparams.text_document_position.text_document.uri.path();
|
||||||
|
// let line = cparams.text_document_position.position.line;
|
||||||
|
// let character = cparams.text_document_position.position.character;
|
||||||
|
let content = fs::read_to_string(doc).expect("could not read");
|
||||||
|
let file = SkillParser::parse(Rule::skill, &content)
|
||||||
|
.expect("unsuccessful parse")
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut symbols: Vec<CompletionItem> = vec![];
|
||||||
|
|
||||||
|
for record in file.into_inner() {
|
||||||
|
match record.as_rule() {
|
||||||
|
Rule::assign => symbols.push(CompletionItem {
|
||||||
|
label: record.into_inner().next().unwrap().as_str().to_string(),
|
||||||
|
kind: Some(CompletionItemKind::VARIABLE),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some(CompletionResponse::Array(symbols)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
tracing_subscriber::fmt().init();
|
||||||
|
|
||||||
|
let (stdin, stdout) = (tokio::io::stdin(), tokio::io::stdout());
|
||||||
|
|
||||||
|
let (service, socket) = LspService::new(|client| Backend {
|
||||||
|
client,
|
||||||
|
cache: DocumentCache::new(),
|
||||||
|
});
|
||||||
|
Server::new(stdin, stdout, socket).serve(service).await;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue