Skip to content

Commit b1d7751

Browse files
committed
fix(yakshaintellij): use scratch files for error checking .yaka files
1 parent 2528407 commit b1d7751

File tree

1 file changed

+112
-45
lines changed

1 file changed

+112
-45
lines changed

editor/intellij/src/main/java/org/intellij/sdk/language/YakshaCompilerAnnotator.java

+112-45
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,113 @@
22

33
import com.google.gson.JsonObject;
44
import com.google.gson.JsonParser;
5+
import com.google.gson.JsonSyntaxException;
56
import com.intellij.lang.annotation.AnnotationHolder;
67
import com.intellij.lang.annotation.ExternalAnnotator;
78
import com.intellij.lang.annotation.HighlightSeverity;
9+
import com.intellij.openapi.diagnostic.Logger;
810
import com.intellij.openapi.editor.Document;
9-
import com.intellij.openapi.project.DumbAware;
10-
import com.intellij.openapi.project.Project;
11+
import com.intellij.openapi.editor.Editor;
12+
import com.intellij.openapi.util.Pair;
1113
import com.intellij.openapi.util.TextRange;
14+
import com.intellij.openapi.vfs.LocalFileSystem;
1215
import com.intellij.openapi.vfs.VirtualFile;
13-
import com.intellij.psi.PsiDocumentManager;
1416
import com.intellij.psi.PsiFile;
15-
import com.intellij.psi.PsiManager;
16-
import org.intellij.sdk.language.psi.YakshaFile;
1717
import org.intellij.sdk.language.tw.YakshaToolWindow;
1818
import org.jetbrains.annotations.NotNull;
1919
import org.jetbrains.annotations.Nullable;
2020

21+
import java.io.BufferedWriter;
2122
import java.io.File;
2223
import java.io.IOException;
24+
import java.nio.charset.StandardCharsets;
25+
import java.nio.file.Files;
26+
import java.nio.file.Path;
27+
import java.nio.file.Paths;
2328
import java.util.ArrayList;
2429
import java.util.List;
2530
import java.util.concurrent.TimeUnit;
2631

