From 8abf5363433e977c5393bb569e2a5d559cb0a602 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 29 Aug 2018 18:03:14 +0300 Subject: Grand refactoring --- crates/server/src/main_loop/handlers.rs | 384 +++++++++++--------------------- 1 file changed, 131 insertions(+), 253 deletions(-) (limited to 'crates/server/src/main_loop/handlers.rs') diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs index 3ee0873f4..45083b084 100644 --- a/crates/server/src/main_loop/handlers.rs +++ b/crates/server/src/main_loop/handlers.rs @@ -2,16 +2,13 @@ use std::collections::HashMap; use languageserver_types::{ Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, - Command, TextDocumentIdentifier, WorkspaceEdit, + Command, TextDocumentIdentifier, SymbolInformation, Position, Location, TextEdit, CompletionItem, InsertTextFormat, CompletionItemKind, }; -use serde_json::{to_value, from_value}; -use url_serde; -use libanalysis::{self, Query, FileId}; -use libeditor; +use serde_json::to_value; +use libanalysis::{Query, FileId, RunnableKind}; use libsyntax2::{ - TextUnit, text_utils::contains_offset_nonstrict, }; @@ -26,8 +23,8 @@ pub fn handle_syntax_tree( params: req::SyntaxTreeParams, ) -> Result { let id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(id)?; - Ok(libeditor::syntax_tree(&file)) + let res = world.analysis().syntax_tree(id); + Ok(res) } pub fn handle_extend_selection( @@ -35,11 +32,11 @@ pub fn handle_extend_selection( params: req::ExtendSelectionParams, ) -> Result { let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file = world.analysis().file_syntax(file_id); + let line_index = world.analysis().file_line_index(file_id); let selections = params.selections.into_iter() .map_conv_with(&line_index) - .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) + .map(|r| world.analysis().extend_selection(&file, r)) .map_conv_with(&line_index) .collect(); Ok(req::ExtendSelectionResult { selections }) @@ -50,13 +47,13 @@ pub fn handle_find_matching_brace( params: req::FindMatchingBraceParams, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; + let file = world.analysis().file_syntax(file_id); + let line_index = world.analysis().file_line_index(file_id); let res = params.offsets .into_iter() .map_conv_with(&line_index) .map(|offset| { - libeditor::matching_brace(&file, offset).unwrap_or(offset) + world.analysis().matching_brace(&file, offset).unwrap_or(offset) }) .map_conv_with(&line_index) .collect(); @@ -66,13 +63,31 @@ pub fn handle_find_matching_brace( pub fn handle_join_lines( world: ServerWorld, params: req::JoinLinesParams, -) -> Result> { +) -> Result { let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; + let line_index = world.analysis().file_line_index(file_id); let range = params.range.conv_with(&line_index); - let res = libeditor::join_lines(&file, range); - Ok(res.edit.conv_with(&line_index)) + world.analysis().join_lines(file_id, range) + .try_conv_with(&world) +} + +pub fn handle_on_type_formatting( + world: ServerWorld, + params: req::DocumentOnTypeFormattingParams, +) -> Result>> { + 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)) } pub fn handle_document_symbol( @@ -80,12 +95,11 @@ pub fn handle_document_symbol( params: req::DocumentSymbolParams, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; + let line_index = world.analysis().file_line_index(file_id); let mut parents: Vec<(DocumentSymbol, Option)> = Vec::new(); - for symbol in libeditor::file_structure(&file) { + for symbol in world.analysis().file_structure(file_id) { let doc_symbol = DocumentSymbol { name: symbol.label, detail: Some("".to_string()), @@ -114,130 +128,6 @@ pub fn handle_document_symbol( Ok(Some(req::DocumentSymbolResponse::Nested(res))) } -pub fn handle_code_action( - world: ServerWorld, - params: req::CodeActionParams, -) -> Result>> { - let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; - let offset = params.range.conv_with(&line_index).start(); - let mut res = Vec::new(); - - let actions = &[ - (ActionId::FlipComma, libeditor::flip_comma(&file, offset).is_some()), - (ActionId::AddDerive, libeditor::add_derive(&file, offset).is_some()), - (ActionId::AddImpl, libeditor::add_impl(&file, offset).is_some()), - ]; - - for (id, edit) in actions { - if *edit { - let cmd = apply_code_action_cmd(*id, params.text_document.clone(), offset); - res.push(cmd); - } - } - - for (diag, quick_fix) in world.analysis().diagnostics(file_id)? { - let quick_fix = match quick_fix { - Some(quick_fix) => quick_fix, - None => continue, - }; - if !contains_offset_nonstrict(diag.range, offset) { - continue; - } - let mut ops = Vec::new(); - for op in quick_fix.fs_ops { - let op = match op { - libanalysis::FsOp::CreateFile { anchor, path } => { - let uri = world.file_id_to_uri(anchor)?; - let path = &path.as_str()[3..]; // strip `../` b/c url is weird - let uri = uri.join(path)?; - FsOp::CreateFile { uri } - }, - libanalysis::FsOp::MoveFile { file, path } => { - let src = world.file_id_to_uri(file)?; - let path = &path.as_str()[3..]; // strip `../` b/c url is weird - let dst = src.join(path)?; - FsOp::MoveFile { src, dst } - }, - }; - ops.push(op) - } - let cmd = Command { - title: "Create module".to_string(), - command: "libsyntax-rust.fsEdit".to_string(), - arguments: Some(vec![to_value(ops).unwrap()]), - }; - res.push(cmd) - } - return Ok(Some(res)); -} - -#[derive(Serialize)] -#[serde(tag = "type", rename_all = "camelCase")] -enum FsOp { - CreateFile { - #[serde(with = "url_serde")] - uri: Url - }, - MoveFile { - #[serde(with = "url_serde")] - src: Url, - #[serde(with = "url_serde")] - dst: Url, - } -} - -pub fn handle_runnables( - world: ServerWorld, - params: req::RunnablesParams, -) -> Result> { - let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - 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 libeditor::runnables(&file) { - if let Some(offset) = offset { - if !contains_offset_nonstrict(runnable.range, offset) { - continue; - } - } - - let r = req::Runnable { - range: runnable.range.conv_with(&line_index), - label: match &runnable.kind { - libeditor::RunnableKind::Test { name } => - format!("test {}", name), - libeditor::RunnableKind::Bin => - "run binary".to_string(), - }, - bin: "cargo".to_string(), - args: match runnable.kind { - libeditor::RunnableKind::Test { name } => { - vec![ - "test".to_string(), - "--".to_string(), - name, - "--nocapture".to_string(), - ] - } - libeditor::RunnableKind::Bin => vec!["run".to_string()] - }, - env: { - let mut m = HashMap::new(); - m.insert( - "RUST_BACKTRACE".to_string(), - "short".to_string(), - ); - m - } - }; - res.push(r); - } - return Ok(res); -} - pub fn handle_workspace_symbol( world: ServerWorld, params: req::WorkspaceSymbolParams, @@ -265,8 +155,8 @@ pub fn handle_workspace_symbol( fn exec_query(world: &ServerWorld, query: Query) -> Result> { let mut res = Vec::new(); - for (file_id, symbol) in world.analysis().world_symbols(query) { - let line_index = world.analysis().file_line_index(file_id)?; + for (file_id, symbol) in world.analysis().symbol_search(query) { + let line_index = world.analysis().file_line_index(file_id); let info = SymbolInformation { name: symbol.name.to_string(), kind: symbol.kind.conv(), @@ -287,11 +177,11 @@ pub fn handle_goto_definition( params: req::TextDocumentPositionParams, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; - let line_index = world.analysis().file_line_index(file_id)?; + let line_index = world.analysis().file_line_index(file_id); let offset = params.position.conv_with(&line_index); let mut res = Vec::new(); - for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset)? { - let line_index = world.analysis().file_line_index(file_id)?; + for (file_id, symbol) in world.analysis().approximately_resolve_symbol(file_id, offset) { + let line_index = world.analysis().file_line_index(file_id); let location = to_location( file_id, symbol.node_range, &world, &line_index, @@ -308,7 +198,7 @@ pub fn handle_parent_module( let file_id = params.try_conv_with(&world)?; let mut res = Vec::new(); for (file_id, symbol) in world.analysis().parent_module(file_id) { - let line_index = world.analysis().file_line_index(file_id)?; + let line_index = world.analysis().file_line_index(file_id); let location = to_location( file_id, symbol.node_range, &world, &line_index @@ -318,15 +208,71 @@ pub fn handle_parent_module( Ok(res) } +pub fn handle_runnables( + world: ServerWorld, + params: req::RunnablesParams, +) -> Result> { + 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; + } + } + + 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(), + args: match runnable.kind { + RunnableKind::Test { name } => { + vec![ + "test".to_string(), + "--".to_string(), + name, + "--nocapture".to_string(), + ] + } + RunnableKind::Bin => vec!["run".to_string()] + }, + env: { + let mut m = HashMap::new(); + m.insert( + "RUST_BACKTRACE".to_string(), + "short".to_string(), + ); + m + } + }; + res.push(r); + } + return Ok(res); +} + +pub fn handle_decorations( + world: ServerWorld, + params: TextDocumentIdentifier, +) -> Result> { + let file_id = params.try_conv_with(&world)?; + Ok(highlight(&world, file_id)) +} + pub fn handle_completion( world: ServerWorld, params: req::CompletionParams, ) -> Result> { let file_id = params.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; + let line_index = world.analysis().file_line_index(file_id); let offset = params.position.conv_with(&line_index); - let items = match libeditor::scope_completion(&file, offset) { + let items = match world.analysis().completions(file_id, offset) { None => return Ok(None), Some(items) => items, }; @@ -348,91 +294,33 @@ pub fn handle_completion( Ok(Some(req::CompletionResponse::Array(items))) } -pub fn handle_on_type_formatting( +pub fn handle_code_action( world: ServerWorld, - params: req::DocumentOnTypeFormattingParams, -) -> Result>> { - if params.ch != "=" { - return Ok(None); - } - + params: req::CodeActionParams, +) -> Result>> { 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 file = world.analysis().file_syntax(file_id)?; - let action = match libeditor::on_eq_typed(&file, offset) { - None => return Ok(None), - Some(action) => action, - }; - Ok(Some(action.edit.conv_with(&line_index))) -} - -pub fn handle_execute_command( - world: ServerWorld, - mut params: req::ExecuteCommandParams, -) -> Result<(req::ApplyWorkspaceEditParams, Option)> { - if params.command.as_str() != "apply_code_action" { - bail!("unknown cmd: {:?}", params.command); - } - if params.arguments.len() != 1 { - bail!("expected single arg, got {}", params.arguments.len()); - } - let arg = params.arguments.pop().unwrap(); - let arg: ActionRequest = from_value(arg)?; - let file_id = arg.text_document.try_conv_with(&world)?; - let file = world.analysis().file_syntax(file_id)?; - let action_result = match arg.id { - ActionId::FlipComma => libeditor::flip_comma(&file, arg.offset).map(|f| f()), - ActionId::AddDerive => libeditor::add_derive(&file, arg.offset).map(|f| f()), - ActionId::AddImpl => libeditor::add_impl(&file, arg.offset).map(|f| f()), - }.ok_or_else(|| format_err!("command not applicable"))?; - let line_index = world.analysis().file_line_index(file_id)?; - let mut changes = HashMap::new(); - changes.insert( - arg.text_document.uri, - action_result.edit.conv_with(&line_index), - ); - let edit = WorkspaceEdit { - changes: Some(changes), - document_changes: None, - }; - let edit = req::ApplyWorkspaceEditParams { edit }; - let cursor_pos = action_result.cursor_position - .map(|off| off.conv_with(&line_index)); - Ok((edit, cursor_pos)) -} + let line_index = world.analysis().file_line_index(file_id); + let offset = params.range.conv_with(&line_index).start(); -#[derive(Serialize, Deserialize)] -struct ActionRequest { - id: ActionId, - text_document: TextDocumentIdentifier, - offset: TextUnit, -} + let assists = world.analysis().assists(file_id, offset).into_iter(); + let fixes = world.analysis().diagnostics(file_id).into_iter() + .filter_map(|d| Some((d.range, d.fix?))) + .filter(|(range, _fix)| contains_offset_nonstrict(*range, offset)) + .map(|(_range, fix)| fix); -fn apply_code_action_cmd(id: ActionId, doc: TextDocumentIdentifier, offset: TextUnit) -> Command { - let action_request = ActionRequest { id, text_document: doc, offset }; - Command { - title: id.title().to_string(), - command: "apply_code_action".to_string(), - arguments: Some(vec![to_value(action_request).unwrap()]), + 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, + command: "libsyntax-rust.applySourceChange".to_string(), + arguments: Some(vec![to_value(edit).unwrap()]), + }; + res.push(cmd); } -} -#[derive(Serialize, Deserialize, Clone, Copy)] -enum ActionId { - FlipComma, - AddDerive, - AddImpl, -} - -impl ActionId { - fn title(&self) -> &'static str { - match *self { - ActionId::FlipComma => "Flip `,`", - ActionId::AddDerive => "Add `#[derive]`", - ActionId::AddImpl => "Add impl", - } - } + Ok(Some(res)) } pub fn publish_diagnostics( @@ -440,28 +328,20 @@ pub fn publish_diagnostics( uri: Url ) -> Result { let file_id = world.uri_to_file_id(&uri)?; - let line_index = world.analysis().file_line_index(file_id)?; - let diagnostics = world.analysis().diagnostics(file_id)? + let line_index = world.analysis().file_line_index(file_id); + let diagnostics = world.analysis().diagnostics(file_id) .into_iter() - .map(|(d, _quick_fix)| Diagnostic { + .map(|d| Diagnostic { range: d.range.conv_with(&line_index), severity: Some(DiagnosticSeverity::Error), code: None, source: Some("libsyntax2".to_string()), - message: d.msg, + message: d.message, related_information: None, }).collect(); Ok(req::PublishDiagnosticsParams { uri, diagnostics }) } -pub fn handle_decorations( - world: ServerWorld, - params: TextDocumentIdentifier, -) -> Result> { - let file_id = params.try_conv_with(&world)?; - highlight(&world, file_id) -} - pub fn publish_decorations( world: ServerWorld, uri: Url @@ -469,18 +349,16 @@ pub fn publish_decorations( let file_id = world.uri_to_file_id(&uri)?; Ok(req::PublishDecorationsParams { uri, - decorations: highlight(&world, file_id)? + decorations: highlight(&world, file_id), }) } -fn highlight(world: &ServerWorld, file_id: FileId) -> Result> { - let file = world.analysis().file_syntax(file_id)?; - let line_index = world.analysis().file_line_index(file_id)?; - let res = libeditor::highlight(&file) +fn highlight(world: &ServerWorld, file_id: FileId) -> Vec { + let line_index = world.analysis().file_line_index(file_id); + world.analysis().highlight(file_id) .into_iter() .map(|h| Decoration { range: h.range.conv_with(&line_index), tag: h.tag, - }).collect(); - Ok(res) + }).collect() } -- cgit v1.2.3