소스 검색

Merge pull request #39783 from neikeq/messaging-codecompletion-localize-fix

C#: Fix completion request with case insensitive resource path
Rémi Verschelde 5 년 전
부모
커밋
7d60a88888

+ 2 - 1
modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs

@@ -25,8 +25,9 @@ namespace GodotTools.Core
             bool rooted = path.IsAbsolutePath();
 
             path = path.Replace('\\', '/');
+            path = path[path.Length - 1] == '/' ? path.Substring(0, path.Length - 1) : path;
 
-            string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
+            string[] parts = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
 
             path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim();
 

+ 7 - 1
modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs

@@ -12,6 +12,7 @@ using GodotTools.IdeMessaging;
 using GodotTools.IdeMessaging.Requests;
 using GodotTools.IdeMessaging.Utils;
 using GodotTools.Internals;
+using GodotTools.Utils;
 using Newtonsoft.Json;
 using Directory = System.IO.Directory;
 using File = System.IO.File;
@@ -362,8 +363,13 @@ namespace GodotTools.Ides
 
             private static async Task<Response> HandleCodeCompletionRequest(CodeCompletionRequest request)
             {
+                // This is needed if the "resource path" part of the path is case insensitive.
+                // However, it doesn't fix resource loading if the rest of the path is also case insensitive.
+                string scriptFileLocalized = FsPathUtils.LocalizePathWithCaseChecked(request.ScriptFile);
+
                 var response = new CodeCompletionResponse {Kind = request.Kind, ScriptFile = request.ScriptFile};
-                response.Suggestions = await Task.Run(() => Internal.CodeCompletionRequest(response.Kind, response.ScriptFile));
+                response.Suggestions = await Task.Run(() =>
+                    Internal.CodeCompletionRequest(response.Kind, scriptFileLocalized ?? request.ScriptFile));
                 return response;
             }
         }

+ 48 - 0
modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs

@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using Godot;
+using GodotTools.Core;
+using JetBrains.Annotations;
+
+namespace GodotTools.Utils
+{
+    public static class FsPathUtils
+    {
+        private static readonly string ResourcePath = ProjectSettings.GlobalizePath("res://");
+
+        private static bool PathStartsWithAlreadyNorm(this string childPath, string parentPath)
+        {
+            // This won't work for Linux/macOS case insensitive file systems, but it's enough for our current problems
+            bool caseSensitive = !OS.IsWindows;
+
+            string parentPathNorm = parentPath.NormalizePath() + Path.DirectorySeparatorChar;
+            string childPathNorm = childPath.NormalizePath() + Path.DirectorySeparatorChar;
+
+            return childPathNorm.StartsWith(parentPathNorm,
+                caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+        }
+
+        public static bool PathStartsWith(this string childPath, string parentPath)
+        {
+            string childPathNorm = childPath.NormalizePath() + Path.DirectorySeparatorChar;
+            string parentPathNorm = parentPath.NormalizePath() + Path.DirectorySeparatorChar;
+
+            return childPathNorm.PathStartsWithAlreadyNorm(parentPathNorm);
+        }
+
+        [CanBeNull]
+        public static string LocalizePathWithCaseChecked(string path)
+        {
+            string pathNorm = path.NormalizePath() + Path.DirectorySeparatorChar;
+            string resourcePathNorm = ResourcePath.NormalizePath() + Path.DirectorySeparatorChar;
+
+            if (!pathNorm.PathStartsWithAlreadyNorm(resourcePathNorm))
+                return null;
+
+            string result = "res://" + pathNorm.Substring(resourcePathNorm.Length);
+
+            // Remove the last separator we added
+            return result.Substring(0, result.Length - 1);
+        }
+    }
+}