mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 21:17:32 +00:00
Added constructors to script class types and hooked up their hover infos
This commit is contained in:
1 parent
dfc0232e99
commit
ce5a67eaa2
6 files changed
+217
-3
No files matched your search
@@ -459,6 +459,45 @@ public class ScriptDocument {
|
||||
methodName, returnType, params, absPos, methodBodyStart, methodBodyEnd, modifiers, documentation);
|
||||
scriptType.addMethod(methodInfo);
|
||||
}
|
||||
|
||||
// Parse constructors (ClassName(params) { ... })
|
||||
// Constructor pattern: ClassName matches the script type name, no return type
|
||||
String typeName = scriptType.getSimpleName();
|
||||
Pattern constructorPattern = Pattern.compile(
|
||||
"\\b" + Pattern.quote(typeName) + "\\s*\\(([^)]*)\\)\\s*\\{");
|
||||
Matcher cm = constructorPattern.matcher(bodyText);
|
||||
while (cm.find()) {
|
||||
int absPos = bodyStart + 1 + cm.start();
|
||||
if (isExcluded(absPos)) continue;
|
||||
|
||||
String paramList = cm.group(1);
|
||||
|
||||
int constructorBodyStart = bodyStart + 1 + cm.end() - 1;
|
||||
int constructorBodyEnd = findMatchingBrace(constructorBodyStart);
|
||||
if (constructorBodyEnd < 0) constructorBodyEnd = bodyEnd;
|
||||
|
||||
// Extract documentation before this constructor
|
||||
String documentation = extractDocumentationBefore(absPos);
|
||||
|
||||
// Extract modifiers by scanning backwards
|
||||
int modifiers = extractModifiersBackwards(cm.start() - 1, bodyText);
|
||||
|
||||
// Parse parameters with their actual positions
|
||||
List<FieldInfo> params = parseParametersWithPositions(paramList, bodyStart + 1 + cm.start(1));
|
||||
|
||||
// Constructors don't have a return type, but we'll use the containing type as a marker
|
||||
MethodInfo constructorInfo = MethodInfo.declaration(
|
||||
typeName,
|
||||
scriptType, // Return type is the type itself
|
||||
params,
|
||||
absPos,
|
||||
constructorBodyStart,
|
||||
constructorBodyEnd,
|
||||
modifiers,
|
||||
documentation
|
||||
);
|
||||
scriptType.addConstructor(constructorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1202,7 +1241,6 @@ public class ScriptDocument {
|
||||
|
||||
// Type declarations and usages
|
||||
markTypeDeclarations(marks);
|
||||
addPatternMarks(marks, NEW_TYPE_PATTERN, TokenType.NEW_TYPE, 1);
|
||||
|
||||
// Methods
|
||||
markMethodDeclarations(marks);
|
||||
@@ -1534,6 +1572,19 @@ public class ScriptDocument {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class to hold both TypeInfo and constructor MethodInfo for "new" expressions.
|
||||
*/
|
||||
static class NewExpressionInfo {
|
||||
final TypeInfo typeInfo;
|
||||
final MethodInfo constructor;
|
||||
|
||||
NewExpressionInfo(TypeInfo typeInfo, MethodInfo constructor) {
|
||||
this.typeInfo = typeInfo;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively parse and mark generic type parameters.
|
||||
* Handles arbitrarily nested generics like Map<String, List<Map<String, String>>>.
|
||||
@@ -2534,6 +2585,19 @@ public class ScriptDocument {
|
||||
marks.add(new ScriptLine.Mark(pos, pos + name.length(), TokenType.PARAMETER, param));
|
||||
}
|
||||
}
|
||||
|
||||
// Mark constructor parameters from script types
|
||||
for (ScriptTypeInfo scriptType : scriptTypes.values()) {
|
||||
for (MethodInfo constructor : scriptType.getConstructors()) {
|
||||
for (FieldInfo param : constructor.getParameters()) {
|
||||
int pos = param.getDeclarationOffset();
|
||||
if (pos >= 0) {
|
||||
String name = param.getName();
|
||||
marks.add(new ScriptLine.Mark(pos, pos + name.length(), TokenType.PARAMETER, param));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pattern identifier = Pattern.compile("\\b([a-zA-Z_][a-zA-Z0-9_]*)\\b");
|
||||
Matcher m = identifier.matcher(text);
|
||||
@@ -3279,6 +3343,7 @@ public class ScriptDocument {
|
||||
|
||||
while (tm.find()) {
|
||||
String className = tm.group(2);
|
||||
String newKeyword = tm.group(1);
|
||||
int start = tm.start(2);
|
||||
int end = tm.end(2);
|
||||
|
||||
@@ -3292,6 +3357,51 @@ public class ScriptDocument {
|
||||
// Try to resolve the class
|
||||
TypeInfo info = resolveType(className);
|
||||
if (info != null && info.isResolved()) {
|
||||
boolean isNewCreation = newKeyword != null && newKeyword.trim().equals("new");
|
||||
boolean isConstructorDecl = info instanceof ScriptTypeInfo && className.equals(info.getSimpleName());
|
||||
|
||||
// Check if this is a "new" expression or constructor declaration
|
||||
if (isNewCreation || isConstructorDecl) {
|
||||
// Find opening paren after the class name
|
||||
int searchPos = end;
|
||||
while (searchPos < text.length() && Character.isWhitespace(text.charAt(searchPos)))
|
||||
searchPos++;
|
||||
|
||||
if (searchPos < text.length() && text.charAt(searchPos) == '(') {
|
||||
int openParen = searchPos;
|
||||
int closeParen = findMatchingParen(openParen);
|
||||
|
||||
if (closeParen >= 0) {
|
||||
// For constructor declarations, verify it's followed by opening brace
|
||||
if (isConstructorDecl && !isNewCreation) {
|
||||
int braceSearch = closeParen + 1;
|
||||
while (braceSearch < text.length() && Character.isWhitespace(text.charAt(braceSearch)))
|
||||
braceSearch++;
|
||||
|
||||
if (braceSearch >= text.length() || text.charAt(braceSearch) != '{') {
|
||||
// Not a constructor declaration, treat as normal type usage
|
||||
marks.add(new ScriptLine.Mark(start, end, info.getTokenType(), info));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse arguments to find matching constructor
|
||||
List<MethodCallInfo.Argument> arguments = parseMethodArguments(openParen + 1, closeParen);
|
||||
int argCount = arguments.size();
|
||||
|
||||
if (info.hasConstructors()) {
|
||||
MethodInfo constructor = info.findConstructor(argCount);
|
||||
if (constructor != null) {
|
||||
// Attach both type info and constructor
|
||||
NewExpressionInfo newExpr = new NewExpressionInfo(info, constructor);
|
||||
marks.add(new ScriptLine.Mark(start, end, info.getTokenType(), newExpr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
marks.add(new ScriptLine.Mark(start, end, info.getTokenType(), info));
|
||||
} else {
|
||||
// Unknown type - mark as undefined
|
||||
|
||||
@@ -152,6 +152,10 @@ public class ScriptLine {
|
||||
if (mark.metadata != null) {
|
||||
if (mark.metadata instanceof TypeInfo) {
|
||||
token.setTypeInfo((TypeInfo) mark.metadata);
|
||||
} else if (mark.metadata instanceof ScriptDocument.NewExpressionInfo) {
|
||||
ScriptDocument.NewExpressionInfo newExpr = (ScriptDocument.NewExpressionInfo) mark.metadata;
|
||||
token.setTypeInfo(newExpr.typeInfo);
|
||||
token.setMethodInfo(newExpr.constructor);
|
||||
} else if (mark.metadata instanceof FieldInfo.ArgInfo) {
|
||||
FieldInfo.ArgInfo ctx = (FieldInfo.ArgInfo) mark.metadata;
|
||||
token.setFieldInfo(ctx.fieldInfo);
|
||||
|
||||
@@ -23,6 +23,7 @@ public class ScriptTypeInfo extends TypeInfo {
|
||||
// Script-defined members
|
||||
private final Map<String, FieldInfo> fields = new HashMap<>();
|
||||
private final Map<String, List<MethodInfo>> methods = new HashMap<>(); // name -> list of overloads
|
||||
private final List<MethodInfo> constructors = new ArrayList<>(); // List of constructors
|
||||
private final List<ScriptTypeInfo> innerClasses = new ArrayList<>();
|
||||
|
||||
// Parent class reference (for inner class resolution)
|
||||
@@ -143,6 +144,36 @@ public class ScriptTypeInfo extends TypeInfo {
|
||||
return new HashMap<>(methods);
|
||||
}
|
||||
|
||||
// ==================== CONSTRUCTOR MANAGEMENT ====================
|
||||
|
||||
public void addConstructor(MethodInfo constructor) {
|
||||
constructors.add(constructor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MethodInfo> getConstructors() {
|
||||
return new ArrayList<>(constructors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConstructors() {
|
||||
return !constructors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the best matching constructor for the given argument count.
|
||||
* Returns null if no constructor matches.
|
||||
*/
|
||||
@Override
|
||||
public MethodInfo findConstructor(int argCount) {
|
||||
for (MethodInfo constructor : constructors) {
|
||||
if (constructor.getParameterCount() == argCount) {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ==================== INNER CLASS LOOKUP ====================
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package noppes.npcs.client.gui.util.script.interpreter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents resolved type information for a class/interface/enum.
|
||||
* Base class for type metadata. Extended by ScriptTypeInfo for script-defined types.
|
||||
@@ -175,6 +178,30 @@ public class TypeInfo {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this type has constructors.
|
||||
* Override in ScriptTypeInfo for script-defined types.
|
||||
*/
|
||||
public boolean hasConstructors() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the constructors for this type.
|
||||
* Override in ScriptTypeInfo for script-defined types.
|
||||
*/
|
||||
public List<MethodInfo> getConstructors() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the best matching constructor for the given argument count.
|
||||
* Override in ScriptTypeInfo for script-defined types.
|
||||
*/
|
||||
public MethodInfo findConstructor(int argCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this type has a field with the given name.
|
||||
|
||||
@@ -151,7 +151,7 @@ public class HoverState {
|
||||
public void update(int mouseX, int mouseY, Token token, int tokenX, int tokenY, int tokenW) {
|
||||
lastMouseX = mouseX;
|
||||
lastMouseY = mouseY;
|
||||
clickToPinEnabled=false;
|
||||
clickToPinEnabled=true;
|
||||
// If a token has been pinned by click, ignore mouse movement updates
|
||||
if (pinnedToken != null) {
|
||||
// keep pinned tooltip visible
|
||||
|
||||
+43
-1
@@ -397,6 +397,14 @@ public class TokenHoverInfo {
|
||||
errors.add("Cannot resolve class '" + typeInfo.getSimpleName() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a NEW_TYPE token with constructor info, show the constructor signature
|
||||
if (token.getMethodInfo() != null) {
|
||||
MethodInfo constructor = token.getMethodInfo();
|
||||
declaration.add(new TextSegment("\n", TokenType.DEFAULT.getHexColor()));
|
||||
additionalInfo.add("Constructor");
|
||||
buildConstructorDeclaration(constructor, typeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void extractMethodCallInfo(Token token) {
|
||||
@@ -607,7 +615,41 @@ public class TokenHoverInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== HELPER METHODS ====================
|
||||
private void buildConstructorDeclaration(MethodInfo constructor, TypeInfo containingType) {
|
||||
// Modifiers (public, private, etc.)
|
||||
declaration.clear();
|
||||
int mods = constructor.getModifiers();
|
||||
if (Modifier.isPublic(mods)) addSegment("public ", TokenType.MODIFIER.getHexColor());
|
||||
else if (Modifier.isProtected(mods)) addSegment("protected ", TokenType.MODIFIER.getHexColor());
|
||||
else if (Modifier.isPrivate(mods)) addSegment("private ", TokenType.MODIFIER.getHexColor());
|
||||
|
||||
// Constructor name (same as class name)
|
||||
addSegment(constructor.getName(), containingType.getTokenType().getHexColor());
|
||||
|
||||
// Parameters
|
||||
addSegment("(", TokenType.DEFAULT.getHexColor());
|
||||
List<FieldInfo> params = constructor.getParameters();
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
if (i > 0) addSegment(", ", TokenType.DEFAULT.getHexColor());
|
||||
FieldInfo param = params.get(i);
|
||||
TypeInfo paramType = param.getDeclaredType();
|
||||
if (paramType != null) {
|
||||
int paramTypeColor = getColorForTypeInfo(paramType);
|
||||
addSegment(paramType.getSimpleName(), paramTypeColor);
|
||||
addSegment(" ", TokenType.DEFAULT.getHexColor());
|
||||
}
|
||||
addSegment(param.getName(), TokenType.PARAMETER.getHexColor());
|
||||
}
|
||||
addSegment(")", TokenType.DEFAULT.getHexColor());
|
||||
|
||||
// Add documentation if available
|
||||
if (constructor.getDocumentation() != null && !constructor.getDocumentation().isEmpty()) {
|
||||
String[] docLines = constructor.getDocumentation().split("\n");
|
||||
for (String line : docLines) {
|
||||
documentation.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addSegment(String text, int color) {
|
||||
declaration.add(new TextSegment(text, color));
|
||||
|
||||
Reference in new issue
Block a user