Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add support for formatting capabilities to the LSP #1216

Merged
merged 12 commits into from
Apr 13, 2023
69 changes: 69 additions & 0 deletions lsp/nls/src/requests/formatting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use std::process;

use lsp_server::{ErrorCode, RequestId, Response, ResponseError};
use lsp_types::{DocumentFormattingParams, Position, Range, TextEdit};

use crate::server::{self, Server};

pub fn handle_format_document(
params: DocumentFormattingParams,
id: RequestId,
server: &mut Server,
) -> Result<(), ResponseError> {
let document_id = params.text_document.uri.to_file_path().unwrap();
let file_id = server.cache.id_of(document_id).unwrap();
let text = server.cache.files().source(file_id).clone();
let document_length = text.lines().count() as u32;
let last_line_length = text.lines().rev().next().unwrap().len() as u32;

let formatting_command = server::FORMATTING_COMMAND;
let Ok(mut topiary) = process::Command::new(formatting_command[0])
.args(&formatting_command[1..])
.stdin(process::Stdio::piped())
.stdout(process::Stdio::piped())
.stderr(process::Stdio::piped())
.spawn() else {
let message = "Executing topiary failed";
return Err(ResponseError {
code: ErrorCode::InternalError as i32,
message: String::from(message),
data: None,
});
};

let mut stdin = topiary.stdin.take().unwrap();

std::thread::spawn(move || {
let mut text_bytes = text.as_bytes();
std::io::copy(&mut text_bytes, &mut stdin).unwrap();
});

let output = topiary.wait_with_output().unwrap();

if !output.status.success() {
let error = String::from_utf8_lossy(&output.stderr);
return Err(ResponseError {
code: ErrorCode::InternalError as i32,
message: error.to_string(),
data: None,
});
}

let new_text = String::from_utf8(output.stdout).unwrap();

let result = Some(vec![TextEdit {
range: Range {
start: Position {
line: 0,
character: 0,
},
end: Position {
line: document_length - 1,
character: last_line_length,
},
},
new_text,
}]);
server.reply(Response::new_ok(id, result));
Ok(())
}
1 change: 1 addition & 0 deletions lsp/nls/src/requests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod completion;
pub mod formatting;
pub mod goto;
pub mod hover;
pub mod symbols;
17 changes: 13 additions & 4 deletions lsp/nls/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use lsp_types::{
notification::{DidChangeTextDocument, DidOpenTextDocument},
request::{Request as RequestTrait, *},
CompletionOptions, CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams,
DocumentSymbolParams, GotoDefinitionParams, HoverOptions, HoverParams, HoverProviderCapability,
OneOf, ReferenceParams, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
TextDocumentSyncOptions, WorkDoneProgressOptions,
DocumentFormattingParams, DocumentSymbolParams, GotoDefinitionParams, HoverOptions,
HoverParams, HoverProviderCapability, OneOf, ReferenceParams, ServerCapabilities,
TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
WorkDoneProgressOptions,
};

use nickel_lang::{
Expand All @@ -26,11 +27,12 @@ use nickel_lang::{stdlib, typecheck::Context};
use crate::{
cache::CacheExt,
linearization::{completed::Completed, interface::TermKind, Environment, ItemId},
requests::{completion, goto, hover, symbols},
requests::{completion, formatting, goto, hover, symbols},
trace::Trace,
};

pub const DOT_COMPL_TRIGGER: &str = ".";
pub const FORMATTING_COMMAND: [&str; 3] = ["topiary", "--language", "nickel"];

pub struct Server {
pub connection: Connection,
Expand Down Expand Up @@ -62,6 +64,7 @@ impl Server {
..Default::default()
}),
document_symbol_provider: Some(OneOf::Left(true)),
document_formatting_provider: Some(OneOf::Left(true)),
..ServerCapabilities::default()
}
}
Expand Down Expand Up @@ -244,6 +247,12 @@ impl Server {
symbols::handle_document_symbols(params, req.id.clone(), self)
}

Formatting::METHOD => {
debug!("handle formatting");
let params: DocumentFormattingParams = serde_json::from_value(req.params).unwrap();
formatting::handle_format_document(params, req.id.clone(), self)
}

_ => Ok(()),
};

Expand Down