mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	Half of code-actions
This commit is contained in:
		
							parent
							
								
									66be735aa9
								
							
						
					
					
						commit
						23c06db9c2
					
				@ -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,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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 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<Option<Vec<Command>>> {
 | 
			
		||||
    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<req::PublishDiagnos
 | 
			
		||||
    let diagnostics = libeditor::diagnostics(&file)
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|d| Diagnostic {
 | 
			
		||||
            range: to_vs_range(&line_index, d.range),
 | 
			
		||||
            range: d.range.conv_with(&line_index),
 | 
			
		||||
            severity: Some(DiagnosticSeverity::Error),
 | 
			
		||||
            code: None,
 | 
			
		||||
            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)
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|h| Decoration {
 | 
			
		||||
            range: to_vs_range(&line_index, h.range),
 | 
			
		||||
            range: h.range.conv_with(&line_index),
 | 
			
		||||
            tag: h.tag,
 | 
			
		||||
        }).collect();
 | 
			
		||||
    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 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::<req::DocumentSymbolRequest>(
 | 
			
		||||
                    &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;
 | 
			
		||||
                dispatch::handle_request::<req::Shutdown, _>(&mut req, |(), resp| {
 | 
			
		||||
                    resp.result(io, ())?;
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,8 @@ use url_serde;
 | 
			
		||||
pub use languageserver_types::{
 | 
			
		||||
    request::*, notification::*,
 | 
			
		||||
    InitializeResult, PublishDiagnosticsParams,
 | 
			
		||||
    DocumentSymbolParams, DocumentSymbolResponse
 | 
			
		||||
    DocumentSymbolParams, DocumentSymbolResponse,
 | 
			
		||||
    CodeActionParams,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user