2018-08-11 14:44:12 +03:00
|
|
|
use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, SymbolKind};
|
|
|
|
use libsyntax2::SyntaxKind;
|
2018-08-10 21:13:39 +03:00
|
|
|
use libanalysis::World;
|
2018-08-10 22:23:17 +03:00
|
|
|
use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};
|
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-11 00:12:31 +03:00
|
|
|
util::FilePath,
|
|
|
|
};
|
2018-08-10 21:13:39 +03:00
|
|
|
|
|
|
|
pub fn handle_syntax_tree(
|
|
|
|
world: World,
|
2018-08-10 22:23:17 +03:00
|
|
|
params: req::SyntaxTreeParams,
|
2018-08-10 21:13:39 +03:00
|
|
|
) -> Result<String> {
|
2018-08-10 22:23:17 +03:00
|
|
|
let path = params.text_document.file_path()?;
|
2018-08-10 21:13:39 +03:00
|
|
|
let file = world.file_syntax(&path)?;
|
|
|
|
Ok(libeditor::syntax_tree(&file))
|
|
|
|
}
|
2018-08-10 22:23:17 +03:00
|
|
|
|
|
|
|
pub fn handle_extend_selection(
|
|
|
|
world: World,
|
|
|
|
params: req::ExtendSelectionParams,
|
|
|
|
) -> Result<req::ExtendSelectionResult> {
|
|
|
|
let path = params.text_document.file_path()?;
|
|
|
|
let file = world.file_syntax(&path)?;
|
|
|
|
let line_index = world.file_line_index(&path)?;
|
|
|
|
let selections = params.selections.into_iter()
|
|
|
|
.map(|r| {
|
|
|
|
let r = to_text_range(&line_index, r);
|
|
|
|
let r = libeditor::extend_selection(&file, r).unwrap_or(r);
|
|
|
|
to_vs_range(&line_index, r)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
Ok(req::ExtendSelectionResult { selections })
|
|
|
|
}
|
|
|
|
|
2018-08-11 14:44:12 +03:00
|
|
|
pub fn handle_document_symbol(
|
|
|
|
world: World,
|
|
|
|
params: req::DocumentSymbolParams,
|
|
|
|
) -> Result<Option<req::DocumentSymbolResponse>> {
|
|
|
|
let path = params.text_document.file_path()?;
|
|
|
|
let file = world.file_syntax(&path)?;
|
|
|
|
let line_index = world.file_line_index(&path)?;
|
|
|
|
|
|
|
|
let mut res: Vec<DocumentSymbol> = Vec::new();
|
|
|
|
|
|
|
|
for symbol in libeditor::file_symbols(&file) {
|
|
|
|
let doc_symbol = DocumentSymbol {
|
|
|
|
name: symbol.name.clone(),
|
|
|
|
detail: Some(symbol.name),
|
|
|
|
kind: to_symbol_kind(symbol.kind),
|
|
|
|
deprecated: None,
|
|
|
|
range: to_vs_range(&line_index, symbol.node_range),
|
|
|
|
selection_range: to_vs_range(&line_index, symbol.name_range),
|
|
|
|
children: None,
|
|
|
|
};
|
|
|
|
if let Some(idx) = symbol.parent {
|
|
|
|
let children = &mut res[idx].children;
|
|
|
|
if children.is_none() {
|
|
|
|
*children = Some(Vec::new());
|
|
|
|
}
|
|
|
|
children.as_mut().unwrap().push(doc_symbol);
|
|
|
|
} else {
|
|
|
|
res.push(doc_symbol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(Some(req::DocumentSymbolResponse::Nested(res)))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_symbol_kind(kind: SyntaxKind) -> SymbolKind {
|
|
|
|
match kind {
|
|
|
|
SyntaxKind::FUNCTION => SymbolKind::Function,
|
|
|
|
SyntaxKind::STRUCT => SymbolKind::Struct,
|
|
|
|
SyntaxKind::ENUM => SymbolKind::Enum,
|
|
|
|
SyntaxKind::TRAIT => SymbolKind::Interface,
|
|
|
|
SyntaxKind::MODULE => SymbolKind::Module,
|
2018-08-11 16:20:37 +03:00
|
|
|
SyntaxKind::TYPE_ITEM => SymbolKind::TypeParameter,
|
|
|
|
SyntaxKind::STATIC_ITEM => SymbolKind::Constant,
|
|
|
|
SyntaxKind::CONST_ITEM => SymbolKind::Constant,
|
2018-08-11 14:44:12 +03:00
|
|
|
_ => SymbolKind::Variable,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-10 23:30:11 +03:00
|
|
|
pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnosticsParams> {
|
|
|
|
let path = uri.file_path()?;
|
|
|
|
let file = world.file_syntax(&path)?;
|
|
|
|
let line_index = world.file_line_index(&path)?;
|
|
|
|
let diagnostics = libeditor::diagnostics(&file)
|
|
|
|
.into_iter()
|
|
|
|
.map(|d| Diagnostic {
|
|
|
|
range: to_vs_range(&line_index, d.range),
|
|
|
|
severity: Some(DiagnosticSeverity::Error),
|
|
|
|
code: None,
|
|
|
|
source: Some("libsyntax2".to_string()),
|
|
|
|
message: d.msg,
|
|
|
|
related_information: None,
|
|
|
|
}).collect();
|
|
|
|
Ok(req::PublishDiagnosticsParams { uri, diagnostics })
|
|
|
|
}
|
|
|
|
|
2018-08-11 00:55:32 +03:00
|
|
|
pub fn publish_decorations(world: World, uri: Url) -> Result<req::PublishDecorationsParams> {
|
|
|
|
let path = uri.file_path()?;
|
|
|
|
let file = world.file_syntax(&path)?;
|
|
|
|
let line_index = world.file_line_index(&path)?;
|
|
|
|
let decorations = libeditor::highlight(&file)
|
|
|
|
.into_iter()
|
|
|
|
.map(|h| Decoration {
|
|
|
|
range: to_vs_range(&line_index, h.range),
|
|
|
|
tag: h.tag,
|
|
|
|
}).collect();
|
|
|
|
Ok(req::PublishDecorationsParams { uri, decorations })
|
|
|
|
}
|
2018-08-10 22:23:17 +03:00
|
|
|
|
|
|
|
fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange {
|
|
|
|
TextRange::from_to(
|
|
|
|
to_text_unit(line_index, range.start),
|
|
|
|
to_text_unit(line_index, range.end),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_text_unit(line_index: &LineIndex, position: Position) -> TextUnit {
|
|
|
|
// TODO: UTF-16
|
|
|
|
let line_col = LineCol {
|
|
|
|
line: position.line as u32,
|
|
|
|
col: (position.character as u32).into(),
|
|
|
|
};
|
|
|
|
line_index.offset(line_col)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn to_vs_range(line_index: &LineIndex, range: TextRange) -> Range {
|
|
|
|
Range::new(
|
|
|
|
to_vs_position(line_index, range.start()),
|
|
|
|
to_vs_position(line_index, range.end()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_vs_position(line_index: &LineIndex, offset: TextUnit) -> Position {
|
|
|
|
let line_col = line_index.line_col(offset);
|
|
|
|
// TODO: UTF-16
|
|
|
|
Position::new(line_col.line as u64, u32::from(line_col.col) as u64)
|
|
|
|
}
|