1 //! This module defines the `Assist` data structure. The actual assist live in
2 //! the `ide_assists` downstream crate. We want to define the data structures in
3 //! this low-level crate though, because `ide_diagnostics` also need them
4 //! (fixits for diagnostics and assists are the same thing under the hood). We
5 //! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so
6 //! we pull the common definitions upstream, to this crate.
10 use syntax::TextRange;
12 use crate::{label::Label, source_change::SourceChange};
14 #[derive(Debug, Clone)]
17 /// Short description of the assist, as shown in the UI.
19 pub group: Option<GroupLabel>,
20 /// Target ranges are used to sort assists: the smaller the target range,
21 /// the more specific assist is, and so it should be sorted first.
22 pub target: TextRange,
23 /// Computing source change sometimes is much more costly then computing the
24 /// other fields. Additionally, the actual change is not required to show
25 /// the lightbulb UI, it only is needed when the user tries to apply an
26 /// assist. So, we compute it lazily: the API allow requesting assists with
27 /// or without source change. We could (and in fact, used to) distinguish
28 /// between resolved and unresolved assists at the type level, but this is
29 /// cumbersome, especially if you want to embed an assist into another data
30 /// structure, such as a diagnostic.
31 pub source_change: Option<SourceChange>,
34 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
36 // FIXME: does the None variant make sense? Probably not.
48 pub fn contains(self, other: AssistKind) -> bool {
54 AssistKind::None | AssistKind::Generate => true,
55 AssistKind::Refactor => matches!(
57 AssistKind::RefactorExtract
58 | AssistKind::RefactorInline
59 | AssistKind::RefactorRewrite
65 pub fn name(&self) -> &str {
67 AssistKind::None => "None",
68 AssistKind::QuickFix => "QuickFix",
69 AssistKind::Generate => "Generate",
70 AssistKind::Refactor => "Refactor",
71 AssistKind::RefactorExtract => "RefactorExtract",
72 AssistKind::RefactorInline => "RefactorInline",
73 AssistKind::RefactorRewrite => "RefactorRewrite",
78 impl FromStr for AssistKind {
81 fn from_str(s: &str) -> Result<Self, Self::Err> {
83 "None" => Ok(AssistKind::None),
84 "QuickFix" => Ok(AssistKind::QuickFix),
85 "Generate" => Ok(AssistKind::Generate),
86 "Refactor" => Ok(AssistKind::Refactor),
87 "RefactorExtract" => Ok(AssistKind::RefactorExtract),
88 "RefactorInline" => Ok(AssistKind::RefactorInline),
89 "RefactorRewrite" => Ok(AssistKind::RefactorRewrite),
90 unknown => Err(format!("Unknown AssistKind: '{}'", unknown)),
95 /// Unique identifier of the assist, should not be shown to the user
97 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
98 pub struct AssistId(pub &'static str, pub AssistKind);
100 /// A way to control how many asssist to resolve during the assist resolution.
101 /// When an assist is resolved, its edits are calculated that might be costly to always do by default.
103 pub enum AssistResolveStrategy {
104 /// No assists should be resolved.
106 /// All assists should be resolved.
108 /// Only a certain assist should be resolved.
109 Single(SingleResolve),
112 /// Hold the [`AssistId`] data of a certain assist to resolve.
113 /// The original id object cannot be used due to a `'static` lifetime
114 /// and the requirement to construct this struct dynamically during the resolve handling.
116 pub struct SingleResolve {
117 /// The id of the assist.
118 pub assist_id: String,
119 // The kind of the assist.
120 pub assist_kind: AssistKind,
123 impl AssistResolveStrategy {
124 pub fn should_resolve(&self, id: &AssistId) -> bool {
126 AssistResolveStrategy::None => false,
127 AssistResolveStrategy::All => true,
128 AssistResolveStrategy::Single(single_resolve) => {
129 single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1
135 #[derive(Clone, Debug)]
136 pub struct GroupLabel(pub String);