How to style the text of a collapsed outline region?


I’m working on a Visual Studio 2022 C# extension to customize the text of C++ #pragma region #pragma endregion

enter image description here

1: default, 2: modified using the code below, 3: collapsed

I would like to ask how i could customize the text show when the block is collapsed and how to remove that outline border around it.

What i’m trying to achieve is to make it show just // REGION when collapsed:

enter image description here

And if possible to customize the text when its at the "collapsed state", i.e another font color, size, etc.

using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Tagging;
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows.Media;

namespace Extension;



internal class PragmaRegion : ITagger<ClassificationTag>
{
    private IClassificationType _regionClassificationType      = null;
    private IClassificationType _transparentClassificationType = null;

    internal PragmaRegion(ITextBuffer buffer,
                          IClassificationTypeRegistryService classificationTypeRegistry)
    {
        _regionClassificationType      = classificationTypeRegistry.GetClassificationType("region");
        _transparentClassificationType = classificationTypeRegistry.GetClassificationType("transparent");
    }



    public event EventHandler<SnapshotSpanEventArgs> TagsChanged;



    private static bool isPragmaRegion(string lineText, out int i)
    {
        for (i = 0; i < lineText.Length; i++)
        {
            char textAt = lineText[i];
            if (textAt == '#') // Search for \s*#p
            {
                if (i + 1 < lineText.Length && lineText[i + 1] == 'p')
                    return true;
                return false;
            }
            if (textAt != ' ' && textAt != '\t')
                return false;
        }
        i = -1;
        return false;
    }

    private static int _minLength = 14; // Length of the text "#pragma region"

    IEnumerable<ITagSpan<ClassificationTag>> ITagger<ClassificationTag>.GetTags(NormalizedSnapshotSpanCollection spans)
    {
        if (spans.Count == 0)
            yield break;

        foreach (var currentSpan in spans)
        {
            foreach (var line in currentSpan.Snapshot.Lines)
            {
                var lineText = line.GetText();
                if (lineText.Length < _minLength || !isPragmaRegion(lineText, out int regionIndex))
                    continue;

                // Starting from regionIndex, look for "#pragma region" or "#pragma endregion"
                string pragmaText = lineText.Substring(regionIndex);
                if (pragmaText.Length < _minLength)
                    continue;

                // Check if its #pragma region (14) or #pragma endregion (17)
                int pragmaLength     = pragmaText[8] == 'r' ? _minLength : 17;
                int displayNameIndex = regionIndex + pragmaLength;

                // Create tag for the pragma directive
                yield return new TagSpan<ClassificationTag>(
                    new SnapshotSpan(line.Start + regionIndex, pragmaLength),
                    new ClassificationTag(_transparentClassificationType));

                // Create tag for the display name (if any)
                if (displayNameIndex >= 0 && displayNameIndex < lineText.Length)
                {
                    string displayName = lineText.Substring(displayNameIndex);
                    if (!string.IsNullOrWhiteSpace(displayName))
                    {
                        yield return new TagSpan<ClassificationTag>(
                            new SnapshotSpan(line.Start + displayNameIndex, displayName.Length),
                            new ClassificationTag(_regionClassificationType));
                    }
                }
            }
        }
    }
}



// https://github.com/smhoff/regionsareevil

internal sealed class ClassifierProvider
{
    [Export]
    [Name("transparent")]
    internal static ClassificationTypeDefinition TransparentDefinition;

    [Export]
    [Name("region")]
    internal static ClassificationTypeDefinition RegionDefinition;
}



[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "transparent")]
[Name("Transparent")]
[DisplayName("Transparent")]
[UserVisible(true)]
[Order(After = "Default Priority", Before = "High Priority")]
internal sealed class TransparentClassification : ClassificationFormatDefinition
{
    public TransparentClassification()
    {
        FontRenderingSize = 0.1;
    }
}



[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = "region")]
[Name("Region")]
[DisplayName("Region")]
[UserVisible(true)]
[Order(After = "Default Priority", Before = "High Priority")]
internal sealed class RegionClassification : ClassificationFormatDefinition
{
    public RegionClassification()
    {
        ForegroundColor = Color.FromArgb(255, 71, 165, 10);
        FontRenderingSize = 10;
        //ForegroundOpacity = 0.5;
    }
}



[Export(typeof(ITaggerProvider))]
[ContentType("C/C++")]
[TagType(typeof(ClassificationTag))]
internal class TaggerProvider : ITaggerProvider
{
    [Import]
    internal IClassificationTypeRegistryService _classificationTypeRegistry = null;

    public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
    {
        if (buffer == null)
            return null;

        return buffer.Properties.GetOrCreateSingletonProperty(
            () => new PragmaRegion(buffer, _classificationTypeRegistry)) as ITagger<T>;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *