ide_db/
assists.rs

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.
7
8use std::str::FromStr;
9
10use syntax::TextRange;
11
12use crate::{label::Label, source_change::SourceChange};
13
14#[derive(Debug, Clone)]
15pub struct Assist {
16    pub id: AssistId,
17    /// Short description of the assist, as shown in the UI.
18    pub label: Label,
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>,
32    /// The command to execute after the assist is applied.
33    pub command: Option<Command>,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum Command {
38    /// Show the parameter hints popup.
39    TriggerParameterHints,
40    /// Rename the just inserted item.
41    Rename,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum AssistKind {
46    QuickFix,
47    Generate,
48    Refactor,
49    RefactorExtract,
50    RefactorInline,
51    RefactorRewrite,
52}
53
54impl AssistKind {
55    pub fn contains(self, other: AssistKind) -> bool {
56        if self == other {
57            return true;
58        }
59
60        match self {
61            AssistKind::Generate => true,
62            AssistKind::Refactor => matches!(
63                other,
64                AssistKind::RefactorExtract
65                    | AssistKind::RefactorInline
66                    | AssistKind::RefactorRewrite
67            ),
68            _ => false,
69        }
70    }
71
72    pub fn name(&self) -> &str {
73        match self {
74            AssistKind::QuickFix => "QuickFix",
75            AssistKind::Generate => "Generate",
76            AssistKind::Refactor => "Refactor",
77            AssistKind::RefactorExtract => "RefactorExtract",
78            AssistKind::RefactorInline => "RefactorInline",
79            AssistKind::RefactorRewrite => "RefactorRewrite",
80        }
81    }
82}
83
84impl FromStr for AssistKind {
85    type Err = String;
86
87    fn from_str(s: &str) -> Result<Self, Self::Err> {
88        match s {
89            "QuickFix" => Ok(AssistKind::QuickFix),
90            "Generate" => Ok(AssistKind::Generate),
91            "Refactor" => Ok(AssistKind::Refactor),
92            "RefactorExtract" => Ok(AssistKind::RefactorExtract),
93            "RefactorInline" => Ok(AssistKind::RefactorInline),
94            "RefactorRewrite" => Ok(AssistKind::RefactorRewrite),
95            unknown => Err(format!("Unknown AssistKind: '{unknown}'")),
96        }
97    }
98}
99
100/// Unique identifier of the assist, should not be shown to the user
101/// directly.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct AssistId(pub &'static str, pub AssistKind, pub Option<usize>);
104
105impl AssistId {
106    pub fn quick_fix(id: &'static str) -> AssistId {
107        AssistId(id, AssistKind::QuickFix, None)
108    }
109
110    pub fn generate(id: &'static str) -> AssistId {
111        AssistId(id, AssistKind::Generate, None)
112    }
113
114    pub fn refactor(id: &'static str) -> AssistId {
115        AssistId(id, AssistKind::Refactor, None)
116    }
117
118    pub fn refactor_extract(id: &'static str) -> AssistId {
119        AssistId(id, AssistKind::RefactorExtract, None)
120    }
121
122    pub fn refactor_inline(id: &'static str) -> AssistId {
123        AssistId(id, AssistKind::RefactorInline, None)
124    }
125
126    pub fn refactor_rewrite(id: &'static str) -> AssistId {
127        AssistId(id, AssistKind::RefactorRewrite, None)
128    }
129}
130
131/// A way to control how many assist to resolve during the assist resolution.
132/// When an assist is resolved, its edits are calculated that might be costly to always do by default.
133#[derive(Debug)]
134pub enum AssistResolveStrategy {
135    /// No assists should be resolved.
136    None,
137    /// All assists should be resolved.
138    All,
139    /// Only a certain assist should be resolved.
140    Single(SingleResolve),
141}
142
143/// Hold the [`AssistId`] data of a certain assist to resolve.
144/// The original id object cannot be used due to a `'static` lifetime
145/// and the requirement to construct this struct dynamically during the resolve handling.
146#[derive(Debug)]
147pub struct SingleResolve {
148    /// The id of the assist.
149    pub assist_id: String,
150    // The kind of the assist.
151    pub assist_kind: AssistKind,
152    /// Subtype of the assist. When many assists have the same id, it differentiates among them.
153    pub assist_subtype: Option<usize>,
154}
155
156impl AssistResolveStrategy {
157    pub fn should_resolve(&self, id: &AssistId) -> bool {
158        match self {
159            AssistResolveStrategy::None => false,
160            AssistResolveStrategy::All => true,
161            AssistResolveStrategy::Single(single_resolve) => {
162                single_resolve.assist_id == id.0
163                    && single_resolve.assist_kind == id.1
164                    && single_resolve.assist_subtype == id.2
165            }
166        }
167    }
168}
169
170#[derive(Clone, Debug)]
171pub struct GroupLabel(pub String);
172
173#[derive(Clone, Debug, PartialEq, Eq)]
174pub enum ExprFillDefaultMode {
175    Todo,
176    Default,
177    Underscore,
178}
179impl Default for ExprFillDefaultMode {
180    fn default() -> Self {
181        Self::Todo
182    }
183}