From 23c06db9c236db0f9c8ef5117fb1adefd6616c43 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 12 Aug 2018 21:02:56 +0300 Subject: Half of code-actions --- crates/server/src/caps.rs | 2 +- crates/server/src/conv.rs | 81 +++++++++++++++++++++++++++++++++ crates/server/src/handlers.rs | 103 ++++++++++++++++++++---------------------- crates/server/src/main.rs | 7 ++- crates/server/src/req.rs | 3 +- 5 files changed, 139 insertions(+), 57 deletions(-) create mode 100644 crates/server/src/conv.rs (limited to 'crates/server') diff --git a/crates/server/src/caps.rs b/crates/server/src/caps.rs index dca07ebc9..b502b0865 100644 --- a/crates/server/src/caps.rs +++ b/crates/server/src/caps.rs @@ -25,7 +25,7 @@ pub const SERVER_CAPABILITIES: ServerCapabilities = ServerCapabilities { document_highlight_provider: None, document_symbol_provider: Some(true), workspace_symbol_provider: None, - code_action_provider: None, + code_action_provider: Some(true), code_lens_provider: None, document_formatting_provider: None, document_range_formatting_provider: None, diff --git a/crates/server/src/conv.rs b/crates/server/src/conv.rs new file mode 100644 index 000000000..c7bea15df --- /dev/null +++ b/crates/server/src/conv.rs @@ -0,0 +1,81 @@ +use languageserver_types::{Range, SymbolKind, Position}; +use libeditor::{LineIndex, LineCol}; +use libsyntax2::{SyntaxKind, TextUnit, TextRange}; + +pub trait Conv { + type Output; + fn conv(&self) -> Self::Output; +} + +pub trait ConvWith { + type Ctx; + type Output; + fn conv_with(&self, ctx: &Self::Ctx) -> Self::Output; +} + +impl Conv for SyntaxKind { + type Output = SymbolKind; + + fn conv(&self) -> ::Output { + match *self { + SyntaxKind::FUNCTION => SymbolKind::Function, + SyntaxKind::STRUCT => SymbolKind::Struct, + SyntaxKind::ENUM => SymbolKind::Enum, + SyntaxKind::TRAIT => SymbolKind::Interface, + SyntaxKind::MODULE => SymbolKind::Module, + SyntaxKind::TYPE_ITEM => SymbolKind::TypeParameter, + SyntaxKind::STATIC_ITEM => SymbolKind::Constant, + SyntaxKind::CONST_ITEM => SymbolKind::Constant, + _ => SymbolKind::Variable, + } + } +} + +impl ConvWith for Position { + type Ctx = LineIndex; + type Output = TextUnit; + + fn conv_with(&self, line_index: &LineIndex) -> TextUnit { + // TODO: UTF-16 + let line_col = LineCol { + line: self.line as u32, + col: (self.character as u32).into(), + }; + line_index.offset(line_col) + } +} + +impl ConvWith for TextUnit { + type Ctx = LineIndex; + type Output = Position; + + fn conv_with(&self, line_index: &LineIndex) -> Position { + let line_col = line_index.line_col(*self); + // TODO: UTF-16 + Position::new(line_col.line as u64, u32::from(line_col.col) as u64) + } +} + +impl ConvWith for TextRange { + type Ctx = LineIndex; + type Output = Range; + + fn conv_with(&self, line_index: &LineIndex) -> Range { + Range::new( + self.start().conv_with(line_index), + self.end().conv_with(line_index), + ) + } +} + +impl ConvWith for Range { + type Ctx = LineIndex; + type Output = TextRange; + + fn conv_with(&self, line_index: &LineIndex) -> TextRange { + TextRange::from_to( + self.start.conv_with(line_index), + self.end.conv_with(line_index), + ) + } +} diff --git a/crates/server/src/handlers.rs b/crates/server/src/handlers.rs index f6f960d22..c6db22289 100644 --- a/crates/server/src/handlers.rs +++ b/crates/server/src/handlers.rs @@ -1,11 +1,15 @@ -use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, SymbolKind}; -use libsyntax2::SyntaxKind; +use languageserver_types::{ + Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, + Command +}; use libanalysis::World; -use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit}; +use libeditor; +use serde_json::to_value; use ::{ req::{self, Decoration}, Result, util::FilePath, + conv::{Conv, ConvWith}, }; pub fn handle_syntax_tree( @@ -25,11 +29,9 @@ pub fn handle_extend_selection( 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) - }) + .map(|r| r.conv_with(&line_index)) + .map(|r| libeditor::extend_selection(&file, r).unwrap_or(r)) + .map(|r| r.conv_with(&line_index)) .collect(); Ok(req::ExtendSelectionResult { selections }) } @@ -48,10 +50,10 @@ pub fn handle_document_symbol( let doc_symbol = DocumentSymbol { name: symbol.name.clone(), detail: Some(symbol.name), - kind: to_symbol_kind(symbol.kind), + kind: symbol.kind.conv(), deprecated: None, - range: to_vs_range(&line_index, symbol.node_range), - selection_range: to_vs_range(&line_index, symbol.name_range), + range: symbol.node_range.conv_with(&line_index), + selection_range: symbol.name_range.conv_with(&line_index), children: None, }; if let Some(idx) = symbol.parent { @@ -67,17 +69,40 @@ pub fn handle_document_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, - SyntaxKind::TYPE_ITEM => SymbolKind::TypeParameter, - SyntaxKind::STATIC_ITEM => SymbolKind::Constant, - SyntaxKind::CONST_ITEM => SymbolKind::Constant, - _ => SymbolKind::Variable, +pub fn handle_code_action( + world: World, + params: req::CodeActionParams, +) -> Result>> { + let path = params.text_document.file_path()?; + let file = world.file_syntax(&path)?; + let line_index = world.file_line_index(&path)?; + let offset = params.range.conv_with(&line_index).start(); + let ret = if libeditor::flip_comma(&file, offset).is_some() { + Some(vec![apply_code_action_cmd(ActionId::FlipComma)]) + } else { + None + }; + Ok(ret) +} + +fn apply_code_action_cmd(id: ActionId) -> Command { + Command { + title: id.title().to_string(), + command: "apply_code_action".to_string(), + arguments: Some(vec![to_value(id).unwrap()]), + } +} + +#[derive(Serialize, Deserialize, Clone, Copy)] +enum ActionId { + FlipComma +} + +impl ActionId { + fn title(&self) -> &'static str { + match *self { + ActionId::FlipComma => "Flip `,`", + } } } @@ -88,7 +113,7 @@ pub fn publish_diagnostics(world: World, uri: Url) -> Result Result 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) -} diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs index 916638d49..3ff300e3d 100644 --- a/crates/server/src/main.rs +++ b/crates/server/src/main.rs @@ -23,6 +23,7 @@ mod req; mod dispatch; mod handlers; mod util; +mod conv; use threadpool::ThreadPool; use crossbeam_channel::{bounded, Sender, Receiver}; @@ -33,7 +34,7 @@ use libanalysis::{WorldState, World}; use ::{ io::{Io, RawMsg, RawRequest}, handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations, - handle_document_symbol}, + handle_document_symbol, handle_code_action}, util::{FilePath, FnBox} }; @@ -182,6 +183,10 @@ fn main_loop( handle_request_on_threadpool::( &mut req, pool, world, &sender, handle_document_symbol )?; + handle_request_on_threadpool::( + &mut req, pool, world, &sender, handle_code_action + )?; + let mut shutdown = false; dispatch::handle_request::(&mut req, |(), resp| { resp.result(io, ())?; diff --git a/crates/server/src/req.rs b/crates/server/src/req.rs index 6a0926084..e3b1cdf50 100644 --- a/crates/server/src/req.rs +++ b/crates/server/src/req.rs @@ -5,7 +5,8 @@ use url_serde; pub use languageserver_types::{ request::*, notification::*, InitializeResult, PublishDiagnosticsParams, - DocumentSymbolParams, DocumentSymbolResponse + DocumentSymbolParams, DocumentSymbolResponse, + CodeActionParams, }; -- cgit v1.2.3