[gh-125] Implemented AST-hover for Roslyn.
This commit is contained in:
Родитель
e7375fcd82
Коммит
6a4467b60c
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using MirrorSharp.Advanced;
|
||||
using SharpLab.Server.Decompilation.Internal;
|
||||
|
||||
|
@ -26,6 +27,7 @@ namespace SharpLab.Server.Decompilation.AstOnly {
|
|||
var parentPropertyName = specialParentPropertyName ?? RoslynSyntaxHelper.GetParentPropertyName(node);
|
||||
if (parentPropertyName != null)
|
||||
writer.WriteProperty("property", parentPropertyName);
|
||||
SerializeSpanProperty(node.FullSpan, writer);
|
||||
writer.WritePropertyStartArray("children");
|
||||
foreach (var child in node.ChildNodesAndTokens()) {
|
||||
if (child.IsNode) {
|
||||
|
@ -47,12 +49,18 @@ namespace SharpLab.Server.Decompilation.AstOnly {
|
|||
if (parentPropertyName != null)
|
||||
writer.WriteProperty("property", parentPropertyName);
|
||||
|
||||
SerializeSpanProperty(token.FullSpan, writer);
|
||||
|
||||
if (token.HasLeadingTrivia || token.HasTrailingTrivia) {
|
||||
writer.WritePropertyStartArray("children");
|
||||
foreach (var trivia in token.LeadingTrivia) {
|
||||
SerializeTrivia(trivia, writer);
|
||||
}
|
||||
writer.WriteValue(token.ToString());
|
||||
writer.WriteStartObject();
|
||||
writer.WriteProperty("type", "value");
|
||||
writer.WriteProperty("value", token.ValueText);
|
||||
SerializeSpanProperty(token.Span, writer);
|
||||
writer.WriteEndObject();
|
||||
foreach (var trivia in token.TrailingTrivia) {
|
||||
SerializeTrivia(trivia, writer);
|
||||
}
|
||||
|
@ -68,6 +76,7 @@ namespace SharpLab.Server.Decompilation.AstOnly {
|
|||
writer.WriteStartObject();
|
||||
writer.WriteProperty("type", "trivia");
|
||||
writer.WriteProperty("kind", RoslynSyntaxHelper.GetKindName(trivia.RawKind));
|
||||
SerializeSpanProperty(trivia.FullSpan, writer);
|
||||
if (trivia.HasStructure) {
|
||||
writer.WritePropertyStartArray("children");
|
||||
SerializeNode(trivia.GetStructure(), writer, "Structure");
|
||||
|
@ -79,6 +88,15 @@ namespace SharpLab.Server.Decompilation.AstOnly {
|
|||
writer.WriteEndObject();
|
||||
}
|
||||
|
||||
private void SerializeSpanProperty(TextSpan span, IFastJsonWriter writer) {
|
||||
writer.WritePropertyName("range");
|
||||
using (var stringWriter = writer.OpenString()) {
|
||||
stringWriter.Write(span.Start);
|
||||
stringWriter.Write(":");
|
||||
stringWriter.Write(span.End);
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> SupportedLanguageNames { get; } = new[] {
|
||||
LanguageNames.CSharp,
|
||||
LanguageNames.VisualBasic
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.2.1" />
|
||||
<PackageReference Include="Microsoft.Owin.Cors" Version="3.0.1" />
|
||||
<PackageReference Include="Microsoft.Owin.Host.SystemWeb" Version="3.0.1" />
|
||||
<PackageReference Include="MirrorSharp.Common" Version="0.9.0-pre-20170528" />
|
||||
<PackageReference Include="MirrorSharp.Common" Version="0.9.0-pre-20170620" />
|
||||
<PackageReference Include="MirrorSharp.FSharp" Version="0.9.0-pre-20170523" />
|
||||
<PackageReference Include="MirrorSharp.Owin" Version="0.9.0-pre-20170523" />
|
||||
<PackageReference Include="MirrorSharp.VisualBasic" Version="0.9.0-pre-20170523" />
|
||||
|
|
|
@ -7,19 +7,27 @@
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "CompilationUnit",
|
||||
"range": "0:19",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "ClassDeclaration",
|
||||
"range": "0:19",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "PublicKeyword",
|
||||
"range": "0:7",
|
||||
"children": [
|
||||
"public",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "public",
|
||||
"range": "0:6"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "6:7",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -28,11 +36,17 @@
|
|||
"type": "token",
|
||||
"kind": "ClassKeyword",
|
||||
"property": "Keyword",
|
||||
"range": "7:13",
|
||||
"children": [
|
||||
"class",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "class",
|
||||
"range": "7:12"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "12:13",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -41,11 +55,17 @@
|
|||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "Identifier",
|
||||
"range": "13:15",
|
||||
"children": [
|
||||
"C",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "C",
|
||||
"range": "13:14"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "14:15",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -54,11 +74,17 @@
|
|||
"type": "token",
|
||||
"kind": "OpenBraceToken",
|
||||
"property": "OpenBraceToken",
|
||||
"range": "15:18",
|
||||
"children": [
|
||||
"{",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "{",
|
||||
"range": "15:16"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "16:18",
|
||||
"value": "\r\n"
|
||||
}
|
||||
]
|
||||
|
@ -67,6 +93,7 @@
|
|||
"type": "token",
|
||||
"kind": "CloseBraceToken",
|
||||
"property": "CloseBraceToken",
|
||||
"range": "18:19",
|
||||
"value": "}"
|
||||
}
|
||||
]
|
||||
|
@ -75,6 +102,7 @@
|
|||
"type": "token",
|
||||
"kind": "EndOfFileToken",
|
||||
"property": "EndOfFileToken",
|
||||
"range": "19:19",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
|
|
|
@ -13,20 +13,28 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "CompilationUnit",
|
||||
"range": "0:102",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "ClassDeclaration",
|
||||
"range": "0:102",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "ClassKeyword",
|
||||
"property": "Keyword",
|
||||
"range": "0:6",
|
||||
"children": [
|
||||
"class",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "class",
|
||||
"range": "0:5"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "5:6",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -35,11 +43,17 @@ b";
|
|||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "Identifier",
|
||||
"range": "6:8",
|
||||
"children": [
|
||||
"C",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "C",
|
||||
"range": "6:7"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "7:8",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -48,11 +62,17 @@ b";
|
|||
"type": "token",
|
||||
"kind": "OpenBraceToken",
|
||||
"property": "OpenBraceToken",
|
||||
"range": "8:11",
|
||||
"children": [
|
||||
"{",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "{",
|
||||
"range": "8:9"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "9:11",
|
||||
"value": "\r\n"
|
||||
}
|
||||
]
|
||||
|
@ -60,31 +80,41 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "FieldDeclaration",
|
||||
"range": "11:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclaration",
|
||||
"property": "Declaration",
|
||||
"range": "11:24",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "PredefinedType",
|
||||
"property": "Type",
|
||||
"range": "11:19",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IntKeyword",
|
||||
"property": "Keyword",
|
||||
"range": "11:19",
|
||||
"children": [
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "11:15",
|
||||
"value": " "
|
||||
},
|
||||
"int",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "int",
|
||||
"range": "15:18"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "18:19",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -94,16 +124,23 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclarator",
|
||||
"range": "19:24",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "Identifier",
|
||||
"range": "19:21",
|
||||
"children": [
|
||||
"i",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "i",
|
||||
"range": "19:20"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "20:21",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -112,16 +149,23 @@ b";
|
|||
"type": "node",
|
||||
"kind": "EqualsValueClause",
|
||||
"property": "Initializer",
|
||||
"range": "21:24",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "EqualsToken",
|
||||
"property": "EqualsToken",
|
||||
"range": "21:23",
|
||||
"children": [
|
||||
"=",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "=",
|
||||
"range": "21:22"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "22:23",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -130,11 +174,13 @@ b";
|
|||
"type": "node",
|
||||
"kind": "NumericLiteralExpression",
|
||||
"property": "Value",
|
||||
"range": "23:24",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "NumericLiteralToken",
|
||||
"property": "Token",
|
||||
"range": "23:24",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
|
@ -149,11 +195,17 @@ b";
|
|||
"type": "token",
|
||||
"kind": "SemicolonToken",
|
||||
"property": "SemicolonToken",
|
||||
"range": "24:27",
|
||||
"children": [
|
||||
";",
|
||||
{
|
||||
"type": "value",
|
||||
"value": ";",
|
||||
"range": "24:25"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "25:27",
|
||||
"value": "\r\n"
|
||||
}
|
||||
]
|
||||
|
@ -163,31 +215,41 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "FieldDeclaration",
|
||||
"range": "27:46",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclaration",
|
||||
"property": "Declaration",
|
||||
"range": "27:43",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "PredefinedType",
|
||||
"property": "Type",
|
||||
"range": "27:36",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "CharKeyword",
|
||||
"property": "Keyword",
|
||||
"range": "27:36",
|
||||
"children": [
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "27:31",
|
||||
"value": " "
|
||||
},
|
||||
"char",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "char",
|
||||
"range": "31:35"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "35:36",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -197,16 +259,23 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclarator",
|
||||
"range": "36:43",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "Identifier",
|
||||
"range": "36:38",
|
||||
"children": [
|
||||
"c",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "c",
|
||||
"range": "36:37"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "37:38",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -215,16 +284,23 @@ b";
|
|||
"type": "node",
|
||||
"kind": "EqualsValueClause",
|
||||
"property": "Initializer",
|
||||
"range": "38:43",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "EqualsToken",
|
||||
"property": "EqualsToken",
|
||||
"range": "38:40",
|
||||
"children": [
|
||||
"=",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "=",
|
||||
"range": "38:39"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "39:40",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -233,11 +309,13 @@ b";
|
|||
"type": "node",
|
||||
"kind": "CharacterLiteralExpression",
|
||||
"property": "Value",
|
||||
"range": "40:43",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "CharacterLiteralToken",
|
||||
"property": "Token",
|
||||
"range": "40:43",
|
||||
"value": "'c'"
|
||||
}
|
||||
]
|
||||
|
@ -252,11 +330,17 @@ b";
|
|||
"type": "token",
|
||||
"kind": "SemicolonToken",
|
||||
"property": "SemicolonToken",
|
||||
"range": "43:46",
|
||||
"children": [
|
||||
";",
|
||||
{
|
||||
"type": "value",
|
||||
"value": ";",
|
||||
"range": "43:44"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "44:46",
|
||||
"value": "\r\n"
|
||||
}
|
||||
]
|
||||
|
@ -266,36 +350,47 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "FieldDeclaration",
|
||||
"range": "46:75",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclaration",
|
||||
"property": "Declaration",
|
||||
"range": "46:72",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "PredefinedType",
|
||||
"property": "Type",
|
||||
"range": "46:59",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "StringKeyword",
|
||||
"property": "Keyword",
|
||||
"range": "46:59",
|
||||
"children": [
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "46:48",
|
||||
"value": "\r\n"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "48:52",
|
||||
"value": " "
|
||||
},
|
||||
"string",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "string",
|
||||
"range": "52:58"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "58:59",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -305,16 +400,23 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclarator",
|
||||
"range": "59:72",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "Identifier",
|
||||
"range": "59:62",
|
||||
"children": [
|
||||
"s1",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "s1",
|
||||
"range": "59:61"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "61:62",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -323,16 +425,23 @@ b";
|
|||
"type": "node",
|
||||
"kind": "EqualsValueClause",
|
||||
"property": "Initializer",
|
||||
"range": "62:72",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "EqualsToken",
|
||||
"property": "EqualsToken",
|
||||
"range": "62:64",
|
||||
"children": [
|
||||
"=",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "=",
|
||||
"range": "62:63"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "63:64",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -341,11 +450,13 @@ b";
|
|||
"type": "node",
|
||||
"kind": "StringLiteralExpression",
|
||||
"property": "Value",
|
||||
"range": "64:72",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "StringLiteralToken",
|
||||
"property": "Token",
|
||||
"range": "64:72",
|
||||
"value": "\"a\\r\\nb\""
|
||||
}
|
||||
]
|
||||
|
@ -360,11 +471,17 @@ b";
|
|||
"type": "token",
|
||||
"kind": "SemicolonToken",
|
||||
"property": "SemicolonToken",
|
||||
"range": "72:75",
|
||||
"children": [
|
||||
";",
|
||||
{
|
||||
"type": "value",
|
||||
"value": ";",
|
||||
"range": "72:73"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "73:75",
|
||||
"value": "\r\n"
|
||||
}
|
||||
]
|
||||
|
@ -374,31 +491,41 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "FieldDeclaration",
|
||||
"range": "75:101",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclaration",
|
||||
"property": "Declaration",
|
||||
"range": "75:98",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "PredefinedType",
|
||||
"property": "Type",
|
||||
"range": "75:86",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "StringKeyword",
|
||||
"property": "Keyword",
|
||||
"range": "75:86",
|
||||
"children": [
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "75:79",
|
||||
"value": " "
|
||||
},
|
||||
"string",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "string",
|
||||
"range": "79:85"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "85:86",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -408,16 +535,23 @@ b";
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "VariableDeclarator",
|
||||
"range": "86:98",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "Identifier",
|
||||
"range": "86:89",
|
||||
"children": [
|
||||
"s2",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "s2",
|
||||
"range": "86:88"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "88:89",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -426,16 +560,23 @@ b";
|
|||
"type": "node",
|
||||
"kind": "EqualsValueClause",
|
||||
"property": "Initializer",
|
||||
"range": "89:98",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "EqualsToken",
|
||||
"property": "EqualsToken",
|
||||
"range": "89:91",
|
||||
"children": [
|
||||
"=",
|
||||
{
|
||||
"type": "value",
|
||||
"value": "=",
|
||||
"range": "89:90"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "WhitespaceTrivia",
|
||||
"range": "90:91",
|
||||
"value": " "
|
||||
}
|
||||
]
|
||||
|
@ -444,11 +585,13 @@ b";
|
|||
"type": "node",
|
||||
"kind": "StringLiteralExpression",
|
||||
"property": "Value",
|
||||
"range": "91:98",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "StringLiteralToken",
|
||||
"property": "Token",
|
||||
"range": "91:98",
|
||||
"value": "@\"a\r\nb\""
|
||||
}
|
||||
]
|
||||
|
@ -463,11 +606,17 @@ b";
|
|||
"type": "token",
|
||||
"kind": "SemicolonToken",
|
||||
"property": "SemicolonToken",
|
||||
"range": "98:101",
|
||||
"children": [
|
||||
";",
|
||||
{
|
||||
"type": "value",
|
||||
"value": ";",
|
||||
"range": "98:99"
|
||||
},
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "EndOfLineTrivia",
|
||||
"range": "99:101",
|
||||
"value": "\r\n"
|
||||
}
|
||||
]
|
||||
|
@ -478,6 +627,7 @@ b";
|
|||
"type": "token",
|
||||
"kind": "CloseBraceToken",
|
||||
"property": "CloseBraceToken",
|
||||
"range": "101:102",
|
||||
"value": "}"
|
||||
}
|
||||
]
|
||||
|
@ -486,6 +636,7 @@ b";
|
|||
"type": "token",
|
||||
"kind": "EndOfFileToken",
|
||||
"property": "EndOfFileToken",
|
||||
"range": "102:102",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
|
|
|
@ -6,35 +6,46 @@
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "CompilationUnit",
|
||||
"range": "0:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "EndOfFileToken",
|
||||
"property": "EndOfFileToken",
|
||||
"range": "0:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "SingleLineDocumentationCommentTrivia",
|
||||
"range": "0:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "SingleLineDocumentationCommentTrivia",
|
||||
"property": "Structure",
|
||||
"range": "0:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "XmlText",
|
||||
"range": "0:4",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "XmlTextLiteralToken",
|
||||
"range": "0:4",
|
||||
"children": [
|
||||
{
|
||||
"type": "trivia",
|
||||
"kind": "DocumentationCommentExteriorTrivia",
|
||||
"range": "0:3",
|
||||
"value": "///"
|
||||
},
|
||||
" "
|
||||
{
|
||||
"type": "value",
|
||||
"value": " ",
|
||||
"range": "3:4"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -42,27 +53,32 @@
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "XmlElement",
|
||||
"range": "4:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "XmlElementStartTag",
|
||||
"property": "StartTag",
|
||||
"range": "4:13",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "LessThanToken",
|
||||
"property": "LessThanToken",
|
||||
"range": "4:5",
|
||||
"value": "<"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "XmlName",
|
||||
"property": "Name",
|
||||
"range": "5:12",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "LocalName",
|
||||
"range": "5:12",
|
||||
"value": "summary"
|
||||
}
|
||||
]
|
||||
|
@ -71,6 +87,7 @@
|
|||
"type": "token",
|
||||
"kind": "GreaterThanToken",
|
||||
"property": "GreaterThanToken",
|
||||
"range": "12:13",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
|
@ -78,10 +95,12 @@
|
|||
{
|
||||
"type": "node",
|
||||
"kind": "XmlText",
|
||||
"range": "13:17",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "XmlTextLiteralToken",
|
||||
"range": "13:17",
|
||||
"value": "Test"
|
||||
}
|
||||
]
|
||||
|
@ -90,22 +109,26 @@
|
|||
"type": "node",
|
||||
"kind": "XmlElementEndTag",
|
||||
"property": "EndTag",
|
||||
"range": "17:27",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "LessThanSlashToken",
|
||||
"property": "LessThanSlashToken",
|
||||
"range": "17:19",
|
||||
"value": "</"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"kind": "XmlName",
|
||||
"property": "Name",
|
||||
"range": "19:26",
|
||||
"children": [
|
||||
{
|
||||
"type": "token",
|
||||
"kind": "IdentifierToken",
|
||||
"property": "LocalName",
|
||||
"range": "19:26",
|
||||
"value": "summary"
|
||||
}
|
||||
]
|
||||
|
@ -114,6 +137,7 @@
|
|||
"type": "token",
|
||||
"kind": "GreaterThanToken",
|
||||
"property": "GreaterThanToken",
|
||||
"range": "26:27",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
|
@ -124,13 +148,18 @@
|
|||
"type": "token",
|
||||
"kind": "EndOfDocumentationCommentToken",
|
||||
"property": "EndOfComment",
|
||||
"range": "27:27",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
""
|
||||
{
|
||||
"type": "value",
|
||||
"value": "",
|
||||
"range": "27:27"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
<app-mirrorsharp v-bind:initial-text="lastLoadedCode"
|
||||
v-bind:service-url="serviceUrl"
|
||||
v-bind:server-options="serverOptions"
|
||||
v-bind:highlighted-range="highlightedCodeRange"
|
||||
v-on:text-change="code = arguments[0]()"
|
||||
v-on:slow-update-result="applyUpdateResult"
|
||||
v-on:server-error="applyServerError"
|
||||
|
@ -106,7 +107,8 @@
|
|||
<app-ast-view class="ast"
|
||||
v-if="lastResultOfType.ast"
|
||||
v-show="result.type === 'ast'"
|
||||
v-bind:roots="lastResultOfType.ast.value"></app-ast-view>
|
||||
v-bind:roots="lastResultOfType.ast.value"
|
||||
v-on:item-hover="applyAstHover"></app-ast-view>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -144,23 +146,18 @@
|
|||
Built by Andrey Shchekin (<a href="http://twitter.com/ashmind">@ashmind</a>). See <a href="http://github.com/ashmind/SharpLab">SharpLab</a> on GitHub.
|
||||
</footer>
|
||||
|
||||
<script type="text/x-template" id="app-ast-view">
|
||||
<ol>
|
||||
<li v-for="(item, index) in roots" class="collapsed" v-bind:class="{ leaf: !item.children }">
|
||||
<span v-if="typeof item === 'string'" class="ast-item-wrap ast-item-value">
|
||||
<span class="ast-item-type"></span>
|
||||
{{renderValue(item, 'value')}}
|
||||
</span>
|
||||
<span v-else v-bind:class="'ast-item-wrap ast-item-' + item.type">
|
||||
<button v-if="item.children"></button>
|
||||
<span class="ast-item-type" v-bind:title="item.type"></span>
|
||||
<span class="ast-item-property" v-if="item.property">{{item.property}}:</span>
|
||||
<span v-if="item.value !== undefined" class="ast-inline-value">{{renderValue(item.value, item.type)}}</span>
|
||||
<span class="ast-item-kind">{{item.kind}}</span>
|
||||
</span>
|
||||
<app-ast-view v-if="item.children" v-bind:roots="item.children"></app-ast-view>
|
||||
</li>
|
||||
</ol>
|
||||
<script type="text/x-template" id="app-ast-view-item">
|
||||
<span v-if="typeof item === 'string'" class="ast-item-wrap ast-item-value">
|
||||
<span class="ast-item-type"></span>
|
||||
{{renderValue(item, 'value')}}
|
||||
</span>
|
||||
<span v-else v-bind:class="'ast-item-wrap ast-item-' + item.type">
|
||||
<button v-if="item.children"></button>
|
||||
<span class="ast-item-type" v-bind:title="item.type"></span>
|
||||
<span class="ast-item-property" v-if="item.property">{{item.property}}:</span>
|
||||
<span v-if="item.value !== undefined" class="ast-inline-value">{{renderValue(item.value, item.type)}}</span>
|
||||
<span class="ast-item-kind">{{item.kind}}</span>
|
||||
</span>
|
||||
</script>
|
||||
|
||||
<!-- build:js -->
|
||||
|
|
|
@ -52,6 +52,16 @@ function getServiceUrl(branch) {
|
|||
return `${httpRoot.replace(/^http/, 'ws')}/mirrorsharp`;
|
||||
}
|
||||
|
||||
function applyAstHover(item) {
|
||||
if (!item || !item.range) {
|
||||
this.highlightedCodeRange = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const [start, end] = item.range.split(':');
|
||||
this.highlightedCodeRange = { start, end };
|
||||
}
|
||||
|
||||
async function createAppAsync() {
|
||||
const data = Object.assign({
|
||||
languages,
|
||||
|
@ -70,7 +80,9 @@ async function createAppAsync() {
|
|||
errors: [],
|
||||
warnings: []
|
||||
},
|
||||
lastResultOfType: { code: null, ast: null }
|
||||
lastResultOfType: { code: null, ast: null },
|
||||
|
||||
highlightedCodeRange: null
|
||||
});
|
||||
await state.loadAsync(data);
|
||||
data.lastLoadedCode = data.code;
|
||||
|
@ -114,7 +126,7 @@ async function createAppAsync() {
|
|||
return { name: 'default', color: '#4684ee' };
|
||||
}
|
||||
},
|
||||
methods: { applyUpdateResult, applyServerError, applyConnectionChange }
|
||||
methods: { applyUpdateResult, applyServerError, applyConnectionChange, applyAstHover }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,44 +1,71 @@
|
|||
import Vue from 'vue';
|
||||
import AstViewItem from './internal/app-ast-view-item.js';
|
||||
|
||||
Vue.component('app-ast-view', {
|
||||
props: {
|
||||
roots: Array
|
||||
},
|
||||
methods: {
|
||||
renderValue: function(value, type) {
|
||||
if (type === 'trivia')
|
||||
return escapeTrivia(value);
|
||||
|
||||
return escapeCommon(value);
|
||||
}
|
||||
},
|
||||
data: () => ({
|
||||
expanded: []
|
||||
}),
|
||||
mounted: function() {
|
||||
const getItem = li => this.allById[li.getAttribute('data-id')];
|
||||
|
||||
let hoverSupported = false;
|
||||
let lastHoverByClick = null;
|
||||
Vue.nextTick(() => {
|
||||
this.$el.addEventListener('click', e => {
|
||||
const li = findLI(e);
|
||||
if (!li)
|
||||
return;
|
||||
handleOnLI(this.$el, 'click', li => {
|
||||
li.classList.toggle('collapsed');
|
||||
e.stopPropagation();
|
||||
if (hoverSupported)
|
||||
return;
|
||||
|
||||
if (lastHoverByClick)
|
||||
lastHoverByClick.classList.remove('hover');
|
||||
this.$emit('item-hover', getItem(li));
|
||||
li.classList.add('hover');
|
||||
lastHoverByClick = li;
|
||||
});
|
||||
handleOnLI(this.$el, 'mouseover', li => {
|
||||
hoverSupported = true;
|
||||
this.$emit('item-hover', getItem(li));
|
||||
li.classList.add('hover');
|
||||
});
|
||||
handleOnLI(this.$el, 'mouseout', li => {
|
||||
this.$emit('item-hover', null);
|
||||
li.classList.remove('hover');
|
||||
});
|
||||
});
|
||||
},
|
||||
template: '#app-ast-view'
|
||||
render: function(h) {
|
||||
this.allById = {};
|
||||
return h('div', [renderTree(h, this.roots, this.allById)]);
|
||||
}
|
||||
});
|
||||
|
||||
function escapeCommon(value) {
|
||||
return value
|
||||
.replace('\r', '\\r')
|
||||
.replace('\n', '\\n')
|
||||
.replace('\t', '\\t');
|
||||
function renderTree(h, items, allById, parentId) {
|
||||
return h('ol',
|
||||
items.map((item, index) => renderLI(h, item, allById, (parentId != null) ? parentId + '.' + index : index))
|
||||
);
|
||||
}
|
||||
|
||||
function escapeTrivia(value) {
|
||||
return escapeCommon(value)
|
||||
.replace(/(^ +| +$)/g, (_,$1) => $1.length > 1 ? `<space:${$1.length}>` : '<space>');
|
||||
function renderLI(h, item, allById, id) {
|
||||
allById[id] = item;
|
||||
return h('li',
|
||||
{
|
||||
class: { collapsed: true, leaf: !item.children },
|
||||
attrs: { 'data-id': id }
|
||||
},
|
||||
[
|
||||
h(AstViewItem, { props: { item } }),
|
||||
item.children ? renderTree(h, item.children, allById, id) : null
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function handleOnLI(root, event, action) {
|
||||
root.addEventListener(event, e => {
|
||||
const li = findLI(e);
|
||||
if (!li)
|
||||
return;
|
||||
action(li);
|
||||
});
|
||||
}
|
||||
|
||||
function findLI(e) {
|
||||
|
|
|
@ -4,9 +4,10 @@ import 'codemirror/mode/mllike/mllike';
|
|||
|
||||
Vue.component('app-mirrorsharp', {
|
||||
props: {
|
||||
initialText: String,
|
||||
serverOptions: Object,
|
||||
serviceUrl: String
|
||||
initialText: String,
|
||||
serverOptions: Object,
|
||||
serviceUrl: String,
|
||||
highlightedRange: Object
|
||||
},
|
||||
mounted: function() {
|
||||
Vue.nextTick(() => {
|
||||
|
@ -41,6 +42,21 @@ Vue.component('app-mirrorsharp', {
|
|||
if (this.serverOptions)
|
||||
instance.sendServerOptions(this.serverOptions);
|
||||
});
|
||||
|
||||
let currentMarker = null;
|
||||
this.$watch('highlightedRange', range => {
|
||||
const cm = instance.getCodeMirror();
|
||||
if (currentMarker) {
|
||||
currentMarker.clear();
|
||||
currentMarker = null;
|
||||
}
|
||||
if (!range)
|
||||
return;
|
||||
|
||||
const from = cm.posFromIndex(range.start);
|
||||
const to = cm.posFromIndex(range.end);
|
||||
currentMarker = cm.markText(from, to, { className: 'highlighted' });
|
||||
});
|
||||
});
|
||||
},
|
||||
template: '<textarea></textarea>'
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
export default {
|
||||
props: {
|
||||
item: {}
|
||||
},
|
||||
methods: {
|
||||
renderValue
|
||||
},
|
||||
template: '#app-ast-view-item'
|
||||
};
|
||||
|
||||
function renderValue(value, type) {
|
||||
if (type === 'trivia')
|
||||
return escapeTrivia(value);
|
||||
|
||||
return escapeCommon(value);
|
||||
}
|
||||
|
||||
function escapeCommon(value) {
|
||||
return value
|
||||
.replace('\r', '\\r')
|
||||
.replace('\n', '\\n')
|
||||
.replace('\t', '\\t');
|
||||
}
|
||||
|
||||
function escapeTrivia(value) {
|
||||
return escapeCommon(value)
|
||||
.replace(/(^ +| +$)/g, (_,$1) => $1.length > 1 ? `<space:${$1.length}>` : '<space>');
|
||||
}
|
|
@ -7,9 +7,8 @@
|
|||
bottom: 0;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-left: 4px;
|
||||
margin-top: 2px;
|
||||
|
||||
|
@ -20,13 +19,23 @@
|
|||
padding-left: 20px;
|
||||
}
|
||||
|
||||
> ol {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding-top: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
padding-right: 6px;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
&.hover {
|
||||
background-color: @highlight-color;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
|
|
|
@ -34,4 +34,8 @@ textarea, .CodeMirror {
|
|||
.cm-tag {
|
||||
color: #bbb;
|
||||
}
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
background-color: @highlight-color;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
@error-color: #dc3912;
|
||||
@warning-color: #ff9900;
|
||||
@offline-color: #aaa;
|
||||
@highlight-color: #efefef;
|
||||
|
||||
.code-text() {
|
||||
font-family: Consolas, Menlo, Monaco, monospace;
|
||||
|
|
Загрузка…
Ссылка в новой задаче