mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
Half of code-actions
This commit is contained in:
parent
66be735aa9
commit
23c06db9c2
5 changed files with 139 additions and 57 deletions
|
@ -25,7 +25,7 @@ pub const SERVER_CAPABILITIES: ServerCapabilities = ServerCapabilities {
|
||||||
document_highlight_provider: None,
|
document_highlight_provider: None,
|
||||||
document_symbol_provider: Some(true),
|
document_symbol_provider: Some(true),
|
||||||
workspace_symbol_provider: None,
|
workspace_symbol_provider: None,
|
||||||
code_action_provider: None,
|
code_action_provider: Some(true),
|
||||||
code_lens_provider: None,
|
code_lens_provider: None,
|
||||||
document_formatting_provider: None,
|
document_formatting_provider: None,
|
||||||
document_range_formatting_provider: None,
|
document_range_formatting_provider: None,
|
||||||
|
|
81
crates/server/src/conv.rs
Normal file
81
crates/server/src/conv.rs
Normal file
|
@ -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) -> <Self as Conv>::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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, SymbolKind};
|
use languageserver_types::{
|
||||||
use libsyntax2::SyntaxKind;
|
Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
|
||||||
|
Command
|
||||||
|
};
|
||||||
use libanalysis::World;
|
use libanalysis::World;
|
||||||
use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};
|
use libeditor;
|
||||||
|
use serde_json::to_value;
|
||||||
|
|
||||||
use ::{
|
use ::{
|
||||||
req::{self, Decoration}, Result,
|
req::{self, Decoration}, Result,
|
||||||
util::FilePath,
|
util::FilePath,
|
||||||
|
conv::{Conv, ConvWith},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn handle_syntax_tree(
|
pub fn handle_syntax_tree(
|
||||||
|
@ -25,11 +29,9 @@ pub fn handle_extend_selection(
|
||||||
let file = world.file_syntax(&path)?;
|
let file = world.file_syntax(&path)?;
|
||||||
let line_index = world.file_line_index(&path)?;
|
let line_index = world.file_line_index(&path)?;
|
||||||
let selections = params.selections.into_iter()
|
let selections = params.selections.into_iter()
|
||||||
.map(|r| {
|
.map(|r| r.conv_with(&line_index))
|
||||||
let r = to_text_range(&line_index, r);
|
.map(|r| libeditor::extend_selection(&file, r).unwrap_or(r))
|
||||||
let r = libeditor::extend_selection(&file, r).unwrap_or(r);
|
.map(|r| r.conv_with(&line_index))
|
||||||
to_vs_range(&line_index, r)
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
Ok(req::ExtendSelectionResult { selections })
|
Ok(req::ExtendSelectionResult { selections })
|
||||||
}
|
}
|
||||||
|
@ -48,10 +50,10 @@ pub fn handle_document_symbol(
|
||||||
let doc_symbol = DocumentSymbol {
|
let doc_symbol = DocumentSymbol {
|
||||||
name: symbol.name.clone(),
|
name: symbol.name.clone(),
|
||||||
detail: Some(symbol.name),
|
detail: Some(symbol.name),
|
||||||
kind: to_symbol_kind(symbol.kind),
|
kind: symbol.kind.conv(),
|
||||||
deprecated: None,
|
deprecated: None,
|
||||||
range: to_vs_range(&line_index, symbol.node_range),
|
range: symbol.node_range.conv_with(&line_index),
|
||||||
selection_range: to_vs_range(&line_index, symbol.name_range),
|
selection_range: symbol.name_range.conv_with(&line_index),
|
||||||
children: None,
|
children: None,
|
||||||
};
|
};
|
||||||
if let Some(idx) = symbol.parent {
|
if let Some(idx) = symbol.parent {
|
||||||
|
@ -67,17 +69,40 @@ pub fn handle_document_symbol(
|
||||||
Ok(Some(req::DocumentSymbolResponse::Nested(res)))
|
Ok(Some(req::DocumentSymbolResponse::Nested(res)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_symbol_kind(kind: SyntaxKind) -> SymbolKind {
|
pub fn handle_code_action(
|
||||||
match kind {
|
world: World,
|
||||||
SyntaxKind::FUNCTION => SymbolKind::Function,
|
params: req::CodeActionParams,
|
||||||
SyntaxKind::STRUCT => SymbolKind::Struct,
|
) -> Result<Option<Vec<Command>>> {
|
||||||
SyntaxKind::ENUM => SymbolKind::Enum,
|
let path = params.text_document.file_path()?;
|
||||||
SyntaxKind::TRAIT => SymbolKind::Interface,
|
let file = world.file_syntax(&path)?;
|
||||||
SyntaxKind::MODULE => SymbolKind::Module,
|
let line_index = world.file_line_index(&path)?;
|
||||||
SyntaxKind::TYPE_ITEM => SymbolKind::TypeParameter,
|
let offset = params.range.conv_with(&line_index).start();
|
||||||
SyntaxKind::STATIC_ITEM => SymbolKind::Constant,
|
let ret = if libeditor::flip_comma(&file, offset).is_some() {
|
||||||
SyntaxKind::CONST_ITEM => SymbolKind::Constant,
|
Some(vec![apply_code_action_cmd(ActionId::FlipComma)])
|
||||||
_ => SymbolKind::Variable,
|
} 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<req::PublishDiagnos
|
||||||
let diagnostics = libeditor::diagnostics(&file)
|
let diagnostics = libeditor::diagnostics(&file)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|d| Diagnostic {
|
.map(|d| Diagnostic {
|
||||||
range: to_vs_range(&line_index, d.range),
|
range: d.range.conv_with(&line_index),
|
||||||
severity: Some(DiagnosticSeverity::Error),
|
severity: Some(DiagnosticSeverity::Error),
|
||||||
code: None,
|
code: None,
|
||||||
source: Some("libsyntax2".to_string()),
|
source: Some("libsyntax2".to_string()),
|
||||||
|
@ -105,38 +130,8 @@ pub fn publish_decorations(world: World, uri: Url) -> Result<req::PublishDecorat
|
||||||
let decorations = libeditor::highlight(&file)
|
let decorations = libeditor::highlight(&file)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|h| Decoration {
|
.map(|h| Decoration {
|
||||||
range: to_vs_range(&line_index, h.range),
|
range: h.range.conv_with(&line_index),
|
||||||
tag: h.tag,
|
tag: h.tag,
|
||||||
}).collect();
|
}).collect();
|
||||||
Ok(req::PublishDecorationsParams { uri, decorations })
|
Ok(req::PublishDecorationsParams { uri, decorations })
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ mod req;
|
||||||
mod dispatch;
|
mod dispatch;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod conv;
|
||||||
|
|
||||||
use threadpool::ThreadPool;
|
use threadpool::ThreadPool;
|
||||||
use crossbeam_channel::{bounded, Sender, Receiver};
|
use crossbeam_channel::{bounded, Sender, Receiver};
|
||||||
|
@ -33,7 +34,7 @@ use libanalysis::{WorldState, World};
|
||||||
use ::{
|
use ::{
|
||||||
io::{Io, RawMsg, RawRequest},
|
io::{Io, RawMsg, RawRequest},
|
||||||
handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations,
|
handlers::{handle_syntax_tree, handle_extend_selection, publish_diagnostics, publish_decorations,
|
||||||
handle_document_symbol},
|
handle_document_symbol, handle_code_action},
|
||||||
util::{FilePath, FnBox}
|
util::{FilePath, FnBox}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -182,6 +183,10 @@ fn main_loop(
|
||||||
handle_request_on_threadpool::<req::DocumentSymbolRequest>(
|
handle_request_on_threadpool::<req::DocumentSymbolRequest>(
|
||||||
&mut req, pool, world, &sender, handle_document_symbol
|
&mut req, pool, world, &sender, handle_document_symbol
|
||||||
)?;
|
)?;
|
||||||
|
handle_request_on_threadpool::<req::CodeActionRequest>(
|
||||||
|
&mut req, pool, world, &sender, handle_code_action
|
||||||
|
)?;
|
||||||
|
|
||||||
let mut shutdown = false;
|
let mut shutdown = false;
|
||||||
dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
|
dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
|
||||||
resp.result(io, ())?;
|
resp.result(io, ())?;
|
||||||
|
|
|
@ -5,7 +5,8 @@ use url_serde;
|
||||||
pub use languageserver_types::{
|
pub use languageserver_types::{
|
||||||
request::*, notification::*,
|
request::*, notification::*,
|
||||||
InitializeResult, PublishDiagnosticsParams,
|
InitializeResult, PublishDiagnosticsParams,
|
||||||
DocumentSymbolParams, DocumentSymbolResponse
|
DocumentSymbolParams, DocumentSymbolResponse,
|
||||||
|
CodeActionParams,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue