aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/handlers.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/rust-analyzer/src/handlers.rs')
-rw-r--r--crates/rust-analyzer/src/handlers.rs158
1 files changed, 97 insertions, 61 deletions
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 66f8bee99..25692793b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -5,11 +5,13 @@
5use std::{ 5use std::{
6 io::Write as _, 6 io::Write as _,
7 process::{self, Stdio}, 7 process::{self, Stdio},
8 sync::Arc,
8}; 9};
9 10
10use ide::{ 11use ide::{
11 CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, 12 AssistConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction,
12 NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, SymbolKind, TextEdit, 13 HoverGotoTypeData, LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind,
14 SearchScope, SourceChange, SymbolKind, TextEdit,
13}; 15};
14use itertools::Itertools; 16use itertools::Itertools;
15use lsp_server::ErrorCode; 17use lsp_server::ErrorCode;
@@ -400,6 +402,45 @@ pub(crate) fn handle_workspace_symbol(
400 } 402 }
401} 403}
402 404
405pub(crate) fn handle_will_rename_files(
406 snap: GlobalStateSnapshot,
407 params: lsp_types::RenameFilesParams,
408) -> Result<Option<lsp_types::WorkspaceEdit>> {
409 let _p = profile::span("handle_will_rename_files");
410
411 let source_changes: Vec<SourceChange> = params
412 .files
413 .into_iter()
414 .filter_map(|file_rename| {
415 let from = Url::parse(&file_rename.old_uri).ok()?;
416 let to = Url::parse(&file_rename.new_uri).ok()?;
417
418 let from_path = from.to_file_path().ok()?;
419 let to_path = to.to_file_path().ok()?;
420
421 // Limit to single-level moves for now.
422 match (from_path.parent(), to_path.parent()) {
423 (Some(p1), Some(p2)) if p1 == p2 => {
424 let new_name = to_path.file_stem()?;
425 let new_name = new_name.to_str()?;
426 Some((snap.url_to_file_id(&from).ok()?, new_name.to_string()))
427 }
428 _ => None,
429 }
430 })
431 .filter_map(|(file_id, new_name)| {
432 snap.analysis.will_rename_file(file_id, &new_name).ok()?
433 })
434 .collect();
435
436 // Drop file system edits since we're just renaming things on the same level
437 let edits = source_changes.into_iter().map(|it| it.source_file_edits).flatten().collect();
438 let source_change = SourceChange::from_edits(edits, Vec::new());
439
440 let workspace_edit = to_proto::workspace_edit(&snap, source_change)?;
441 Ok(Some(workspace_edit))
442}
443
403pub(crate) fn handle_goto_definition( 444pub(crate) fn handle_goto_definition(
404 snap: GlobalStateSnapshot, 445 snap: GlobalStateSnapshot,
405 params: lsp_types::GotoDefinitionParams, 446 params: lsp_types::GotoDefinitionParams,
@@ -865,58 +906,8 @@ pub(crate) fn handle_formatting(
865 } 906 }
866} 907}
867 908
868fn handle_fixes(
869 snap: &GlobalStateSnapshot,
870 params: &lsp_types::CodeActionParams,
871 res: &mut Vec<lsp_ext::CodeAction>,
872) -> Result<()> {
873 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
874 let line_index = snap.analysis.file_line_index(file_id)?;
875 let range = from_proto::text_range(&line_index, params.range);
876
877 match &params.context.only {
878 Some(v) => {
879 if !v.iter().any(|it| {
880 it == &lsp_types::CodeActionKind::EMPTY
881 || it == &lsp_types::CodeActionKind::QUICKFIX
882 }) {
883 return Ok(());
884 }
885 }
886 None => {}
887 };
888
889 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, file_id)?;
890
891 for fix in diagnostics
892 .into_iter()
893 .filter_map(|d| d.fix)
894 .filter(|fix| fix.fix_trigger_range.intersect(range).is_some())
895 {
896 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
897 let action = lsp_ext::CodeAction {
898 title: fix.label.to_string(),
899 group: None,
900 kind: Some(CodeActionKind::QUICKFIX),
901 edit: Some(edit),
902 is_preferred: Some(false),
903 data: None,
904 };
905 res.push(action);
906 }
907
908 for fix in snap.check_fixes.get(&file_id).into_iter().flatten() {
909 let fix_range = from_proto::text_range(&line_index, fix.range);
910 if fix_range.intersect(range).is_none() {
911 continue;
912 }
913 res.push(fix.action.clone());
914 }
915 Ok(())
916}
917
918pub(crate) fn handle_code_action( 909pub(crate) fn handle_code_action(
919 mut snap: GlobalStateSnapshot, 910 snap: GlobalStateSnapshot,
920 params: lsp_types::CodeActionParams, 911 params: lsp_types::CodeActionParams,
921) -> Result<Option<Vec<lsp_ext::CodeAction>>> { 912) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
922 let _p = profile::span("handle_code_action"); 913 let _p = profile::span("handle_code_action");
@@ -932,24 +923,35 @@ pub(crate) fn handle_code_action(
932 let range = from_proto::text_range(&line_index, params.range); 923 let range = from_proto::text_range(&line_index, params.range);
933 let frange = FileRange { file_id, range }; 924 let frange = FileRange { file_id, range };
934 925
935 snap.config.assist.allowed = params 926 let assists_config = AssistConfig {
936 .clone() 927 allowed: params
937 .context 928 .clone()
938 .only 929 .context
939 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); 930 .only
931 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()),
932 ..snap.config.assist
933 };
940 934
941 let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); 935 let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
942 936
943 handle_fixes(&snap, &params, &mut res)?; 937 let include_quick_fixes = match &params.context.only {
938 Some(v) => v.iter().any(|it| {
939 it == &lsp_types::CodeActionKind::EMPTY || it == &lsp_types::CodeActionKind::QUICKFIX
940 }),
941 None => true,
942 };
943 if include_quick_fixes {
944 add_quick_fixes(&snap, frange, &line_index, &mut res)?;
945 }
944 946
945 if snap.config.client_caps.code_action_resolve { 947 if snap.config.client_caps.code_action_resolve {
946 for (index, assist) in 948 for (index, assist) in
947 snap.analysis.unresolved_assists(&snap.config.assist, frange)?.into_iter().enumerate() 949 snap.analysis.unresolved_assists(&assists_config, frange)?.into_iter().enumerate()
948 { 950 {
949 res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?); 951 res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?);
950 } 952 }
951 } else { 953 } else {
952 for assist in snap.analysis.resolved_assists(&snap.config.assist, frange)?.into_iter() { 954 for assist in snap.analysis.resolved_assists(&assists_config, frange)?.into_iter() {
953 res.push(to_proto::resolved_code_action(&snap, assist)?); 955 res.push(to_proto::resolved_code_action(&snap, assist)?);
954 } 956 }
955 } 957 }
@@ -957,6 +959,40 @@ pub(crate) fn handle_code_action(
957 Ok(Some(res)) 959 Ok(Some(res))
958} 960}
959 961
962fn add_quick_fixes(
963 snap: &GlobalStateSnapshot,
964 frange: FileRange,
965 line_index: &Arc<LineIndex>,
966 acc: &mut Vec<lsp_ext::CodeAction>,
967) -> Result<()> {
968 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, frange.file_id)?;
969
970 for fix in diagnostics
971 .into_iter()
972 .filter_map(|d| d.fix)
973 .filter(|fix| fix.fix_trigger_range.intersect(frange.range).is_some())
974 {
975 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
976 let action = lsp_ext::CodeAction {
977 title: fix.label.to_string(),
978 group: None,
979 kind: Some(CodeActionKind::QUICKFIX),
980 edit: Some(edit),
981 is_preferred: Some(false),
982 data: None,
983 };
984 acc.push(action);
985 }
986
987 for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
988 let fix_range = from_proto::text_range(&line_index, fix.range);
989 if fix_range.intersect(frange.range).is_some() {
990 acc.push(fix.action.clone());
991 }
992 }
993 Ok(())
994}
995
960pub(crate) fn handle_code_action_resolve( 996pub(crate) fn handle_code_action_resolve(
961 mut snap: GlobalStateSnapshot, 997 mut snap: GlobalStateSnapshot,
962 mut code_action: lsp_ext::CodeAction, 998 mut code_action: lsp_ext::CodeAction,