diff --git a/server/OpenRA.MiniYamlParser/MiniYaml.cs b/server/OpenRA.MiniYamlParser/MiniYaml.cs index 9528c89..7b5a50f 100644 --- a/server/OpenRA.MiniYamlParser/MiniYaml.cs +++ b/server/OpenRA.MiniYamlParser/MiniYaml.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; namespace OpenRA.MiniYamlParser { @@ -91,5 +92,11 @@ public IEnumerable ToLines(string key, string comment = null) foreach (var line in Nodes.ToLines()) yield return "\t" + line; } + + public static List Load(IEnumerable files) + { + var yaml = files.Select(f => MiniYamlLoader.FromFile(f)); + return MiniYamlMerger.Merge(yaml); + } } } diff --git a/server/Oraide.LanguageServer/Abstractions/LanguageServerProtocolHandlers/BaseRpcMessageHandler.cs b/server/Oraide.LanguageServer/Abstractions/LanguageServerProtocolHandlers/BaseRpcMessageHandler.cs index 1a115b0..ef5d586 100644 --- a/server/Oraide.LanguageServer/Abstractions/LanguageServerProtocolHandlers/BaseRpcMessageHandler.cs +++ b/server/Oraide.LanguageServer/Abstractions/LanguageServerProtocolHandlers/BaseRpcMessageHandler.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using LspTypes; +using OpenRA.MiniYamlParser; using Oraide.Core; using Oraide.Core.Entities; using Oraide.Core.Entities.MiniYaml; @@ -66,6 +68,14 @@ protected virtual bool TryGetCursorTarget(TextDocumentPositionParams positionPar var (fileNodes, flattenedNodes, fileLines) = openFileCache[fileUri.AbsoluteUri]; var targetLine = fileLines[targetLineIndex]; + + // If the target line is a comment we probably don't care about it - bail out early. + if (Regex.IsMatch(targetLine, "^\\s#")) + { + target = default; + return false; + } + var pre = targetLine.Substring(0, targetCharacterIndex); var post = targetLine.Substring(targetCharacterIndex); @@ -224,6 +234,22 @@ protected bool TryGetTargetStringIndentation(YamlNode yamlNode, out int indentat return true; } + protected bool TryMergeYamlFiles(IEnumerable filePaths, out List nodes) + { + // As long as the merging passes there's a good chance we really do have a node like the target one to be removed. + // If the target node removal doesn't have a corresponding node addition (is invalid), MiniYaml loading will throw. + try + { + nodes = OpenRA.MiniYamlParser.MiniYaml.Load(filePaths); + return true; + } + catch (Exception) + { + nodes = null; + return false; + } + } + protected string NormalizeFilePath(string filePath) { // Because VSCode sends us weird partially-url-encoded file paths. diff --git a/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentCompletionHandler.cs b/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentCompletionHandler.cs index 76805de..07e5541 100644 --- a/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentCompletionHandler.cs +++ b/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentCompletionHandler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using LspTypes; using Oraide.Core; using Oraide.Core.Entities; @@ -112,6 +113,14 @@ protected override bool TryGetCursorTarget(TextDocumentPositionParams positionPa var (fileNodes, flattenedNodes, fileLines) = openFileCache[fileUri.AbsoluteUri]; var targetLine = fileLines[targetLineIndex]; + + // If the target line is a comment we probably don't care about it - bail out early. + if (Regex.IsMatch(targetLine, "^\\s#")) + { + target = default; + return false; + } + var pre = targetLine.Substring(0, targetCharacterIndex); var targetNode = flattenedNodes[targetLineIndex]; diff --git a/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentHoverHandler.cs b/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentHoverHandler.cs index 750adca..1cb716c 100644 --- a/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentHoverHandler.cs +++ b/server/Oraide.LanguageServer/LanguageServerProtocolHandlers/TextDocument/TextDocumentHoverHandler.cs @@ -99,6 +99,20 @@ protected override Hover HandleRulesKey(CursorTarget cursorTarget) return HoverFromHoverInfo(content, range); } + if (cursorTarget.TargetString[0] == '-') + { + traitInfoName = traitInfoName.Substring(1); + if (codeSymbols.TraitInfos.Contains(traitInfoName)) + { + var modData = symbolCache[cursorTarget.ModId]; + var fileList = modData.ModManifest.RulesFiles; + var resolvedFileList = fileList.Select(x => OpenRaFolderUtils.ResolveFilePath(x, (modData.ModId, modData.ModFolder))); + + if (TryMergeYamlFiles(resolvedFileList, out _)) + return HoverFromHoverInfo($"Removes trait `{cursorTarget.TargetString.Substring(1)}` from the actor.", range); + } + } + return null; } @@ -267,6 +281,16 @@ protected override Hover HandleWeaponKey(CursorTarget cursorTarget) if (prop.Name != null) return HoverFromHoverInfo(prop.ToMarkdownInfoString(), range); + if (cursorTarget.TargetString[0] == '-') + { + var modData = symbolCache[cursorTarget.ModId]; + var fileList = modData.ModManifest.WeaponsFiles; + var resolvedFileList = fileList.Select(x => OpenRaFolderUtils.ResolveFilePath(x, (modData.ModId, modData.ModFolder))); + + if (TryMergeYamlFiles(resolvedFileList, out _)) + return HoverFromHoverInfo($"Removes `{cursorTarget.TargetNode.Key.Substring(1)}` from the weapon.", range); + } + return null; }