Skip to content

Commit

Permalink
Add semantic highlighting for properties and events
Browse files Browse the repository at this point in the history
Also add a fallback mechanism for colors: if a color definition is empty, another one can be used instead.
  • Loading branch information
ltrzesniewski committed Feb 23, 2023
1 parent 0253b1a commit a9572d1
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 42 deletions.
109 changes: 67 additions & 42 deletions ILSpy/Languages/CSharpHighlightingTokenWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,12 @@ class CSharpHighlightingTokenWriter : DecoratingTokenWriter

HighlightingColor methodCallColor;
HighlightingColor methodDeclarationColor;

HighlightingColor fieldDeclarationColor;
HighlightingColor fieldAccessColor;
HighlightingColor propertyDeclarationColor;
HighlightingColor propertyAccessColor;
HighlightingColor eventDeclarationColor;
HighlightingColor eventAccessColor;

HighlightingColor valueKeywordColor;
HighlightingColor thisKeywordColor;
Expand All @@ -74,39 +77,49 @@ public CSharpHighlightingTokenWriter(TokenWriter decoratedWriter, ISmartTextOutp
this.locatable = locatable;
this.textOutput = textOutput;

this.visibilityKeywordsColor = highlighting.GetNamedColor("Visibility");
this.namespaceKeywordsColor = highlighting.GetNamedColor("NamespaceKeywords");
this.structureKeywordsColor = highlighting.GetNamedColor("Keywords");
this.gotoKeywordsColor = highlighting.GetNamedColor("GotoKeywords");
this.queryKeywordsColor = highlighting.GetNamedColor("QueryKeywords");
this.exceptionKeywordsColor = highlighting.GetNamedColor("ExceptionKeywords");
this.checkedKeywordColor = highlighting.GetNamedColor("CheckedKeyword");
this.unsafeKeywordsColor = highlighting.GetNamedColor("UnsafeKeywords");
this.valueTypeKeywordsColor = highlighting.GetNamedColor("ValueTypeKeywords");
this.referenceTypeKeywordsColor = highlighting.GetNamedColor("ReferenceTypeKeywords");
this.operatorKeywordsColor = highlighting.GetNamedColor("OperatorKeywords");
this.parameterModifierColor = highlighting.GetNamedColor("ParameterModifiers");
this.modifiersColor = highlighting.GetNamedColor("Modifiers");
this.accessorKeywordsColor = highlighting.GetNamedColor("GetSetAddRemove");
this.visibilityKeywordsColor = GetColor("Visibility") ?? GetColor("Keywords");
this.namespaceKeywordsColor = GetColor("NamespaceKeywords") ?? GetColor("Keywords");
this.structureKeywordsColor = GetColor("Keywords");
this.gotoKeywordsColor = GetColor("GotoKeywords") ?? GetColor("Keywords");
this.queryKeywordsColor = GetColor("QueryKeywords") ?? GetColor("Keywords");
this.exceptionKeywordsColor = GetColor("ExceptionKeywords") ?? GetColor("Keywords");
this.checkedKeywordColor = GetColor("CheckedKeyword") ?? GetColor("Keywords");
this.unsafeKeywordsColor = GetColor("UnsafeKeywords") ?? GetColor("Keywords");
this.valueTypeKeywordsColor = GetColor("ValueTypeKeywords") ?? GetColor("Keywords");
this.referenceTypeKeywordsColor = GetColor("ReferenceTypeKeywords") ?? GetColor("Keywords");
this.operatorKeywordsColor = GetColor("OperatorKeywords") ?? GetColor("Keywords");
this.parameterModifierColor = GetColor("ParameterModifiers") ?? GetColor("Keywords");
this.modifiersColor = GetColor("Modifiers") ?? GetColor("Keywords");
this.accessorKeywordsColor = GetColor("GetSetAddRemove") ?? GetColor("Keywords");

this.referenceTypeColor = highlighting.GetNamedColor("ReferenceTypes");
this.valueTypeColor = highlighting.GetNamedColor("ValueTypes");
this.interfaceTypeColor = highlighting.GetNamedColor("InterfaceTypes");
this.enumerationTypeColor = highlighting.GetNamedColor("EnumTypes");
this.typeParameterTypeColor = highlighting.GetNamedColor("TypeParameters");
this.delegateTypeColor = highlighting.GetNamedColor("DelegateTypes");
this.methodDeclarationColor = this.methodCallColor = highlighting.GetNamedColor("MethodCall");
//this.eventDeclarationColor = this.eventAccessColor = defaultTextColor;
//this.propertyDeclarationColor = this.propertyAccessColor = defaultTextColor;
this.fieldDeclarationColor = this.fieldAccessColor = highlighting.GetNamedColor("FieldAccess");
this.referenceTypeColor = GetColor("ReferenceTypes") ?? GetColor("Types");
this.valueTypeColor = GetColor("ValueTypes") ?? GetColor("Types");
this.interfaceTypeColor = GetColor("InterfaceTypes") ?? GetColor("Types");
this.enumerationTypeColor = GetColor("EnumTypes") ?? GetColor("Types");
this.typeParameterTypeColor = GetColor("TypeParameters") ?? GetColor("Types");
this.delegateTypeColor = GetColor("DelegateTypes") ?? GetColor("Types");
this.methodDeclarationColor = GetColor("MethodDeclaration") ?? GetColor("MethodCall");
this.methodCallColor = GetColor("MethodCall") ?? GetColor("MethodDeclaration");
this.fieldDeclarationColor = GetColor("FieldDeclaration") ?? GetColor("FieldAccess");
this.fieldAccessColor = GetColor("FieldAccess") ?? GetColor("FieldDeclaration");
this.propertyDeclarationColor = GetColor("PropertyDeclaration") ?? GetColor("PropertyAccess");
this.propertyAccessColor = GetColor("PropertyAccess") ?? GetColor("PropertyDeclaration");
this.eventDeclarationColor = GetColor("EventDeclaration") ?? GetColor("EventAccess");
this.eventAccessColor = GetColor("EventAccess") ?? GetColor("EventDeclaration");
//this.variableDeclarationColor = this.variableAccessColor = defaultTextColor;
//this.parameterDeclarationColor = this.parameterAccessColor = defaultTextColor;
this.valueKeywordColor = highlighting.GetNamedColor("NullOrValueKeywords");
this.thisKeywordColor = highlighting.GetNamedColor("ThisOrBaseReference");
this.trueKeywordColor = highlighting.GetNamedColor("TrueFalse");
this.typeKeywordsColor = highlighting.GetNamedColor("TypeKeywords");
this.attributeKeywordsColor = highlighting.GetNamedColor("AttributeKeywords");
this.valueKeywordColor = GetColor("NullOrValueKeywords") ?? GetColor("Keywords");
this.thisKeywordColor = GetColor("ThisOrBaseReference") ?? GetColor("Keywords");
this.trueKeywordColor = GetColor("TrueFalse") ?? GetColor("Keywords");
this.typeKeywordsColor = GetColor("TypeKeywords") ?? GetColor("Keywords");
this.attributeKeywordsColor = GetColor("AttributeKeywords") ?? GetColor("Keywords");
//this.externAliasKeywordColor = ...;

HighlightingColor GetColor(string colorName)
{
var color = highlighting.GetNamedColor(colorName);
return color is not { Foreground: null, Background: null, FontFamily: null, FontWeight: null, FontSize: null, FontStyle: null, Strikethrough: null, Underline: null } ? color : null;
}
}

