Поддержка фрагментов кода (MPF)
Фрагмент кода является частью кода, который вставляется в исходный файл. Сам фрагмент основанный на XML шаблон с набором полей. Эти поля выбраны после вставки фрагмента и может иметь разные значения в зависимости от контекста, в котором вставить фрагмент. Сразу после вставки фрагмента языковую службу может отформатировать фрагмент.
Фрагмент вставляется в специальный режим правки, позволяющий поля фрагмента, которое будет переходить с помощью клавиши tab. Поля могут поддерживать раскрывающемся меню IntelliSense-стиля. Пользователь фиксирует фрагмент к файлу источника можно ввести или ВСТАВИТЬ либо ключ ESC. Дополнительные сведения о фрагментах см. Фрагменты кода.
Управляемая поддержка .NET Framework пакета для фрагментов кода
Управляемые границы пакетов (MPF) поддерживают большинство функциональных возможностей фрагмента от считывания шаблон вставке фрагмента и включить специальный режим правки. Поддержка управляемой посредством ExpansionProvider класс.
После Source создается класс CreateExpansionProvider метод LanguageService класс называется для получения ExpansionProvider объект (примечание, base LanguageService класс всегда возвращает новую ExpansionProvider объект для каждого Source объект).
MPF не поддерживает функции расширения. Функции расширения функцию, которая внедрена в шаблоне фрагмента и возвращает одну или несколько значений, который необходимо поместить в поле. Значения возвращаются службой самой с помощью языка ExpansionFunction объект. ExpansionFunction объект должен быть реализован службой языка для поддержки функций расширения.
Предоставление поддержки для фрагментов кода
Чтобы включить поддержку для фрагментов кода, необходимо предоставить или устанавливать фрагменты и необходимо предоставить средства для пользователя ввод эти фрагменты. 3 Шага на включение поддержки для фрагментов кода:
Устанавливать файлы фрагмента.
Включение фрагменты кода для языковой службы.
Вызов ExpansionProvider объект.
Устанавливать файлы фрагментов
Все фрагменты для языка хранятся в виде шаблонов в xml-файле, обычно одном шаблоне фрагмента в файл. Дополнительные сведения о схеме XML, используемом для шаблонов фрагмента кода см. в разделе Справочник по схеме фрагментов кода. Каждый шаблон фрагмента определен с идентификатором языка Это идентификатор языка указывается в реестре и помещается в Language атрибут <код> тег в шаблоне.
Обычно 2 местах, где хранятся файлы шаблонов фрагмента. язык 1), где был устанавливается и 2) в папке пользователя. Эти расположения будут добавлены к реестру, что Visual Studio Диспетчер фрагментов кода удается найти фрагменты. Папка пользователя, в которых хранятся фрагменты, созданные пользователем.
Типичная структура папок для устанавливанных файлов шаблонов фрагмента выглядит следующим образом: [InstallRoot]\[TestLanguage]Фрагменты \ \[код языка]\ Фрагменты.
[InstallRoot] устанавливается в папку языка.
[TestLanguage] имя языка, как имя папки.
[код языка] идентификатор языкового стандарта Это называется локализованные версии фрагментов сохраняются. Например, код языка для английского 1033, [код языка] заменяет значение 1033.
Один дополнительный файл должен быть введен и обычно файл с именем индекса, SnippetsIndex.xml или ExpansionsIndex.xml (можно использовать любую допустимую конец имени файла в xml). Этот файл обычно хранится в [InstallRoot]\[TestLanguage] папка и указывает точное местоположение папки фрагментов, а также идентификатор языка и GUID языковой службы, использующей фрагменты. Точный путь к файлу индекса помещается в реестр как описано ниже в подразделе "установка записи реестра". Ниже приведен пример файла SnippetsIndex.xml:
<?xml version="1.0" encoding="utf-8" ?>
<SnippetCollection>
<Language Lang="Testlanguage" Guid="{b614a40a-80d9-4fac-a6ad-fc2868fff7cd}">
<SnippetDir>
<OnOff>On</OnOff>
<Installed>true</Installed>
<Locale>1033</Locale>
<DirPath>%InstallRoot%\TestLanguage\Snippets\%LCID%\Snippets\</DirPath>
<LocalizedName>Snippets</LocalizedName>
</SnippetDir>
</Language>
</SnippetCollection>
<Язык> тег указывает идентификатор языка ( Lang атрибут) и GUID языковой службы.
В этом примере предполагается, что отражаемого служба языка в папке установки Visual Studio. %LCID% Заменено с идентификатором языкового стандарта текущего пользователя Несколько <SnippetDir> теги можно добавить, по одному для каждого из другого каталога и языковой стандарт. Кроме того, папка фрагмента может содержать вложенные папки, каждая из которых определена в файле индекса <SnippetSubDir> тег, внедренный в a <SnippetDir> тег.
Пользователи могут также создать свои собственные фрагменты для выбранного языка. Данные обычно хранятся в папке, например параметров пользователя [TestDocs]\ Code snippets \[TestLanguage]Фрагменты кода теста, где \ [TestDocs] расположение папки параметров пользователя для Visual Studio.
Следующие элементы подстановки может быть помещен в пути, хранимые в <DirPath> тег в файле индекса.
Элемент |
Описание |
---|---|
%LCID% |
Код языка. |
%InstallRoot% |
Корневой папкой установки для Visual Studio, например, Visual Studio 8 по адресу C:\Program Files\Microsoft. |
%ProjDir% |
Папка, содержащая текущий проект. |
%ProjItem% |
Папка, содержащая элемент текущего проекта. |
%TestDocs% |
Папка в папке " параметры пользователя, например C:\Documents and Settings\[имя пользователя]\ Мои документы \ Visual Studio \ 8. |
Включение фрагменты кода службы языка
Можно включить фрагменты кода для языковой службы, добавляя ProvideLanguageCodeExpansionAttribute атрибут в VSPackage (см. Регистрация службы языка (MPF) дополнительные сведения). ShowRoots и SearchPaths параметры являются необязательными, но необходимо включить SearchPaths параметр отчета Диспетчер фрагментов кода расположения собственных фрагментов.
Далее приведен пример того, как использовать этот атрибут:
[ProvideLanguageCodeExpansion(
typeof(TestSnippetLanguageService),
"Test Snippet Language", // Name of language used as registry key
0, // Resource ID of localized name of language service
"Test Snippet Language", // Name of Language attribute in snippet template
@"%InstallRoot%\Test Snippet Language\Snippets\%LCID%\SnippetsIndex.xml", // Path to snippets index
SearchPaths = @"%InstallRoot%\Test Snippet Language\Snippets\%LCID%\")] // Path to snippets
Вызов поставщика расширения
Вызываются управления службами любого языка вставка фрагментов кода, а также способа вставки.
Вызов поставщика расширения для фрагментов кода
2 Способа вызова поставщика расширения: с помощью команд меню или с помощью ярлыка из списка завершения.
Вставка фрагментов кода с помощью команды меню
Для использования команды меню, чтобы отобразить обозреватель фрагмента, необходимо добавить команды меню, а затем вызовите DisplayExpansionBrowser метод ExpansionProvider интерфейс в ответ на эту команду меню.
Добавьте команду и кнопка к файлу .vsct. Можно найти, выполнив поэтому в инструкции Пошаговое руководство: Создание команды меню ресурсов с помощью шаблона пакета Visual Studio.
Создайте класс из ViewFilter класс, переопределяющий QueryCommandStatus метод, чтобы показать поддержку новой команды меню. Данный пример всегда включает команду меню.
using Microsoft.VisualStudio.Package; namespace TestLanguagePackage { class TestViewFilter : ViewFilter { public TestViewFilter(CodeWindowManager mgr, IVsTextView view) : base(mgr, view) { } protected override int QueryCommandStatus(ref Guid guidCmdGroup, uint nCmdId) { int hr = base.QueryCommandStatus(ref guidCmdGroup, nCmdId); // If the base class did not recognize the command then // see if we can handle the command. if (hr == (int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_UNKNOWNGROUP) { if (guidCmdGroup == GuidList.guidTestLanguagePackageCmdSet) { if (nCmdId == PkgCmdIDList.InvokeCodeSnippetsBrowser) { hr = (int)(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED); } } } return hr; } } }
Переопределите DisplayExpansionBrowser метод ViewFilter класс для получения ExpansionProvider объект и вызывает HandlePreExec метод объекта.
using Microsoft.VisualStudio.Package; namespace TestLanguagePackage { class TestViewFilter : ViewFilter { public override bool HandlePreExec(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { if (base.HandlePreExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut)) { // Base class handled the command. Do nothing more here. return true; } if (guidCmdGroup == GuidList.guidTestLanguagePackageCmdSet) { if (nCmdId == PkgCmdIDList.InvokeCodeSnippetsBrowser) { ExpansionProvider ep = this.GetExpansionProvider(); if (this.TextView != null && ep != null) { bool bDisplayed = ep.DisplayExpansionBrowser( this.TextView, "TestLanguagePackage Snippet:", null, false, null, false); } return true; // Handled the command. } } return false; // Did not handle the command. } } }
Следующие методы в ExpansionProvider класс называется Visual Studio в заданном порядке в процессе введя фрагмент.
-
После OnAfterInsertion метод вызывается был представлен фрагмент и ExpansionProvider объект в нерегламентированном режиме правки, используемом для изменения только фрагмент, куда был вставлен.
Вставка фрагментов кода с помощью ярлыка
Реализация ярлыка из списка завершения гораздо более включена, чем реализация команды меню. Сначала необходимо добавлять ярлыки фрагмента в список завершения машинного слов IntelliSense. Затем необходимо определить, когда имя ярлыка фрагмента было введено в результате завершения. Наконец, необходимо получить имя и путь фрагмента, используя имя и передавать эти сведения для ярлыков InsertNamedExpansion метод ExpansionProvider метод.
Чтобы добавлять ярлыки фрагмента до завершения машинного слова, добавьте их в списке Declarations объект находится в своем AuthoringScope класс. Необходимо убедиться, что можно указать ярлык, как имя фрагмента. Пример см. в разделе Пошаговое руководство: Получение списка установленных фрагментов кода (MPF).
Можно определить вставки фрагмента кода в ярлыков OnAutoComplete метод Declarations класс. Поскольку его имя уже было введено в исходный файл, его необходимо удалить, когда расширение. InsertNamedExpansion метод принимает диапазон, описывающий точку вставки фрагментов; если диапазон включает все его имя в исходном файле, то имя заменяется фрагментом.
Здесь версия a Declarations класс, который выполняет вставку фрагмента по заданному имени ярлыка. Другие методы Declarations класс был пропущен для наглядности. Обратите внимание, что конструктор данного класса принимает a LanguageService объект. Это может быть передан в пределах от версии AuthoringScope объект (например, реализация AuthoringScope класс может потребоваться LanguageService объект в его конструкторе и передаче его в on TestDeclarations конструктор класса).
[C#]
using Microsoft.VisualStudio.Package;
using Microsoft.VisualStudio.TextManager.Interop;
namespace TestLanguagePackage
{
internal class TestDeclarations : Declarations
{
private ArrayList declarations;
private LanguageService languageService;
private TextSpan commitSpan;
public TestDeclarations(LanguageService langService)
: base()
{
languageService = langService;
declarations = new ArrayList();
}
// This method is used to add declarations to the internal list.
public void AddDeclaration(TestDeclaration declaration)
{
declarations.Add(declaration);
}
// This method is called to get the string to commit to the source buffer.
// Note that the initial extent is only what the user has typed so far.
public override string OnCommit(IVsTextView textView,
string textSoFar,
char commitCharacter,
int index,
ref TextSpan initialExtent)
{
// We intercept this call only to get the initial extent
// of what was committed to the source buffer.
commitSpan = initialExtent;
return base.OnCommit(textView,
textSoFar,
commitCharacter,
index,
ref initialExtent);
}
// This method is called after the string has been committed to the source buffer.
public override char OnAutoComplete(IVsTextView textView,
string committedText,
char commitCharacter,
int index)
{
TestDeclaration item = declarations[index] as TestDeclaration;
if (item != null)
{
// In this example, TestDeclaration identifies types with a string.
// You can choose a different approach.
if (item.Type == "snippet")
{
Source src = languageService.GetSource(textView);
if (src != null)
{
ExpansionProvider ep = src.GetExpansionProvider();
if (ep != null)
{
string title;
string path;
int commitLength = commitSpan.iEndIndex - commitSpan.iStartIndex;
if (commitLength < committedText.Length)
{
// Replace everything that was inserted
// so calculate the span of the full
// insertion, taking into account what
// was inserted when the commitSpan
// was obtained in the first place.
commitSpan.iEndIndex += (committedText.Length - commitLength);
}
if (ep.FindExpansionByShortcut(textView,
committedText,
commitSpan,
true,
out title,
out path))
{
ep.InsertNamedExpansion(textView,
title,
path,
commitSpan,
false);
}
}
}
}
}
return '\0';
}
}
}
Когда служба языка возвращает имя ярлыка, она вызывает FindExpansionByShortcut метод получения имени файла и заголовок фрагмента кода. Служба языка затем вызывает метод InsertNamedExpansion метод ExpansionProvider класс для вставки фрагмента кода. Следующие методы, вызываемые Visual Studio в заданном порядке ExpansionProvider класс в процессе введя фрагмент.
Дополнительные сведения о получении список устанавливанных фрагментов кода для службы языка см. в разделе Пошаговое руководство: Получение списка установленных фрагментов кода (MPF).
Реализация класса ExpansionFunction
Функции расширения функцию, которая внедрена в шаблоне фрагмента и возвращает одну или несколько значений, который необходимо поместить в поле. Для поддержки функций расширения в службе языка, необходимо создать класс из ExpansionFunction класс, реализующий GetCurrentValue метод. Затем необходимо переопределить CreateExpansionFunction метод LanguageService класс, чтобы возвратить новый экземпляр данной версии ExpansionFunction класс для каждой функции расширения требуется поддержка. Если требуется поддержка список возможных значений из функции расширения, необходимо также переопределить GetIntellisenseList метод ExpansionFunction класс для получения списка этих значений.
Функции расширения, которую принимает аргументы или требуется получить доступ другие поля не должна быть связана с редактируемые поля, как поставщик расширений не может быть полностью инициализирован к моменту будет вызвана функция расширения. В результате функции расширения может не получить значение его аргументов или любого другого поля.
Пример
Ниже приведен пример того, как простая функция расширения вызвавшей GetName может быть реализовано. Эта функция расширения добавляют номер к имени базового класса каждый раз при создании функции расширения (которая соответствует связанному фрагмент кода добавляется каждый раз).
using Microsoft.VisualStudio.Package;
namespace TestLanguagePackage
{
public class TestLanguageService : LanguageService
{
private int classNameCounter = 0;
public override ExpansionFunction CreateExpansionFunction(
ExpansionProvider provider,
string functionName)
{
ExpansionFunction function = null;
if (functionName == "GetName")
{
++classNameCounter;
function = new TestGetNameExpansionFunction(provider, classNameCounter);
}
return function;
}
}
internal class TestGetNameExpansionFunction : ExpansionFunction
{
private int nameCount;
TestGetNameExpansionFunction(ExpansionProvider provider, int counter)
: base(provider)
{
nameCount = counter;
}
public override string GetCurrentValue()
{
string name = "TestClass";
name += nameCount.ToString();
return name;
}
}
}
См. также
Задачи
Пошаговое руководство: Получение списка установленных фрагментов кода (MPF)
Основные понятия
Регистрация службы языка (MPF)