rust/crates/server/src/handlers.rs

143 lines
4.7 KiB
Rust
Raw Normal View History

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)
}