2018-09-24 09:52:33 -04:00
|
|
|
use std::collections::{HashMap};
|
2018-08-13 02:38:34 +03:00
|
|
|
|
2018-08-12 21:02:56 +03:00
|
|
|
use languageserver_types::{
|
2018-08-30 16:27:09 +03:00
|
|
|
Diagnostic, DiagnosticSeverity, DocumentSymbol,
|
2018-09-23 11:10:57 -04:00
|
|
|
CodeActionResponse, Command, TextDocumentIdentifier,
|
2018-08-23 22:14:51 +03:00
|
|
|
SymbolInformation, Position, Location, TextEdit,
|
2018-08-28 21:11:17 +03:00
|
|
|
CompletionItem, InsertTextFormat, CompletionItemKind,
|
2018-09-23 11:13:27 -04:00
|
|
|
FoldingRange, FoldingRangeParams, FoldingRangeKind
|
2018-08-12 21:02:56 +03:00
|
|
|
};
|
2018-08-29 18:03:14 +03:00
|
|
|
use serde_json::to_value;
|
2018-09-24 09:52:33 -04:00
|
|
|
use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind};
|
2018-09-16 12:54:24 +03:00
|
|
|
use ra_syntax::{
|
2018-09-24 09:52:33 -04:00
|
|
|
text_utils::contains_offset_nonstrict
|
2018-08-24 13:41:25 +03:00
|
|
|
};
|
2018-08-10 23:30:11 +03:00
|
|
|
|
2018-08-11 00:12:31 +03:00
|
|
|
use ::{
|
2018-08-11 00:55:32 +03:00
|
|
|
req::{self, Decoration}, Result,
|
2018-08-15 17:24:20 +03:00
|
|
|
conv::{Conv, ConvWith, TryConvWith, MapConvWith, to_location},
|
2018-08-17 19:54:08 +03:00
|
|
|
server_world::ServerWorld,
|
2018-09-02 16:36:03 +03:00
|
|
|
project_model::TargetKind,
|
2018-08-11 00:12:31 +03:00
|
|
|
};
|
2018-08-10 21:13:39 +03:00
|
|
|
|
|
|
|
pub fn handle_syntax_tree(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-10 22:23:17 +03:00
|
|
|
params: req::SyntaxTreeParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-10 21:13:39 +03:00
|
|
|
) -> Result<String> {
|
2018-08-17 19:54:08 +03:00
|
|
|
let id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let res = world.analysis().syntax_tree(id);
|
|
|
|
Ok(res)
|
2018-08-10 21:13:39 +03:00
|
|
|
}
|
2018-08-10 22:23:17 +03:00
|
|
|
|
|
|
|
pub fn handle_extend_selection(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-10 22:23:17 +03:00
|
|
|
params: req::ExtendSelectionParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-10 22:23:17 +03:00
|
|
|
) -> Result<req::ExtendSelectionResult> {
|
2018-08-17 19:54:08 +03:00
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let file = world.analysis().file_syntax(file_id);
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-10 22:23:17 +03:00
|
|
|
let selections = params.selections.into_iter()
|
2018-08-13 02:38:34 +03:00
|
|
|
.map_conv_with(&line_index)
|
2018-08-29 18:03:14 +03:00
|
|
|
.map(|r| world.analysis().extend_selection(&file, r))
|
2018-08-13 02:38:34 +03:00
|
|
|
.map_conv_with(&line_index)
|
2018-08-10 22:23:17 +03:00
|
|
|
.collect();
|
|
|
|
Ok(req::ExtendSelectionResult { selections })
|
|
|
|
}
|
|
|
|
|
2018-08-16 00:23:22 +03:00
|
|
|
pub fn handle_find_matching_brace(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-16 00:23:22 +03:00
|
|
|
params: req::FindMatchingBraceParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-16 00:23:22 +03:00
|
|
|
) -> Result<Vec<Position>> {
|
2018-08-17 19:54:08 +03:00
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let file = world.analysis().file_syntax(file_id);
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-16 00:23:22 +03:00
|
|
|
let res = params.offsets
|
|
|
|
.into_iter()
|
|
|
|
.map_conv_with(&line_index)
|
|
|
|
.map(|offset| {
|
2018-08-29 18:03:14 +03:00
|
|
|
world.analysis().matching_brace(&file, offset).unwrap_or(offset)
|
2018-08-16 00:23:22 +03:00
|
|
|
})
|
|
|
|
.map_conv_with(&line_index)
|
|
|
|
.collect();
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
2018-08-23 22:14:51 +03:00
|
|
|
pub fn handle_join_lines(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: req::JoinLinesParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-29 18:03:14 +03:00
|
|
|
) -> Result<req::SourceChange> {
|
2018-08-23 22:14:51 +03:00
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-23 22:14:51 +03:00
|
|
|
let range = params.range.conv_with(&line_index);
|
2018-08-29 18:03:14 +03:00
|
|
|
world.analysis().join_lines(file_id, range)
|
|
|
|
.try_conv_with(&world)
|
|
|
|
}
|
|
|
|
|
2018-10-09 16:00:20 +03:00
|
|
|
pub fn handle_on_enter(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: req::TextDocumentPositionParams,
|
|
|
|
_token: JobToken,
|
|
|
|
) -> Result<Option<req::SourceChange>> {
|
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
|
|
|
let offset = params.position.conv_with(&line_index);
|
|
|
|
match world.analysis().on_enter(file_id, offset) {
|
|
|
|
None => Ok(None),
|
|
|
|
Some(edit) => Ok(Some(edit.try_conv_with(&world)?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
pub fn handle_on_type_formatting(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: req::DocumentOnTypeFormattingParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-29 18:03:14 +03:00
|
|
|
) -> Result<Option<Vec<TextEdit>>> {
|
|
|
|
if params.ch != "=" {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
|
|
|
let offset = params.position.conv_with(&line_index);
|
|
|
|
let edits = match world.analysis().on_eq_typed(file_id, offset) {
|
|
|
|
None => return Ok(None),
|
|
|
|
Some(mut action) => action.source_file_edits.pop().unwrap().edits,
|
|
|
|
};
|
|
|
|
let edits = edits.into_iter().map_conv_with(&line_index).collect();
|
|
|
|
Ok(Some(edits))
|
2018-08-23 22:14:51 +03:00
|
|
|
}
|
|
|
|
|
2018-08-11 14:44:12 +03:00
|
|
|
pub fn handle_document_symbol(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-11 14:44:12 +03:00
|
|
|
params: req::DocumentSymbolParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-11 14:44:12 +03:00
|
|
|
) -> Result<Option<req::DocumentSymbolResponse>> {
|
2018-08-17 19:54:08 +03:00
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-11 14:44:12 +03:00
|
|
|
|
2018-08-14 11:20:09 +03:00
|
|
|
let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new();
|
2018-08-11 14:44:12 +03:00
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
for symbol in world.analysis().file_structure(file_id) {
|
2018-08-11 14:44:12 +03:00
|
|
|
let doc_symbol = DocumentSymbol {
|
2018-08-14 11:20:09 +03:00
|
|
|
name: symbol.label,
|
|
|
|
detail: Some("".to_string()),
|
2018-08-12 21:02:56 +03:00
|
|
|
kind: symbol.kind.conv(),
|
2018-08-11 14:44:12 +03:00
|
|
|
deprecated: None,
|
2018-08-12 21:02:56 +03:00
|
|
|
range: symbol.node_range.conv_with(&line_index),
|
2018-08-14 11:20:09 +03:00
|
|
|
selection_range: symbol.navigation_range.conv_with(&line_index),
|
2018-08-11 14:44:12 +03:00
|
|
|
children: None,
|
|
|
|
};
|
2018-08-14 11:20:09 +03:00
|
|
|
parents.push((doc_symbol, symbol.parent));
|
|
|
|
}
|
|
|
|
let mut res = Vec::new();
|
|
|
|
while let Some((node, parent)) = parents.pop() {
|
|
|
|
match parent {
|
|
|
|
None => res.push(node),
|
|
|
|
Some(i) => {
|
|
|
|
let children = &mut parents[i].0.children;
|
|
|
|
if children.is_none() {
|
|
|
|
*children = Some(Vec::new());
|
|
|
|
}
|
|
|
|
children.as_mut().unwrap().push(node);
|
2018-08-11 14:44:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-14 11:20:09 +03:00
|
|
|
|
2018-08-11 14:44:12 +03:00
|
|
|
Ok(Some(req::DocumentSymbolResponse::Nested(res)))
|
|
|
|
}
|
|
|
|
|
2018-08-13 15:35:53 +03:00
|
|
|
pub fn handle_workspace_symbol(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-13 15:35:53 +03:00
|
|
|
params: req::WorkspaceSymbolParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
token: JobToken,
|
2018-08-13 15:35:53 +03:00
|
|
|
) -> Result<Option<Vec<SymbolInformation>>> {
|
2018-08-14 13:33:44 +03:00
|
|
|
let all_symbols = params.query.contains("#");
|
2018-09-03 21:03:37 +03:00
|
|
|
let libs = params.query.contains("*");
|
2018-08-13 16:07:05 +03:00
|
|
|
let query = {
|
|
|
|
let query: String = params.query.chars()
|
2018-09-03 21:03:37 +03:00
|
|
|
.filter(|&c| c != '#' && c != '*')
|
2018-08-13 16:07:05 +03:00
|
|
|
.collect();
|
|
|
|
let mut q = Query::new(query);
|
|
|
|
if !all_symbols {
|
|
|
|
q.only_types();
|
|
|
|
}
|
2018-09-03 21:03:37 +03:00
|
|
|
if libs {
|
|
|
|
q.libs();
|
|
|
|
}
|
2018-08-13 17:19:27 +03:00
|
|
|
q.limit(128);
|
2018-08-13 16:07:05 +03:00
|
|
|
q
|
|
|
|
};
|
2018-08-31 12:04:33 +03:00
|
|
|
let mut res = exec_query(&world, query, &token)?;
|
2018-08-14 13:33:44 +03:00
|
|
|
if res.is_empty() && !all_symbols {
|
|
|
|
let mut query = Query::new(params.query);
|
|
|
|
query.limit(128);
|
2018-08-31 12:04:33 +03:00
|
|
|
res = exec_query(&world, query, &token)?;
|
2018-08-14 13:33:44 +03:00
|
|
|
}
|
2018-08-13 16:07:05 +03:00
|
|
|
|
2018-08-14 13:33:44 +03:00
|
|
|
return Ok(Some(res));
|
|
|
|
|
2018-08-31 12:04:33 +03:00
|
|
|
fn exec_query(world: &ServerWorld, query: Query, token: &JobToken) -> Result<Vec<SymbolInformation>> {
|
2018-08-14 13:33:44 +03:00
|
|
|
let mut res = Vec::new();
|
2018-08-31 12:04:33 +03:00
|
|
|
for (file_id, symbol) in world.analysis().symbol_search(query, token) {
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-14 13:33:44 +03:00
|
|
|
let info = SymbolInformation {
|
|
|
|
name: symbol.name.to_string(),
|
|
|
|
kind: symbol.kind.conv(),
|
2018-08-15 17:24:20 +03:00
|
|
|
location: to_location(
|
|
|
|
file_id, symbol.node_range,
|
2018-08-17 19:54:08 +03:00
|
|
|
world, &line_index
|
2018-08-15 17:24:20 +03:00
|
|
|
)?,
|
2018-08-14 13:33:44 +03:00
|
|
|
container_name: None,
|
2018-09-23 11:13:27 -04:00
|
|
|
deprecated: None,
|
2018-08-14 13:33:44 +03:00
|
|
|
};
|
|
|
|
res.push(info);
|
2018-08-13 15:35:53 +03:00
|
|
|
};
|
2018-08-14 13:33:44 +03:00
|
|
|
Ok(res)
|
|
|
|
}
|
2018-08-13 15:35:53 +03:00
|
|
|
}
|
|
|
|
|
2018-08-13 16:35:17 +03:00
|
|
|
pub fn handle_goto_definition(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-13 16:35:17 +03:00
|
|
|
params: req::TextDocumentPositionParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
token: JobToken,
|
2018-08-13 16:35:17 +03:00
|
|
|
) -> Result<Option<req::GotoDefinitionResponse>> {
|
2018-08-17 19:54:08 +03:00
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-13 16:35:17 +03:00
|
|
|
let offset = params.position.conv_with(&line_index);
|
|
|
|
let mut res = Vec::new();
|
2018-08-31 12:04:33 +03:00
|
|
|
for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset, &token) {
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-15 17:24:20 +03:00
|
|
|
let location = to_location(
|
|
|
|
file_id, symbol.node_range,
|
2018-08-17 19:54:08 +03:00
|
|
|
&world, &line_index,
|
2018-08-15 17:24:20 +03:00
|
|
|
)?;
|
2018-08-13 16:35:17 +03:00
|
|
|
res.push(location)
|
|
|
|
}
|
|
|
|
Ok(Some(req::GotoDefinitionResponse::Array(res)))
|
|
|
|
}
|
|
|
|
|
2018-08-22 10:18:58 +03:00
|
|
|
pub fn handle_parent_module(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: TextDocumentIdentifier,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-22 10:18:58 +03:00
|
|
|
) -> Result<Vec<Location>> {
|
|
|
|
let file_id = params.try_conv_with(&world)?;
|
|
|
|
let mut res = Vec::new();
|
|
|
|
for (file_id, symbol) in world.analysis().parent_module(file_id) {
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-22 10:18:58 +03:00
|
|
|
let location = to_location(
|
|
|
|
file_id, symbol.node_range,
|
|
|
|
&world, &line_index
|
|
|
|
)?;
|
|
|
|
res.push(location);
|
|
|
|
}
|
|
|
|
Ok(res)
|
|
|
|
}
|
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
pub fn handle_runnables(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: req::RunnablesParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-29 18:03:14 +03:00
|
|
|
) -> Result<Vec<req::Runnable>> {
|
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
|
|
|
let offset = params.position.map(|it| it.conv_with(&line_index));
|
|
|
|
let mut res = Vec::new();
|
|
|
|
for runnable in world.analysis().runnables(file_id) {
|
|
|
|
if let Some(offset) = offset {
|
|
|
|
if !contains_offset_nonstrict(runnable.range, offset) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-02 16:36:03 +03:00
|
|
|
let args = runnable_args(&world, file_id, &runnable.kind);
|
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
let r = req::Runnable {
|
|
|
|
range: runnable.range.conv_with(&line_index),
|
|
|
|
label: match &runnable.kind {
|
|
|
|
RunnableKind::Test { name } =>
|
|
|
|
format!("test {}", name),
|
|
|
|
RunnableKind::Bin =>
|
|
|
|
"run binary".to_string(),
|
|
|
|
},
|
|
|
|
bin: "cargo".to_string(),
|
2018-09-02 16:36:03 +03:00
|
|
|
args,
|
2018-08-29 18:03:14 +03:00
|
|
|
env: {
|
|
|
|
let mut m = HashMap::new();
|
|
|
|
m.insert(
|
|
|
|
"RUST_BACKTRACE".to_string(),
|
|
|
|
"short".to_string(),
|
|
|
|
);
|
|
|
|
m
|
|
|
|
}
|
|
|
|
};
|
|
|
|
res.push(r);
|
|
|
|
}
|
|
|
|
return Ok(res);
|
2018-09-02 16:36:03 +03:00
|
|
|
|
|
|
|
fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Vec<String> {
|
|
|
|
let spec = if let Some(&crate_id) = world.analysis().crate_for(file_id).first() {
|
|
|
|
let file_id = world.analysis().crate_root(crate_id);
|
|
|
|
let path = world.path_map.get_path(file_id);
|
|
|
|
world.workspaces.iter()
|
|
|
|
.filter_map(|ws| {
|
|
|
|
let tgt = ws.target_by_root(path)?;
|
|
|
|
Some((tgt.package(ws).name(ws).clone(), tgt.name(ws).clone(), tgt.kind(ws)))
|
|
|
|
})
|
|
|
|
.next()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
let mut res = Vec::new();
|
|
|
|
match kind {
|
|
|
|
RunnableKind::Test { name } => {
|
|
|
|
res.push("test".to_string());
|
|
|
|
if let Some((pkg_name, tgt_name, tgt_kind)) = spec {
|
|
|
|
spec_args(pkg_name, tgt_name, tgt_kind, &mut res);
|
|
|
|
}
|
|
|
|
res.push("--".to_string());
|
|
|
|
res.push(name.to_string());
|
|
|
|
res.push("--nocapture".to_string());
|
|
|
|
}
|
|
|
|
RunnableKind::Bin => {
|
|
|
|
res.push("run".to_string());
|
|
|
|
if let Some((pkg_name, tgt_name, tgt_kind)) = spec {
|
|
|
|
spec_args(pkg_name, tgt_name, tgt_kind, &mut res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
|
|
|
fn spec_args(pkg_name: &str, tgt_name: &str, tgt_kind: TargetKind, buf: &mut Vec<String>) {
|
|
|
|
buf.push("--package".to_string());
|
|
|
|
buf.push(pkg_name.to_string());
|
|
|
|
match tgt_kind {
|
|
|
|
TargetKind::Bin => {
|
|
|
|
buf.push("--bin".to_string());
|
|
|
|
buf.push(tgt_name.to_string());
|
|
|
|
}
|
|
|
|
TargetKind::Test => {
|
|
|
|
buf.push("--test".to_string());
|
|
|
|
buf.push(tgt_name.to_string());
|
|
|
|
}
|
|
|
|
TargetKind::Bench => {
|
|
|
|
buf.push("--bench".to_string());
|
|
|
|
buf.push(tgt_name.to_string());
|
|
|
|
}
|
|
|
|
TargetKind::Example => {
|
|
|
|
buf.push("--example".to_string());
|
|
|
|
buf.push(tgt_name.to_string());
|
|
|
|
}
|
|
|
|
TargetKind::Lib => {
|
|
|
|
buf.push("--lib".to_string());
|
|
|
|
}
|
|
|
|
TargetKind::Other => (),
|
|
|
|
}
|
|
|
|
}
|
2018-08-29 18:03:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn handle_decorations(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: TextDocumentIdentifier,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-29 18:03:14 +03:00
|
|
|
) -> Result<Vec<Decoration>> {
|
|
|
|
let file_id = params.try_conv_with(&world)?;
|
|
|
|
Ok(highlight(&world, file_id))
|
|
|
|
}
|
|
|
|
|
2018-08-26 12:51:45 +03:00
|
|
|
pub fn handle_completion(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: req::CompletionParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-08-26 12:51:45 +03:00
|
|
|
) -> Result<Option<req::CompletionResponse>> {
|
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-08-26 12:51:45 +03:00
|
|
|
let offset = params.position.conv_with(&line_index);
|
2018-08-29 18:03:14 +03:00
|
|
|
let items = match world.analysis().completions(file_id, offset) {
|
2018-08-26 12:51:45 +03:00
|
|
|
None => return Ok(None),
|
|
|
|
Some(items) => items,
|
|
|
|
};
|
|
|
|
let items = items.into_iter()
|
2018-08-28 21:11:17 +03:00
|
|
|
.map(|item| {
|
|
|
|
let mut res = CompletionItem {
|
2018-09-03 15:10:06 +03:00
|
|
|
label: item.label,
|
|
|
|
filter_text: item.lookup,
|
2018-08-28 21:11:17 +03:00
|
|
|
.. Default::default()
|
|
|
|
};
|
|
|
|
if let Some(snip) = item.snippet {
|
|
|
|
res.insert_text = Some(snip);
|
|
|
|
res.insert_text_format = Some(InsertTextFormat::Snippet);
|
|
|
|
res.kind = Some(CompletionItemKind::Keyword);
|
|
|
|
};
|
|
|
|
res
|
2018-08-26 12:51:45 +03:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
Ok(Some(req::CompletionResponse::Array(items)))
|
|
|
|
}
|
|
|
|
|
2018-09-23 11:13:27 -04:00
|
|
|
pub fn handle_folding_range(
|
|
|
|
world: ServerWorld,
|
|
|
|
params: FoldingRangeParams,
|
|
|
|
_token: JobToken,
|
|
|
|
) -> Result<Option<Vec<FoldingRange>>> {
|
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
|
|
|
|
2018-09-24 09:52:33 -04:00
|
|
|
let res = Some(world.analysis()
|
|
|
|
.folding_ranges(file_id)
|
|
|
|
.into_iter()
|
|
|
|
.map(|fold| {
|
|
|
|
let kind = match fold.kind {
|
|
|
|
FoldKind::Comment => FoldingRangeKind::Comment,
|
|
|
|
FoldKind::Imports => FoldingRangeKind::Imports
|
|
|
|
};
|
|
|
|
let range = fold.range.conv_with(&line_index);
|
|
|
|
FoldingRange {
|
|
|
|
start_line: range.start.line,
|
|
|
|
start_character: Some(range.start.character),
|
|
|
|
end_line: range.end.line,
|
|
|
|
end_character: Some(range.start.character),
|
|
|
|
kind: Some(kind)
|
2018-09-23 11:13:27 -04:00
|
|
|
}
|
2018-09-24 09:52:33 -04:00
|
|
|
})
|
|
|
|
.collect());
|
2018-09-23 11:13:27 -04:00
|
|
|
|
2018-09-24 09:52:33 -04:00
|
|
|
Ok(res)
|
2018-09-23 11:13:27 -04:00
|
|
|
}
|
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
pub fn handle_code_action(
|
2018-08-28 11:12:42 +03:00
|
|
|
world: ServerWorld,
|
2018-08-29 18:03:14 +03:00
|
|
|
params: req::CodeActionParams,
|
2018-08-31 12:04:33 +03:00
|
|
|
_token: JobToken,
|
2018-09-23 11:10:57 -04:00
|
|
|
) -> Result<Option<CodeActionResponse>> {
|
2018-08-28 11:12:42 +03:00
|
|
|
let file_id = params.text_document.try_conv_with(&world)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
2018-09-06 00:59:07 +03:00
|
|
|
let range = params.range.conv_with(&line_index);
|
2018-08-13 02:38:34 +03:00
|
|
|
|
2018-09-06 00:59:07 +03:00
|
|
|
let assists = world.analysis().assists(file_id, range).into_iter();
|
2018-08-29 18:03:14 +03:00
|
|
|
let fixes = world.analysis().diagnostics(file_id).into_iter()
|
|
|
|
.filter_map(|d| Some((d.range, d.fix?)))
|
2018-09-06 00:59:07 +03:00
|
|
|
.filter(|(range, _fix)| contains_offset_nonstrict(*range, range.start()))
|
2018-08-29 18:03:14 +03:00
|
|
|
.map(|(_range, fix)| fix);
|
2018-08-13 02:38:34 +03:00
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
let mut res = Vec::new();
|
|
|
|
for source_edit in assists.chain(fixes) {
|
|
|
|
let title = source_edit.label.clone();
|
|
|
|
let edit = source_edit.try_conv_with(&world)?;
|
|
|
|
let cmd = Command {
|
|
|
|
title,
|
2018-09-29 21:59:34 +03:00
|
|
|
command: "ra-lsp.applySourceChange".to_string(),
|
2018-08-29 18:03:14 +03:00
|
|
|
arguments: Some(vec![to_value(edit).unwrap()]),
|
|
|
|
};
|
|
|
|
res.push(cmd);
|
2018-08-12 21:02:56 +03:00
|
|
|
}
|
|
|
|
|
2018-09-23 11:10:57 -04:00
|
|
|
Ok(Some(CodeActionResponse::Commands(res)))
|
2018-08-11 14:44:12 +03:00
|
|
|
}
|
|
|
|
|
2018-08-15 17:24:20 +03:00
|
|
|
pub fn publish_diagnostics(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-30 16:27:09 +03:00
|
|
|
file_id: FileId,
|
2018-08-15 17:24:20 +03:00
|
|
|
) -> Result<req::PublishDiagnosticsParams> {
|
2018-08-30 16:27:09 +03:00
|
|
|
let uri = world.file_id_to_uri(file_id)?;
|
2018-08-29 18:03:14 +03:00
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
|
|
|
let diagnostics = world.analysis().diagnostics(file_id)
|
2018-08-10 23:30:11 +03:00
|
|
|
.into_iter()
|
2018-08-29 18:03:14 +03:00
|
|
|
.map(|d| Diagnostic {
|
2018-08-12 21:02:56 +03:00
|
|
|
range: d.range.conv_with(&line_index),
|
2018-08-10 23:30:11 +03:00
|
|
|
severity: Some(DiagnosticSeverity::Error),
|
|
|
|
code: None,
|
2018-09-18 17:40:33 -04:00
|
|
|
source: Some("rust-analyzer".to_string()),
|
2018-08-29 18:03:14 +03:00
|
|
|
message: d.message,
|
2018-08-10 23:30:11 +03:00
|
|
|
related_information: None,
|
|
|
|
}).collect();
|
|
|
|
Ok(req::PublishDiagnosticsParams { uri, diagnostics })
|
|
|
|
}
|
|
|
|
|
2018-08-15 17:24:20 +03:00
|
|
|
pub fn publish_decorations(
|
2018-08-17 19:54:08 +03:00
|
|
|
world: ServerWorld,
|
2018-08-30 16:27:09 +03:00
|
|
|
file_id: FileId,
|
2018-08-15 17:24:20 +03:00
|
|
|
) -> Result<req::PublishDecorationsParams> {
|
2018-08-30 16:27:09 +03:00
|
|
|
let uri = world.file_id_to_uri(file_id)?;
|
2018-08-28 00:20:59 +03:00
|
|
|
Ok(req::PublishDecorationsParams {
|
|
|
|
uri,
|
2018-08-29 18:03:14 +03:00
|
|
|
decorations: highlight(&world, file_id),
|
2018-08-28 00:20:59 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-08-29 18:03:14 +03:00
|
|
|
fn highlight(world: &ServerWorld, file_id: FileId) -> Vec<Decoration> {
|
|
|
|
let line_index = world.analysis().file_line_index(file_id);
|
|
|
|
world.analysis().highlight(file_id)
|
2018-08-11 00:55:32 +03:00
|
|
|
.into_iter()
|
|
|
|
.map(|h| Decoration {
|
2018-08-12 21:02:56 +03:00
|
|
|
range: h.range.conv_with(&line_index),
|
2018-08-11 00:55:32 +03:00
|
|
|
tag: h.tag,
|
2018-08-29 18:03:14 +03:00
|
|
|
}).collect()
|
2018-08-11 00:55:32 +03:00
|
|
|
}
|