627 lines
20 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
2018-08-13 02:38:34 +03:00
use rustc_hash::FxHashMap;
2018-08-12 21:02:56 +03:00
use languageserver_types::{
CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
DiagnosticSeverity, DocumentSymbol, FoldingRange, FoldingRangeKind, FoldingRangeParams,
InsertTextFormat, Location, Position, SymbolInformation, TextDocumentIdentifier, TextEdit,
2018-10-19 15:25:10 -04:00
RenameParams, WorkspaceEdit, PrepareRenameResponse
2018-08-12 21:02:56 +03:00
};
use gen_lsp_server::ErrorCode;
2018-10-20 22:59:54 +03:00
use ra_analysis::{FileId, FoldKind, Query, RunnableKind};
use ra_syntax::text_utils::contains_offset_nonstrict;
2018-08-29 18:03:14 +03:00
use serde_json::to_value;
2018-08-10 23:30:11 +03:00
2018-10-15 20:15:53 +03:00
use crate::{
conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith},
2018-09-02 16:36:03 +03:00
project_model::TargetKind,
req::{self, Decoration},
server_world::ServerWorld,
Result, LspError
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-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,
) -> 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);
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,
) -> 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);
let res = params
.offsets
2018-08-16 00:23:22 +03:00
.into_iter()
.map_conv_with(&line_index)
.map(|offset| {
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-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);
world
.analysis()
.join_lines(file_id, range)
2018-08-29 18:03:14 +03:00
.try_conv_with(&world)
}
pub fn handle_on_enter(
world: ServerWorld,
params: req::TextDocumentPositionParams,
) -> 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,
) -> 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,
) -> 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,
) -> Result<Option<Vec<SymbolInformation>>> {
let all_symbols = params.query.contains('#');
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-10-20 22:02:41 +03:00
let mut res = exec_query(&world, query)?;
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-10-20 22:02:41 +03:00
res = exec_query(&world, query)?;
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));
fn exec_query(
world: &ServerWorld,
query: Query,
) -> Result<Vec<SymbolInformation>> {
2018-08-14 13:33:44 +03:00
let mut res = Vec::new();
2018-10-20 22:09:12 +03:00
for (file_id, symbol) in world.analysis().symbol_search(query)? {
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(),
location: to_location(file_id, symbol.node_range, world, &line_index)?,
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-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,
) -> 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();
for (file_id, symbol) in world
.analysis()
2018-10-20 22:09:12 +03:00
.approximately_resolve_symbol(file_id, offset)?
{
2018-08-29 18:03:14 +03:00
let line_index = world.analysis().file_line_index(file_id);
let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
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,
) -> Result<Vec<Location>> {
let file_id = params.try_conv_with(&world)?;
let mut res = Vec::new();
2018-10-20 21:52:49 +03:00
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);
let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
2018-08-22 10:18:58 +03:00
res.push(location);
}
Ok(res)
}
2018-08-29 18:03:14 +03:00
pub fn handle_runnables(
world: ServerWorld,
params: req::RunnablesParams,
) -> 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();
2018-10-20 22:02:41 +03:00
for runnable in world.analysis().runnables(file_id)? {
2018-08-29 18:03:14 +03:00
if let Some(offset) = offset {
if !contains_offset_nonstrict(runnable.range, offset) {
continue;
}
}
2018-10-20 22:02:41 +03:00
let args = runnable_args(&world, file_id, &runnable.kind)?;
2018-09-02 16:36:03 +03:00
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(),
2018-08-29 18:03:14 +03:00
},
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 = FxHashMap::default();
m.insert("RUST_BACKTRACE".to_string(), "short".to_string());
2018-08-29 18:03:14 +03:00
m
},
2018-08-29 18:03:14 +03:00
};
res.push(r);
}
let mut check_args = vec!["check".to_string()];
match CargoTargetSpec::for_file(&world, file_id)? {
Some(spec) => spec.push_to(&mut check_args),
None => check_args.push("--all".to_string()),
}
2018-10-25 10:29:39 +03:00
// Always add `cargo check`.
res.push(req::Runnable {
range: Default::default(),
label: "cargo check".to_string(),
bin: "cargo".to_string(),
args: check_args,
2018-10-25 10:29:39 +03:00
env: FxHashMap::default(),
});
2018-08-29 18:03:14 +03:00
return Ok(res);
2018-09-02 16:36:03 +03:00
2018-10-20 22:02:41 +03:00
fn runnable_args(world: &ServerWorld, file_id: FileId, kind: &RunnableKind) -> Result<Vec<String>> {
let spec = CargoTargetSpec::for_file(world, file_id)?;
2018-09-02 16:36:03 +03:00
let mut res = Vec::new();
match kind {
RunnableKind::Test { name } => {
res.push("test".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
2018-09-02 16:36:03 +03:00
}
res.push("--".to_string());
res.push(name.to_string());
res.push("--nocapture".to_string());
}
RunnableKind::Bin => {
res.push("run".to_string());
if let Some(spec) = spec {
spec.push_to(&mut res);
2018-09-02 16:36:03 +03:00
}
}
}
2018-10-20 22:02:41 +03:00
Ok(res)
2018-09-02 16:36:03 +03:00
}
struct CargoTargetSpec {
package: String,
target: String,
target_kind: TargetKind,
}
impl CargoTargetSpec {
fn for_file(world: &ServerWorld, file_id: FileId) -> Result<Option<CargoTargetSpec>> {
let &crate_id = match world.analysis().crate_for(file_id)?.first() {
Some(crate_id) => crate_id,
None => return Ok(None),
};
let file_id = world.analysis().crate_root(crate_id)?;
let path = world.path_map.get_path(file_id);
let res = world
.workspaces
.iter()
.find_map(|ws| {
let tgt = ws.target_by_root(path)?;
let res = CargoTargetSpec {
package: tgt.package(ws).name(ws).to_string(),
target: tgt.name(ws).to_string(),
target_kind: tgt.kind(ws),
};
Some(res)
});
Ok(res)
}
fn push_to(self, buf: &mut Vec<String>) {
buf.push("--package".to_string());
buf.push(self.package);
match self.target_kind {
TargetKind::Bin => {
buf.push("--bin".to_string());
buf.push(self.target);
}
TargetKind::Test => {
buf.push("--test".to_string());
buf.push(self.target);
}
TargetKind::Bench => {
buf.push("--bench".to_string());
buf.push(self.target);
}
TargetKind::Example => {
buf.push("--example".to_string());
buf.push(self.target);
}
TargetKind::Lib => {
buf.push("--lib".to_string());
}
TargetKind::Other => (),
2018-09-02 16:36:03 +03:00
}
2018-09-02 16:36:03 +03:00
}
}
2018-08-29 18:03:14 +03:00
}
pub fn handle_decorations(
world: ServerWorld,
params: TextDocumentIdentifier,
) -> Result<Vec<Decoration>> {
let file_id = params.try_conv_with(&world)?;
2018-10-20 22:02:41 +03:00
highlight(&world, file_id)
2018-08-29 18:03:14 +03:00
}
2018-08-26 12:51:45 +03:00
pub fn handle_completion(
world: ServerWorld,
params: req::CompletionParams,
) -> 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-10-20 22:02:41 +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,
..Default::default()
2018-08-28 21:11:17 +03:00
};
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,
) -> Result<Option<Vec<FoldingRange>>> {
let file_id = params.text_document.try_conv_with(&world)?;
let line_index = world.analysis().file_line_index(file_id);
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),
}
})
.collect(),
);
2018-09-23 11:13:27 -04:00
Ok(res)
2018-09-23 11:13:27 -04:00
}
pub fn handle_signature_help(
world: ServerWorld,
params: req::TextDocumentPositionParams,
) -> Result<Option<req::SignatureHelp>> {
use languageserver_types::{ParameterInformation, SignatureInformation};
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);
if let Some((descriptor, active_param)) =
2018-10-20 22:09:12 +03:00
world.analysis().resolve_callable(file_id, offset)?
{
let parameters: Vec<ParameterInformation> = descriptor
.params
.iter()
.map(|param| ParameterInformation {
label: param.clone(),
documentation: None,
})
.collect();
let sig_info = SignatureInformation {
label: descriptor.label,
documentation: None,
parameters: Some(parameters),
};
Ok(Some(req::SignatureHelp {
signatures: vec![sig_info],
active_signature: Some(0),
active_parameter: active_param.map(|a| a as u64),
}))
} else {
Ok(None)
}
}
2018-10-19 15:25:10 -04:00
pub fn handle_prepare_rename(
world: ServerWorld,
params: req::TextDocumentPositionParams,
) -> Result<Option<PrepareRenameResponse>> {
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);
// We support renaming references like handle_rename does.
// In the future we may want to reject the renaming of things like keywords here too.
2018-10-20 22:09:12 +03:00
let refs = world.analysis().find_all_refs(file_id, offset)?;
2018-10-19 15:25:10 -04:00
if refs.is_empty() {
return Ok(None);
}
let r = refs.first().unwrap();
let loc = to_location(r.0, r.1, &world, &line_index)?;
Ok(Some(PrepareRenameResponse::Range(loc.range)))
}
2018-10-18 17:56:22 -04:00
pub fn handle_rename(
world: ServerWorld,
params: RenameParams,
) -> Result<Option<WorkspaceEdit>> {
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);
if params.new_name.is_empty() {
return Err(LspError::new(ErrorCode::InvalidParams as i32, "New Name cannot be empty".into()).into());
2018-10-18 17:56:22 -04:00
}
2018-10-20 22:09:12 +03:00
let refs = world.analysis().find_all_refs(file_id, offset)?;
2018-10-18 17:56:22 -04:00
if refs.is_empty() {
return Ok(None);
}
let mut changes = HashMap::new();
for r in refs {
if let Ok(loc) = to_location(r.0, r.1, &world, &line_index) {
changes.entry(loc.uri).or_insert(Vec::new()).push(
TextEdit {
range: loc.range,
new_text: params.new_name.clone()
});
}
}
Ok(Some(WorkspaceEdit {
changes: Some(changes),
// TODO: return this instead if client/server support it. See #144
document_changes : None,
}))
}
pub fn handle_references(
world: ServerWorld,
params: req::ReferenceParams,
) -> Result<Option<Vec<Location>>> {
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);
2018-10-20 22:09:12 +03:00
let refs = world.analysis().find_all_refs(file_id, offset)?;
Ok(Some(refs.into_iter()
.filter_map(|r| to_location(r.0, r.1, &world, &line_index).ok())
.collect()))
}
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-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-10-20 22:02:41 +03:00
let assists = world.analysis().assists(file_id, range)?.into_iter();
let fixes = world
.analysis()
2018-10-20 22:02:41 +03:00
.diagnostics(file_id)?
.into_iter()
2018-08-29 18:03:14 +03:00
.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-10-15 22:36: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()
2018-10-20 22:02:41 +03:00
.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();
2018-08-10 23:30:11 +03:00
Ok(req::PublishDiagnosticsParams { uri, diagnostics })
}
2018-08-15 17:24:20 +03:00
pub fn publish_decorations(
2018-10-15 22:36: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-10-20 22:02:41 +03:00
decorations: highlight(&world, file_id)?,
2018-08-28 00:20:59 +03:00
})
}
2018-10-20 22:02:41 +03:00
fn highlight(world: &ServerWorld, file_id: FileId) -> Result<Vec<Decoration>> {
2018-08-29 18:03:14 +03:00
let line_index = world.analysis().file_line_index(file_id);
2018-10-20 22:02:41 +03:00
let res = world
.analysis()
2018-10-20 22:02:41 +03:00
.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-10-20 22:02:41 +03:00
.collect();
Ok(res)
2018-08-11 00:55:32 +03:00
}