mirror of https://github.com/lapce/lapce.git
added main changes from Golang Support PR again
This commit is contained in:
parent
9f0b0a67ea
commit
7881e86e9d
|
@ -57,6 +57,7 @@ pub struct LspState {
|
|||
#[derive(Clone)]
|
||||
pub struct LspClient {
|
||||
exec_path: String,
|
||||
binary_args: Vec<String>,
|
||||
options: Option<Value>,
|
||||
state: Arc<Mutex<LspState>>,
|
||||
dispatcher: Dispatcher,
|
||||
|
@ -84,15 +85,51 @@ pub fn start_server(
|
|||
language_id: &str,
|
||||
options: Option<Value>,
|
||||
) {
|
||||
let binary_args = self.get_plugin_binary_args(options.clone());
|
||||
let client = LspClient::new(
|
||||
language_id.to_string(),
|
||||
exec_path,
|
||||
options,
|
||||
binary_args.to_owned(),
|
||||
self.dispatcher.clone().unwrap(),
|
||||
);
|
||||
self.clients.insert(language_id.to_string(), client);
|
||||
}
|
||||
|
||||
fn get_plugin_binary_args(&mut self, option: Option<Value>) -> Vec<String> {
|
||||
let mut vals = Vec::new();
|
||||
|
||||
let option = match option {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return vals;
|
||||
}
|
||||
};
|
||||
|
||||
let binary = match option["binary"].as_object() {
|
||||
Some(binary) => binary,
|
||||
None => return vals,
|
||||
};
|
||||
|
||||
let option = match binary.get("binary_args") {
|
||||
Some(binary_args) => binary_args,
|
||||
None => return vals,
|
||||
};
|
||||
|
||||
let option = if let Some(option) = option.as_array() {
|
||||
option
|
||||
} else {
|
||||
println!("binary_args value should be of type [String].");
|
||||
return vals;
|
||||
};
|
||||
|
||||
for val in option {
|
||||
vals.push(String::from(val.as_str().unwrap()));
|
||||
}
|
||||
|
||||
return vals;
|
||||
}
|
||||
|
||||
pub fn new_buffer(
|
||||
&self,
|
||||
buffer_id: &BufferId,
|
||||
|
@ -368,15 +405,18 @@ pub fn new(
|
|||
_language_id: String,
|
||||
exec_path: &str,
|
||||
options: Option<Value>,
|
||||
binary_args: Vec<String>,
|
||||
dispatcher: Dispatcher,
|
||||
) -> Arc<LspClient> {
|
||||
let mut process = Self::process(exec_path);
|
||||
//TODO: better handling of binary args in plugin
|
||||
let mut process = Self::process(exec_path, binary_args.clone());
|
||||
let writer = Box::new(BufWriter::new(process.stdin.take().unwrap()));
|
||||
let stdout = process.stdout.take().unwrap();
|
||||
|
||||
let lsp_client = Arc::new(LspClient {
|
||||
dispatcher,
|
||||
exec_path: exec_path.to_string(),
|
||||
binary_args: binary_args,
|
||||
options,
|
||||
state: Arc::new(Mutex::new(LspState {
|
||||
next_id: 0,
|
||||
|
@ -414,8 +454,12 @@ fn handle_stdout(&self, stdout: ChildStdout) {
|
|||
});
|
||||
}
|
||||
|
||||
fn process(exec_path: &str) -> Child {
|
||||
fn process(exec_path: &str, binary_args: Vec<String>) -> Child {
|
||||
let mut process = Command::new(exec_path);
|
||||
|
||||
for arg in binary_args {
|
||||
process.arg(arg);
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
let process = process.creation_flags(0x08000000);
|
||||
process
|
||||
|
@ -426,7 +470,8 @@ fn process(exec_path: &str) -> Child {
|
|||
}
|
||||
|
||||
fn reload(&self) {
|
||||
let mut process = Self::process(&self.exec_path);
|
||||
//TODO: avoid clone using a &[String] ?
|
||||
let mut process = Self::process(&self.exec_path, self.binary_args.clone());
|
||||
let writer = Box::new(BufWriter::new(process.stdin.take().unwrap()));
|
||||
let stdout = process.stdout.take().unwrap();
|
||||
|
||||
|
@ -473,9 +518,15 @@ pub fn get_uri(&self, buffer: &Buffer) -> Url {
|
|||
}
|
||||
|
||||
pub fn handle_message(&self, message: &str) {
|
||||
println!("Received message! {}", message);
|
||||
match JsonRpc::parse(message) {
|
||||
Ok(JsonRpc::Request(_obj)) => {
|
||||
// trace!("client received unexpected request: {:?}", obj)
|
||||
Ok(value @ JsonRpc::Request(_)) => {
|
||||
let id = value.get_id().unwrap();
|
||||
self.handle_request(
|
||||
value.get_method().unwrap(),
|
||||
id,
|
||||
value.get_params().unwrap(),
|
||||
)
|
||||
}
|
||||
Ok(value @ JsonRpc::Notification(_)) => {
|
||||
self.handle_notification(
|
||||
|
@ -497,6 +548,20 @@ pub fn handle_message(&self, message: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_request(&self, method: &str, id: Id, _params: Params) {
|
||||
match method {
|
||||
"window/workDoneProgress/create" => {
|
||||
// Token is ignored as the workProgress Widget is always working
|
||||
// In the future, for multiple workProgress Handling we should
|
||||
// probably store the token
|
||||
self.send_success_response(id, &json!({}));
|
||||
}
|
||||
method => {
|
||||
println!("Received unhandled request {method}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_notification(&self, method: &str, params: Params) {
|
||||
match method {
|
||||
"textDocument/publishDiagnostics" => {
|
||||
|
@ -515,7 +580,19 @@ pub fn handle_notification(&self, method: &str, params: Params) {
|
|||
}),
|
||||
);
|
||||
}
|
||||
_ => (),
|
||||
"window/showMessage" => {
|
||||
// TODO: send message to display
|
||||
}
|
||||
"window/logMessage" => {
|
||||
// TODO: We should log the message here. Waiting for
|
||||
// the discussion about handling plugins logs before doing anything
|
||||
}
|
||||
"experimental/serverStatus" => {
|
||||
//TODO: Logging of server status
|
||||
}
|
||||
method => {
|
||||
println!("Received unhandled notification {}", method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,6 +641,22 @@ pub fn send_request(&self, method: &str, params: Params, completion: Callback) {
|
|||
self.send_rpc(&to_value(&request).unwrap());
|
||||
}
|
||||
|
||||
pub fn send_success_response(&self, id: Id, result: &Value) {
|
||||
let response = JsonRpc::success(id, result);
|
||||
|
||||
self.send_rpc(&to_value(&response).unwrap());
|
||||
}
|
||||
|
||||
pub fn send_error_response(
|
||||
&self,
|
||||
id: jsonrpc_lite::Id,
|
||||
error: jsonrpc_lite::Error,
|
||||
) {
|
||||
let response = JsonRpc::error(id, error);
|
||||
|
||||
self.send_rpc(&to_value(&response).unwrap());
|
||||
}
|
||||
|
||||
fn initialize(&self) {
|
||||
if let Some(workspace) = self.dispatcher.workspace.lock().clone() {
|
||||
let root_url = Url::from_directory_path(workspace).unwrap();
|
||||
|
|
|
@ -171,10 +171,15 @@ fn start_plugin(
|
|||
|
||||
let output = Pipe::new();
|
||||
let input = Pipe::new();
|
||||
let env = match plugin_desc.get_plugin_env() {
|
||||
Ok(env) => env,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
let mut wasi_env = WasiState::new("Lapce")
|
||||
.map_dir("/", plugin_desc.dir.clone().unwrap())?
|
||||
.stdin(Box::new(input))
|
||||
.stdout(Box::new(output))
|
||||
.envs(env)
|
||||
.finalize()?;
|
||||
let wasi = wasi_env.import_object(&module)?;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::path::PathBuf;
|
||||
use std::{path::PathBuf, process::Command};
|
||||
|
||||
use anyhow::{format_err, Error};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
|
@ -27,3 +28,81 @@ pub struct PluginInfo {
|
|||
pub os: String,
|
||||
pub configuration: Option<Value>,
|
||||
}
|
||||
|
||||
impl PluginDescription {
|
||||
pub fn get_plugin_env(&self) -> Result<Vec<(String, String)>, Error> {
|
||||
let mut vars = Vec::new();
|
||||
|
||||
let conf = match &self.configuration {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(format_err!(
|
||||
"Empty configuration for plugin {}",
|
||||
self.display_name
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let conf = match conf.as_object() {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(format_err!(
|
||||
"Empty configuration for plugin {}",
|
||||
self.display_name
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let env = match conf.get("env_command") {
|
||||
Some(env) => env,
|
||||
// We do not print any error as no env is allowed.
|
||||
None => return Ok(vars),
|
||||
};
|
||||
|
||||
let args = match env.as_str() {
|
||||
Some(arg) => arg,
|
||||
None => {
|
||||
return Err(format_err!(
|
||||
"Plugin {}: env_command is not a string",
|
||||
self.display_name
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let output = if cfg!(target_os = "windows") {
|
||||
Command::new("cmd").arg("/c").arg(args).output()
|
||||
} else {
|
||||
Command::new("sh").arg("-c").arg(args).output()
|
||||
};
|
||||
|
||||
let output = match output {
|
||||
Ok(val) => val.stdout,
|
||||
Err(err) => {
|
||||
return Err(format_err!(
|
||||
"Error during env command execution for plugin {}: {}",
|
||||
self.name,
|
||||
err
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let data = match String::from_utf8(output) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return Err(format_err!(
|
||||
"Error during UTF-8 conversion for plugin {}: {}",
|
||||
self.display_name,
|
||||
err
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
for l in data.lines() {
|
||||
if let Some((key, value)) = l.split_once('=') {
|
||||
vars.push((String::from(key), String::from(value)));
|
||||
};
|
||||
}
|
||||
|
||||
return Ok(vars);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue