From e0d322694583af2b30efaee0b006d0412ccd5e8d Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Mon, 22 Dec 2025 18:45:54 +0200 Subject: [PATCH] Fully functional syntax highlight of classes resolved from import wildcards i.e. import java.util.* List list --- .../gui/util/script/ClassPathFinder.java | 58 +++++++++++++++++-- .../gui/util/script/JavaTextContainer.java | 6 +- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/ClassPathFinder.java b/src/main/java/noppes/npcs/client/gui/util/script/ClassPathFinder.java index 4ceb33a90..f12c08a8b 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/ClassPathFinder.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/ClassPathFinder.java @@ -326,6 +326,16 @@ public class ClassPathFinder { * Get the ClassInfo for a simple class name, using provided imports map */ public ClassInfo resolveSimpleName(String simpleName, Map importedClasses) { + return resolveSimpleName(simpleName, importedClasses, Collections.emptySet()); + } + + /** + * Resolve a simple class name using explicit imports, java.lang, or wildcard imports. + * Supports package wildcard imports (e.g., java.util.*) and class-member wildcards + * that have been added to `importedPackages` (e.g., kamkeel..IOverlay.* treated as + * attempting to resolve inner types of IOverlay). + */ + public ClassInfo resolveSimpleName(String simpleName, Map importedClasses, Set importedPackages) { if (simpleName == null || simpleName.isEmpty()) { return null; } @@ -333,12 +343,45 @@ public class ClassPathFinder { // Check imported classes first String fullName = importedClasses.get(simpleName); if (fullName != null) { - return tryResolveClass(fullName); + ClassInfo info = tryResolveClass(fullName); + if (info != null) return info; } // Check java.lang classes if (JAVA_LANG_CLASSES.contains(simpleName)) { - return tryResolveClass("java.lang." + simpleName); + ClassInfo info = tryResolveClass("java.lang." + simpleName); + if (info != null) return info; + } + + // Check wildcard imports: these can be package wildcards (pkg.*) or + // class-member wildcards (Outer.*) where we want to allow resolving + // inner types of the Outer class. Heuristic: if the last segment of + // the imported path starts with uppercase, treat it as a class; otherwise + // treat it as a package. + if (importedPackages != null && !importedPackages.isEmpty()) { + for (String p : importedPackages) { + if (p == null || p.isEmpty()) continue; + String[] segs = p.split("\\."); + String last = segs[segs.length - 1]; + boolean lastIsClass = last.length() > 0 && Character.isUpperCase(last.charAt(0)); + + // Try package wildcard: pkg.SimpleName + if (!lastIsClass) { + String candidate = p + "." + simpleName; + ClassInfo info = tryResolveClass(candidate); + if (info != null) return info; + } else { + // Try inner type under the class: Outer$Inner + String candidateInner = p + "$" + simpleName; + ClassInfo info = tryResolveClass(candidateInner); + if (info != null) return info; + + // Also try package-like (in case someone imported a class-looking path but it is actually a package) + String candidatePkg = p + "." + simpleName; + info = tryResolveClass(candidatePkg); + if (info != null) return info; + } + } } return null; @@ -536,8 +579,12 @@ public class ClassPathFinder { * @return List of TypeOccurrence with position and type info */ public List parseGenericTypes(String genericContent, Map importedClasses) { + return parseGenericTypes(genericContent, importedClasses, Collections.emptySet()); + } + + public List parseGenericTypes(String genericContent, Map importedClasses, Set importedPackages) { List results = new ArrayList<>(); - parseGenericTypesRecursive(genericContent, 0, importedClasses, results); + parseGenericTypesRecursive(genericContent, 0, importedClasses, importedPackages, results); return results; } @@ -560,6 +607,7 @@ public class ClassPathFinder { private void parseGenericTypesRecursive(String content, int baseOffset, Map importedClasses, + Set importedPackages, List results) { if (content == null || content.isEmpty()) return; @@ -584,7 +632,7 @@ public class ClassPathFinder { // Only process if it looks like a type name (starts with uppercase) if (Character.isUpperCase(typeName.charAt(0))) { // Resolve the type - ClassInfo info = resolveSimpleName(typeName, importedClasses); + ClassInfo info = resolveSimpleName(typeName, importedClasses, importedPackages); ClassType classType = (info != null) ? info.type : ClassType.CLASS; results.add(new TypeOccurrence(baseOffset + start, baseOffset + i, typeName, classType)); @@ -613,7 +661,7 @@ public class ClassPathFinder { // Recursively parse nested content if (nestedStart < i - 1) { String nestedContent = content.substring(nestedStart, i - 1); - parseGenericTypesRecursive(nestedContent, baseOffset + nestedStart, importedClasses, results); + parseGenericTypesRecursive(nestedContent, baseOffset + nestedStart, importedClasses, importedPackages, results); } } } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java b/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java index 0fe40e117..c8e552356 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/JavaTextContainer.java @@ -164,7 +164,7 @@ public class JavaTextContainer extends TextContainer { private void highlightGenericTypes(String genericContent, int contentStart, List marks, List excluded) { if (genericContent == null || genericContent.isEmpty()) return; - List occurrences = classPathFinder.parseGenericTypes(genericContent, importedClasses); + List occurrences = classPathFinder.parseGenericTypes(genericContent, importedClasses, importedPackages); for (ClassPathFinder.TypeOccurrence occ : occurrences) { int absStart = contentStart + occ.startOffset; @@ -680,7 +680,7 @@ public class JavaTextContainer extends TextContainer { if (isImported && !isShadowed) { // Resolve the class to determine its type - ClassPathFinder.ClassInfo info = classPathFinder.resolveSimpleName(className, importedClasses); + ClassPathFinder.ClassInfo info = classPathFinder.resolveSimpleName(className, importedClasses, importedPackages); TokenType tokenType = TokenType.IMPORTED_CLASS; if (info != null) { switch (info.type) { @@ -884,7 +884,7 @@ public class JavaTextContainer extends TextContainer { // This looks like a type declaration // Resolve the main type - ClassPathFinder.ClassInfo info = classPathFinder.resolveSimpleName(typeName, importedClasses); + ClassPathFinder.ClassInfo info = classPathFinder.resolveSimpleName(typeName, importedClasses, importedPackages); TokenType tokenType = TokenType.UNDEFINED_VAR; if (info != null) { switch (info.type) {