Návod: Zobrazení návrhů žárovky
Žárovky jsou ikony v editoru sady Visual Studio, které rozbalují zobrazení sady akcí, například opravy problémů identifikovaných integrovanými analyzátory kódu nebo refaktoringem kódu.
V editorech Visual C# a Visual Basic můžete také pomocí platformy .NET Compiler Platform (Roslyn) napsat a zabalit vlastní analyzátory kódu s akcemi, které zobrazují žárovky automaticky. Další informace najdete tady:
Návod: Jak napsat diagnostiku a opravu kódu v jazyce Visual Basic
Další jazyky, jako je C++, také poskytují žárovky pro některé rychlé akce, například návrh na vytvoření implementace kostry této funkce.
Takto vypadá žárovka. V projektu Visual Basic nebo Visual C# se pod názvem proměnné zobrazí červená vlnovka, pokud je název proměnné neplatný. Pokud najedete myší na neplatný identifikátor, zobrazí se u kurzoru žárovka.
Pokud kliknete na šipku dolů u žárovky, zobrazí se sada navrhovaných akcí spolu s náhledem vybrané akce. V tomto případě se zobrazí změny provedené v kódu, pokud akci provedete.
Žárovky můžete použít pro navržení vlastních akcí. Můžete například zadat akce pro přesunutí začátečních složených závorek na nový řádek nebo jejich přesunutí na konec předchozího řádku. Následující návod ukazuje, jak vytvořit žárovku, která se zobrazí na aktuálním slově a má dvě navrhované akce: Převést na velká písmena a Převést na malá písmena.
Vytvoření projektu MEF (Managed Extensibility Framework)
Vytvořte projekt VSIX jazyka C#. (V dialogovém okně Nový projekt vyberte Visual C# / Rozšiřitelnost a pak projekt VSIX.) Pojmenujte řešení
LightBulbTest
.Přidejte do projektu šablonu položky Editor Classifier . Další informace najdete v tématu Vytvoření rozšíření pomocí šablony položek editoru.
Odstraňte existující soubory třídy.
Přidejte do projektu následující referenci a nastavte Kopírovat lokálně na
False
:Microsoft.VisualStudio.Language.Intellisense
Přidejte nový soubor třídy a pojmenujte ho LightBulbTest .
Přidejte následující direktivy using:
using System; using System.Linq; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Utilities; using System.ComponentModel.Composition; using System.Threading;
Implementujte poskytovatele zdroje žárovkového světla
V souboru třídy LightBulbTest.cs odstraňte třídu LightBulbTest. Přidejte třídu s názvem TestSuggestedActionsSourceProvider, která implementuje ISuggestedActionsSourceProvider. Exportujte ho s názvem Test Suggested Actions a ContentTypeAttribute ve formě "text".
[Export(typeof(ISuggestedActionsSourceProvider))] [Name("Test Suggested Actions")] [ContentType("text")] internal class TestSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider
Uvnitř třídy zdrojového poskytovatele naimportujte ITextStructureNavigatorSelectorService a přidejte ho jako vlastnost.
[Import(typeof(ITextStructureNavigatorSelectorService))] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
Implementujte CreateSuggestedActionsSource metodu pro vrácení ISuggestedActionsSource objektu. Zdroj je popsán v další části.
public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer) { if (textBuffer == null || textView == null) { return null; } return new TestSuggestedActionsSource(this, textView, textBuffer); }
Implementujte ISuggestedActionSource
Navrhovaný zdroj akcí zodpovídá za shromažďování sady navrhovaných akcí a jejich přidání do správného kontextu. V tomto případě je kontext aktuálním slovem a navrhované akce jsou UpperCaseSuggestedAction a LowerCaseSuggestedAction, která je popsána v následující části.
Přidejte třídu TestSuggestedActionsSource, která implementuje ISuggestedActionsSource.
internal class TestSuggestedActionsSource : ISuggestedActionsSource
Přidejte soukromá, readonly pole pro poskytovatele navrhovaných akcí, textový buffer a textové zobrazení.
private readonly TestSuggestedActionsSourceProvider m_factory; private readonly ITextBuffer m_textBuffer; private readonly ITextView m_textView;
Přidejte konstruktor, který nastaví soukromá pole.
public TestSuggestedActionsSource(TestSuggestedActionsSourceProvider testSuggestedActionsSourceProvider, ITextView textView, ITextBuffer textBuffer) { m_factory = testSuggestedActionsSourceProvider; m_textBuffer = textBuffer; m_textView = textView; }
Přidejte soukromou metodu, která vrací slovo, které je právě pod kurzorem. Následující metoda se podívá na aktuální umístění kurzoru a požádá navigátor struktury textu o rozsah slova. Pokud je kurzor na slově, TextExtent se vrátí v out parametru; v opačném případě je parametr
out
null
a metoda vrátífalse
.private bool TryGetWordUnderCaret(out TextExtent wordExtent) { ITextCaret caret = m_textView.Caret; SnapshotPoint point; if (caret.Position.BufferPosition > 0) { point = caret.Position.BufferPosition - 1; } else { wordExtent = default(TextExtent); return false; } ITextStructureNavigator navigator = m_factory.NavigatorService.GetTextStructureNavigator(m_textBuffer); wordExtent = navigator.GetExtentOfWord(point); return true; }
Implementujte metodu HasSuggestedActionsAsync. Editor volá tuto metodu, aby zjistil, zda se má žárovka zobrazit. Toto volání se často provádí například pokaždé, když se kurzor přesune z jednoho řádku na jiný nebo když najede myší na vlnovku chyby. Je asynchronní, aby ostatní operace uživatelského rozhraní mohly pokračovat v době, kdy tato metoda funguje. Ve většině případů tato metoda potřebuje provést nějaké parsování a analýzu aktuálního řádku, takže zpracování může nějakou dobu trvat.
V této implementaci asynchronně obdrží TextExtent a určí, zda je velikost významná, to znamená, zda obsahuje text kromě bílých znaků.
public Task<bool> HasSuggestedActionsAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) { return Task.Factory.StartNew(() => { TextExtent extent; if (TryGetWordUnderCaret(out extent)) { // don't display the action if the extent has whitespace return extent.IsSignificant; } return false; }); }
Implementujte GetSuggestedActions metodu, která vrací pole SuggestedActionSet objektů, které obsahují různé ISuggestedAction objekty. Tato metoda je volána, když dojde k rozšíření žárovky.
Varování
Měli byste se ujistit, že implementace
HasSuggestedActionsAsync()
aGetSuggestedActions()
jsou konzistentní; to znamená, že pokudHasSuggestedActionsAsync()
vrátítrue
, pakGetSuggestedActions()
by měly mít nějaké akce, které se mají zobrazit. V mnoha případech seHasSuggestedActionsAsync()
nazývá těsně předGetSuggestedActions()
, ale to není vždy případ. Například pokud uživatel vyvolá akce žárovky stisknutím (CTRL+ .) je volána pouzeGetSuggestedActions()
.public IEnumerable<SuggestedActionSet> GetSuggestedActions(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) { TextExtent extent; if (TryGetWordUnderCaret(out extent) && extent.IsSignificant) { ITrackingSpan trackingSpan = range.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive); var upperAction = new UpperCaseSuggestedAction(trackingSpan); var lowerAction = new LowerCaseSuggestedAction(trackingSpan); return new SuggestedActionSet[] { new SuggestedActionSet(new ISuggestedAction[] { upperAction, lowerAction }) }; } return Enumerable.Empty<SuggestedActionSet>(); }
Definujte událost
SuggestedActionsChanged
.public event EventHandler<EventArgs> SuggestedActionsChanged;
K dokončení implementace přidejte implementace pro
Dispose()
aTryGetTelemetryId()
metody. Nechcete provádět telemetrii, takže stačí vrátitfalse
a nastavit identifikátor GUID naEmpty
.public void Dispose() { } public bool TryGetTelemetryId(out Guid telemetryId) { // This is a sample provider and doesn't participate in LightBulb telemetry telemetryId = Guid.Empty; return false; }
Implementovat funkce žárovky
V projektu přidejte odkaz na Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll a nastavte Kopírovat lokálně na
False
.Vytvořte dvě třídy, první pojmenovanou
UpperCaseSuggestedAction
a druhou s názvemLowerCaseSuggestedAction
. Obě třídy implementují ISuggestedAction.internal class UpperCaseSuggestedAction : ISuggestedAction internal class LowerCaseSuggestedAction : ISuggestedAction
Obě třídy jsou stejné s tím rozdílem, že jedna volá ToUpper a druhá volá ToLower. Následující kroky pokrývají pouze třídu akcí velkými písmeny, ale musíte implementovat obě třídy. Kroky pro implementaci akce velkými písmeny použijte jako vzor pro implementaci akce malými písmeny.
Přidejte tyto "using" direktivy pro následující třídy:
using Microsoft.VisualStudio.Imaging.Interop; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media;
Deklarujte sadu privátních polí.
private ITrackingSpan m_span; private string m_upper; private string m_display; private ITextSnapshot m_snapshot;
Přidejte konstruktor, který nastaví pole.
public UpperCaseSuggestedAction(ITrackingSpan span) { m_span = span; m_snapshot = span.TextBuffer.CurrentSnapshot; m_upper = span.GetText(m_snapshot).ToUpper(); m_display = string.Format("Convert '{0}' to upper case", span.GetText(m_snapshot)); }
Implementujte metodu GetPreviewAsync tak, aby zobrazovala náhled akce.
public Task<object> GetPreviewAsync(CancellationToken cancellationToken) { var textBlock = new TextBlock(); textBlock.Padding = new Thickness(5); textBlock.Inlines.Add(new Run() { Text = m_upper }); return Task.FromResult<object>(textBlock); }
Implementujte metodu GetActionSetsAsync tak, aby vrátila prázdný výčet SuggestedActionSet.
public Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken) { return Task.FromResult<IEnumerable<SuggestedActionSet>>(null); }
Implementujte vlastnosti následujícím způsobem.
public bool HasActionSets { get { return false; } } public string DisplayText { get { return m_display; } } public ImageMoniker IconMoniker { get { return default(ImageMoniker); } } public string IconAutomationText { get { return null; } } public string InputGestureText { get { return null; } } public bool HasPreview { get { return true; } }
Implementujte metodu Invoke nahrazením textu ve vybraném rozsahu převodem na velká písmena.
public void Invoke(CancellationToken cancellationToken) { m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper); }
Varování
Netřeba očekávat, že akce žárovky s metodou vyvolá zobrazení uživatelského rozhraní. Pokud vaše akce vyvolá nové uživatelské rozhraní (například náhled nebo dialogové okno výběru), nezobrazujte uživatelské rozhraní přímo z metody Invoke, ale místo toho naplánujte zobrazení svého uživatelského rozhraní po návratu z metody Invoke.
K dokončení implementace přidejte
Dispose()
aTryGetTelemetryId()
metody.public void Dispose() { } public bool TryGetTelemetryId(out Guid telemetryId) { // This is a sample action and doesn't participate in LightBulb telemetry telemetryId = Guid.Empty; return false; }
Nezapomeňte udělat totéž pro
LowerCaseSuggestedAction
změnou zobrazeného textu na "Převést '{0}' na malá písmena" a zavolat ToUpper na ToLower.
Sestavení a otestování kódu
Tento kód otestujete tak, že sestavíte řešení LightBulbTest a spustíte ho v experimentální instanci.
Sestavte řešení.
Když tento projekt spustíte v ladicím programu, spustí se druhá instance sady Visual Studio.
Vytvořte textový soubor a zadejte nějaký text. Nalevo od textu by se měla zobrazit žárovka.
TestLIghtBulb
Nasměrujte na žárovku. Měla by se zobrazit šipka dolů.
Když kliknete na žárovku, měly by se zobrazit dvě navrhované akce spolu s náhledem vybrané akce.
Pokud kliknete na první akci, měl by být veškerý text v aktuálním slově převeden na velká písmena. Pokud kliknete na druhou akci, měl by být veškerý text převeden na malá písmena.