-
Notifications
You must be signed in to change notification settings - Fork 0
/
lsp.rs
122 lines (107 loc) · 3.72 KB
/
lsp.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#![cfg(feature = "lsp")]
use anyhow::{Context, Result};
use tower_lsp::lsp_types::{
Diagnostic, DiagnosticSeverity, DidChangeTextDocumentParams, DidOpenTextDocumentParams,
InitializeParams, InitializeResult, Position, Range, ServerCapabilities, ServerInfo,
TextDocumentSyncKind,
};
use tower_lsp::{jsonrpc, Client, LanguageServer, LspService, Server};
use crate::diagnose::{Diagnoser, Diagnosis, DiagnosisPosition, DiagnosisRange, DiagnosisSeverity};
#[derive(Debug)]
struct Backend {
client: Client,
}
impl Backend {
pub fn new(client: Client) -> Self {
Self { client }
}
}
#[tower_lsp::async_trait]
impl LanguageServer for Backend {
async fn initialize(&self, _: InitializeParams) -> jsonrpc::Result<InitializeResult> {
Ok(InitializeResult {
capabilities: ServerCapabilities {
text_document_sync: Some(TextDocumentSyncKind::FULL.into()),
..Default::default()
},
server_info: Some(ServerInfo {
name: env!("CARGO_PKG_NAME").to_string(),
version: Some(env!("CARGO_PKG_VERSION").to_string()),
}),
})
}
async fn shutdown(&self) -> jsonrpc::Result<()> {
Ok(())
}
async fn did_open(&self, params: DidOpenTextDocumentParams) {
let source = ¶ms.text_document.text;
let uri = params.text_document.uri;
let version = Some(params.text_document.version);
let diagnostics = Diagnoser::get_diagnostics(source);
self.client
.publish_diagnostics(
uri,
diagnostics.iter().map(|x| (*x).clone().into()).collect(),
version,
)
.await;
}
async fn did_change(&self, params: DidChangeTextDocumentParams) {
let source = ¶ms.content_changes.first().unwrap().text;
let uri = params.text_document.uri;
let version = Some(params.text_document.version);
let diagnostics = Diagnoser::get_diagnostics(source);
self.client
.publish_diagnostics(
uri,
diagnostics.iter().map(|x| (*x).clone().into()).collect(),
version,
)
.await;
}
}
impl From<Diagnosis> for Diagnostic {
fn from(value: Diagnosis) -> Self {
Diagnostic {
range: value.range.into(),
severity: value.severity.map(|x| x.into()),
message: value.message,
..Default::default()
}
}
}
impl From<DiagnosisPosition> for Position {
fn from(value: DiagnosisPosition) -> Self {
Position { line: value.line, character: value.character }
}
}
impl From<DiagnosisRange> for Range {
fn from(value: DiagnosisRange) -> Self {
Range { start: value.start.into(), end: value.end.into() }
}
}
impl From<DiagnosisSeverity> for DiagnosticSeverity {
fn from(value: DiagnosisSeverity) -> Self {
match value {
DiagnosisSeverity::ERROR => DiagnosticSeverity::ERROR,
DiagnosisSeverity::HINT => DiagnosticSeverity::HINT,
DiagnosisSeverity::INFORMATION => DiagnosticSeverity::INFORMATION,
DiagnosisSeverity::WARNING => DiagnosticSeverity::WARNING,
_ => panic!("Invalid diagnosis severity {:?}", value),
}
}
}
pub fn serve() -> Result<()> {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.context("failed to start async runtime")?
.block_on(serve_async());
Ok(())
}
async fn serve_async() {
let stdin = tokio::io::stdin();
let stdout = tokio::io::stdout();
let (service, socket) = LspService::new(Backend::new);
Server::new(stdin, stdout, socket).serve(service).await;
}