VS2010 – робимо свою підсвічування синтаксису, Різне, Програмування, статті

Поставив у себе VS2010 RC1. На вінчестері сім гигов займає, однако.

Подивився як робляться Аддони і зокрема розмальовка синтаксису. Читав я про це ще рік тому, а тут в зв’язку з виходом RC вирішив випробувати в справі.

Для прикладу вирішив зробити підсвічування синтаксису для асемблера Z80.
Перші результати вдалося отримати через пару годин, ще за пару годин зробив однорядковий розбір – мітки, коментарі, оператори та псевдо-оператори:

image

У Visual Studio 10 застосовується нова модель розширень – весь код аддонов пишеться виключно на managed-коді, ніяких COM. Це дуже серйозно полегшує життя, та й на загальній стабільності системи позначається дуже позитивно.
Власне, до справи. По-перше, існує кілька способів поширення розширень студії, я використовував VSIX – найзручніше для налагодження. Має сенс поставити Microsoft Visual Studio 2010 SDK – студія доповнюється шаблонами проектів для швидкого створення розширень. Але наскільки я розумію створювати їх можна і так. З використанням VS2010 SDK новий проект для кастомний підсвічування синтаксису створюється через пункт Extensibility > Editor Classifier.

Підсвічування синтаксису визначається класом, що реалізує інтерфейс IClassifier – цей клас задає логіку розбору тексту. Для використання класифікатора потрібний провайдер – реалізує IClassifierProvider і визначальний як наш класифікатор буде використовуватися.

    [Export(typeof(IClassifierProvider))]
    [ContentType(“text”)]
    internal class Z80EditorClassifierProvider : IClassifierProvider
    {
      [Import]
      internal IClassificationTypeRegistryService ClassificationRegistry = null; // Set via MEF

      public IClassifier GetClassifier(ITextBuffer buffer)
      {
        return buffer.Properties.GetOrCreateSingletonProperty<Z80EditorClassifier>(
          delegate { return new Z80EditorClassifier(ClassificationRegistry); });
      }
    }


Основний метод класифікатора – GetClassificationSpans () – для заданого фрагмента тексту функція повинна повернути список фрагментів із зазначенням типу фрагмента – класу, що реалізовує інтерфейс IClassificationType.

    class Z80EditorClassifier : IClassifier
    {

      public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
      {
        List<ClassificationSpan> result = new List<ClassificationSpan>();

        …

        return result;
      }

    }

 

При цьому з GetClassificationSpans () звичайно можна отримати доступ до разбираемому тексту – через властивість span.Snapshot. У моєму випадку мене цікавив простий синтаксис, що зводиться до розбору одного рядка.

    public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan span)
    {
      List<ClassificationSpan> result = new List<ClassificationSpan>();
      if (span.Length == 0) return result;
      
      ITextSnapshot snapshot = span.Snapshot;
      ITextSnapshotLine line = snapshot.GetLineFromPosition(span.Start.Position);
      ITextSnapshotLine endLine = snapshot.GetLineFromPosition(span.End.Position);

      while (true)
      {
        // Process current line
        ProcessLine(line, result);

        if (line.LineNumber == endLine.LineNumber)
          break;
        // Next line
        line = snapshot.GetLineFromPosition(line.EndIncludingLineBreak + 1);
      }

      return result;
    }

 

Усередині ProcessLine залишається ідентифікувати окремі фрагменти рядки і додати їх у список, вказавши для кожного тип фрагмента. Наприклад, ось так додається підсвічування для коментаря:

        IClassificationType commentClassifType = registry.GetClassificationType(“z80comment”);
        result.Add(new ClassificationSpan(
          new SnapshotSpan(line.Snapshot, new Span(line.Start + commentPos, commentLength)),
          commentClassifType));

 

Типи фрагментів можна описати все відразу в одному класі:

  internal static class Z80EditorClassifierClassificationDefinition
  {
    /// <summary>
    /// Defines the “z80operator” classification type – Z80 Assembly Operator.
    /// </summary>
    [Export(typeof(ClassificationTypeDefinition))]
    [Name(“z80operator”)]
    internal static ClassificationTypeDefinition Z80OperatorDefinition = null;

    /// <summary>
    /// Defines the “z80comment” classification type – Z80 Assembly Comment.
    /// </summary>
    [Export(typeof(ClassificationTypeDefinition))]
    [Name(“z80comment”)]
    internal static ClassificationTypeDefinition Z80CommentDefinition = null;
  }

 

Класифікатором може бути зіставлений форматтер – клас, породжений від ClassificationFormatDefinition і визначальний спосіб підсвічування тексту.

  [Export(typeof(EditorFormatDefinition))]
  [ClassificationType(ClassificationTypeNames = “z80operator”)]
  [Name(“z80operator”)]
  [UserVisible(true)]
  [Order(Before = Priority.Default)]
  internal sealed class Z80EditorOperatorFormat : ClassificationFormatDefinition
  {
    public Z80EditorOperatorFormat()
    {
      this.DisplayName = “Z80 Assembly Operator”;
      this.BackgroundColor = Color.FromRgb(230,255,230);
      this.ForegroundColor = Colors.Blue;
    }
  }

 

Загалом-то, для такого невеликого результату – це практично все що потрібно знати.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*