가이드: 전구 추천 표시
전구는 Visual Studio 편집기의 아이콘으로, 기본 제공 코드 분석기 또는 코드 리팩터링으로 식별되는 문제에 대한 수정과 같은 작업 집합을 표시하도록 확장됩니다.
Visual C# 및 Visual Basic 편집기에서 .NET 컴파일러 플랫폼("Roslyn")을 사용하여 자동으로 전구 아이콘을 표시하는 동작과 함께 사용자 고유의 코드 분석기를 작성하고 패키징할 수도 있습니다. 자세한 내용은 다음을 참조하세요.
방법: Visual Basic 진단 및 코드 수정을 작성하는 법
C++와 같은 다른 언어는 해당 함수의 스텁 구현을 만드는 제안과 같은 몇 가지 빠른 작업에 대한 전구를 제공합니다.
전구의 모양은 다음과 같습니다. Visual Basic 또는 Visual C# 프로젝트에서 변수 이름이 잘못된 경우, 변수 이름 아래에 빨간색 물결선이 나타납니다. 잘못된 식별자를 마우스로 가리키면 커서 근처에 전구가 나타납니다.
전구
전구 전구 옆의 아래쪽 화살표를 클릭하면 선택한 작업의 미리 보기와 함께 제안된 작업 집합이 나타납니다. 이 경우 작업을 실행하는 경우 코드에 대한 변경 내용이 표시됩니다.
전구를 사용하여 고유한 제안된 작업을 제공할 수 있습니다. 예를 들어 여는 중괄호를 새 줄로 이동하거나 이전 줄의 끝으로 이동하는 작업을 제공할 수 있습니다. 다음 연습에서는 현재 단어 옆에 표시되고 두 가지 제안된 작업이 있는 전구 아이콘을 만드는 방법을 보여줍니다. 대문자로 변환하기 하고 소문자로 변환하기.
MEF(Managed Extensibility Framework) 프로젝트 만들기
C# VSIX 프로젝트를 만듭니다. (새 프로젝트 대화 상자에서 C# / 확장성을 선택한 후 VSIX 프로젝트를 선택하세요.) 솔루션 이름을
LightBulbTest
로 지정하십시오.편집기 분류자 항목 템플릿을 프로젝트에 추가합니다. 자세한 내용은 편집기 항목 템플릿사용하여 확장 만들기를 참조하세요.
기존 클래스 파일을 삭제합니다.
프로젝트에 다음 참조를 추가하고 Copy Local을
False
로 설정합니다.Microsoft.VisualStudio.Language.Intellisense
새 클래스 파일을 추가하고 이름을 LightBulbTest으로 지정합니다.
다음 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;
전구 원본 공급자 구현
LightBulbTest.cs 클래스 파일에서 LightBulbTest 클래스를 삭제합니다. TestSuggestedActionsSourceProvider 클래스를 ISuggestedActionsSourceProvider를 구현하도록 추가합니다. 테스트 제안된 작업 이름 및 "텍스트" ContentTypeAttribute 사용하여 내보냅니다.
[Export(typeof(ISuggestedActionsSourceProvider))] [Name("Test Suggested Actions")] [ContentType("text")] internal class TestSuggestedActionsSourceProvider : ISuggestedActionsSourceProvider
원본 공급자 클래스 내에서 ITextStructureNavigatorSelectorService 가져와 속성으로 추가합니다.
[Import(typeof(ITextStructureNavigatorSelectorService))] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
ISuggestedActionsSource 개체를 반환하는 CreateSuggestedActionsSource 메서드를 구현합니다. 원본은 다음 섹션에서 설명합니다.
public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer textBuffer) { if (textBuffer == null || textView == null) { return null; } return new TestSuggestedActionsSource(this, textView, textBuffer); }
ISuggestedActionSource을 구현
제안된 작업 원본은 제안된 작업 집합을 수집하고 올바른 컨텍스트에 추가하는 작업을 담당합니다. 이 경우, 문맥은 현재 단어이며, 제안된 작업은 UpperCaseSuggestedAction 및 LowerCaseSuggestedAction로, 이는 다음 섹션에서 논의됩니다.
구현하는 TestSuggestedActionsSource 클래스를 추가합니다. internal class TestSuggestedActionsSource : ISuggestedActionsSource
제안된 작업 원본 공급자, 텍스트 버퍼 및 텍스트 뷰에 대한 프라이빗 읽기 전용 필드를 추가합니다.
private readonly TestSuggestedActionsSourceProvider m_factory; private readonly ITextBuffer m_textBuffer; private readonly ITextView m_textView;
프라이빗 필드를 설정하는 생성자를 추가합니다.
public TestSuggestedActionsSource(TestSuggestedActionsSourceProvider testSuggestedActionsSourceProvider, ITextView textView, ITextBuffer textBuffer) { m_factory = testSuggestedActionsSourceProvider; m_textBuffer = textBuffer; m_textView = textView; }
현재 커서 아래에 있는 단어를 반환하는 private 메서드를 추가합니다. 다음 메서드는 커서의 현재 위치를 확인하고 텍스트 구조 탐색기에서 단어의 범위를 묻습니다. 커서가 단어 위에 있으면 TextExtent이 out 매개변수로 반환됩니다. 그렇지 않으면
out
매개변수는null
로 설정되고, 메서드는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; }
HasSuggestedActionsAsync 메서드를 구현합니다. 편집기에서 이 메서드를 호출하여 전구를 표시할지 여부를 확인합니다. 예를 들어 커서가 한 줄에서 다른 줄로 이동하거나 마우스가 오류 물결선 위로 이동할 때마다 이 호출이 빈번하게 발생합니다. 이 메서드가 작동하는 동안 다른 UI 작업이 계속되도록 하기 위해 비동기적입니다. 대부분의 경우 이 메서드는 현재 줄의 일부 구문 분석 및 분석을 수행해야 하므로 처리에 다소 시간이 걸릴 수 있습니다.
이 구현에서는 비동기적으로 TextExtent을 가져와서, 공백 이외의 일부 텍스트가 있는지와 같이 범위가 의미가 있는지를 결정합니다.
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; }); }
다른 ISuggestedAction 개체를 포함하는 SuggestedActionSet 개체의 배열을 반환하는 GetSuggestedActions 메서드를 구현합니다. 이 메서드는 전구가 확장될 때 호출됩니다.
경고
HasSuggestedActionsAsync()
및GetSuggestedActions()
구현이 일관된지 확인해야 합니다. 즉,HasSuggestedActionsAsync()
true
반환하는 경우GetSuggestedActions()
표시할 몇 가지 작업이 있어야 합니다. 대부분의 경우HasSuggestedActionsAsync()
GetSuggestedActions()
직전에 호출되지만 항상 그런 것은 아닙니다. 예를 들어 사용자가 (CTRL+ .)을 눌러 전구 관련 작업을 수행하려고 할 때, 실제로는GetSuggestedActions()
만 호출됩니다.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>(); }
SuggestedActionsChanged
이벤트를 정의합니다.public event EventHandler<EventArgs> SuggestedActionsChanged;
구현을 완료하려면
Dispose()
및TryGetTelemetryId()
메서드에 대한 구현을 추가합니다. 원격 분석을 원하지 않으시면,false
을 반환하고 GUID를Empty
으로 설정하세요.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; }
전구 동작 구현
프로젝트에서 Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll 대한 참조를 추가하고 로컬 복사를
False
설정합니다.두 개의 클래스를 만듭니다. 첫 번째 이름은
UpperCaseSuggestedAction
, 두 번째 클래스는LowerCaseSuggestedAction
. 두 클래스 모두 ISuggestedAction구현합니다.internal class UpperCaseSuggestedAction : ISuggestedAction internal class LowerCaseSuggestedAction : ISuggestedAction
두 클래스는 비슷하지만, 하나는 ToUpper를 호출하고 다른 하나는 ToLower를 호출합니다. 다음 단계에서는 대문자 작업 클래스만 다루지만 두 클래스를 모두 구현해야 합니다. 대문자 동작을 구현하는 단계를 소문자 동작을 구현하기 위한 패턴으로 사용하십시오.
이러한 클래스에 대해 다음 using 지시문을 추가합니다.
using Microsoft.VisualStudio.Imaging.Interop; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media;
비공개 필드 집합을 선언합니다.
private ITrackingSpan m_span; private string m_upper; private string m_display; private ITextSnapshot m_snapshot;
필드를 설정하는 생성자를 추가합니다.
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)); }
작업 미리 보기를 표시할 수 있도록 GetPreviewAsync 메서드를 구현합니다.
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); }
빈 SuggestedActionSet 열거형을 반환할 수 있도록 GetActionSetsAsync 메서드를 구현합니다.
public Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken) { return Task.FromResult<IEnumerable<SuggestedActionSet>>(null); }
다음과 같이 속성을 구현합니다.
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; } }
범위의 텍스트를 해당하는 대문자로 바꿔 Invoke 메서드를 구현합니다.
public void Invoke(CancellationToken cancellationToken) { m_span.TextBuffer.Replace(m_span.GetSpan(m_snapshot), m_upper); }
경고
호출 메서드에
전구 작업은 UI를 표시할 것으로 예상되지 않습니다. 사용자 작업이 새 UI(예: 미리 보기 또는 선택 대화 상자)를 불러오는 경우, Invoke 메서드 내에서 직접 UI를 표시하지 말고, Invoke반환한 후에 UI를 표시하도록 예약하세요. 구현을 완료하려면
Dispose()
및TryGetTelemetryId()
메서드를 추가합니다.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; }
"
LowerCaseSuggestedAction
에 대해 동일한 작업을 수행하고, 표시 텍스트를 '{0}'을 소문자로 변환'으로 바꾸세요. 그리고 ToUpper를 ToLower으로 호출하는 것을 잊지 마세요."
코드 빌드 및 테스트
이 코드를 테스트하려면 LightBulbTest 솔루션을 빌드하고 실험적 인스턴스에서 실행합니다.
솔루션을 빌드합니다.
디버거에서 이 프로젝트를 실행하면 Visual Studio의 두 번째 인스턴스가 시작됩니다.
텍스트 파일을 만들고 일부 텍스트를 입력합니다. 텍스트 왼쪽에 전구가 표시됩니다.
전구를 가리킵니다. 아래쪽 화살표가 보여야 합니다.
전구를 클릭하면 선택한 작업의 미리 보기와 함께 두 개의 제안된 작업이 표시됩니다.
첫 번째 작업을 클릭하면 현재 단어의 모든 텍스트가 대문자로 변환됩니다. 두 번째 작업을 클릭하면 모든 텍스트를 소문자로 변환해야 합니다.