public void HandleClosedFile(SkriptFile file) { if (Current.Files.ContainsKey(file.Url)) { Current.Files.TryRemove(file.Url, out _); } }
protected sealed override void Inspect(SkriptFile file, int line, AbstractFileNode node) { if (node.MatchedSyntax != null) { Inspect(file, line, node, node.MatchedSyntax); } }
public void HandleOpenedFile(SkriptFile file) { if (!Current.Files.ContainsKey(file.Url)) { Current.Files[file.Url] = file; } }
public sealed override void Inspect(SkriptFile file, int line) { var node = file.Nodes[line]; if (node != null) { Inspect(file, line, node); } }
public void AssertResource(string name) { var parser = new AnnotationParser(); parser.RegisterAnnotation <AssertInspectionAnnotation>(); SkriptFile file = null; var host = new InspectionDelegatingHost((uri, list) => { foreach (var diagnostic in list) { // ReSharper disable AccessToModifiedClosure Debug.Assert(file != null, nameof(file) + " != null"); var node = file.Nodes[diagnostic.Range.Start.Line]; //TODO: Allow multiple annotations to a single node by parsing the comments directly above. var comment = node.RawComment.TrimStart('#').Trim(); if (!comment.StartsWith("@")) { continue; } var annotation = parser.TryParse(comment); switch (annotation) { case AssertInspectionAnnotation assertInspectionAnnotation: Assert.Equal(assertInspectionAnnotation.InspectionType, diagnostic.Code); break; default: throw new ArgumentOutOfRangeException(nameof(annotation)); } // ReSharper restore AccessToModifiedClosure } }); WorkspaceManager.CurrentHost = host; var current = WorkspaceManager.CurrentWorkspace; var code = ReadResource(name); file = new SkriptFile(new Uri($"memory://{name}")); file.HandleChange(new TextDocumentContentChangeEvent { Text = code }); file.PrepareNodes(); parser.UnregisterAnnotation <AssertInspectionAnnotation>(); }
public override void DoWork(SkriptFile file, int lineNumber, string rawContent, FileParseContext context) { var node = file.Nodes[lineNumber]; //Only attempt to parse already matched syntax if the user is changing the contents of the file if (!context.File.IsDoingNodesChange && node.MatchedSyntax != null) { return; } var workDone = false; foreach (var elements in WorkspaceManager.Instance.Current.AddonDocumentations.Select(addon => node.IsSectionNode ? addon.Events : addon.Expressions.Cast <AbstractSyntaxElement>().Concat(addon.Effects))) { foreach (var effect in elements) { for (var index = 0; index < effect.PatternNodes.Length; index++) { var effectPattern = effect.PatternNodes[index]; context.Matches = new List <ParseMatch>(); context.CurrentLine = lineNumber; var result = effectPattern.Parse(context); if (result.IsSuccess) { result.Context = context.Clone(); result.Matches = result.Context.Matches; node.MatchedSyntax = new SyntaxMatch(effect, result) { PatternIndex = index }; workDone = true; } if (workDone) { break; } } if (workDone) { break; } } if (workDone) { break; } } }
public sealed override void DoWork(SkriptFile file, int lineNumber, string rawContent, FileParseContext context) { if (!CanInspect(file, lineNumber)) { return; } StaticProblemsHolder.Value = file.ProblemsHolder; Inspect(file, lineNumber); StaticProblemsHolder.Value = null; }
protected override void Inspect(SkriptFile file, int line, AbstractFileNode node) { var signatureRequiresSection = node.GetType().GetCustomAttribute <SectionNodeAttribute>() != null; var isSectionMismatch = node.IsSectionNode != signatureRequiresSection; if (isSectionMismatch) { AddProblem(DiagnosticSeverity.Error, $"{(signatureRequiresSection ? "E" : "Une")}xpected section at the end of this line", node); } }
protected override void Inspect(SkriptFile file, int line, AbstractFileNode node, SyntaxMatch match) { var cancelEvent = node.GetSyntaxNode <EffCancelEvent>(); if (cancelEvent == null) { return; } if (node.RootParentSyntax?.Element is SkriptEvent @event && [email protected]) { AddProblem(DiagnosticSeverity.Error, $"This event can't be {(!cancelEvent.ToCancel ? "un" : "")}cancelled.", node); } }
public void MatchesMessagePlayer(string code, int expectedMatches) { var file = new SkriptFile(new Uri("memory://file")) { RawContents = ("on chat:\n" + " " + code).SplitOnNewLines() }; WorkspaceManager.Instance.HandleOpenedFile(file); file.PrepareNodes(); var effMessageNode = file.Nodes[1]; Assert.NotNull(effMessageNode); Assert.NotNull(effMessageNode.MatchedSyntax); Assert.True(effMessageNode.MatchedSyntax.Result.IsSuccess); Assert.Equal(expectedMatches, effMessageNode.MatchedSyntax.Result.Matches.Count); }
public void FileKnowsHowToSwitchLinesOnTheContext(int count) { const string selector = "abcd"; var fileContent = string.Join("\n", Enumerable.Range(0, count).Select(_ => selector)); var file = new SkriptFile(MemoryFile) { RawContents = fileContent.SplitOnNewLines() }; for (var i = 0; i < count; i++) { Assert.Equal(selector, file.ParseContext.ReadNext(selector.Length)); } Assert.True(file.ParseContext.HasReachedEndOfFile); }
public void EmptyUnitTest() { Debugger.Break(); var code = "{_test}.hello().world().bruh()"; var file = new SkriptFile(new Uri("memory://file")) { RawContents = ("on chat:\n" + " " + code).SplitOnNewLines() }; WorkspaceManager.Instance.HandleOpenedFile(file); file.PrepareNodes(); var node = file.Nodes[1]; Debugger.Break(); _testOutputHelper.WriteLine(node.ToJson()); }
public void BasicNodeInformationIsCorrect() { AbstractFileNode resultNode = new BaseFileNode(); const string content = "this is a##test"; const string rawContent = @" " + content + " #comment"; const int lineNumber = 0; var expectedContentRange = RangeExtensions.From(lineNumber, 4, 19); var expectedCommentRange = RangeExtensions.From(lineNumber, 19, 28); var expectedIndentationRange = RangeExtensions.From(lineNumber, 0, 4); var file = new SkriptFile(new Uri("memory://tests")); NodeContentHelper.ApplyBasicNodeInfoToNode(rawContent, lineNumber, file, ref resultNode); Assert.Equal(content, resultNode.NodeContent); Assert.Equal(expectedContentRange, resultNode.ContentRange); Assert.Equal(expectedCommentRange, resultNode.CommentRange); Assert.Equal(expectedIndentationRange, resultNode.IndentationRange); Assert.Equal(new[] { new NodeIndentation(IndentType.Space, 4) }, resultNode.Indentations); Assert.Single(resultNode.Indentations); }
public static void ApplyBasicNodeInfoToNode(string content, int line, SkriptFile file, ref AbstractFileNode node) { ExtractBasicNodeInformationFrom(content, line, out var indentations, out var indentRange, out var contentRange, out var nodeRange, out var commentRange, out var commentContent, out var nodeContent); node.RawText = content; node.LineNumber = line; node.Indentations = indentations; node.IndentationRange = indentRange; node.Range = nodeRange; node.CommentRange = commentRange; node.RawComment = commentContent; node.ContentRange = contentRange; node.NodeContent = nodeContent; node.File = file; if (nodeContent.EndsWith(":")) { node.IsSectionNode = true; } }
public void KnowsHowToParseSimpleSendEffect() { var url = new Uri("memory://file1"); var contents = "on chat\n send \"hi\"".SplitOnNewLines(); var file = new SkriptFile(url) { RawContents = contents }; WorkspaceManager.Instance.HandleOpenedFile(file); file.PrepareNodes(); file.HandleChange(new TextDocumentContentChangeEvent { Range = RangeExtensions.From(0, 7, 7), RangeLength = 1, Text = ":" }); Assert.Equal(2, file.Nodes.Count); //Basic node match just to be sure for (var i = 0; i < file.Nodes.Count; i++) { Assert.Equal(contents[i], file.Nodes[i].ToString()); } var results = new[] { "org.bukkit.event.player.AsyncPlayerChatEvent", "ch.njol.skript.effects.EffMessage" }; for (var i = 0; i < results.Length; i++) { Assert.True(file.Nodes[i].IsMatchOfType(results[i]), $"{i}: {file.Nodes[i].NodeContent} supposed to be {results[i]}"); } }
protected abstract void Inspect(SkriptFile file, int line, AbstractFileNode node);
protected virtual bool CanInspect(SkriptFile file, int line, AbstractFileNode node) { return(true); }
public abstract void DoWork(SkriptFile file, int lineNumber, string rawContent, FileParseContext context);
public void KnowsHowToHandleParentsAndChildren() { var url = new Uri("memory://file1"); var contents = ( "on chat\n" + " if message contains \"h\"\n" + " if message contains \"i\"\n" + " send \"hi\"" ).SplitOnNewLines(); var file = new SkriptFile(url) { RawContents = contents }; WorkspaceManager.Instance.HandleOpenedFile(file); file.PrepareNodes(); file.HandleChange(new TextDocumentContentChangeEvent { Range = RangeExtensions.From(2, 31, 31), RangeLength = 1, Text = ":" }); file.HandleChange(new TextDocumentContentChangeEvent { Range = RangeExtensions.From(1, 27, 27), RangeLength = 1, Text = ":" }); file.HandleChange(new TextDocumentContentChangeEvent { Range = RangeExtensions.From(0, 7, 7), RangeLength = 1, Text = ":" }); Assert.Equal(4, file.Nodes.Count); //Basic node match just to be sure for (var i = 0; i < file.Nodes.Count; i++) { Assert.Equal(contents[i], file.Nodes[i].ToString()); } var results = new[] { "org.bukkit.event.player.AsyncPlayerChatEvent", "", "", "ch.njol.skript.effects.EffMessage" }; for (var i = 0; i < results.Length; i++) { if (!string.IsNullOrEmpty(results[i])) { Assert.True(file.Nodes[i].IsMatchOfType(results[i]), $"{i}: {file.Nodes[i].NodeContent} supposed to be {results[i]}"); } } Assert.Equal(file.Nodes[0], file.Nodes[1].Parent); Assert.Equal(file.Nodes[1], file.Nodes[2].Parent); Assert.Equal(file.Nodes[2], file.Nodes[3].Parent); }
/// <summary> /// Inspect the code. /// </summary> /// <param name="file">The file to get inspected</param> /// <param name="line">The line number from the file to inspect</param> /// <param name="problemHolder">The instance that holds the problems that are found by this inspection</param> public abstract void Inspect(SkriptFile file, int line);
/// <summary> /// A simple check performed to see if a certain line of a file can be inspected by the current inspection. /// </summary> /// <param name="file">The file to get inspected</param> /// <param name="line">The line number from the file to inspect</param> /// <returns></returns> public abstract bool CanInspect(SkriptFile file, int line);
protected sealed override bool CanInspect(SkriptFile file, int line, AbstractFileNode node) { return(node.MatchedSyntax != null && node.MatchedSyntax.Result.IsSuccess && CanInspect(file, line, node, node.MatchedSyntax)); }
public override void DoWork(SkriptFile file, int lineNumber, string rawContent, FileParseContext context) { AbstractFileNode resultNode = new BaseFileNode(); NodeContentHelper.ApplyBasicNodeInfoToNode(rawContent, lineNumber, file, ref resultNode); if (resultNode.NodeContent.IsEmpty() && !resultNode.RawComment.IsEmpty()) { AbstractFileNode commentNode = new CommentLineNode(); NodeContentHelper.ApplyBasicNodeInfoToOtherNode(resultNode, ref commentNode); resultNode = commentNode; } else if (resultNode.NodeContent.IsEmpty() && resultNode.RawComment.IsEmpty()) { AbstractFileNode emptyLineNode = new EmptyLineNode(); emptyLineNode.MatchedSyntax = new SyntaxMatch(SignatureElements.EmptyLine, ParseResult.Success(context)); NodeContentHelper.ApplyBasicNodeInfoToOtherNode(resultNode, ref emptyLineNode); resultNode = emptyLineNode; } else { if (file.IsNodeVisible(resultNode)) { var ctx = ParseContext.FromCode(rawContent); var signatureMatches = new List <(bool isSectionMismatch, AbstractFileNode node)>(); //Try to match to one of our known signatures foreach (var(signatureNodeType, signatureDelegate) in NodeSignaturesManager.Instance.SignatureTypes ) { ctx.Matches.Clear(); ctx.CurrentPosition = context.IndentationChars; var isSectionTypeMismatch = resultNode.IsSectionNode != (signatureNodeType.GetCustomAttribute <SectionNodeAttribute>() != null); var tryParseResult = signatureDelegate.DynamicInvoke(ctx); // We matched one signature if (tryParseResult != null && ctx.HasFinishedLine) { var instance = signatureNodeType.NewInstance(tryParseResult); if (instance is AbstractFileNode fileNode) { NodeContentHelper.ApplyBasicNodeInfoToOtherNode(resultNode, ref fileNode); signatureMatches.Add((isSectionTypeMismatch, fileNode)); } if (!isSectionTypeMismatch) { break; } } } var resultingNode = signatureMatches.FirstOrDefault(x => !x.isSectionMismatch).node; if (resultingNode != null) { resultNode = resultingNode; } } } file.Nodes[lineNumber] = resultNode; }
protected override bool CanInspect(SkriptFile file, int line, AbstractFileNode node) { return(node.MatchedSyntax == null && node.GetType().IsSubclassOfRawGeneric(typeof(SignatureFileNode <>))); }
public sealed override bool CanInspect(SkriptFile file, int line) { return(file.Nodes[line] != null && CanInspect(file, line, file.Nodes[line])); }
protected abstract void Inspect(SkriptFile file, int line, AbstractFileNode node, SyntaxMatch match);