27-
public class YakshaCompilerAnnotator extends ExternalAnnotator<YakshaFile, List<YakshaCompilerAnnotator.CompilerError>> implements DumbAware {
32+
public class YakshaCompilerAnnotator extends ExternalAnnotator<Pair<Editor, PsiFile>, List<YakshaCompilerAnnotator.CompilerError>> {
33+
34+
private static final Logger LOGGER = Logger.getInstance(YakshaCompilerAnnotator.class);
35+
public static final int MAX_DEPTH = 5;
36+
37+
private static void log(final String s) {
38+
// System.out.println(s);
39+
LOGGER.info(s);
40+
}
41+
2842
@Override
29-
public @Nullable YakshaFile collectInformation(@NotNull PsiFile file) {
30-
if (file instanceof YakshaFile) {
31-
return (YakshaFile) file;
32-
}
33-
return null;
43+
public @Nullable Pair<Editor, PsiFile> collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) {
44+
return Pair.create(editor, file);
3445
}
3546

3647
@Override
37-
public @NotNull List<CompilerError> doAnnotate(@Nullable YakshaFile collectedInfo) {
48+
public @NotNull List<CompilerError> doAnnotate(@Nullable Pair<Editor, PsiFile> collectedInfo) {
3849
if (collectedInfo == null) {
3950
return List.of();
4051
}
41-
final var project = collectedInfo.getProject();
42-
final var virtualFile = collectedInfo.getVirtualFile();
43-
File mainFile = findMainFile(new File(virtualFile.getPath()), 5);
44-
if (mainFile == null) {
52+
final var editor = collectedInfo.first;
53+
final var psiFile = collectedInfo.second;
54+
final var virtualFile = psiFile.getVirtualFile();
55+
56+
File f = new File(virtualFile.getPath());
57+
final File cleanup;
58+
final File directory = f.getParentFile();
59+
60+
if (f.getName().startsWith("_.")) {
61+
log("You are editing a scratch file: " + f.getPath());
4562
return List.of();
4663
}
4764

65+
if (f.getName().equals("main.yaka")) {
66+
final var scratch = Paths.get(directory.getAbsolutePath(), "_.main.yaka");
67+
log("Wrote scratch file:" + scratch);
68+
final var temp = createSyncedFile(editor.getDocument(), scratch);
69+
if (temp == null) {
70+
f = Paths.get(directory.getAbsolutePath(), "_.main.yaka").toFile();
71+
} else {
72+
f = new File(temp.getPath());
73+
}
74+
cleanup = f;
75+
} else {
76+
final var name = "_." + f.getName();
77+
final var scratch = Paths.get(f.getAbsoluteFile().getParent(), name);
78+
cleanup = scratch.toFile();
79+
createSyncedFile(editor.getDocument(), scratch);
80+
log("Wrote scratch file:" + scratch);
81+
f = findMainFile(new File(directory.getPath()));
82+
if (f == null) {
83+
deleteScratch(cleanup);
84+
return List.of();
85+
}
86+
}
87+
88+
final var result = runCompiler(f);
89+
deleteScratch(cleanup);
90+
return result;
91+
}
92+
93+
private static void deleteScratch(@NotNull File f) {
94+
try {
95+
final var success = f.delete();
96+
log("Deleted " + f.getPath() + " success = " + success);
97+
} catch (Exception ignored) {
98+
log("Failed to delete " + f.getPath());
99+
}
100+
}
48101

49-
return runCompiler(mainFile);
102+
private static VirtualFile createSyncedFile(Document doc, Path tmp) {
103+
try {
104+
try (BufferedWriter out = Files.newBufferedWriter(tmp, StandardCharsets.UTF_8)) {
105+
out.write(doc.getText());
106+
}
107+
File f = tmp.toFile();
108+
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(f);
109+
} catch (IOException ex) {
110+
throw new RuntimeException(ex);
111+
}
50112
}
51113

52114
@Override
@@ -59,6 +121,13 @@ public void apply(@NotNull PsiFile file, List<CompilerError> annotationResult, @
59121
if (document == null) {
60122
return;
61123
}
124+
final var f = new File(file.getVirtualFile().getPath());
125+
if (f.getName().startsWith("_.")) {
126+
return;
127+
}
128+
129+
final var givenFile = f.getAbsolutePath();
130+
final var givenFileScratch = Paths.get(Paths.get(givenFile).getParent().toString(), "_." + f.getName()).toFile().getAbsolutePath();
62131

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

70-
holder.newAnnotation(HighlightSeverity.ERROR, error.message).range(new TextRange(startOffset, endOffset)).create();
71-
}
72-
}
139+
final var absPath = new File(error.file).getAbsolutePath();
73140

74-
private @Nullable Document getDoc(Project project, VirtualFile file) {
75-
final var psiFile = PsiManager.getInstance(project).findFile(file);
76-
if (psiFile == null) {
77-
return null;
141+
if (absPath.equals(givenFile) || absPath.equals(givenFileScratch)) {
142+
holder.newAnnotation(HighlightSeverity.ERROR, error.message).range(new TextRange(startOffset, endOffset)).create();
143+
}
78144
}
79-
return PsiDocumentManager.getInstance(project).getDocument(psiFile);
80145
}
81146

82147
public static class CompilerError {
148+
final String file;
83149
final String message;
84150
final int line;
85151
final int column;
86152
final int length;
87153

88-
private CompilerError(final String message, final int line, final int column, final int length) {
154+
private CompilerError(final String file, final String message, final int line, final int column, final int length) {
155+
this.file = file;
89156
this.message = message;
90157
this.line = line;
91158
this.column = column;
92159
this.length = length;
93160
}
94161
}
95162

96-
private File findMainFile(File dir, int maxDepth) {
163+
private File findMainFile(final File dir) {
97164
File currentDir = dir;
98-
for (int i = 0; i <= maxDepth; i++) {
165+
for (int i = 0; i <= YakshaCompilerAnnotator.MAX_DEPTH; i++) {
99166
File mainCFile = new File(currentDir, "main.yaka");
100167
if (mainCFile.exists() && mainCFile.isFile()) {
101168
return mainCFile;
@@ -107,31 +174,28 @@ private File findMainFile(File dir, int maxDepth) {
107174
}
108175

109176
private List<CompilerError> runCompiler(File mainFile) {
110-
List<CompilerError> errors = new ArrayList<>();
177+
final List<CompilerError> errors = new ArrayList<>();
111178
final var compiler = YakshaToolWindow.YAKSHA_EXE_PATH;
112179
if (compiler.isBlank()) {
113-
System.out.println("------ yaksha compiler path is not set -----");
180+
log("------ yaksha compiler path is not set -----");
114181
return errors;
115182
}
116183

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

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

121188
try {
122-
Process process = new ProcessBuilder(command)
123-
.directory(mainFile.getParentFile())
124-
.redirectErrorStream(true)
125-
.start();
189+
final Process process = new ProcessBuilder(command).directory(mainFile.getParentFile()).redirectErrorStream(true).start();
126190

127191
process.waitFor(60, TimeUnit.SECONDS);
128192

129193
String output = new String(process.getInputStream().readAllBytes());
130-
int exitCode = process.exitValue();
131-
132-
errors.addAll(parseCompilerErrors(output, mainFile.getAbsolutePath()));
133-
} catch (IOException | InterruptedException e) {
134-
e.printStackTrace();
194+
final var result = parseCompilerErrors(output, mainFile.getAbsolutePath());
195+
log("Found errors " + result.size());
196+
errors.addAll(result);
197+
} catch (IOException | InterruptedException ignored) {
198+
log("-------------- error ");
135199
}
136200

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

144208
for (String line : lines) {
145209
if (!line.trim().isEmpty()) {
146-
JsonObject json = JsonParser.parseString(line).getAsJsonObject();
210+
final JsonObject json;
211+
try {
212+
json = JsonParser.parseString(line).getAsJsonObject();
213+
} catch (JsonSyntaxException exception) {
214+
continue;
215+
}
147216
String file = json.has("file") ? json.get("file").getAsString() : mainFilePath;
148217
int lineNumber = json.has("line") ? json.get("line").getAsInt() : 0;
149218
int columnNumber = json.has("pos") ? json.get("pos").getAsInt() : 0;
150219
String message = json.get("message").getAsString();
151220
int tokenLength = json.has("token") ? json.get("token").getAsString().length() : 1;
152221

153-
if (mainFilePath.equals(file)) {
154-
errors.add(new CompilerError(message, lineNumber, columnNumber, tokenLength));
155-
}
222+
errors.add(new CompilerError(file, message, lineNumber, columnNumber, tokenLength));
156223
}
157224
}
158225

0 commit comments

Comments
 (0)