gpt4 book ai didi

c# - VSIX IClassifier 分配多个 ClassificationTypes

转载 作者:行者123 更新时间:2023-11-30 20:20:02 24 4
gpt4 key购买 nike

使用标准模板,我设法制作了一个自定义荧光笔,它将所有出现的字符串“Archive??????Key”(其中 ???? 是变量名称中允许的任何字符集合)变成粉红色。然而,我真正想要的是“存档”和“关键”部分变成粉红色,而“????”部分变成栗色。据我了解 VSIX 荧光笔(我真的不了解)这意味着定义两个 ClassificationFormatDefinition,但每次尝试都会破坏项目。

我的 GetClassificationSpans 方法(这是与标准模板的唯一显着差异)如下所示:

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

string text = span.GetText();
int idx0 = 0;
int idx1;

while (true)
{
idx0 = text.IndexOf(keyPrefix, idx0);
if (idx0 < 0)
break;

idx1 = text.IndexOf(keySuffix, idx0 + 6);
if (idx1 < 0)
break;

// TODO: make sure the prefix and suffix are part of the same object identifier.
string name = text.Substring(idx0 + lengthPrefix, idx1 - idx0 - lengthPrefix);
string full = text.Substring(idx0, idx1 - idx0 + keySuffix.Length);

SnapshotSpan span0 = new SnapshotSpan(span.Start + idx0, idx1 - idx0 + lengthSuffix);
SnapshotSpan span1 = new SnapshotSpan(span.Start + idx0 + lengthPrefix, idx1 - idx0 - lengthPrefix);
SnapshotSpan span2 = new SnapshotSpan(span.Start + idx1, lengthSuffix);

spans.Add(new ClassificationSpan(span0, classificationType));
spans.Add(new ClassificationSpan(span1, classificationType)); // I'd like to assign a different IClassificationType to this span.
spans.Add(new ClassificationSpan(span2, classificationType));
idx0 = idx1 + 5;
}
return spans;
}

span1 是我要分配不同样式的地方。我不明白执行这一(!)事情所需的分类器、格式、提供者和定义类如何相互关联,以及哪些可以了解多种样式。

最佳答案

模板很适合入门,但通常一旦您知道自己的前进方向,更直接地重新实现所有内容会更简单。

以下是所有部分如何组合在一起:

  • 分类器(实际上是 IClassificationTag 标记器)根据需要为文本缓冲区的给定部分生成分类标记跨度。
  • Classification tag-spans 由缓冲区中应用标签的范围和分类标签本身组成。分类标签只是指定要应用的分类类型。
  • 分类类型用于将该分类的标签与给定格式相关联。
  • 格式(特别是 ClassificationFormatDefinitions)通过 MEF(作为 EditorFormatDefinitions)导出,以便 VS 可以发现它们并将它们用于具有关联分类的颜色范围类型。它们还(可选)出现在“字体和颜色”选项中。
  • 分类器提供程序通过 MEF 导出,以便 VS 发现它;它为 VS 提供了一种为每个打开的缓冲区实例化分类器的方法(从而发现其中的标签)。

因此,您需要的是定义和导出分别与两种分类类型关联的两种分类格式定义的代码。然后你的分类器需要相应地产生两种类型的标签。这是一个示例(未经测试):

public static class Classifications
{
// These are the strings that will be used to form the classification types
// and bind those types to formats
public const string ArchiveKey = "MyProject/ArchiveKey";
public const string ArchiveKeyVar = "MyProject/ArchiveKeyVar";

// These MEF exports define the types themselves
[Export]
[Name(ArchiveKey)]
private static ClassificationTypeDefinition ArchiveKeyType = null;

[Export]
[Name(ArchiveKeyVar)]
private static ClassificationTypeDefinition ArchiveKeyVarType = null;

// These are the format definitions that specify how things will look
[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = ArchiveKey)]
[UserVisible(true)] // Controls whether it appears in Fonts & Colors options for user configuration
[Name(ArchiveKey)] // This could be anything but I like to reuse the classification type name
[Order(After = Priority.Default, Before = Priority.High)] // Optionally include this attribute if your classification should
// take precedence over some of the builtin ones like keywords
public sealed class ArchiveKeyFormatDefinition : ClassificationFormatDefinition
{
public ArchiveKeyFormatDefinition()
{
ForegroundColor = Color.FromRgb(0xFF, 0x69, 0xB4); // pink!
DisplayName = "This will display in Fonts & Colors";
}
}

[Export(typeof(EditorFormatDefinition))]
[ClassificationType(ClassificationTypeNames = ArchiveKeyVar)]
[UserVisible(true)]
[Name(ArchiveKeyVar)]
[Order(After = Priority.Default, Before = Priority.High)]
public sealed class ArchiveKeyVarFormatDefinition : ClassificationFormatDefinition
{
public ArchiveKeyVarFormatDefinition()
{
ForegroundColor = Color.FromRgb(0xB0, 0x30, 0x60); // maroon
DisplayName = "This too will display in Fonts & Colors";
}
}
}

提供商:

[Export(typeof(ITaggerProvider))]
[ContentType("text")] // or whatever content type your tagger applies to
[TagType(typeof(ClassificationTag))]
public class ArchiveKeyClassifierProvider : ITaggerProvider
{
[Import]
public IClassificationTypeRegistryService ClassificationTypeRegistry { get; set; }

public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
return buffer.Properties.GetOrCreateSingletonProperty(() =>
new ArchiveKeyClassifier(buffer, ClassificationTypeRegistry)) as ITagger<T>;
}
}

最后,标注器本身:

public class ArchiveKeyClassifier : ITagger<ClassificationTag>
{
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;

private Dictionary<string, ClassificationTag> _tags;

public ArchiveKeyClassifier(ITextBuffer subjectBuffer, IClassificationTypeRegistryService classificationRegistry)
{
// Build the tags that correspond to each of the possible classifications
_tags = new Dictionary<string, ClassificationTag> {
{ Classifications.ArchiveKey, BuildTag(classificationRegistry, Classifications.ArchiveKey) },
{ Classifications.ArchiveKeyVar, BuildTag(classificationRegistry, Classifications.ArchiveKeyVar) }
};
}

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

foreach (var span in spans) {
if (span.IsEmpty)
continue;

foreach (var identSpan in LexIdentifiers(span)) {
var ident = identSpan.GetText();
if (!ident.StartsWith("Archive") || !ident.EndsWith("Key"))
continue;

var varSpan = new SnapshotSpan(
identSpan.Start + "Archive".Length,
identSpan.End - "Key".Length);

yield return new TagSpan<ClassificationTag>(new SnapshotSpan(identSpan.Start, varSpan.Start), _tags[Classifications.ArchiveKey]);
yield return new TagSpan<ClassificationTag>(varSpan, _tags[Classifications.ArchiveKeyVar]);
yield return new TagSpan<ClassificationTag>(new SnapshotSpan(varSpan.End, identSpan.End), _tags[Classifications.ArchiveKey]);
}
}
}

private static IEnumerable<SnapshotSpan> LexIdentifiers(SnapshotSpan span)
{
// Tokenize the string into identifiers and numbers, returning only the identifiers
var s = span.GetText();
for (int i = 0; i < s.Length; ) {
if (char.IsLetter(s[i])) {
var start = i;
for (++i; i < s.Length && IsTokenChar(s[i]); ++i);
yield return new SnapshotSpan(span.Start + start, i - start);
continue;
}
if (char.IsDigit(s[i])) {
for (++i; i < s.Length && IsTokenChar(s[i]); ++i);
continue;
}
++i;
}
}

private static bool IsTokenChar(char c)
{
return char.IsLetterOrDigit(c) || c == '_';
}

private static ClassificationTag BuildTag(IClassificationTypeRegistryService classificationRegistry, string typeName)
{
return new ClassificationTag(classificationRegistry.GetClassificationType(typeName));
}
}

还有一点要注意:为了加速启动,VS保留了一个MEF导出的缓存。但是,这个缓存通常没有在应该失效的时候失效。此外,如果您更改现有分类格式定义的默认颜色,您的更改很可能不会被拾取,因为 VS 将以前的值保存在注册表中。为了减轻这种情况,最好在编译之间运行批处理脚本,以便在任何与 MEF 或格式相关的更改以清除内容时运行。下面是 VS2013 和 Exp 根后缀的示例(测试 VSIXes 时默认使用):

@echo off

del "%LOCALAPPDATA%\Microsoft\VisualStudio\12.0Exp\ComponentModelCache\Microsoft.VisualStudio.Default.cache" 2> nul
rmdir /S /Q "%LOCALAPPDATA%\Microsoft\VisualStudio\12.0Exp\ComponentModelCache" 2> nul

reg delete HKCU\Software\Microsoft\VisualStudio\12.0Exp\FontAndColors\Cache\{75A05685-00A8-4DED-BAE5-E7A50BFA929A} /f

关于c# - VSIX IClassifier 分配多个 ClassificationTypes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37579509/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com