У меня был точно такой же вопрос, и теперь я несколько часов просматриваю Интернет, пока не смог понять и объяснить, как вам нужно начинать с таким расширением.
В моем следующем примере мы будемсоздайте маленькое и немое расширение, которое всегда будет добавлять «Hello» в начало файла кода, когда будет выполнено редактирование.Это очень простой способ, но он должен дать вам представление о том, как продолжить разработку.
Имейте в виду: вы должны полностью разобрать файлы кода - Visual Studio не дает вам никакой информации о том, где классы, методыили что там есть и что они содержат.Это самое большое препятствие, которое необходимо принять при работе с инструментом форматирования кода, и оно не будет рассмотрено в этом ответе. [*]
Для тех, кто пропустил этот ответ, убедитесь, что вы сначала загрузили и установили Visual Studio SDKили вы не найдете тип проекта, упомянутый в первом шаге.
Создание проекта
Начните с создания нового проекта типа "Visual C #> Расширяемость> Проект VSIX "(отображается только в том случае, если в качестве целевой платформы выбран .NET Framework 4). Обратите внимание, что вам может потребоваться выбрать тип проекта «Редактор классификатора» вместо типа «Проект VSIX», чтобы он работал, s.комментарий ниже.
После того, как проект будет создан, откроется файл «source.extension.vsixmanifest», который даст вам возможность указать название продукта, автора,версия, описание, значок и так далее.Я думаю, что этот шаг довольно понятен, вы можете закрыть вкладку сейчас и восстановить ее позже, открыв файл vsixmanifest.
Создание класса слушателя для получения уведомлений о текстеСоздание экземпляра редактора
Далее нам нужно прослушивать всякий раз, когда в Visual Studio был создан текстовый редактор, и связывать с ним наш инструмент форматирования кода.Текстовый редактор в VS2010 является экземпляром IWpfTextView
.
Добавьте новый класс в наш проект и назовите его TextViewCreationListener
.Этот класс должен реализовывать интерфейс Microsoft.VisualStudio.Text.Editor.IWpfTextViewCreationListener
.Вам нужно добавить ссылку на Microsoft.VisualStudio.Text.UI.Wpf в ваш проект.DLL-библиотека сборки находится в каталоге Visual Studio SDK в VisualStudioIntegration \ Common \ Assemblies \ v4.0 .
Необходимо реализовать метод TextViewCreated
интерфейс.Этот метод имеет параметр, указывающий экземпляр текстового редактора, который был создан.Мы создадим новый класс форматирования кода, которому этот экземпляр будет передан позже.
Нам нужно сделать класс TextViewCreationListener
видимым для Visual Studio, указав атрибут [Export(typeof(IWpfTextViewCreationListener))]
.Добавьте ссылку на System.ComponentModel.Composition в свой проект для атрибута Export
.
Кроме того, нам необходимо указать, с какими типами файлов кодФорматер должен быть привязан к текстовому редактору.Нам нравится форматировать только файлы кода, а не текстовые файлы, поэтому мы добавляем атрибут [ContentType("code")]
в класс слушателя.Для этого вы должны добавить ссылку на Microsoft.VisualStudio.CoreUtility в ваш проект.
Кроме того, мы хотим изменить только редактируемый код, а не цвета илиукрашения вокруг него (как видно из примеров проектов), поэтому мы добавляем атрибут [TextViewRole(PredefinedTextViewRoles.Editable)]
в класс.Опять же, вам нужна новая ссылка, на этот раз Microsoft.VisualStudio.Text.UI .
Пометить класс как внутренний запечатанный.По крайней мере, это моя рекомендация.Теперь ваш класс должен выглядеть примерно так:
[ContentType("code")]
[Export(typeof(IWpfTextViewCreationListener))]
[TextViewRole(PredefinedTextViewRoles.Editable)]
internal sealed class TextViewCreationListener : IWpfTextViewCreationListener
{
public void TextViewCreated(IWpfTextView textView)
{
}
}
Создание класса для форматирования кода
Далее нам нужен класс, обрабатывающийлогика форматирования кода, методы сортировки и так далее.Опять же, в этом примере он будет просто добавлять «Hello» в начало файла всякий раз, когда будет выполнено редактирование.
Добавить новый класс с именем Formatter
в ваш проект.
Добавить конструктор, который принимает один IWpfTextView
аргумент. Помните, что мы хотели передать созданный экземпляр редактора этому классу форматирования в методе TextViewCreated
нашего класса слушателя (просто добавьте new Formatter(textView);
в метод там).
Сохранить переданный экземпляр в переменной-члене. Это станет удобным при последующем форматировании кода (например, для получения позиции каретки). Также свяжите события Changed
и PostChanged
свойства TextBuffer
экземпляра редактора:
public Formatter(IWpfTextView view)
{
_view = view;
_view.TextBuffer.Changed += new EventHandler<TextContentChangedEventArgs>(TextBuffer_Changed);
_view.TextBuffer.PostChanged += new EventHandler(TextBuffer_PostChanged);
}
Событие Changed
вызывается каждый раз, когда выполняется редактирование (например, ввод символа, вставка кода или программные изменения). Поскольку он также реагирует на программные изменения, я использую bool, определяющий, изменяет ли наше расширение или пользователь / что-либо еще код в данный момент, и вызываю мой пользовательский метод FormatCode()
, только если наше расширение еще не редактируется. В противном случае вы будете рекурсивно вызывать этот метод, что приведет к сбою Visual Studio:
private void TextBuffer_Changed(object sender, TextContentChangedEventArgs e)
{
if (!_isChangingText)
{
_isChangingText = true;
FormatCode(e);
}
}
Мы должны сбросить эту переменную члена bool в обработчике событий PostChanged
снова на false
.
Давайте передадим аргументы события Changed
нашему пользовательскому методу FormatCode
, потому что они содержат то, что изменилось между последним редактированием и сейчас. Эти правки хранятся в массиве e.Changes
типа INormalizedTextChangeCollection
(см. Ссылку в конце моего поста для получения дополнительной информации об этом типе). Мы перебираем все эти правки и вызываем наш пользовательский метод HandleChange
с новым текстом, созданным этим редактором.
private void FormatCode(TextContentChangedEventArgs e)
{
if (e.Changes != null)
{
for (int i = 0; i < e.Changes.Count; i++)
{
HandleChange(e.Changes[0].NewText);
}
}
}
В методе HandleChange
мы могли бы на самом деле сканировать ключевые слова, чтобы обрабатывать их определенным образом (помните, что вы должны анализировать любой код на себе!) - но здесь мы просто тупо добавляем «Hello» к запуск файла для тестирования. Например. мы должны изменить TextBuffer
нашего экземпляра редактора. Для этого нам нужно создать объект ITextEdit
, с помощью которого мы можем манипулировать текстом и впоследствии применять его изменения. Код довольно понятен:
private void HandleChange(string newText)
{
ITextEdit edit = _view.TextBuffer.CreateEdit();
edit.Insert(0, "Hello");
edit.Apply();
}
При компиляции этой надстройки экспериментальный куст Visual Studio запускается только с загруженным нашим расширением. Создайте новый файл C # и начните вводить, чтобы увидеть результаты.
Я надеюсь, что это даст вам некоторые идеи, как продолжить эту тему. Я должен сам исследовать это сейчас.
Я настоятельно рекомендую документацию текстовой модели редактора в MSDN, чтобы получить подсказки о том, как вы можете сделать то и это.
http://msdn.microsoft.com/en-us/library/dd885240.aspx#textmodel
Сноска
[*] Обратите внимание, что Visual Studio 2015 или новее поставляется с платформой компилятора Rosyln, которая действительно уже анализирует файлы C # и VB.NET для вас (и, возможно, других предустановленных языков тоже) и предоставляет их иерархическую синтаксическую структуру, но Я еще не эксперт в этой теме, чтобы дать ответ о том, как пользоваться этими новыми услугами. Основной прогресс запуска расширения редактора остается таким же, как описано в этом ответе в любом случае. Имейте в виду, что - если вы используете эти службы - вы станете зависимыми от Visual Studio 2015+, и расширение не будет работать в более ранних версиях.