Пошаговое руководство: Создание фрагментов кода
Можно создать фрагменты кода и включить их в расширении редактор, чтобы пользователи могли добавлять их к их расширения своего кода.
Фрагмент кода фрагмент кода или другого текста, который можно включить в файл. Чтобы просмотреть все фрагменты, которые были зарегистрированы для конкретных языков программирования, в меню Сервис нажмите кнопку Диспетчер фрагментов кода. Чтобы вставить фрагмент в файл, щелкните правой кнопкой мыши где требуется фрагмент, щелкните Вставить фрагмент или Разместить во фрагменте, обнаруживают расположение фрагмента, а затем дважды щелкните их. Нажмите клавишу TAB или SHIFT+TAB для изменения соответствующие части фрагмента, а затем нажмите клавишу ввод или ESC, чтобы принять его. Дополнительные сведения см. в разделе Фрагменты кода.
Фрагмент кода содержится в XML-файл, который имеет расширение имени файла с расширением .snippet. Фрагмент может содержать поля, выбранных после вставки фрагмента, чтобы пользователь мог находить и изменять их. Файл фрагмента также предоставляет сведения для Диспетчер фрагментов кода таким образом, чтобы он мог указать имя фрагмента в правильную категории. Дополнительные сведения о схеме фрагмента см. в разделе Справочник по схеме фрагментов кода.
В этом пошаговом руководстве назначения, как выполнять эти задачи.
Создайте и зарегистрируйте фрагменты кода для указанного языка.
Добавьте команду Вставить фрагмент в контекстное меню.
Реализуйте расширение фрагмента.
В этом пошаговом руководстве основано на Пошаговое руководство: Завершение операторов отображение.
Обязательные компоненты
Чтобы выполнить это пошаговое руководство, необходимо установить пакет SDK Visual Studio 2010. Дополнительные сведения о пакет Visual Studio SDK и загрузить его см. в Центр разработчиков расширяемости Visual Studio разделе на веб-сайте MSDN.
Создание и регистрация фрагменты кода
Обычно фрагменты кода связаны с зарегистрированной службой языка. Однако не следует реализовывать LanguageService для регистрации фрагментов кода. Вместо этого просто укажите идентификатор GUID в файле индекса фрагмента, а затем используйте один и тот же идентификатор GUID в ProvideLanguageCodeExpansionAttribute, добавляемые в проект.
Следующие шаги демонстрируют, как создать фрагменты кода и связать их с определенным идентификатором GUID.
Создание фрагментов кода
Создайте следующую структуру каталогов.
%InstallDir%\TestSnippets\Snippets\1033\
где %InstallDir% — это папка установки Visual Studio. (Хотя этот путь обычно используется для задания фрагменты кода, можно указать любой путь).
В папке \1033\ создайте XML-файл и задайте для него имя SnippetIndex.xml. (Хотя это имя, как правило, используется для файла индекса фрагмента, можно задать любое имя, если оно имеет расширение имени файла XML). Добавьте следующий текст, а затем удалите GUID заполнителя и добавьте необходимые требования.
<?xml version="1.0" encoding="utf-8" ?> <SnippetCollection> <Language Lang="TestSnippets" Guid="{00000000-0000-0000-0000-000000000000}"> <SnippetDir> <OnOff>On</OnOff> <Installed>true</Installed> <Locale>1033</Locale> <DirPath>%InstallRoot%\TestSnippets\Snippets\%LCID%\</DirPath> <LocalizedName>Snippets</LocalizedName> </SnippetDir> </Language> </SnippetCollection>
Создайте файл в папке фрагментов, назовите его тестом .snippet, а затем добавьте следующий текст:
<?xml version="1.0" encoding="utf-8" ?> <CodeSnippets xmlns="https://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>Test replacement fields</Title> <Shortcut>test</Shortcut> <Description>Code snippet for testing replacement fields</Description> <Author>MSIT</Author> <SnippetTypes> <SnippetType>Expansion</SnippetType> </SnippetTypes> </Header> <Snippet> <Declarations> <Literal> <ID>param1</ID> <ToolTip>First field</ToolTip> <Default>first</Default> </Literal> <Literal> <ID>param2</ID> <ToolTip>Second field</ToolTip> <Default>second</Default> </Literal> </Declarations> <References> <Reference> <Assembly>System.Windows.Forms.dll</Assembly> </Reference> </References> <Code Language="TestSnippets"> <![CDATA[MessageBox.Show("$param1$"); MessageBox.Show("$param2$");]]> </Code> </Snippet> </CodeSnippet> </CodeSnippets>
Следующие шаги показывают, как регистрировать фрагментов кода.
Регистрация фрагменты кода для конкретного идентификатора GUID
Открытие проекта CompletionTest. Сведения о том, как создать этот проект, см. в разделе Пошаговое руководство: Завершение операторов отображение.
В проекте добавьте ссылки на следующие сборки:
Microsoft.VisualStudio.TextManager.Interop
Microsoft.VisualStudio.TextManager.Interop.8.0
microsoft.msxml
Чтобы зарегистрировать фрагменты кода, проект должен выводить файл .pkgdef. Дополнительные сведения см. в разделе Registering VSPackages.
В проекте откройте файл source.extension.vsixmanifest.
В разделе Содержимое нажмите кнопку Добавление содержимого выберите тип содержимого Пакет VS выберите параметр Проект и выберите TestCompletion в раскрывающемся списке.
Следующая линия должна появиться в файл.
TestCompletion;PkgdefProjectOutputGroup|
Сохраните файл и закройте его. source.extension.vsixmanifest
Добавьте статический класс SnippetUtilities в проект.
Module SnippetUtilities
static class SnippetUtilities
В классе SnippetUtilities укажите идентификатор GUID и присвойте ему значение, выбранное в файле SnippetsIndex.xml.
Friend Const LanguageServiceGuidStr As String = "00000000-0000-0000-0000-00000000"
internal const string LanguageServiceGuidStr = "00000000-0000-0000-0000-00000000";
Добавьте в класс ProvideLanguageCodeExpansionAttributeTestCompletionHandler. Этот атрибут можно добавить к любому пользователю предоставлено или нестатическими внутреннему классу () в проекте. (Можно добавить оператор using для пространства имен Microsoft.VisualStudio.Shell).
<ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", 0, "TestSnippets", "%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", SearchPaths:="%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs:="%InstallRoot%\TestSnippets\Snippets\%LCID%\")> Friend Class TestCompletionCommandHandler Implements IOleCommandTarget
[ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", //the language name 0, //the resource id of the language "TestSnippets", //the language ID used in the .snippet files @"%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", //the path of the index file SearchPaths = @"%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs = @"%InstallRoot%\TestSnippets\Snippets\%LCID%\")] internal class TestCompletionCommandHandler : IOleCommandTarget
Выполните построение и запуск проекта. В экспериментальном экземпляре Visual Studio, которое запускается при запуске проекта фрагмент просто регистрации должен отображаться в Диспетчер фрагментов кода с языком TestSnippets.
Добавление команды вставить фрагмент в контекстное меню
Команда Вставить фрагмент не включается в контекстном меню для текстового файла. Поэтому необходимо включить команды.
Добавление команды вставить фрагмент в контекстное меню
Откройте файл класса TestCompletionCommandHandler.
Поскольку этот класс реализует IOleCommandTarget, можно активировать команды Вставить фрагмент в методе QueryStatus. Прежде чем включать команду, убедитесь, что этот метод не вызывается внутри функции автоматизации, поскольку если команда Вставить фрагмент ", она будет отображать пользовательский интерфейс выбора фрагмента (пользовательский интерфейс).
Public Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal cCmds As UInteger, ByVal prgCmds As OLECMD(), ByVal pCmdText As IntPtr) As Integer Implements IOleCommandTarget.QueryStatus If Not VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider) Then If pguidCmdGroup = VSConstants.VSStd2K AndAlso cCmds > 0 Then ' make the Insert Snippet command appear on the context menu If CUInt(prgCmds(0).cmdID) = CUInt(VSConstants.VSStd2KCmdID.INSERTSNIPPET) Then prgCmds(0).cmdf = CInt(Constants.MSOCMDF_ENABLED) Or CInt(Constants.MSOCMDF_SUPPORTED) Return VSConstants.S_OK End If End If End If Return m_nextCommandHandler.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText) End Function
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) { if (!VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { if (pguidCmdGroup == VSConstants.VSStd2K && cCmds > 0) { // make the Insert Snippet command appear on the context menu if ((uint)prgCmds[0].cmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET) { prgCmds[0].cmdf = (int)Constants.MSOCMDF_ENABLED | (int)Constants.MSOCMDF_SUPPORTED; return VSConstants.S_OK; } } } return m_nextCommandHandler.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText); }
Выполните построение и запуск проекта. В экспериментальном экземпляре, откройте файл с расширением имени файла и щелкните правой кнопкой мыши в любом месте .zzz их. Команда Вставить фрагмент должна появиться в контекстном меню.
Реализация расширения фрагмента в пользовательском интерфейсе snippet picker
В этом подразделе показано, как реализовать расширение фрагмента кода, так что пользовательский интерфейс выбора фрагмента отображается при Вставить фрагмент будет нажата кнопка в контекстном меню. Фрагмент кода также развернут когда пользователь вводит ярлык код-фрагмента и нажмите клавишу TAB.
Для отображения пользовательского интерфейса и snippet picker, чтобы обеспечить принятие фрагмента навигации и POST-вставки, используйте метод Exec. Вставка OnItemChosen сама обрабатывается методом.
Реализация расширения фрагмента кода использует устаревшие интерфейсы Microsoft.VisualStudio.TextManager.Interop. Если переводите от текущих классов редактора к устаревшим кодом, помните, что устаревшие интерфейсы используются номера линии сочетание и номера столбца для определения расположения в текстовом буфере, но существующие классы используют один индекс. Поэтому, если буфер содержит 3 линии, каждый из которых имеет 10 символов (плюс новой строки, который считается 1 символов), четвертый символ в третьей линии в позиции 27 в текущей реализации, но на линии 2, то положение 3 в старой реализации.
К расширению фрагмента "
К файлу, который содержит класс TestCompletionCommandHandler добавьте следующие using выписки.
Imports Microsoft.VisualStudio.Text.Operations Imports MSXML
using Microsoft.VisualStudio.Text.Operations; using MSXML; using System.ComponentModel.Composition;
Сделайте класс TestCompletionCommandHandler реализовать интерфейс IVsExpansionClient.
<ProvideLanguageCodeExpansion( SnippetUtilities.LanguageServiceGuidStr, "TestSnippets", 0, "TestSnippets", "%InstallRoot%\TestSnippets\Snippets\%LCID%\SnippetsIndex.xml", SearchPaths:="%InstallRoot%\TestSnippets\Snippets\%LCID%\", ForceCreateDirs:="%InstallRoot%\TestSnippets\Snippets\%LCID%\")> Friend Class TestCompletionCommandHandler Implements IOleCommandTarget Implements IVsExpansionClient
internal class TestCompletionCommandHandler : IOleCommandTarget, IVsExpansionClient
В классе TestCompletionCommandHandlerProvider, импортировать ITextStructureNavigatorSelectorService.
<Import()> Friend Property NavigatorService As ITextStructureNavigatorSelectorService
[Import] internal ITextStructureNavigatorSelectorService NavigatorService { get; set; }
Добавьте закрытые поля для некоторых интерфейсов модулей кода и IVsTextView.
Dim m_vsTextView As IVsTextView Dim m_exManager As IVsExpansionManager Dim m_exSession As IVsExpansionSession
IVsTextView m_vsTextView; IVsExpansionManager m_exManager; IVsExpansionSession m_exSession;
В конструкторе класса TestCompletionCommandHandler установите следующие поля.
Friend Sub New(ByVal textViewAdapter As IVsTextView, ByVal textView As ITextView, ByVal provider As TestCompletionHandlerProvider) Me.m_textView = textView Me.m_provider = provider Me.m_vsTextView = textViewAdapter Dim textManager As IVsTextManager2 = DirectCast(m_provider.ServiceProvider.GetService(GetType(SVsTextManager)), IVsTextManager2) textManager.GetExpansionManager(m_exManager) m_exSession = Nothing 'add the command to the command chain textViewAdapter.AddCommandFilter(Me, m_nextCommandHandler) End Sub
internal TestCompletionCommandHandler(IVsTextView textViewAdapter, ITextView textView, TestCompletionHandlerProvider provider) { this.m_textView = textView; m_vsTextView = textViewAdapter; m_provider = provider; //get the text manager from the service provider IVsTextManager2 textManager = (IVsTextManager2)m_provider.ServiceProvider.GetService(typeof(SVsTextManager)); textManager.GetExpansionManager(out m_exManager); m_exSession = null; //add the command to the command chain textViewAdapter.AddCommandFilter(this, out m_nextCommandHandler); }
Snippet picker для отображения, когда пользователь выбирает соответствующую команду Вставить фрагмент добавьте следующий код в метод Exec. (Это сделать объяснение более четким, не показан код exec (), используемый для завершения выписки; вместо этого блоки кода добавляются к существующему методу). Добавьте следующий блок кода после кода, который проверяет наличие знака.
'code previously written for Exec If pguidCmdGroup = VSConstants.VSStd2K AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TYPECHAR) Then typedChar = ChrW(CUShort(Marshal.GetObjectForNativeVariant(pvaIn))) End If 'the snippet picker code starts here If nCmdID = CUInt(VSConstants.VSStd2KCmdID.INSERTSNIPPET) Then Dim textManager As IVsTextManager2 = DirectCast(m_provider.ServiceProvider.GetService(GetType(SVsTextManager)), IVsTextManager2) textManager.GetExpansionManager(m_exManager) m_exManager.InvokeInsertionUI( m_vsTextView, Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), Nothing, 0, 0, Nothing, 0, 0, "TestSnippets", String.Empty) Return VSConstants.S_OK End If
//code previously written for Exec if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } //the snippet picker code starts here if (nCmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET) { IVsTextManager2 textManager = (IVsTextManager2)m_provider.ServiceProvider.GetService(typeof(SVsTextManager)); textManager.GetExpansionManager(out m_exManager); m_exManager.InvokeInsertionUI( m_vsTextView, this, //the expansion client new Guid(SnippetUtilities.LanguageServiceGuidStr), null, //use all snippet types 0, //number of types (0 for all) 0, //ignored if iCountTypes == 0 null, //use all snippet kinds 0, //use all snippet kinds 0, //ignored if iCountTypes == 0 "TestSnippets", //the text to show in the prompt string.Empty); //only the ENTER key causes insert return VSConstants.S_OK; }
Если фрагмент содержит поля, которые можно перейти, сеанс расширения быть открыто до тех пор, пока расширение явно не принимаются. если фрагмент не содержит поля, сеанс закрыт и возвращается как null методом InvokeInsertionUI. В методе Exec, after code snippet picker пользовательского интерфейса, созданного на предыдущем этапе, добавьте следующий код к переходов фрагмента маркера (если пользователь отожмет TAB или SHIFT+TAB после вставки фрагмента).
'the expansion insertion is handled in OnItemChosen 'if the expansion session is still active, handle tab/backtab/return/cancel If m_exSession IsNot Nothing Then If nCmdID = CUInt(VSConstants.VSStd2KCmdID.BACKTAB) Then m_exSession.GoToPreviousExpansionField() Return VSConstants.S_OK ElseIf nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) Then m_exSession.GoToNextExpansionField(0) 'false to support cycling through all the fields Return VSConstants.S_OK ElseIf nCmdID = CUInt(VSConstants.VSStd2KCmdID.[RETURN]) OrElse nCmdID = CUInt(VSConstants.VSStd2KCmdID.CANCEL) Then If m_exSession.EndCurrentExpansion(0) = VSConstants.S_OK Then m_exSession = Nothing Return VSConstants.S_OK End If End If End If
//the expansion insertion is handled in OnItemChosen //if the expansion session is still active, handle tab/backtab/return/cancel if (m_exSession != null) { if (nCmdID == (uint)VSConstants.VSStd2KCmdID.BACKTAB) { m_exSession.GoToPreviousExpansionField(); return VSConstants.S_OK; } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { m_exSession.GoToNextExpansionField(0); //false to support cycling through all the fields return VSConstants.S_OK; } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.CANCEL) { if (m_exSession.EndCurrentExpansion(0) == VSConstants.S_OK) { m_exSession = null; return VSConstants.S_OK; } } }
Чтобы вставить фрагмент кода, когда пользователь вводит соответствующий ярлык, а затем нажмите клавишу TAB, добавить код в метод Exec. Закрытый метод, который представляет фрагмент будет отображаться на более позднем шаге. Добавьте следующий код после кода навигации, созданного на предыдущем шаге.
'neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut If m_session Is Nothing AndAlso m_exSession Is Nothing AndAlso nCmdID = CUInt(VSConstants.VSStd2KCmdID.TAB) Then 'get the word that was just added Dim pos As CaretPosition = m_textView.Caret.Position Dim word As TextExtent = m_provider.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1) Dim textString As String = word.Span.GetText() 'if it is a code snippet, insert it, otherwise carry on If InsertAnyExpansion(textString, Nothing, Nothing) Then Return VSConstants.S_OK End If End If
//neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut if (m_session == null && m_exSession == null && nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { //get the word that was just added CaretPosition pos = m_textView.Caret.Position; TextExtent word = m_provider.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1); //use the position 1 space back string textString = word.Span.GetText(); //the word that was just added //if it is a code snippet, insert it, otherwise carry on if (InsertAnyExpansion(textString, null, null)) return VSConstants.S_OK; }
Реализуйте методы интерфейса IVsExpansionClient. В данной реализации EndExpansion только методы, представляющие интерес, а OnItemChosen. Другие методы должны просто возвращать [F:Microsoft.VisualStudio.VSConstants.S_ОК].
Public Function EndExpansion() As Integer Implements IVsExpansionClient.EndExpansion m_exSession = Nothing Return VSConstants.S_OK End Function Public Function FormatSpan(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan()) As Integer Implements IVsExpansionClient.FormatSpan Return VSConstants.S_OK End Function Public Function GetExpansionFunction(ByVal xmlFunctionNode As IXMLDOMNode, ByVal bstrFieldName As String, ByRef pFunc As IVsExpansionFunction) As Integer Implements IVsExpansionClient.GetExpansionFunction pFunc = Nothing Return VSConstants.S_OK End Function Public Function IsValidKind(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan(), ByVal bstrKind As String, ByRef pfIsValidKind As Integer) As Integer Implements IVsExpansionClient.IsValidKind pfIsValidKind = 1 Return VSConstants.S_OK End Function Public Function IsValidType(ByVal pBuffer As IVsTextLines, ByVal ts() As TextSpan, ByVal rgTypes() As String, ByVal iCountTypes As Integer, ByRef pfIsValidType As Integer) As Integer Implements IVsExpansionClient.IsValidType pfIsValidType = 1 Return VSConstants.S_OK End Function Public Function OnAfterInsertion(ByVal pSession As IVsExpansionSession) As Integer Implements IVsExpansionClient.OnAfterInsertion Return VSConstants.S_OK End Function Public Function OnBeforeInsertion(ByVal pSession As IVsExpansionSession) As Integer Implements IVsExpansionClient.OnBeforeInsertion Return VSConstants.S_OK End Function Public Function PositionCaretForEditing(ByVal pBuffer As IVsTextLines, ByVal ts As TextSpan()) As Integer Implements IVsExpansionClient.PositionCaretForEditing Return VSConstants.S_OK End Function
public int EndExpansion() { m_exSession = null; return VSConstants.S_OK; } public int FormatSpan(IVsTextLines pBuffer, TextSpan[] ts) { return VSConstants.S_OK; } public int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bstrFieldName, out IVsExpansionFunction pFunc) { pFunc = null; return VSConstants.S_OK; } public int IsValidKind(IVsTextLines pBuffer, TextSpan[] ts, string bstrKind, out int pfIsValidKind) { pfIsValidKind = 1; return VSConstants.S_OK; } public int IsValidType(IVsTextLines pBuffer, TextSpan[] ts, string[] rgTypes, int iCountTypes, out int pfIsValidType) { pfIsValidType = 1; return VSConstants.S_OK; } public int OnAfterInsertion(IVsExpansionSession pSession) { return VSConstants.S_OK; } public int OnBeforeInsertion(IVsExpansionSession pSession) { return VSConstants.S_OK; } public int PositionCaretForEditing(IVsTextLines pBuffer, TextSpan[] ts) { return VSConstants.S_OK; }
Реализуйте метод OnItemChosen. Вспомогательный метод, который фактически будет предусматриван вставки расширений в последующем шаге. TextSpan предоставляет сведения о линии и столбца, которые можно получить из IVsTextView.
Public Function OnItemChosen(ByVal pszTitle As String, ByVal pszPath As String) As Integer Implements IVsExpansionClient.OnItemChosen InsertAnyExpansion(Nothing, pszTitle, pszPath) Return VSConstants.S_OK End Function
public int OnItemChosen(string pszTitle, string pszPath) { InsertAnyExpansion(null, pszTitle, pszPath); return VSConstants.S_OK; }
Закрытый метод вставляет следующий фрагмент кода, основанный на ярлыке или либо на заголовке и пути. Затем он вызывает метод InsertNamedExpansion с фрагментом.
Private Function InsertAnyExpansion(ByVal shortcut As String, ByVal title As String, ByVal path As String) As Boolean Dim endColumn As Integer, startLine As Integer 'get the column number from the IVsTextView, not the ITextView m_vsTextView.GetCaretPos(startLine, endColumn) Dim addSpan As New TextSpan() addSpan.iStartIndex = endColumn addSpan.iEndIndex = endColumn addSpan.iStartLine = startLine addSpan.iEndLine = startLine 'get the expansion from the shortcut If shortcut IsNot Nothing Then 'reset the TextSpan to the width of the shortcut, because we're going to replace the shortcut with the expansion addSpan.iStartIndex = addSpan.iEndIndex - shortcut.Length m_exManager.GetExpansionByShortcut( Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), shortcut, m_vsTextView, New TextSpan() {addSpan}, 0, path, title) End If If title IsNot Nothing AndAlso path IsNot Nothing Then Dim textLines As IVsTextLines = Nothing m_vsTextView.GetBuffer(textLines) Dim bufferExpansion As IVsExpansion = DirectCast(textLines, IVsExpansion) If bufferExpansion IsNot Nothing Then Dim hr As Integer = bufferExpansion.InsertNamedExpansion( title, path, addSpan, Me, New Guid(SnippetUtilities.LanguageServiceGuidStr), 0, m_exSession) If VSConstants.S_OK = hr Then Return True End If End If End If Return False End Function
private bool InsertAnyExpansion(string shortcut, string title, string path) { //first get the location of the caret, and set up a TextSpan int endColumn, startLine; //get the column number from the IVsTextView, not the ITextView m_vsTextView.GetCaretPos(out startLine, out endColumn); TextSpan addSpan = new TextSpan(); addSpan.iStartIndex = endColumn; addSpan.iEndIndex = endColumn; addSpan.iStartLine = startLine; addSpan.iEndLine = startLine; if (shortcut != null) //get the expansion from the shortcut { //reset the TextSpan to the width of the shortcut, //because we're going to replace the shortcut with the expansion addSpan.iStartIndex = addSpan.iEndIndex - shortcut.Length; m_exManager.GetExpansionByShortcut( this, new Guid(SnippetUtilities.LanguageServiceGuidStr), shortcut, m_vsTextView, new TextSpan[] { addSpan }, 0, out path, out title); } if (title != null && path != null) { IVsTextLines textLines; m_vsTextView.GetBuffer(out textLines); IVsExpansion bufferExpansion = (IVsExpansion)textLines; if (bufferExpansion != null) { int hr = bufferExpansion.InsertNamedExpansion( title, path, addSpan, this, new Guid(SnippetUtilities.LanguageServiceGuidStr), 0, out m_exSession); if (VSConstants.S_OK == hr) { return true; } } } return false; }
Построение и тестирование расширения фрагмента кода
Можно проверить, работает ли расширение фрагмента в проекте.
Построение и расширение фрагмента кода теста
Выполните построение решения. Если запустить этот проект в отладчике, второй экземпляр Visual Studio создается.
Откройте текстовый файл и введите текст.
Щелкните правой кнопкой мыши где-то в текст и выберите пункт Вставить фрагмент.
Пользовательский интерфейс выбора фрагмента должен присутствовать и показаться строка замены «поля». Дважды щелкните эту строку.
Следующий фрагмент должен быть вставлен.
MessageBox.Show("first"); MessageBox.Show("second");
Не нажимайте клавишу ВВОД или ESC.
Нажмите клавишу TAB, SHIFT+TAB для переключения между «first» и «далее».
Примите insert, нажав клавиши или ВВОД или ESC.
В другую часть текста, введите «тест» и нажмите клавишу TAB. Поскольку «тест» ярлык код-фрагмента фрагмент должен быть вставлен попытку.