highlevel-netcode-gen/src/main/java/electrosphere/main/util/ClassSourceUtils.java

170 lines
6.3 KiB
Java

package electrosphere.main.util;
import java.io.File;
import java.util.List;
import org.jboss.forge.roaster.model.source.Import;
import org.jboss.forge.roaster.model.source.JavaClassSource;
import org.jboss.forge.roaster.model.source.MethodSource;
import electrosphere.main.structure.BTreeIdEnum;
import electrosphere.main.structure.BehaviorTree;
import electrosphere.main.structure.ProjectStructure;
import electrosphere.main.targets.TargetFile;
/**
* Utilities for modifying the source code of a class
*/
public class ClassSourceUtils {
//The default indent for a method, field, etc
static final int DEFAULT_INDENT = 4;
/**
* Adds to replaces a method in a given behavior tree
* @param structure The project structure
* @param targetFile The targetFile
* @param methodName The name of the method
* @param methodContent The content of the method that you want to insert or replace with
*/
public static void addOrReplaceMethod(ProjectStructure structure, TargetFile targetFile, String methodName, String methodContent){
//search for method
List<MethodSource<JavaClassSource>> methods = targetFile.getSource().getMethods();
MethodSource<JavaClassSource> methodSource = null;
for(MethodSource<JavaClassSource> methodRaw : methods){
if(methodRaw.getName().equals(methodName)){
if(methodSource != null){
throw new UnknownError("Two methods in a source file have the same name. This is unsupported by the addOrReplaceMethod function at this time!");
}
methodSource = methodRaw;
}
}
StringBuilder modifiedContent = targetFile.getModifiedContent();
if(methodSource == null){
int endOfClass = findEndOfClass(modifiedContent.toString());
String indentedFragment = TemplateInjectionUtils.indentFragment(methodContent, DEFAULT_INDENT);
//must newline
String finalInsertion = indentedFragment + "\n";
modifiedContent.insert(endOfClass, finalInsertion);
} else {
//methodStart is literally the first character of the function's name
int methodStart = methodSource.getStartPosition();
int indent = getCurrentIndent(modifiedContent.toString(),methodStart - 1);
int methodEnd = methodSource.getEndPosition();
String indentedFragment = TemplateInjectionUtils.indentFragment(methodContent, indent).trim();
modifiedContent.replace(methodStart, methodEnd, indentedFragment);
}
targetFile.setModifiedContent(modifiedContent.toString());
targetFile.reparse();
}
/**
* Finds the end of a class file
* @param sourceRaw The raw source
* @return The index of the final curly brace
*/
private static int findEndOfClass(String sourceRaw){
int curr = sourceRaw.length() - 1;
while(sourceRaw.charAt(curr) != '}'){
curr--;
}
return curr;
}
/**
* Gets the current indent of the source file at a given location
* @param sourceRaw The source file
* @param position The position
* @return The indent
*/
private static int getCurrentIndent(String sourceRaw, int position){
int indent = 0;
int curr = position;
while(sourceRaw.charAt(curr) != '\n'){
curr--;
indent++;
}
return indent;
}
/**
* Generates the first part of a class declaration file
* @param name The name of the class
* @param description The description of the class
* @param isPublic True if public, false otherwise
* @return The string containing the class header
*/
public static String generateClassHeader(String name, String description, boolean isPublic){
String rVal = "/**\n * " + description + "\n */\n";
rVal = rVal + "";
rVal = rVal + (isPublic ? "public " : "");
rVal = rVal + "class " + name + " {\n";
return rVal;
}
/**
* When passed in a file object, returns the package declaration that would be used in code to import that source file
* @param fileObj The raw java file object
* @return The package declaration
*/
public static String getPackageSourcePath(ProjectStructure structure, File fileObj){
String rVal = "";
rVal = structure.getRootFolder().toURI().relativize(fileObj.toURI()).getPath();
//delete past last forwardslash
int lastSlashIndex = rVal.length() - 1;
while(rVal.charAt(lastSlashIndex) != '/'){
lastSlashIndex--;
}
rVal = rVal.substring(0, lastSlashIndex);
//delete intro part
rVal = rVal.replace("src/main/java/", "");
rVal = rVal.replace("/",".");
return rVal;
}
/**
* Gets the package declaration for a given package path
* @param structure The project structure
* @param packagePath The package path
* @return The declaration line
*/
public static String getPackageDeclaration(ProjectStructure structure, String packagePath){
String rVal = "";
rVal = "package " + packagePath + ";\n";
return rVal;
}
/**
* Generates the footer of a class declaration file
* @return The string containing the class footer
*/
public static String generateClassEnd(){
return "}\n";
}
/**
* Guarantees that a given path is imported
* @param structure The project structure
* @param tree The tree
* @param qualifiedPath The qualified name to import
*/
public static void importClass(ProjectStructure structure, TargetFile targetFile, String qualifiedPath){
StringBuilder modifiedContent = targetFile.getModifiedContent();
List<Import> imports = targetFile.getSource().getImports();
boolean present = false;
for(Import currentImport : imports){
String importName = currentImport.getQualifiedName();
if(importName.equals(qualifiedPath)){
present = true;
}
}
if(!present){
Utilities.insertIntoSource(modifiedContent, "import " + qualifiedPath + ";", 3);
targetFile.setModifiedContent(modifiedContent.toString());
}
}
}