Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
vv9k committed Jun 15, 2021
1 parent 6ce0726 commit 6b9e70d
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 28 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion helix-lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ license = "MPL-2.0"
helix-core = { path = "../helix-core" }

anyhow = "1.0"
arc-swap = "1"
futures-executor = "0.3"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
jsonrpc-core = { version = "17.1", default-features = false } # don't pull in all of futures
Expand All @@ -20,4 +21,4 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"
tokio = { version = "1.6", features = ["full"] }
tokio-stream = "0.1.6"
tokio-stream = "0.1.6"
47 changes: 43 additions & 4 deletions helix-lsp/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
use crate::{
transport::{Payload, Transport},
Call, Error, OffsetEncoding, Result,
Call, Error, OffsetEncoding, Progress, Result,
};

use arc_swap::ArcSwap;
use helix_core::{find_root, ChangeSet, Rope};
use jsonrpc_core as jsonrpc;
use lsp_types as lsp;
use serde_json::Value;
use std::collections::HashMap;
use std::future::Future;
use std::process::Stdio;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{
atomic::{AtomicU64, Ordering},
Arc,
};
use tokio::{
io::{BufReader, BufWriter},
process::{Child, Command},
Expand All @@ -18,15 +23,22 @@ use tokio::{

#[derive(Debug)]
pub struct Client {
id: usize,
_process: Child,
server_tx: UnboundedSender<Payload>,
request_counter: AtomicU64,
capabilities: Option<lsp::ServerCapabilities>,
offset_encoding: OffsetEncoding,

lsp_progress: HashMap<lsp::ProgressToken, ArcSwap<Progress>>,
}

impl Client {
pub fn start(cmd: &str, args: &[String]) -> Result<(Self, UnboundedReceiver<Call>)> {
pub fn start(
cmd: &str,
args: &[String],
id: usize,
) -> Result<(Self, UnboundedReceiver<(usize, Call)>)> {
let process = Command::new(cmd)
.args(args)
.stdin(Stdio::piped())
Expand All @@ -43,14 +55,16 @@ impl Client {
let reader = BufReader::new(process.stdout.take().expect("Failed to open stdout"));
let stderr = BufReader::new(process.stderr.take().expect("Failed to open stderr"));

let (server_rx, server_tx) = Transport::start(reader, writer, stderr);
let (server_rx, server_tx) = Transport::start(reader, writer, stderr, id);

let client = Self {
id,
_process: process,
server_tx,
request_counter: AtomicU64::new(0),
capabilities: None,
offset_encoding: OffsetEncoding::Utf8,
lsp_progress: HashMap::new(),
};

// TODO: async client.initialize()
Expand All @@ -59,6 +73,31 @@ impl Client {
Ok((client, server_rx))
}

pub fn id(&self) -> usize {
self.id
}

pub fn create_progress(&self, token: lsp::ProgressToken) {
self.lsp_progress.rcu(|inner| {
// ...?
});
}

pub fn update_progress(&mut self, token: lsp::ProgressToken, progress: lsp::WorkDoneProgress) {
let lsp_progress = self.lsp_progress.load_full();
lsp_progress.insert(token, Progress::Started(progress));
}

pub fn delete_progress(&mut self, token: &lsp::ProgressToken) -> Option<Progress> {
let progress = self.lsp_progress.load();
progress.remove(token)
}

pub fn progress(&self, token: &lsp::ProgressToken) -> Option<&Progress> {
let progress = self.lsp_progress.load();
progress.get(token)
}

fn next_request_id(&self) -> jsonrpc::Id {
let id = self.request_counter.fetch_add(1, Ordering::Relaxed);
jsonrpc::Id::Num(id)
Expand Down
13 changes: 10 additions & 3 deletions helix-lsp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use helix_core::syntax::LanguageConfiguration;

use std::{
collections::{hash_map::Entry, HashMap},
sync::Arc,
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};

use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -245,7 +248,8 @@ impl Notification {
pub struct Registry {
inner: HashMap<LanguageId, Arc<Client>>,

pub incoming: SelectAll<UnboundedReceiverStream<Call>>,
counter: AtomicUsize,
pub incoming: SelectAll<UnboundedReceiverStream<(usize, Call)>>,
}

impl Default for Registry {
Expand All @@ -258,6 +262,7 @@ impl Registry {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
counter: AtomicUsize::new(0),
incoming: SelectAll::new(),
}
}
Expand All @@ -272,7 +277,8 @@ impl Registry {
Entry::Occupied(language_server) => Ok(language_server.get().clone()),
Entry::Vacant(entry) => {
// initialize a new client
let (mut client, incoming) = Client::start(&config.command, &config.args)?;
let id = self.counter.fetch_add(1, Ordering::Relaxed);
let (mut client, incoming) = Client::start(&config.command, &config.args, id)?;
// TODO: run this async without blocking
futures_executor::block_on(client.initialize())?;
s_incoming.push(UnboundedReceiverStream::new(incoming));
Expand All @@ -288,6 +294,7 @@ impl Registry {
}
}

#[derive(Debug)]
pub enum Progress {
Created,
Started(lsp::WorkDoneProgress),
Expand Down
12 changes: 9 additions & 3 deletions helix-lsp/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ enum ServerMessage {

#[derive(Debug)]
pub struct Transport {
client_tx: UnboundedSender<jsonrpc::Call>,
id: usize,
client_tx: UnboundedSender<(usize, jsonrpc::Call)>,
client_rx: UnboundedReceiver<Payload>,

pending_requests: HashMap<jsonrpc::Id, Sender<Result<Value>>>,
Expand All @@ -48,11 +49,16 @@ impl Transport {
server_stdout: BufReader<ChildStdout>,
server_stdin: BufWriter<ChildStdin>,
server_stderr: BufReader<ChildStderr>,
) -> (UnboundedReceiver<jsonrpc::Call>, UnboundedSender<Payload>) {
id: usize,
) -> (
UnboundedReceiver<(usize, jsonrpc::Call)>,
UnboundedSender<Payload>,
) {
let (client_tx, rx) = unbounded_channel();
let (tx, client_rx) = unbounded_channel();

let transport = Self {
id,
server_stdout,
server_stdin,
server_stderr,
Expand Down Expand Up @@ -156,7 +162,7 @@ impl Transport {
match msg {
ServerMessage::Output(output) => self.process_request_response(output).await?,
ServerMessage::Call(call) => {
self.client_tx.send(call).unwrap();
self.client_tx.send((self.id, call)).unwrap();
// let notification = Notification::parse(&method, params);
}
};
Expand Down
72 changes: 56 additions & 16 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ pub struct Application {
editor: Editor,

callbacks: LspCallbacks,

lsp_progress: HashMap<lsp::ProgressToken, Progress>,
}

impl Application {
Expand Down Expand Up @@ -76,8 +74,6 @@ impl Application {
editor,

callbacks: FuturesUnordered::new(),

lsp_progress: HashMap::new(),
};

Ok(app)
Expand Down Expand Up @@ -113,8 +109,8 @@ impl Application {
event = reader.next() => {
self.handle_terminal_events(event)
}
Some(call) = self.editor.language_servers.incoming.next() => {
self.handle_language_server_message(call).await
Some((id, call)) = self.editor.language_servers.incoming.next() => {
self.handle_language_server_message(call, id).await
}
Some(callback) = &mut self.callbacks.next() => {
self.handle_language_server_callback(callback)
Expand Down Expand Up @@ -157,7 +153,7 @@ impl Application {
}
}

pub async fn handle_language_server_message(&mut self, call: helix_lsp::Call) {
pub async fn handle_language_server_message(&mut self, call: helix_lsp::Call, id: usize) {
use helix_lsp::{Call, MethodCall, Notification};
match call {
Call::Notification(helix_lsp::jsonrpc::Notification { method, params, .. }) => {
Expand Down Expand Up @@ -247,12 +243,23 @@ impl Application {
}
Notification::ProgressMessage(params) => {
let lsp::ProgressParams { token, value } = params;

let doc = if let Some((_, doc)) =
self.editor.documents.iter().find(|(_, doc)| {
if let Some(server) = doc.language_server() {
return server.id() == id;
}
false
}) {
doc
} else {
log::warn!("can't find document with lsp id `{}`", id);
return;
};

let msg = {
let lsp::ProgressParamsValue::WorkDone(work) = value;
self.lsp_progress
.insert(token.clone(), Progress::Started(work));
let work = self.lsp_progress.get(&token).unwrap().progress().unwrap();
let parts = match work {
let parts = match &work {
lsp::WorkDoneProgress::Begin(lsp::WorkDoneProgressBegin {
title,
message,
Expand Down Expand Up @@ -288,14 +295,25 @@ impl Application {
(None, Some(message), Some(percentage)) => {
format!("{}% {}", percentage, message)
}
(Some(title), None, None) => title.to_string(),
(None, Some(message), None) => message.to_string(),
(Some(title), None, None) => title.to_owned(),
(None, Some(message), None) => message.to_owned(),
(None, None, Some(percentage)) => format!("{}%", percentage),
(None, None, None) => "".into(),
};

if let lsp::WorkDoneProgress::End(_) = work {
self.lsp_progress.remove(&token);
let mut server = doc.language_server_owned().unwrap();
if let Some(server) = Arc::get_mut(&mut server) {
if let lsp::WorkDoneProgress::End(_) = work {
server.delete_progress(&token);
} else {
server.update_progress(token.clone(), work);
}
} else {
log::warn!(
"failed to create progress for server `{}` token `{:?}`",
id,
token
);
}

msg
Expand All @@ -319,7 +337,29 @@ impl Application {

match call {
MethodCall::WorkDoneProgressCreate(params) => {
self.lsp_progress.insert(params.token, Progress::Created);
if let Some(doc) = self
.editor
.documents
.iter_mut()
.find(|(_, doc)| {
if let Some(server) = doc.language_server() {
return server.id() == id;
}
false
})
.map(|(_, doc)| doc)
{
let mut server = doc.language_server_owned().unwrap();
if let Some(server) = Arc::get_mut(&mut server) {
server.create_progress(params.token);
} else {
log::warn!(
"failed to create progress for server `{}` token `{:?}`",
id,
params.token
);
}
}
}
}
// self.language_server.reply(
Expand Down
6 changes: 5 additions & 1 deletion helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use anyhow::{Context, Error};
use std::cell::Cell;
use std::future::Future;
use std::path::{Component, Path, PathBuf};
use std::sync::Arc;
use std::sync::{Arc};

use helix_core::{
history::History,
Expand Down Expand Up @@ -495,6 +495,10 @@ impl Document {
self.language_server.as_deref()
}

pub fn language_server_owned(&self) -> Option<Arc<helix_lsp::Client>> {
self.language_server.clone()
}

/// Tree-sitter AST tree
pub fn syntax(&self) -> Option<&Syntax> {
self.syntax.as_ref()
Expand Down

0 comments on commit 6b9e70d

Please sign in to comment.