Skip to content
This repository was archived by the owner on Jun 19, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/lspc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ pub trait Editor: 'static {
fn events(&self) -> Receiver<Event>;
fn capabilities(&self) -> lsp_types::ClientCapabilities;
fn say_hello(&self) -> Result<(), EditorError>;

fn init(&mut self) -> Result<(), EditorError>;
fn message(&mut self, msg: &str) -> Result<(), EditorError>;
fn show_hover(
&mut self,
Expand All @@ -176,6 +178,11 @@ pub trait Editor: 'static {
) -> Result<(), EditorError>;
fn show_message(&mut self, show_message_params: &ShowMessageParams) -> Result<(), EditorError>;
fn show_references(&mut self, locations: &Vec<Location>) -> Result<(), EditorError>;
fn show_diagnostics(
&mut self,
text_document: &TextDocumentIdentifier,
diagnostics: &[lsp_types::Diagnostic],
) -> Result<(), EditorError>;
fn goto(&mut self, location: &Location) -> Result<(), EditorError>;
fn apply_edits(&self, lines: &Vec<String>, edits: &Vec<TextEdit>) -> Result<(), EditorError>;
fn track_all_buffers(&self) -> Result<(), EditorError>;
Expand Down Expand Up @@ -645,6 +652,23 @@ impl<E: Editor> Lspc<E> {
}
Err(noti) => noti,
};
noti = match noti.cast::<noti::PublishDiagnostics>() {
Ok(params) => {
let (_handler, _tracking_file, editor) =
self.handler_for_file(&params.uri).ok_or_else(|| {
log::info!(
"Received changed event for nontracking file: {:?}",
params.uri
);
MainLoopError::IgnoredMessage
})?;
let text_document = TextDocumentIdentifier::new(params.uri);
editor.show_diagnostics(&text_document, &params.diagnostics)?;

return Ok(());
}
Err(noti) => noti,
};

log::warn!("Not supported notification: {:?}", noti);
}
Expand Down Expand Up @@ -702,6 +726,11 @@ impl<E: Editor> Lspc<E> {
let event_receiver = self.editor.events();
let timer_tick = tick(Duration::from_millis(TIMER_TICK_MS));

if let Err(e) = self.editor.init() {
log::error!("Editor initialization error: {:?}", e);
return;
}

loop {
let selected = select(&event_receiver, &timer_tick, &self.lsp_handlers);
let result = match selected {
Expand Down
86 changes: 82 additions & 4 deletions src/neovim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use rmpv::{
use serde::{
self,
de::{self, SeqAccess, Visitor},
ser::SerializeSeq,
ser::{SerializeMap, SerializeSeq},
Deserialize, Serialize,
};
use url::Url;
Expand All @@ -42,6 +42,7 @@ pub struct Neovim {
next_id: AtomicU64,
subscription_sender: Sender<(u64, Sender<NvimMessage>)>,
thread: JoinHandle<()>,
buf_mapper: Arc<Mutex<BiMap<i64, Url>>>
}

pub trait ToDisplay {
Expand Down Expand Up @@ -443,6 +444,7 @@ impl Neovim {
event_receiver,
rpc_client,
thread,
buf_mapper,
}
}

Expand Down Expand Up @@ -493,7 +495,7 @@ impl Neovim {
.map_err(|_| EditorError::Timeout)
}

pub fn notify(&self, method: &str, params: &[Value]) -> Result<(), EditorError> {
pub fn notify(&self, method: &str, params: Value) -> Result<(), EditorError> {
let noti = NvimMessage::RpcNotification {
method: method.into(),
params: Value::from(params.to_owned()),
Expand Down Expand Up @@ -544,13 +546,14 @@ impl Neovim {
.into();
self.notify(
"nvim_buf_set_virtual_text",
&vec![
vec![
buffer_id.into(),
ns_id.into(),
line.into(),
chunks,
Value::Map(Vec::new()),
],
]
.into(),
)?;

Ok(())
Expand Down Expand Up @@ -601,6 +604,13 @@ impl Editor for Neovim {
Ok(())
}

fn init(&mut self) -> Result<(), EditorError> {
// FIXME: call `nvim_set_client_info` here.
// FIXME: call `sign_define` here.

Ok(())
}

fn message(&mut self, msg: &str) -> Result<(), EditorError> {
self.command(&format!("echo '{}'", msg))?;
Ok(())
Expand Down Expand Up @@ -710,6 +720,74 @@ impl Editor for Neovim {
Ok(())
}

fn show_diagnostics(
&mut self,
text_document: &TextDocumentIdentifier,
diagnostics: &[lsp::Diagnostic],
) -> Result<(), EditorError> {
struct Placement {
lnum: i64,
priority: i64,
}

impl Serialize for Placement {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut s = serializer.serialize_map(Some(2))?;
s.serialize_entry("lnum", &self.lnum)?;
s.serialize_entry("priority", &self.priority)?;
s.end()
}
}

let buf_id = {
let locked_buf_mapper = self.buf_mapper.lock().unwrap();
*locked_buf_mapper.get_by_right(&text_document.uri)
.ok_or_else(|| EditorError::Failed(format!("Buffer not found for {:?}", text_document)))?
};

self.notify(
"nvim_call_function",
vec![
Value::from("sign_unplace"),
vec![
Value::from("lspc-diag"),
Value::Map(vec![(Value::from("buffer"), Value::from(buf_id))]),
].into(),
].into(),
)?;

#[derive(Serialize)]
struct SignParams(i64, String, String, i64, Placement);
for diag in diagnostics {
let sign_name = match diag.severity {
Some(lsp::DiagnosticSeverity::Error) => "ALEErrorSign",
Some(lsp::DiagnosticSeverity::Warning) => "ALEWarningSign",
Some(lsp::DiagnosticSeverity::Information)
| Some(lsp::DiagnosticSeverity::Hint) => "ALEInfoSign",
None => "ALEErrorSign",
};
let placement = Placement {
lnum: diag.range.start.line as i64,
priority: 10,
};
let sign_params =
SignParams(0, "lspc-diag".into(), sign_name.into(), buf_id, placement);

let params = to_value(sign_params).map_err(|e| {
EditorError::Failed(format!("Failed to encode params: {}", e.description()))
})?;
self.notify(
"nvim_call_function",
vec![Value::from("sign_place"), params].into(),
)?;
}

Ok(())
}

fn track_all_buffers(&self) -> Result<(), EditorError> {
self.call_function("lspc#track_all_buffers", Value::Array(vec![]))?;
Ok(())
Expand Down