Skip to content

Instantly share code, notes, and snippets.

@sigmaSd
Last active February 2, 2024 23:32
Show Gist options
  • Save sigmaSd/8147a22054675104c70044964152381b to your computer and use it in GitHub Desktop.
Save sigmaSd/8147a22054675104c70044964152381b to your computer and use it in GitHub Desktop.
spell check lsp server
// [dependencies]
// serde_json = "1.0.96"
// lsp-types = "=0.94"
// lsp-server = "0.7.1"
use std::error::Error;
use std::io::{Read, Write};
use std::process::Stdio;
use lsp_types::{
Diagnostic, DiagnosticSeverity, DidChangeTextDocumentParams, Position,
PublishDiagnosticsParams, Range, TextDocumentSyncCapability, TextDocumentSyncKind,
};
use lsp_types::{InitializeParams, ServerCapabilities};
use lsp_server::{Connection, Message, Notification};
fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
eprintln!("starting generic LSP server");
let (connection, io_threads) = Connection::stdio();
let server_capabilities = serde_json::to_value(ServerCapabilities {
text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::FULL)),
..Default::default()
})
.unwrap();
let initialization_params = connection.initialize(server_capabilities)?;
main_loop(connection, initialization_params)?;
io_threads.join()?;
eprintln!("shutting down server");
Ok(())
}
fn main_loop(
connection: Connection,
params: serde_json::Value,
) -> Result<(), Box<dyn Error + Sync + Send>> {
let _params: InitializeParams = serde_json::from_value(params).unwrap();
eprintln!("starting example main loop");
for msg in &connection.receiver {
match msg {
Message::Request(req) => {
eprintln!("got request: {req:?}");
if connection.handle_shutdown(&req)? {
return Ok(());
}
}
Message::Response(resp) => {
eprintln!("got response: {resp:?}");
}
Message::Notification(not) => {
eprintln!("got notification: {not:?}");
if not.method.as_str() == "textDocument/didChange" {
let params: DidChangeTextDocumentParams = serde_json::from_value(not.params)?;
for change in params.content_changes {
let text = change.text;
let mut aspell = std::process::Command::new("aspell")
.arg("-a")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
aspell
.stdin
.as_mut()
.unwrap()
.write_all(&text.clone().into_bytes())
.unwrap();
drop(aspell.stdin.take().unwrap());
let mut result = String::new();
aspell
.stdout
.as_mut()
.unwrap()
.read_to_string(&mut result)
.unwrap();
let mut diagnostics = vec![];
for line in result.lines() {
if line.starts_with('&') {
let word = line.split_whitespace().nth(1).unwrap();
for (line_index, line) in text.lines().enumerate() {
if let Some(column_index) = line.find(word) {
let diagnostic = Diagnostic {
range: Range {
start: Position {
line: line_index as _,
character: column_index as _,
},
end: Position {
line: line_index as _,
character: (column_index + word.len()) as _,
},
},
severity: Some(DiagnosticSeverity::WARNING),
// TODO: add suggestions here or in code action
message: "misspell".to_owned(),
..Default::default()
};
diagnostics.push(diagnostic);
}
}
}
}
let publish_diagnostics = Notification::new(
"textDocument/publishDiagnostics".to_owned(),
PublishDiagnosticsParams {
uri: params.text_document.uri.clone(),
diagnostics,
version: None,
},
);
connection
.sender
.send(Message::Notification(publish_diagnostics))?;
}
}
}
}
}
Ok(())
}
@sigmaSd
Copy link
Author

sigmaSd commented Jul 4, 2023

Screencast.from.2023-07-04.22-03-17.webm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment