mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 21:17:32 +00:00
Added init values to declaration of local/global fields and their hover info
This commit is contained in:
1 parent
c4bbf6108b
commit
a9cd2ec7ef
3 files changed
+125
-10
No files matched your search
@@ -18,12 +18,17 @@ public final class FieldInfo {
|
||||
private final int declarationOffset; // Where this field was declared in the source
|
||||
private final boolean resolved;
|
||||
private final String documentation; // Javadoc/comment documentation for this field
|
||||
|
||||
// Initialization value range (for displaying "= value" in hover info)
|
||||
private final int initStart; // Position of '=' or -1 if no initializer
|
||||
private final int initEnd; // Position after initializer (before ';') or -1
|
||||
|
||||
// For local/parameter fields, track the containing method
|
||||
private final MethodInfo containingMethod;
|
||||
|
||||
private FieldInfo(String name, Scope scope, TypeInfo declaredType,
|
||||
int declarationOffset, boolean resolved, MethodInfo containingMethod, String documentation) {
|
||||
int declarationOffset, boolean resolved, MethodInfo containingMethod,
|
||||
String documentation, int initStart, int initEnd) {
|
||||
this.name = name;
|
||||
this.scope = scope;
|
||||
this.declaredType = declaredType;
|
||||
@@ -31,34 +36,44 @@ public final class FieldInfo {
|
||||
this.resolved = resolved;
|
||||
this.containingMethod = containingMethod;
|
||||
this.documentation = documentation;
|
||||
this.initStart = initStart;
|
||||
this.initEnd = initEnd;
|
||||
}
|
||||
|
||||
// Factory methods
|
||||
public static FieldInfo globalField(String name, TypeInfo type, int declOffset) {
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, declOffset, type != null && type.isResolved(), null, null);
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, declOffset, type != null && type.isResolved(), null, null, -1, -1);
|
||||
}
|
||||
|
||||
public static FieldInfo globalField(String name, TypeInfo type, int declOffset, String documentation) {
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, declOffset, type != null && type.isResolved(), null, documentation);
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, declOffset, type != null && type.isResolved(), null, documentation, -1, -1);
|
||||
}
|
||||
|
||||
public static FieldInfo globalField(String name, TypeInfo type, int declOffset, String documentation, int initStart, int initEnd) {
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, declOffset, type != null && type.isResolved(), null, documentation, initStart, initEnd);
|
||||
}
|
||||
|
||||
public static FieldInfo localField(String name, TypeInfo type, int declOffset, MethodInfo method) {
|
||||
return new FieldInfo(name, Scope.LOCAL, type, declOffset, type != null && type.isResolved(), method, null);
|
||||
return new FieldInfo(name, Scope.LOCAL, type, declOffset, type != null && type.isResolved(), method, null, -1, -1);
|
||||
}
|
||||
|
||||
public static FieldInfo localField(String name, TypeInfo type, int declOffset, MethodInfo method, int initStart, int initEnd) {
|
||||
return new FieldInfo(name, Scope.LOCAL, type, declOffset, type != null && type.isResolved(), method, null, initStart, initEnd);
|
||||
}
|
||||
|
||||
public static FieldInfo parameter(String name, TypeInfo type, int declOffset, MethodInfo method) {
|
||||
return new FieldInfo(name, Scope.PARAMETER, type, declOffset, type != null && type.isResolved(), method, null);
|
||||
return new FieldInfo(name, Scope.PARAMETER, type, declOffset, type != null && type.isResolved(), method, null, -1, -1);
|
||||
}
|
||||
|
||||
public static FieldInfo unresolved(String name, Scope scope) {
|
||||
return new FieldInfo(name, scope, null, -1, false, null, null);
|
||||
return new FieldInfo(name, scope, null, -1, false, null, null, -1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a FieldInfo from reflection data for method parameters.
|
||||
*/
|
||||
public static FieldInfo reflectionParam(String name, TypeInfo type) {
|
||||
return new FieldInfo(name, Scope.PARAMETER, type, -1, true, null, null);
|
||||
return new FieldInfo(name, Scope.PARAMETER, type, -1, true, null, null, -1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +82,7 @@ public final class FieldInfo {
|
||||
public static FieldInfo fromReflection(java.lang.reflect.Field field, TypeInfo containingType) {
|
||||
String name = field.getName();
|
||||
TypeInfo type = TypeInfo.fromClass(field.getType());
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, -1, true, null, null);
|
||||
return new FieldInfo(name, Scope.GLOBAL, type, -1, true, null, null, -1, -1);
|
||||
}
|
||||
|
||||
// Getters
|
||||
@@ -79,6 +94,9 @@ public final class FieldInfo {
|
||||
public boolean isResolved() { return resolved; }
|
||||
public MethodInfo getContainingMethod() { return containingMethod; }
|
||||
public String getDocumentation() { return documentation; }
|
||||
public int getInitStart() { return initStart; }
|
||||
public int getInitEnd() { return initEnd; }
|
||||
public boolean hasInitializer() { return initStart >= 0 && initEnd > initStart; }
|
||||
|
||||
public boolean isGlobal() { return scope == Scope.GLOBAL; }
|
||||
public boolean isLocal() { return scope == Scope.LOCAL; }
|
||||
|
||||
@@ -583,8 +583,28 @@ public class ScriptDocument {
|
||||
typeInfo = resolveType(typeName);
|
||||
}
|
||||
|
||||
// Extract initialization range if there's an '=' delimiter
|
||||
int initStart = -1;
|
||||
int initEnd = -1;
|
||||
if ("=".equals(delimiter)) {
|
||||
initStart = bodyStart + m.start(3); // Absolute position of '='
|
||||
// Find the semicolon or comma that ends this declaration
|
||||
int searchPos = bodyStart + m.end(3);
|
||||
int depth = 0; // Track nested parens/brackets/braces
|
||||
while (searchPos < text.length()) {
|
||||
char c = text.charAt(searchPos);
|
||||
if (c == '(' || c == '[' || c == '{') depth++;
|
||||
else if (c == ')' || c == ']' || c == '}') depth--;
|
||||
else if ((c == ';' || c == ',') && depth == 0) {
|
||||
initEnd = searchPos; // Position of ';' or ',' (exclusive)
|
||||
break;
|
||||
}
|
||||
searchPos++;
|
||||
}
|
||||
}
|
||||
|
||||
int declPos = bodyStart + m.start(2);
|
||||
FieldInfo fieldInfo = FieldInfo.localField(varName, typeInfo, declPos, method);
|
||||
FieldInfo fieldInfo = FieldInfo.localField(varName, typeInfo, declPos, method, initStart, initEnd);
|
||||
locals.put(varName, fieldInfo);
|
||||
}
|
||||
}
|
||||
@@ -776,6 +796,7 @@ public class ScriptDocument {
|
||||
while (m.find()) {
|
||||
String typeNameRaw = m.group(1);
|
||||
String fieldName = m.group(2);
|
||||
String delimiter = m.group(3);
|
||||
int position = m.start(2);
|
||||
|
||||
// Skip if the field name itself is excluded
|
||||
@@ -798,8 +819,28 @@ public class ScriptDocument {
|
||||
// Extract documentation before this field
|
||||
String documentation = extractDocumentationBefore(m.start());
|
||||
|
||||
// Extract initialization range if there's an '=' delimiter
|
||||
int initStart = -1;
|
||||
int initEnd = -1;
|
||||
if ("=".equals(delimiter)) {
|
||||
initStart = m.start(3); // Position of '='
|
||||
// Find the semicolon that ends this declaration
|
||||
int searchPos = m.end(3);
|
||||
int depth = 0; // Track nested parens/brackets/braces
|
||||
while (searchPos < text.length()) {
|
||||
char c = text.charAt(searchPos);
|
||||
if (c == '(' || c == '[' || c == '{') depth++;
|
||||
else if (c == ')' || c == ']' || c == '}') depth--;
|
||||
else if (c == ';' && depth == 0) {
|
||||
initEnd = searchPos; // Position of ';' (exclusive)
|
||||
break;
|
||||
}
|
||||
searchPos++;
|
||||
}
|
||||
}
|
||||
|
||||
TypeInfo typeInfo = resolveType(typeName);
|
||||
FieldInfo fieldInfo = FieldInfo.globalField(fieldName, typeInfo, position, documentation);
|
||||
FieldInfo fieldInfo = FieldInfo.globalField(fieldName, typeInfo, position, documentation, initStart, initEnd);
|
||||
globalFields.put(fieldName, fieldInfo);
|
||||
}
|
||||
}
|
||||
@@ -3061,6 +3102,31 @@ public class ScriptDocument {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all tokens that fall within a given range [start, end).
|
||||
* Returns tokens in order. Tokens that span across the range boundaries
|
||||
* are included if any part of them is within the range.
|
||||
*/
|
||||
public List<Token> getTokensInRange(int start, int end) {
|
||||
List<Token> result = new ArrayList<>();
|
||||
if (start < 0 || end <= start) return result;
|
||||
|
||||
for (ScriptLine line : lines) {
|
||||
// Skip lines entirely before the range
|
||||
if (line.getGlobalEnd() <= start) continue;
|
||||
// Stop if line is entirely after the range
|
||||
if (line.getGlobalStart() >= end) break;
|
||||
|
||||
for (Token token : line.getTokens()) {
|
||||
// Check if token overlaps with range
|
||||
if (token.getGlobalEnd() > start && token.getGlobalStart() < end) {
|
||||
result.add(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the expected type for an expression at the given position by looking for assignment context.
|
||||
|
||||
+31
@@ -464,6 +464,9 @@ public class TokenHoverInfo {
|
||||
|
||||
// Field name
|
||||
addSegment(fieldInfo.getName(), TokenType.GLOBAL_FIELD.getHexColor());
|
||||
|
||||
// Add initialization value if available
|
||||
addInitializationTokens(token, fieldInfo);
|
||||
}
|
||||
|
||||
private void extractLocalFieldInfo(Token token) {
|
||||
@@ -489,6 +492,9 @@ public class TokenHoverInfo {
|
||||
|
||||
addSegment(fieldInfo.getName(), TokenType.LOCAL_FIELD.getHexColor());
|
||||
|
||||
// Add initialization value if available
|
||||
addInitializationTokens(token, fieldInfo);
|
||||
|
||||
// Show it's a local variable
|
||||
additionalInfo.add("Local variable");
|
||||
}
|
||||
@@ -750,6 +756,31 @@ public class TokenHoverInfo {
|
||||
}
|
||||
return TokenType.IMPORTED_CLASS.getHexColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add initialization tokens from the field's initializer to the declaration.
|
||||
* Fetches the tokens in the initialization range and adds them with their proper coloring.
|
||||
*/
|
||||
private void addInitializationTokens(Token token, FieldInfo fieldInfo) {
|
||||
if (!fieldInfo.hasInitializer()) return;
|
||||
|
||||
ScriptLine line = token.getParentLine();
|
||||
if (line == null || line.getParent() == null) return;
|
||||
|
||||
ScriptDocument doc = line.getParent();
|
||||
// Include the semicolon by extending range by 1
|
||||
List<Token> initTokens = doc.getTokensInRange(fieldInfo.getInitStart(), fieldInfo.getInitEnd() + 1);
|
||||
|
||||
if (initTokens.isEmpty()) return;
|
||||
|
||||
// Add space before '=' for readability
|
||||
addSegment(" ", TokenType.DEFAULT.getHexColor());
|
||||
|
||||
// Add each token with its proper color
|
||||
for (Token initToken : initTokens) {
|
||||
addSegment(initToken.getText(), initToken.getType().getHexColor());
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== GETTERS ====================
|
||||
|
||||
|
||||
Reference in new issue
Block a user