semantic tokens

This commit is contained in:
Dongdong Zhou 2020-11-11 13:27:39 +00:00
parent f6d1ce926a
commit 450362411f
4 changed files with 354 additions and 170 deletions

View File

@ -26,7 +26,7 @@ xi-rope = { path = "../../xi-editor/rust/rope/" }
xi-rpc = { path = "../../xi-editor/rust/rpc/" }
fzyr = "0.1.2"
uuid = { version = "0.7.4", features = ["v4"] }
lsp-types = "0.82.0"
lsp-types = { version = "0.82.0", features = ["proposed"] }
druid = { path = "../../druid/druid", features = ["svg"] }
[build-dependencies]

View File

@ -5,10 +5,14 @@
};
use druid::{Env, PaintCtx};
use language::{new_highlight_config, new_parser, LapceLanguage};
use lsp_types::SemanticTokens;
use lsp_types::SemanticTokensLegend;
use lsp_types::SemanticTokensServerCapabilities;
use lsp_types::{
CodeActionResponse, Position, Range, TextDocumentContentChangeEvent,
};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::{
borrow::Cow,
@ -77,6 +81,7 @@ pub struct Buffer {
pub rope: Rope,
highlight_config: Arc<HighlightConfiguration>,
highlight_names: Vec<String>,
pub semantic_tokens: Option<Vec<(usize, usize, String)>>,
pub highlights: Vec<(usize, usize, Highlight)>,
pub line_highlights: HashMap<usize, Vec<(usize, usize, String)>>,
undos: Vec<Vec<(RopeDelta, RopeDelta)>>,
@ -118,6 +123,7 @@ pub fn new(
id: buffer_id.clone(),
rope,
highlight_config: Arc::new(highlight_config),
semantic_tokens: None,
highlight_names,
highlights: Vec::new(),
line_highlights: HashMap::new(),
@ -200,27 +206,97 @@ pub fn len(&self) -> usize {
self.rope.len()
}
pub fn highlights_apply_delta(
&mut self,
delta: &RopeDelta,
) -> Vec<(usize, usize, Highlight)> {
pub fn highlights_apply_delta(&mut self, delta: &RopeDelta) {
let mut transformer = Transformer::new(delta);
self.highlights
.iter()
.map(|h| {
(
transformer.transform(h.0, true),
transformer.transform(h.1, true),
h.2.clone(),
)
})
.collect()
if let Some(semantic_tokens) = self.semantic_tokens.as_mut() {
self.semantic_tokens = Some(
semantic_tokens
.iter()
.map(|h| {
(
transformer.transform(h.0, true),
transformer.transform(h.1, true),
h.2.clone(),
)
})
.collect(),
)
} else {
self.highlights = self
.highlights
.iter()
.map(|h| {
(
transformer.transform(h.0, true),
transformer.transform(h.1, true),
h.2.clone(),
)
})
.collect()
}
}
fn format_semantic_tokens(
&self,
semantic_tokens_provider: Option<SemanticTokensServerCapabilities>,
value: Value,
) -> Option<Vec<(usize, usize, String)>> {
let semantic_tokens: SemanticTokens = serde_json::from_value(value).ok()?;
let semantic_tokens_provider = semantic_tokens_provider.as_ref()?;
let semantic_lengends = semantic_tokens_lengend(semantic_tokens_provider);
let mut highlights = Vec::new();
let mut line = 0;
let mut start = 0;
for semantic_token in &semantic_tokens.data {
if semantic_token.delta_line > 0 {
line += semantic_token.delta_line as usize;
start = self.offset_of_line(line);
}
start += semantic_token.delta_start as usize;
let end = start + semantic_token.length as usize;
let kind = semantic_lengends.token_types
[semantic_token.token_type as usize]
.as_str()
.to_string();
highlights.push((start, end, kind));
}
Some(highlights)
}
pub fn set_semantic_tokens(
&mut self,
semantic_tokens_provider: Option<SemanticTokensServerCapabilities>,
value: Value,
) -> Option<()> {
let semantic_tokens =
self.format_semantic_tokens(semantic_tokens_provider, value)?;
self.semantic_tokens = Some(semantic_tokens);
self.line_highlights = HashMap::new();
let window_id = self.window_id;
let tab_id = self.tab_id;
let buffer_id = self.id;
thread::spawn(move || {
let state = LAPCE_APP_STATE.get_tab_state(&window_id, &tab_id);
for (view_id, editor) in state.editor_split.lock().editors.iter() {
if editor.buffer_id.as_ref() == Some(&buffer_id) {
LAPCE_APP_STATE.submit_ui_command(
LapceUICommand::FillTextLayouts,
view_id.clone(),
);
}
}
});
None
}
pub fn update_highlights(&mut self) {
self.line_highlights = HashMap::new();
self.sender
.send((self.window_id, self.tab_id, self.id, self.rev));
let state = LAPCE_APP_STATE.get_tab_state(&self.window_id, &self.tab_id);
state.lsp.lock().get_semantic_tokens(&self);
}
pub fn get_line_highligh(
@ -229,23 +305,41 @@ pub fn get_line_highligh(
) -> &Vec<(usize, usize, String)> {
if self.line_highlights.get(&line).is_none() {
let mut line_highlight = Vec::new();
let start_offset = self.offset_of_line(line);
let end_offset = self.offset_of_line(line + 1) - 1;
for (start, end, hl) in &self.highlights {
if *start > end_offset {
break;
if let Some(semantic_tokens) = self.semantic_tokens.as_ref() {
let start_offset = self.offset_of_line(line);
let end_offset = self.offset_of_line(line + 1) - 1;
for (start, end, hl) in semantic_tokens {
if *start > end_offset {
break;
}
if *start >= start_offset && *start <= end_offset {
let end = if *end > end_offset {
end_offset - start_offset
} else {
end - start_offset
};
line_highlight.push((start - start_offset, end, hl.clone()));
}
}
if *start >= start_offset && *start <= end_offset {
let end = if *end > end_offset {
end_offset - start_offset
} else {
end - start_offset
};
line_highlight.push((
start - start_offset,
end,
self.highlight_names[hl.0].to_string(),
));
} else {
let start_offset = self.offset_of_line(line);
let end_offset = self.offset_of_line(line + 1) - 1;
for (start, end, hl) in &self.highlights {
if *start > end_offset {
break;
}
if *start >= start_offset && *start <= end_offset {
let end = if *end > end_offset {
end_offset - start_offset
} else {
end - start_offset
};
line_highlight.push((
start - start_offset,
end,
self.highlight_names[hl.0].to_string(),
));
}
}
}
self.line_highlights.insert(line, line_highlight);
@ -438,7 +532,7 @@ fn apply_delta(
new_count: new_hard_count,
};
self.code_actions = HashMap::new();
self.highlights = self.highlights_apply_delta(delta);
self.highlights_apply_delta(delta);
self.update_size(ui_state, &inval_lines);
ui_state.update_text_layouts(&inval_lines);
}
@ -1139,6 +1233,8 @@ pub fn get_text_layout(
start..end,
TextAttribute::TextColor(color.clone()),
);
} else {
println!("no color for {} {}", hl, start);
}
}
let layout = layout_builder.build().unwrap();
@ -1384,3 +1480,16 @@ pub fn get_document_content_changes(
None
}
fn semantic_tokens_lengend(
semantic_tokens_provider: &SemanticTokensServerCapabilities,
) -> SemanticTokensLegend {
match semantic_tokens_provider {
SemanticTokensServerCapabilities::SemanticTokensOptions(options) => {
options.legend.clone()
}
SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
options,
) => options.semantic_tokens_options.legend.clone(),
}
}

View File

@ -111,7 +111,7 @@ pub fn new(
editor_id: WidgetId::next(),
view_id: WidgetId::next(),
split_id,
tab_id: tab_id,
tab_id,
buffer_id,
char_width: 7.6171875,
width: 0.0,
@ -143,6 +143,7 @@ pub fn update(
let old_editor = old_data.get_editor(&self.view_id);
let line_height = env.get(LapceTheme::EDITOR_LINE_HEIGHT);
if buffer.max_len != old_buffer.max_len
|| buffer.text_layouts.len() != old_buffer.text_layouts.len()
{
@ -1447,11 +1448,12 @@ pub fn show_completion(
let buffer = self.buffers.get(&buffer_id)?;
let offset = editor.selection.get_cursor_offset();
let prev_offset = buffer.prev_code_boundary(offset);
let next_offset = buffer.next_code_boundary(offset);
if request_id != prev_offset {
return None;
}
let input = buffer.slice_to_cow(prev_offset..offset).to_string();
let input = buffer.slice_to_cow(prev_offset..next_offset).to_string();
self.completion.update(input, items);
LAPCE_APP_STATE.submit_ui_command(
LapceUICommand::RequestLayout,

View File

@ -7,6 +7,8 @@
use anyhow::{anyhow, Result};
use druid::{WidgetId, WindowId};
use jsonrpc_lite::{Id, JsonRpc, Params};
use lsp_types::SemanticHighlightingClientCapability;
use lsp_types::SemanticTokensClientCapabilities;
use parking_lot::Mutex;
use std::{
collections::HashMap,
@ -31,7 +33,7 @@
DidSaveTextDocumentParams, DocumentFormattingParams, DocumentSymbolParams,
DocumentSymbolResponse, FormattingOptions, GotoDefinitionParams,
InitializeParams, InitializeResult, PartialResultParams, Position,
PublishDiagnosticsParams, Range, ServerCapabilities,
PublishDiagnosticsParams, Range, SemanticTokensParams, ServerCapabilities,
TextDocumentClientCapabilities, TextDocumentContentChangeEvent,
TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams,
TextDocumentSyncCapability, TextDocumentSyncKind, TextEdit, TraceOption, Url,
@ -58,7 +60,7 @@ pub enum LspProcess {
pub struct LspCatalog {
window_id: WindowId,
tab_id: WidgetId,
clients: HashMap<String, Arc<Mutex<LspClient>>>,
clients: HashMap<String, Arc<LspClient>>,
}
impl Drop for LspCatalog {
@ -78,7 +80,7 @@ pub fn new(window_id: WindowId, tab_id: WidgetId) -> LspCatalog {
pub fn stop(&self) {
for (_, client) in self.clients.iter() {
match &mut client.lock().process {
match &mut client.state.lock().process {
LspProcess::Child(child) => {
child.kill();
}
@ -103,14 +105,20 @@ pub fn start_server(
.clone();
match workspace_type {
LapceWorkspaceType::Local => {
let client =
LspClient::new(self.window_id, self.tab_id, exec_path, options);
let client = LspClient::new(
self.window_id,
self.tab_id,
language_id.to_string(),
exec_path,
options,
);
self.clients.insert(language_id.to_string(), client);
}
LapceWorkspaceType::RemoteSSH(host) => {
if let Ok(client) = LspClient::new_ssh(
self.window_id,
self.tab_id,
language_id.to_string(),
exec_path,
options,
&host,
@ -123,7 +131,7 @@ pub fn start_server(
pub fn save_buffer(&self, buffer: &Buffer) {
if let Some(client) = self.clients.get(&buffer.language_id) {
client.lock().send_did_save(buffer);
client.send_did_save(buffer);
}
}
@ -136,7 +144,7 @@ pub fn new_buffer(
) {
let document_uri = Url::from_file_path(path).unwrap();
if let Some(client) = self.clients.get(language_id) {
client.lock().send_did_open(
client.send_did_open(
buffer_id,
document_uri.clone(),
language_id,
@ -152,7 +160,7 @@ pub fn update(
rev: u64,
) {
if let Some(client) = self.clients.get(&buffer.language_id) {
client.lock().update(buffer, content_change, rev);
client.update(buffer, content_change, rev);
}
}
@ -163,7 +171,13 @@ pub fn get_completion(
position: Position,
) {
if let Some(client) = self.clients.get(&buffer.language_id) {
client.lock().get_completion(request_id, buffer, position);
client.get_completion(request_id, buffer, position);
}
}
pub fn get_semantic_tokens(&self, buffer: &Buffer) {
if let Some(client) = self.clients.get(&buffer.language_id) {
client.get_semantic_tokens(buffer);
}
}
@ -175,9 +189,7 @@ pub fn get_code_actions(&self, offset: usize, buffer: &Buffer) {
end: buffer.offset_to_position(offset),
};
if let Some(client) = self.clients.get(&buffer.language_id) {
client
.lock()
.get_code_actions(buffer, offset, range.clone());
client.get_code_actions(buffer, offset, range.clone());
}
}
@ -186,7 +198,7 @@ pub fn get_document_symbols(
buffer: &Buffer,
) -> Option<DocumentSymbolResponse> {
if let Some(client) = self.clients.get(&buffer.language_id) {
let receiver = { client.lock().get_document_symbols(buffer) };
let receiver = { client.get_document_symbols(buffer) };
let result = receiver.recv_timeout(Duration::from_millis(100));
let result = result.ok()?;
let value = result.ok()?;
@ -203,13 +215,13 @@ pub fn go_to_definition(
position: Position,
) {
if let Some(client) = self.clients.get(&buffer.language_id) {
client.lock().go_to_definition(request_id, buffer, position);
client.go_to_definition(request_id, buffer, position);
}
}
pub fn get_document_formatting(&self, buffer: &Buffer) -> Option<Vec<TextEdit>> {
if let Some(client) = self.clients.get(&buffer.language_id) {
let receiver = { client.lock().get_document_formatting(buffer) };
let receiver = { client.get_document_formatting(buffer) };
let result = receiver.recv_timeout(Duration::from_millis(100));
let result = result.ok()?;
let value = result.ok()?;
@ -221,41 +233,47 @@ pub fn get_document_formatting(&self, buffer: &Buffer) -> Option<Vec<TextEdit>>
pub fn request_document_formatting(&self, buffer: &Buffer) {
if let Some(client) = self.clients.get(&buffer.language_id) {
client.lock().document_formatting(buffer);
client.document_formatting(buffer);
}
}
}
pub trait Callable: Send {
fn call(self: Box<Self>, client: &mut LspClient, result: Result<Value>);
fn call(self: Box<Self>, client: &LspClient, result: Result<Value>);
}
impl<F: Send + FnOnce(&mut LspClient, Result<Value>)> Callable for F {
fn call(self: Box<F>, client: &mut LspClient, result: Result<Value>) {
impl<F: Send + FnOnce(&LspClient, Result<Value>)> Callable for F {
fn call(self: Box<F>, client: &LspClient, result: Result<Value>) {
(*self)(client, result)
}
}
pub struct LspState {
next_id: u64,
writer: Box<dyn Write + Send>,
process: LspProcess,
pending: HashMap<u64, Callback>,
pub server_capabilities: Option<ServerCapabilities>,
pub opened_documents: HashMap<BufferId, Url>,
pub is_initialized: bool,
}
pub struct LspClient {
window_id: WindowId,
tab_id: WidgetId,
writer: Box<dyn Write + Send>,
next_id: u64,
pending: HashMap<u64, Callback>,
language_id: String,
options: Option<Value>,
process: LspProcess,
pub server_capabilities: Option<ServerCapabilities>,
pub opened_documents: HashMap<BufferId, Url>,
pub is_initialized: bool,
state: Arc<Mutex<LspState>>,
}
impl LspClient {
pub fn new(
window_id: WindowId,
tab_id: WidgetId,
language_id: String,
exec_path: &str,
options: Option<Value>,
) -> Arc<Mutex<LspClient>> {
) -> Arc<LspClient> {
let mut process = Command::new(exec_path)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
@ -265,18 +283,21 @@ pub fn new(
let writer = Box::new(BufWriter::new(process.stdin.take().unwrap()));
let stdout = process.stdout.take().unwrap();
let lsp_client = Arc::new(Mutex::new(LspClient {
let lsp_client = Arc::new(LspClient {
window_id,
tab_id,
writer,
next_id: 0,
process: LspProcess::Child(process),
pending: HashMap::new(),
server_capabilities: None,
opened_documents: HashMap::new(),
is_initialized: false,
language_id,
options,
}));
state: Arc::new(Mutex::new(LspState {
next_id: 0,
writer,
process: LspProcess::Child(process),
pending: HashMap::new(),
server_capabilities: None,
opened_documents: HashMap::new(),
is_initialized: false,
})),
});
let local_lsp_client = lsp_client.clone();
thread::spawn(move || {
@ -284,7 +305,7 @@ pub fn new(
loop {
match read_message(&mut reader) {
Ok(message_str) => {
local_lsp_client.lock().handle_message(message_str.as_ref());
local_lsp_client.handle_message(message_str.as_ref());
}
Err(err) => {
eprintln!("lsp read Error occurred {:?}", err);
@ -300,28 +321,32 @@ pub fn new(
pub fn new_ssh(
window_id: WindowId,
tab_id: WidgetId,
language_id: String,
exec_path: &str,
options: Option<Value>,
host: &str,
) -> Result<Arc<Mutex<LspClient>>> {
) -> Result<Arc<LspClient>> {
let mut ssh_session = SshSession::new(host)?;
let mut channel = ssh_session.get_channel()?;
ssh_session.channel_exec(&mut channel, exec_path)?;
println!("lsp {}", exec_path);
let writer = Box::new(ssh_session.get_stream(&channel));
let reader = ssh_session.get_stream(&channel);
let lsp_client = Arc::new(Mutex::new(LspClient {
let lsp_client = Arc::new(LspClient {
window_id,
tab_id,
writer,
next_id: 0,
pending: HashMap::new(),
server_capabilities: None,
process: LspProcess::SshSession(ssh_session),
opened_documents: HashMap::new(),
is_initialized: false,
language_id,
state: Arc::new(Mutex::new(LspState {
next_id: 0,
writer,
process: LspProcess::SshSession(ssh_session),
pending: HashMap::new(),
server_capabilities: None,
opened_documents: HashMap::new(),
is_initialized: false,
})),
options,
}));
});
let local_lsp_client = lsp_client.clone();
// let reader = ssh_session.get_async_stream(channel.stream(0))?;
@ -330,7 +355,7 @@ pub fn new_ssh(
loop {
match read_message(&mut reader) {
Ok(message_str) => {
local_lsp_client.lock().handle_message(message_str.as_ref());
local_lsp_client.handle_message(message_str.as_ref());
}
Err(err) => {
//println!("Error occurred {:?}", err);
@ -343,7 +368,7 @@ pub fn new_ssh(
}
pub fn update(
&mut self,
&self,
buffer: &Buffer,
content_change: &TextDocumentContentChangeEvent,
rev: u64,
@ -355,8 +380,12 @@ pub fn update(
}
}
pub fn get_uri(&mut self, buffer: &Buffer) -> Url {
if !self.opened_documents.contains_key(&buffer.id) {
pub fn get_uri(&self, buffer: &Buffer) -> Url {
let exits = {
let state = self.state.lock();
state.opened_documents.contains_key(&buffer.id)
};
if !exits {
let document_uri = Url::from_file_path(&buffer.path).unwrap();
self.send_did_open(
&buffer.id,
@ -365,11 +394,16 @@ pub fn get_uri(&mut self, buffer: &Buffer) -> Url {
buffer.get_document(),
);
}
self.opened_documents.get(&buffer.id).unwrap().clone()
self.state
.lock()
.opened_documents
.get(&buffer.id)
.unwrap()
.clone()
}
pub fn get_completion(
&mut self,
&self,
request_id: usize,
buffer: &Buffer,
position: Position,
@ -390,12 +424,33 @@ pub fn get_completion(
})
}
pub fn get_code_actions(
&mut self,
buffer: &Buffer,
offset: usize,
range: Range,
) {
pub fn get_semantic_tokens(&self, buffer: &Buffer) {
let uri = self.get_uri(buffer);
let window_id = self.window_id;
let tab_id = self.tab_id;
let rev = buffer.rev;
let buffer_id = buffer.id;
self.request_semantic_tokens(uri, move |lsp_client, result| {
if let Ok(res) = result {
let semantic_tokens_provider = lsp_client
.state
.lock()
.server_capabilities
.as_ref()
.unwrap()
.semantic_tokens_provider
.clone();
thread::spawn(move || {
let state = LAPCE_APP_STATE.get_tab_state(&window_id, &tab_id);
let mut editor_split = state.editor_split.lock();
let buffer = editor_split.buffers.get_mut(&buffer_id).unwrap();
buffer.set_semantic_tokens(semantic_tokens_provider, res);
});
}
})
}
pub fn get_code_actions(&self, buffer: &Buffer, offset: usize, range: Range) {
let uri = self.get_uri(buffer);
let window_id = self.window_id;
let tab_id = self.tab_id;
@ -414,7 +469,7 @@ pub fn get_code_actions(
})
}
pub fn handle_message(&mut self, message: &str) {
pub fn handle_message(&self, message: &str) {
match JsonRpc::parse(message) {
Ok(JsonRpc::Request(obj)) => {
// trace!("client received unexpected request: {:?}", obj)
@ -441,7 +496,7 @@ pub fn handle_message(&mut self, message: &str) {
}
}
pub fn handle_notification(&mut self, method: &str, params: Params) {
pub fn handle_notification(&self, method: &str, params: Params) {
match method {
"textDocument/publishDiagnostics" => {
let window_id = self.window_id;
@ -483,45 +538,43 @@ pub fn handle_notification(&mut self, method: &str, params: Params) {
}
});
}
_ => (),
_ => println!("{} {:?}", method, params),
}
}
pub fn handle_response(&mut self, id: u64, result: Result<Value>) {
pub fn handle_response(&self, id: u64, result: Result<Value>) {
let callback = self
.state
.lock()
.pending
.remove(&id)
.unwrap_or_else(|| panic!("id {} missing from request table", id));
callback.call(self, result);
}
pub fn write(&mut self, msg: &str) {
self.writer
pub fn write(&self, msg: &str) {
let mut state = self.state.lock();
state
.writer
.write_all(msg.as_bytes())
.expect("error writing to stdin");
self.writer.flush().expect("error flushing child stdin");
state.writer.flush().expect("error flushing child stdin");
}
pub fn send_request(
&mut self,
method: &str,
params: Params,
completion: Callback,
) {
let request = JsonRpc::request_with_params(
Id::Num(self.next_id as i64),
method,
params,
);
pub fn send_request(&self, method: &str, params: Params, completion: Callback) {
let request = {
let mut state = self.state.lock();
let next_id = state.next_id;
state.pending.insert(next_id, completion);
state.next_id += 1;
self.pending.insert(self.next_id, completion);
self.next_id += 1;
JsonRpc::request_with_params(Id::Num(next_id as i64), method, params)
};
self.send_rpc(&to_value(&request).unwrap());
}
fn send_rpc(&mut self, value: &Value) {
fn send_rpc(&self, value: &Value) {
let rpc = match prepare_lsp_json(value) {
Ok(r) => r,
Err(err) => panic!("Encoding Error {:?}", err),
@ -530,19 +583,19 @@ fn send_rpc(&mut self, value: &Value) {
self.write(rpc.as_ref());
}
pub fn send_notification(&mut self, method: &str, params: Params) {
pub fn send_notification(&self, method: &str, params: Params) {
let notification = JsonRpc::notification_with_params(method, params);
let res = to_value(&notification).unwrap();
self.send_rpc(&res);
}
pub fn send_initialized(&mut self) {
pub fn send_initialized(&self) {
self.send_notification("initialized", Params::from(json!({})));
}
pub fn send_initialize<CB>(&mut self, root_uri: Option<Url>, on_init: CB)
pub fn send_initialize<CB>(&self, root_uri: Option<Url>, on_init: CB)
where
CB: 'static + Send + FnOnce(&mut LspClient, Result<Value>),
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let client_capabilities = ClientCapabilities {
text_document: Some(TextDocumentClientCapabilities {
@ -576,6 +629,11 @@ pub fn send_initialize<CB>(&mut self, root_uri: Option<Url>, on_init: CB)
}),
..Default::default()
}),
semantic_highlighting_capabilities: Some(
SemanticHighlightingClientCapability {
semantic_highlighting: true,
},
),
..Default::default()
}),
..Default::default()
@ -596,10 +654,7 @@ pub fn send_initialize<CB>(&mut self, root_uri: Option<Url>, on_init: CB)
self.send_request("initialize", params, Box::new(on_init));
}
pub fn get_document_symbols(
&mut self,
buffer: &Buffer,
) -> Receiver<Result<Value>> {
pub fn get_document_symbols(&self, buffer: &Buffer) -> Receiver<Result<Value>> {
let uri = self.get_uri(buffer);
let (sender, receiver) = channel();
self.request_document_symbols(uri, move |lsp_client, result| {
@ -608,9 +663,9 @@ pub fn get_document_symbols(
return receiver;
}
pub fn request_document_symbols<CB>(&mut self, document_uri: Url, cb: CB)
pub fn request_document_symbols<CB>(&self, document_uri: Url, cb: CB)
where
CB: 'static + Send + FnOnce(&mut LspClient, Result<Value>),
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let params = DocumentSymbolParams {
text_document: TextDocumentIdentifier { uri: document_uri },
@ -622,7 +677,7 @@ pub fn request_document_symbols<CB>(&mut self, document_uri: Url, cb: CB)
}
pub fn get_document_formatting(
&mut self,
&self,
buffer: &Buffer,
) -> Receiver<Result<Value>> {
let uri = self.get_uri(buffer);
@ -633,7 +688,7 @@ pub fn get_document_formatting(
return receiver;
}
pub fn document_formatting(&mut self, buffer: &Buffer) {
pub fn document_formatting(&self, buffer: &Buffer) {
let uri = self.get_uri(buffer);
let rev = buffer.rev;
let window_id = self.window_id;
@ -658,9 +713,9 @@ pub fn document_formatting(&mut self, buffer: &Buffer) {
})
}
pub fn request_document_formatting<CB>(&mut self, document_uri: Url, cb: CB)
pub fn request_document_formatting<CB>(&self, document_uri: Url, cb: CB)
where
CB: 'static + Send + FnOnce(&mut LspClient, Result<Value>),
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let params = DocumentFormattingParams {
text_document: TextDocumentIdentifier { uri: document_uri },
@ -676,7 +731,7 @@ pub fn request_document_formatting<CB>(&mut self, document_uri: Url, cb: CB)
}
pub fn go_to_definition(
&mut self,
&self,
request_id: usize,
buffer: &Buffer,
position: Position,
@ -698,12 +753,12 @@ pub fn go_to_definition(
}
pub fn request_definition<CB>(
&mut self,
&self,
document_uri: Url,
position: Position,
on_definition: CB,
) where
CB: 'static + Send + FnOnce(&mut LspClient, Result<Value>),
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let params = GotoDefinitionParams {
text_document_position_params: TextDocumentPositionParams {
@ -721,13 +776,9 @@ pub fn request_definition<CB>(
);
}
pub fn request_code_actions<CB>(
&mut self,
document_uri: Url,
range: Range,
cb: CB,
) where
CB: 'static + Send + FnOnce(&mut LspClient, Result<Value>),
pub fn request_code_actions<CB>(&self, document_uri: Url, range: Range, cb: CB)
where
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let params = CodeActionParams {
text_document: TextDocumentIdentifier { uri: document_uri },
@ -740,13 +791,26 @@ pub fn request_code_actions<CB>(
self.send_request("textDocument/codeAction", params, Box::new(cb));
}
pub fn request_semantic_tokens<CB>(&self, document_uri: Url, cb: CB)
where
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let params = SemanticTokensParams {
text_document: TextDocumentIdentifier { uri: document_uri },
work_done_progress_params: WorkDoneProgressParams::default(),
partial_result_params: PartialResultParams::default(),
};
let params = Params::from(serde_json::to_value(params).unwrap());
self.send_request("textDocument/semanticTokens/full", params, Box::new(cb));
}
pub fn request_completion<CB>(
&mut self,
&self,
document_uri: Url,
position: Position,
on_completion: CB,
) where
CB: 'static + Send + FnOnce(&mut LspClient, Result<Value>),
CB: 'static + Send + FnOnce(&LspClient, Result<Value>),
{
let completion_params = CompletionParams {
text_document_position: TextDocumentPositionParams {
@ -766,14 +830,44 @@ pub fn request_completion<CB>(
}
pub fn send_did_open(
&mut self,
&self,
buffer_id: &BufferId,
document_uri: Url,
language_id: &str,
document_text: String,
) {
self.opened_documents
.insert(buffer_id.clone(), document_uri.clone());
let is_initialized = {
let mut state = self.state.lock();
state
.opened_documents
.insert(buffer_id.clone(), document_uri.clone());
state.is_initialized
};
if !is_initialized {
let workspace_path = LAPCE_APP_STATE
.get_tab_state(&self.window_id, &self.tab_id)
.workspace
.lock()
.path
.clone();
let root_url = Url::from_directory_path(workspace_path).unwrap();
let (sender, receiver) = channel();
self.send_initialize(Some(root_url), move |lsp_client, result| {
if let Ok(result) = result {
{
let init_result: InitializeResult =
serde_json::from_value(result).unwrap();
let mut state = lsp_client.state.lock();
state.server_capabilities = Some(init_result.capabilities);
state.is_initialized = true;
}
lsp_client.send_initialized();
}
sender.send(true);
});
receiver.recv_timeout(Duration::from_millis(1000));
}
let text_document_did_open_params = DidOpenTextDocumentParams {
text_document: TextDocumentItem {
@ -783,35 +877,13 @@ pub fn send_did_open(
text: document_text,
},
};
let params = Params::from(
serde_json::to_value(text_document_did_open_params).unwrap(),
);
let workspace_path = LAPCE_APP_STATE
.get_tab_state(&self.window_id, &self.tab_id)
.workspace
.lock()
.path
.clone();
let root_url = Url::from_directory_path(workspace_path).unwrap();
if !self.is_initialized {
self.send_initialize(Some(root_url), move |lsp_client, result| {
if let Ok(result) = result {
let init_result: InitializeResult =
serde_json::from_value(result).unwrap();
lsp_client.server_capabilities = Some(init_result.capabilities);
lsp_client.is_initialized = true;
lsp_client.send_initialized();
lsp_client.send_notification("textDocument/didOpen", params);
}
});
} else {
self.send_notification("textDocument/didOpen", params);
}
self.send_notification("textDocument/didOpen", params);
}
pub fn send_did_save(&mut self, buffer: &Buffer) {
pub fn send_did_save(&self, buffer: &Buffer) {
let uri = self.get_uri(buffer);
let params = DidSaveTextDocumentParams {
text_document: TextDocumentIdentifier { uri },
@ -822,7 +894,7 @@ pub fn send_did_save(&mut self, buffer: &Buffer) {
}
pub fn send_did_change(
&mut self,
&self,
buffer: &Buffer,
changes: Vec<TextDocumentContentChangeEvent>,
version: u64,
@ -843,7 +915,8 @@ pub fn send_did_change(
}
pub fn get_sync_kind(&self) -> Option<TextDocumentSyncKind> {
let text_document_sync = self
let state = self.state.lock();
let text_document_sync = state
.server_capabilities
.as_ref()
.and_then(|c| c.text_document_sync.as_ref())?;