Skip to content

Commit

Permalink
fix(yakshaintellij): use scratch files for error checking .yaka files
Browse files Browse the repository at this point in the history
  • Loading branch information
JaDogg committed May 26, 2024
1 parent 2528407 commit b1d7751
Showing 1 changed file with 112 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,113 @@

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.ExternalAnnotator;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.intellij.sdk.language.psi.YakshaFile;
import org.intellij.sdk.language.tw.YakshaToolWindow;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class YakshaCompilerAnnotator extends ExternalAnnotator<YakshaFile, List<YakshaCompilerAnnotator.CompilerError>> implements DumbAware {
public class YakshaCompilerAnnotator extends ExternalAnnotator<Pair<Editor, PsiFile>, List<YakshaCompilerAnnotator.CompilerError>> {

private static final Logger LOGGER = Logger.getInstance(YakshaCompilerAnnotator.class);
public static final int MAX_DEPTH = 5;

private static void log(final String s) {
// System.out.println(s);
LOGGER.info(s);
}

@Override
public @Nullable YakshaFile collectInformation(@NotNull PsiFile file) {
if (file instanceof YakshaFile) {
return (YakshaFile) file;
}
return null;
public @Nullable Pair<Editor, PsiFile> collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) {
return Pair.create(editor, file);
}

@Override
public @NotNull List<CompilerError> doAnnotate(@Nullable YakshaFile collectedInfo) {
public @NotNull List<CompilerError> doAnnotate(@Nullable Pair<Editor, PsiFile> collectedInfo) {
if (collectedInfo == null) {
return List.of();
}
final var project = collectedInfo.getProject();
final var virtualFile = collectedInfo.getVirtualFile();
File mainFile = findMainFile(new File(virtualFile.getPath()), 5);
if (mainFile == null) {
final var editor = collectedInfo.first;
final var psiFile = collectedInfo.second;
final var virtualFile = psiFile.getVirtualFile();

File f = new File(virtualFile.getPath());
final File cleanup;
final File directory = f.getParentFile();

if (f.getName().startsWith("_.")) {
log("You are editing a scratch file: " + f.getPath());
return List.of();
}

if (f.getName().equals("main.yaka")) {
final var scratch = Paths.get(directory.getAbsolutePath(), "_.main.yaka");
log("Wrote scratch file:" + scratch);
final var temp = createSyncedFile(editor.getDocument(), scratch);
if (temp == null) {
f = Paths.get(directory.getAbsolutePath(), "_.main.yaka").toFile();
} else {
f = new File(temp.getPath());
}
cleanup = f;
} else {
final var name = "_." + f.getName();
final var scratch = Paths.get(f.getAbsoluteFile().getParent(), name);
cleanup = scratch.toFile();
createSyncedFile(editor.getDocument(), scratch);
log("Wrote scratch file:" + scratch);
f = findMainFile(new File(directory.getPath()));
if (f == null) {
deleteScratch(cleanup);
return List.of();
}
}

final var result = runCompiler(f);
deleteScratch(cleanup);
return result;
}

private static void deleteScratch(@NotNull File f) {
try {
final var success = f.delete();
log("Deleted " + f.getPath() + " success = " + success);
} catch (Exception ignored) {
log("Failed to delete " + f.getPath());
}
}

return runCompiler(mainFile);
private static VirtualFile createSyncedFile(Document doc, Path tmp) {
try {
try (BufferedWriter out = Files.newBufferedWriter(tmp, StandardCharsets.UTF_8)) {
out.write(doc.getText());
}
File f = tmp.toFile();
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}

@Override
Expand All @@ -59,6 +121,13 @@ public void apply(@NotNull PsiFile file, List<CompilerError> annotationResult, @
if (document == null) {
return;
}
final var f = new File(file.getVirtualFile().getPath());
if (f.getName().startsWith("_.")) {
return;
}

final var givenFile = f.getAbsolutePath();
final var givenFileScratch = Paths.get(Paths.get(givenFile).getParent().toString(), "_." + f.getName()).toFile().getAbsolutePath();

for (CompilerError error : annotationResult) {
var line = error.line - 1;
Expand All @@ -67,35 +136,33 @@ public void apply(@NotNull PsiFile file, List<CompilerError> annotationResult, @
var startOffset = document.getLineStartOffset(line) + error.column - 1;
var endOffset = startOffset + error.length;

holder.newAnnotation(HighlightSeverity.ERROR, error.message).range(new TextRange(startOffset, endOffset)).create();
}
}
final var absPath = new File(error.file).getAbsolutePath();

private @Nullable Document getDoc(Project project, VirtualFile file) {
final var psiFile = PsiManager.getInstance(project).findFile(file);
if (psiFile == null) {
return null;
if (absPath.equals(givenFile) || absPath.equals(givenFileScratch)) {
holder.newAnnotation(HighlightSeverity.ERROR, error.message).range(new TextRange(startOffset, endOffset)).create();
}
}
return PsiDocumentManager.getInstance(project).getDocument(psiFile);
}

public static class CompilerError {
final String file;
final String message;
final int line;
final int column;
final int length;

private CompilerError(final String message, final int line, final int column, final int length) {
private CompilerError(final String file, final String message, final int line, final int column, final int length) {
this.file = file;
this.message = message;
this.line = line;
this.column = column;
this.length = length;
}
}

private File findMainFile(File dir, int maxDepth) {
private File findMainFile(final File dir) {
File currentDir = dir;
for (int i = 0; i <= maxDepth; i++) {
for (int i = 0; i <= YakshaCompilerAnnotator.MAX_DEPTH; i++) {
File mainCFile = new File(currentDir, "main.yaka");
if (mainCFile.exists() && mainCFile.isFile()) {
return mainCFile;
Expand All @@ -107,31 +174,28 @@ private File findMainFile(File dir, int maxDepth) {
}

private List<CompilerError> runCompiler(File mainFile) {
List<CompilerError> errors = new ArrayList<>();
final List<CompilerError> errors = new ArrayList<>();
final var compiler = YakshaToolWindow.YAKSHA_EXE_PATH;
if (compiler.isBlank()) {
System.out.println("------ yaksha compiler path is not set -----");
log("------ yaksha compiler path is not set -----");
return errors;
}

System.out.println("----- yaksha compiler: " + compiler);
log("----- yaksha compiler: " + compiler);

List<String> command = List.of(compiler, "compile", "-d", mainFile.getAbsolutePath());
final List<String> command = List.of(compiler, "compile", "-d", "-e", mainFile.getAbsolutePath());

try {
Process process = new ProcessBuilder(command)
.directory(mainFile.getParentFile())
.redirectErrorStream(true)
.start();
final Process process = new ProcessBuilder(command).directory(mainFile.getParentFile()).redirectErrorStream(true).start();

process.waitFor(60, TimeUnit.SECONDS);

String output = new String(process.getInputStream().readAllBytes());
int exitCode = process.exitValue();

errors.addAll(parseCompilerErrors(output, mainFile.getAbsolutePath()));
} catch (IOException | InterruptedException e) {
e.printStackTrace();
final var result = parseCompilerErrors(output, mainFile.getAbsolutePath());
log("Found errors " + result.size());
errors.addAll(result);
} catch (IOException | InterruptedException ignored) {
log("-------------- error ");
}

return errors;
Expand All @@ -143,16 +207,19 @@ private List<CompilerError> parseCompilerErrors(String output, String mainFilePa

for (String line : lines) {
if (!line.trim().isEmpty()) {
JsonObject json = JsonParser.parseString(line).getAsJsonObject();
final JsonObject json;
try {
json = JsonParser.parseString(line).getAsJsonObject();
} catch (JsonSyntaxException exception) {
continue;
}
String file = json.has("file") ? json.get("file").getAsString() : mainFilePath;
int lineNumber = json.has("line") ? json.get("line").getAsInt() : 0;
int columnNumber = json.has("pos") ? json.get("pos").getAsInt() : 0;
String message = json.get("message").getAsString();
int tokenLength = json.has("token") ? json.get("token").getAsString().length() : 1;

if (mainFilePath.equals(file)) {
errors.add(new CompilerError(message, lineNumber, columnNumber, tokenLength));
}
errors.add(new CompilerError(file, message, lineNumber, columnNumber, tokenLength));
}
}

Expand Down

0 comments on commit b1d7751

Please sign in to comment.