|  | //! This module defines the `Assist` data structure. The actual assist live in | 
|  | //! the `ide_assists` downstream crate. We want to define the data structures in | 
|  | //! this low-level crate though, because `ide_diagnostics` also need them | 
|  | //! (fixits for diagnostics and assists are the same thing under the hood). We | 
|  | //! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so | 
|  | //! we pull the common definitions upstream, to this crate. | 
|  |  | 
|  | use std::str::FromStr; | 
|  |  | 
|  | use syntax::TextRange; | 
|  |  | 
|  | use crate::{label::Label, source_change::SourceChange}; | 
|  |  | 
|  | #[derive(Debug, Clone)] | 
|  | pub struct Assist { | 
|  | pub id: AssistId, | 
|  | /// Short description of the assist, as shown in the UI. | 
|  | pub label: Label, | 
|  | pub group: Option<GroupLabel>, | 
|  | /// Target ranges are used to sort assists: the smaller the target range, | 
|  | /// the more specific assist is, and so it should be sorted first. | 
|  | pub target: TextRange, | 
|  | /// Computing source change sometimes is much more costly then computing the | 
|  | /// other fields. Additionally, the actual change is not required to show | 
|  | /// the lightbulb UI, it only is needed when the user tries to apply an | 
|  | /// assist. So, we compute it lazily: the API allow requesting assists with | 
|  | /// or without source change. We could (and in fact, used to) distinguish | 
|  | /// between resolved and unresolved assists at the type level, but this is | 
|  | /// cumbersome, especially if you want to embed an assist into another data | 
|  | /// structure, such as a diagnostic. | 
|  | pub source_change: Option<SourceChange>, | 
|  | /// The command to execute after the assist is applied. | 
|  | pub command: Option<Command>, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 
|  | pub enum Command { | 
|  | /// Show the parameter hints popup. | 
|  | TriggerParameterHints, | 
|  | /// Rename the just inserted item. | 
|  | Rename, | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 
|  | pub enum AssistKind { | 
|  | QuickFix, | 
|  | Generate, | 
|  | Refactor, | 
|  | RefactorExtract, | 
|  | RefactorInline, | 
|  | RefactorRewrite, | 
|  | } | 
|  |  | 
|  | impl AssistKind { | 
|  | pub fn contains(self, other: AssistKind) -> bool { | 
|  | if self == other { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | match self { | 
|  | AssistKind::Generate => true, | 
|  | AssistKind::Refactor => matches!( | 
|  | other, | 
|  | AssistKind::RefactorExtract | 
|  | | AssistKind::RefactorInline | 
|  | | AssistKind::RefactorRewrite | 
|  | ), | 
|  | _ => false, | 
|  | } | 
|  | } | 
|  |  | 
|  | pub fn name(&self) -> &str { | 
|  | match self { | 
|  | AssistKind::QuickFix => "QuickFix", | 
|  | AssistKind::Generate => "Generate", | 
|  | AssistKind::Refactor => "Refactor", | 
|  | AssistKind::RefactorExtract => "RefactorExtract", | 
|  | AssistKind::RefactorInline => "RefactorInline", | 
|  | AssistKind::RefactorRewrite => "RefactorRewrite", | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl FromStr for AssistKind { | 
|  | type Err = String; | 
|  |  | 
|  | fn from_str(s: &str) -> Result<Self, Self::Err> { | 
|  | match s { | 
|  | "QuickFix" => Ok(AssistKind::QuickFix), | 
|  | "Generate" => Ok(AssistKind::Generate), | 
|  | "Refactor" => Ok(AssistKind::Refactor), | 
|  | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | 
|  | "RefactorInline" => Ok(AssistKind::RefactorInline), | 
|  | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | 
|  | unknown => Err(format!("Unknown AssistKind: '{unknown}'")), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Unique identifier of the assist, should not be shown to the user | 
|  | /// directly. | 
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 
|  | pub struct AssistId(pub &'static str, pub AssistKind, pub Option<usize>); | 
|  |  | 
|  | impl AssistId { | 
|  | pub fn quick_fix(id: &'static str) -> AssistId { | 
|  | AssistId(id, AssistKind::QuickFix, None) | 
|  | } | 
|  |  | 
|  | pub fn generate(id: &'static str) -> AssistId { | 
|  | AssistId(id, AssistKind::Generate, None) | 
|  | } | 
|  |  | 
|  | pub fn refactor(id: &'static str) -> AssistId { | 
|  | AssistId(id, AssistKind::Refactor, None) | 
|  | } | 
|  |  | 
|  | pub fn refactor_extract(id: &'static str) -> AssistId { | 
|  | AssistId(id, AssistKind::RefactorExtract, None) | 
|  | } | 
|  |  | 
|  | pub fn refactor_inline(id: &'static str) -> AssistId { | 
|  | AssistId(id, AssistKind::RefactorInline, None) | 
|  | } | 
|  |  | 
|  | pub fn refactor_rewrite(id: &'static str) -> AssistId { | 
|  | AssistId(id, AssistKind::RefactorRewrite, None) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A way to control how many assist to resolve during the assist resolution. | 
|  | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | 
|  | #[derive(Debug)] | 
|  | pub enum AssistResolveStrategy { | 
|  | /// No assists should be resolved. | 
|  | None, | 
|  | /// All assists should be resolved. | 
|  | All, | 
|  | /// Only a certain assist should be resolved. | 
|  | Single(SingleResolve), | 
|  | } | 
|  |  | 
|  | /// Hold the [`AssistId`] data of a certain assist to resolve. | 
|  | /// The original id object cannot be used due to a `'static` lifetime | 
|  | /// and the requirement to construct this struct dynamically during the resolve handling. | 
|  | #[derive(Debug)] | 
|  | pub struct SingleResolve { | 
|  | /// The id of the assist. | 
|  | pub assist_id: String, | 
|  | // The kind of the assist. | 
|  | pub assist_kind: AssistKind, | 
|  | /// Subtype of the assist. When many assists have the same id, it differentiates among them. | 
|  | pub assist_subtype: Option<usize>, | 
|  | } | 
|  |  | 
|  | impl AssistResolveStrategy { | 
|  | pub fn should_resolve(&self, id: &AssistId) -> bool { | 
|  | match self { | 
|  | AssistResolveStrategy::None => false, | 
|  | AssistResolveStrategy::All => true, | 
|  | AssistResolveStrategy::Single(single_resolve) => { | 
|  | single_resolve.assist_id == id.0 | 
|  | && single_resolve.assist_kind == id.1 | 
|  | && single_resolve.assist_subtype == id.2 | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Clone, Debug)] | 
|  | pub struct GroupLabel(pub String); | 
|  |  | 
|  | #[derive(Clone, Debug, PartialEq, Eq, Default)] | 
|  | pub enum ExprFillDefaultMode { | 
|  | #[default] | 
|  | Todo, | 
|  | Default, | 
|  | Underscore, | 
|  | } |