public override void WriteKeyword(Role role, string keyword)
Expand Down Expand Up @@ -191,10 +204,10 @@ public override void WriteKeyword(Role role, string keyword)
case "remove":
case "init":
if (role == PropertyDeclaration.GetKeywordRole ||
role == PropertyDeclaration.SetKeywordRole ||
role == PropertyDeclaration.InitKeywordRole ||
role == CustomEventDeclaration.AddKeywordRole ||
role == CustomEventDeclaration.RemoveKeywordRole)
role == PropertyDeclaration.SetKeywordRole ||
role == PropertyDeclaration.InitKeywordRole ||
role == CustomEventDeclaration.AddKeywordRole ||
role == CustomEventDeclaration.RemoveKeywordRole)
color = accessorKeywordsColor;
break;
case "abstract":
Expand Down Expand Up @@ -339,10 +352,10 @@ public override void WriteIdentifier(Identifier identifier)
{
HighlightingColor color = null;
if (identifier.Name == "value"
&& identifier.Parent?.GetResolveResult() is ILVariableResolveResult rr
&& rr.Variable.Kind == Decompiler.IL.VariableKind.Parameter
&& identifier.Ancestors.OfType<Accessor>().FirstOrDefault() is Accessor accessor
&& accessor.Role != PropertyDeclaration.GetterRole)
&& identifier.Parent?.GetResolveResult() is ILVariableResolveResult rr
&& rr.Variable.Kind == Decompiler.IL.VariableKind.Parameter
&& identifier.Ancestors.OfType<Accessor>().FirstOrDefault() is Accessor accessor
&& accessor.Role != PropertyDeclaration.GetterRole)
{
color = valueKeywordColor;
}
Expand Down Expand Up @@ -380,12 +393,18 @@ public override void WriteIdentifier(Identifier identifier)
break;
}
break;
case IMethod m:
case IMethod:
color = methodDeclarationColor;
break;
case IField f:
case IField:
color = fieldDeclarationColor;
break;
case IProperty:
color = propertyDeclarationColor;
break;
case IEvent:
color = eventDeclarationColor;
break;
}
switch (GetCurrentMemberReference())
{
Expand All @@ -409,12 +428,18 @@ public override void WriteIdentifier(Identifier identifier)
break;
}
break;
case IMethod m:
case IMethod:
color = methodCallColor;
break;
case IField f:
case IField:
color = fieldAccessColor;
break;
case IProperty:
color = propertyAccessColor;
break;
case IEvent:
color = eventAccessColor;
break;
}
if (color != null)
{
Expand Down
9 changes: 9 additions & 0 deletions ILSpy/TextView/CSharp-Mode.xshd
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,23 @@
<Color name="AttributeKeywords" foreground="Navy" exampleText="[assembly: AssemblyVersion(&quot;1.0.0.*&quot;)]" />

<!-- Colors used for semantic highlighting -->
<Color name="Types" exampleText="System.#{#Uri#}# uri;"/>
<Color name="ReferenceTypes" foreground="#004085" exampleText="System.#{#Uri#}# uri;"/>
<Color name="InterfaceTypes" foreground="#004085" exampleText="System.#{#IDisposable#}# obj;"/>
<Color name="TypeParameters" foreground="#004085" exampleText="class MyList&lt;#{#T#}#&gt; { }"/>
<Color name="DelegateTypes" foreground="#004085" exampleText="System.#{#Action#}#; action;"/>
<Color name="ValueTypes" fontWeight="bold" foreground="#004085" exampleText="System.#{#DateTime#}# date;"/>
<Color name="EnumTypes" fontWeight="bold" foreground="#004085" exampleText="System.#{#ConsoleKey#}# key;"/>

<Color name="MethodDeclaration" exampleText="override string #{#ToString#}#() { }"/>
<Color name="MethodCall" foreground="MidnightBlue" fontWeight="bold" exampleText="o.#{#ToString#}#();"/>
<Color name="FieldDeclaration" exampleText="private int #{#name#}#;"/>
<Color name="FieldAccess" fontStyle="italic" exampleText="return this.#{#name#}#;"/>
<Color name="PropertyDeclaration" exampleText="private int #{#name#}# { get; set; }"/>
<Color name="PropertyAccess" exampleText="return this.#{#name#}#;"/>
<Color name="EventDeclaration" exampleText="private event Action #{#name#}#;"/>
<Color name="EventAccess" exampleText="this.#{#name#}#?.Invoke();"/>

<Color name="InactiveCode" foreground="Gray" exampleText="#{#Deactivated by #if#}#"/>
<Color name="SemanticError" foreground="DarkRed" exampleText="o.#{#MissingMethod#}#()"/>

Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Themes/Theme.RSharpDark.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
<themes:SyntaxColor x:Key="SyntaxColor.C#.EnumTypes" Foreground="#ADB0E6" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.MethodCall" Foreground="#00FFFF" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.FieldAccess" Foreground="#C4ADE6" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.PropertyAccess" Foreground="#C4ADE6" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.EventAccess" Foreground="#DDA0DD" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.InactiveCode" Foreground="#A9A9A9" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.SemanticError" Foreground="#FF3333" />

Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Themes/Theme.RSharpLight.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
<themes:SyntaxColor x:Key="SyntaxColor.C#.EnumTypes" Foreground="#3F008F" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.MethodCall" Foreground="#008B8B" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.FieldAccess" Foreground="#660E7A" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.PropertyAccess" Foreground="#660E7A" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.EventAccess" Foreground="#FF00FF" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.InactiveCode" Foreground="#A9A9A9" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.SemanticError" Foreground="#FF0000" />

Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Themes/Theme.VSCodeDarkPlus.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
<themes:SyntaxColor x:Key="SyntaxColor.C#.EnumTypes" Foreground="#4EC9B0" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.MethodCall" Foreground="#DCDCAA" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.FieldAccess" Foreground="#9CDCFE" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.PropertyAccess" Foreground="#9CDCFE" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.EventAccess" Foreground="#9CDCFE" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.InactiveCode" Foreground="#A6A6A6" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.SemanticError" Foreground="#f44747" />

Expand Down
2 changes: 2 additions & 0 deletions ILSpy/Themes/Theme.VSCodeLightPlus.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
<themes:SyntaxColor x:Key="SyntaxColor.C#.EnumTypes" Foreground="#267f99" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.MethodCall" Foreground="#795E26" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.FieldAccess" Foreground="#001080" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.PropertyAccess" Foreground="#001080" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.EventAccess" Foreground="#001080" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.InactiveCode" Foreground="#767676" />
<themes:SyntaxColor x:Key="SyntaxColor.C#.SemanticError" Foreground="#cd3131" />

Expand Down

0 comments on commit a9572d1

Please sign in to comment.