package com.jetbrains.lang.dart.ide.runner.server;
import com.intellij.execution.ConsoleFolding;
import com.intellij.execution.configurations.CommandLineTokenizer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.PathUtil;
import com.jetbrains.lang.dart.ide.runner.DartConsoleFilter;
import com.jetbrains.lang.dart.sdk.DartSdkUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.List;
import java.util.Locale;
public class DartConsoleFolding extends ConsoleFolding {
private static final String DART_MARKER = SystemInfo.isWindows ? "\\bin\\dart.exe " : "/bin/dart ";
private static final String TEST_RUNNER_MARKER = "pub.dart.snapshot run test:test -r json "; // see DartTestRunningState.startProcess()
private static final int MIN_FRAME_DISPLAY_COUNT = 8;
private int myFrameCount = 0;
@Override
public boolean shouldFoldLine(@NotNull final String line) {
// check for a stack trace
if (isFrameLine(line)) {
myFrameCount++;
// Show the first n frames and fold the rest.
return myFrameCount > MIN_FRAME_DISPLAY_COUNT;
}
myFrameCount = 0;
// fold Dart VM command line created in DartCommandLineRunningState.createCommandLine() together with the following "Observatory listening on ..." message
if (line.startsWith(DartConsoleFilter.OBSERVATORY_LISTENING_ON)) return true;
final int index = line.indexOf(DART_MARKER);
if (index < 0) return false;
final String probablySdkPath = line.substring(0, index);
return DartSdkUtil.isDartSdkHome(probablySdkPath);
}
@Nullable
@Override
public String getPlaceholderText(@NotNull final List<String> lines) {
// C:\dart-sdk\bin\dart.exe --checked --pause_isolates_on_start --enable-vm-service:55465 C:\dart_projects\DartSample\bin\file1.dart arg
// is collapsed to "dart file1.dart arg"
// depending on the Moon phase (well, on initialization speed) we may get lines.size() == 2 where first line is Dart VM startup and 2nd line is Observatory URL)
// but more frequently we get these 2 lines one by one
if (lines.size() == 1 && lines.get(0).startsWith(DartConsoleFilter.OBSERVATORY_LISTENING_ON)) {
return " [Observatory: " + lines.get(0).substring(DartConsoleFilter.OBSERVATORY_LISTENING_ON.length()) + "]";
}
if (lines.size() == 1 && lines.get(0).contains(TEST_RUNNER_MARKER)) {
return foldTestRunnerCommand(lines.get(0));
}
// exception folding
if (isFrameLine(lines.get(0))) {
return " [" + lines.size() + " more...]";
}
final String fullText = StringUtil.join(lines, "\n");
if (!lines.get(0).contains(DART_MARKER) ||
lines.size() == 2 && !lines.get(1).startsWith(DartConsoleFilter.OBSERVATORY_LISTENING_ON) ||
lines.size() > 2) {
// unexpected text
return fullText;
}
final String line = lines.get(0);
int index = line.indexOf(' ');
assert index > 0 && line.substring(0, index + 1).endsWith(DART_MARKER) : line;
while (line.length() > index + 1 && line.charAt(index + 1) == '-') {
index = line.indexOf(" ", index + 1);
}
if (index < 0) return fullText; // can't happen
final CommandLineTokenizer tok = new CommandLineTokenizer(line.substring(index));
if (!tok.hasMoreTokens()) return fullText; // can't happen
final String filePath = tok.nextToken();
if (!filePath.contains(File.separator)) return fullText; // can't happen
final StringBuilder b = new StringBuilder();
b.append("dart ");
b.append(PathUtil.getFileName(filePath));
while (tok.hasMoreTokens()) {
b.append(" ").append(tok.nextToken()); // program arguments
}
if (lines.size() == 2 && lines.get(1).startsWith(DartConsoleFilter.OBSERVATORY_LISTENING_ON)) {
b.append(" [Observatory: ").append(lines.get(1).substring(DartConsoleFilter.OBSERVATORY_LISTENING_ON.length())).append("]");
}
return b.toString();
}
private boolean isFrameLine(@NotNull final String line) {
// Handle the "..." ellipses in the middle of a stack overflow trace.
if (myFrameCount > 0 && line.equals("...")) return true;
// Handle "<asynchronous suspension>".
if (myFrameCount > 0 && line.startsWith("<async") && line.endsWith(">")) return true;
// #1 main (file:///Users/foo/projects/bar/tool/generate.dart:30:3)
if (!line.startsWith("#") || !line.endsWith(")")) return false;
if (line.length() < "#1234567x (x)".length()) return false;
if (line.charAt(8) == ' ') return false;
try {
//noinspection ResultOfMethodCallIgnored
Integer.parseInt(line.substring(1, 8).trim());
return true;
}
catch (Throwable t) {
return false;
}
}
private static String foldTestRunnerCommand(@NotNull final String line) {
// C:\dart-sdk\bin\dart.exe --checked file:\\\C:\dart-sdk\bin\snapshots\pub.dart.snapshot run test:test -r json --concurrency=4 C:/MyProject/test/main_test.dart -n "group1 test21|group1 test22"
// folded to
// pub run test main_test.dart -n "group1 test21|group1 test22"
int index = line.indexOf(TEST_RUNNER_MARKER);
index += TEST_RUNNER_MARKER.length();
index = line.toLowerCase(Locale.US).indexOf(".dart", index);
if (index < 0) return line;
index = FileUtil.toSystemIndependentName(line.substring(0, index)).lastIndexOf('/');
if (index < 0) return line;
return "pub run test " + line.substring(index + 1);
}
}