Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;

/** Opens the source location a report points at (its culprit / stack frame) in the editor. */
final class ReportNavigator {
Expand All @@ -17,13 +21,39 @@ private ReportNavigator() {

static boolean navigate(Project project, StFrame frame) {
if (frame == null) return false;
// index queries need a read action; the file lives by simple name in the report

// Index queries need a read action; the file lives by simple name in the report.
Collection<VirtualFile> files = ReadAction.compute(() ->
FilenameIndex.getVirtualFilesByName(frame.fileName(), GlobalSearchScope.projectScope(project)));

if (files.isEmpty()) return false;
VirtualFile target = files.iterator().next();
// OpenFileDescriptor lines are 0-based; report lines are 1-based
new OpenFileDescriptor(project, target, Math.max(0, frame.line() - 1), 0).navigate(true);

List<VirtualFile> candidates = new ArrayList<>(files);
candidates.sort(Comparator.comparing(VirtualFile::getPath));

if (candidates.size() > 1) {
JBPopupFactory.getInstance()
.createPopupChooserBuilder(candidates)
.setTitle("Choose Source File")
.setItemChosenCallback(target ->
openSource(project, target, frame.line()))
.createPopup()
.showCenteredInCurrentWindow(project);

return true;
}

openSource(project, candidates.get(0), frame.line());
return true;
}
}

private static void openSource(Project project, VirtualFile target, int line) {
// OpenFileDescriptor lines are 0-based; report lines are 1-based.
new OpenFileDescriptor(
project,
target,
Math.max(0, line - 1),
0
).navigate(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.SimpleToolWindowPanel;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.JBSplitter;
Expand Down Expand Up @@ -44,15 +45,17 @@ class StacktalePanel extends SimpleToolWindowPanel {
private static final int POLL_MILLIS = 3000;

private final Project project;
private final ToolWindow toolWindow;
private final DefaultListModel<StReport> model = new DefaultListModel<>();
private final JBList<StReport> list = new JBList<>(model);
private final JTextArea detail = new JTextArea();
private final Alarm alarm;
private String lastContent = "";
private String lastContent;

StacktalePanel(Project project) {
StacktalePanel(Project project, ToolWindow toolWindow) {
super(true, true);
this.project = project;
this.toolWindow = toolWindow;
this.alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project);

list.setCellRenderer(new ReportCellRenderer());
Expand Down Expand Up @@ -82,7 +85,7 @@ private ActionToolbar buildToolbar() {
group.add(new AnAction("Refresh", "Re-read errors-ai.log", AllIcons.Actions.Refresh) {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
lastContent = ""; // force a re-read
lastContent = null; // force a re-read
refresh();
}
});
Expand Down Expand Up @@ -113,12 +116,16 @@ private void schedulePoll() {
private void refresh() {
Path log = findLog();
if (log == null) {
toolWindow.setTitle("Stacktale");
model.clear();
detail.setText("No errors-ai.log found in this project yet.\n\n"
+ "Add the stacktale library and trigger an error — reports will appear here.");
lastContent = "";
lastContent = null;
return;
}

toolWindow.setTitle("Stacktale — " + log);

String content;
try {
content = Files.readString(log, StandardCharsets.UTF_8);
Expand All @@ -136,7 +143,9 @@ private void refresh() {
int keep = previouslySelected == null ? 0 : indexOfId(previouslySelected.id());
list.setSelectedIndex(Math.max(0, keep));
} else {
detail.setText("");
detail.setText("No error reports yet — the file has none.\n\n"
+ "Resolved log path:\n" + log);
detail.setCaretPosition(0);
}
}

Expand Down Expand Up @@ -171,7 +180,10 @@ private void showSelected() {

private void jumpToCulprit() {
StReport report = list.getSelectedValue();
if (report != null) ReportNavigator.navigate(project, report.culprit());
if (report != null && !ReportNavigator.navigate(project, report.culprit())) {
detail.setText("Report #" + report.id() + " has no source frame to open.");
detail.setCaretPosition(0);
}
}

private void copySelected() {
Expand All @@ -193,4 +205,4 @@ private static String escape(String s) {
return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class StacktaleToolWindowFactory implements ToolWindowFactory {

@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
StacktalePanel panel = new StacktalePanel(project);
StacktalePanel panel = new StacktalePanel(project, toolWindow);
Content content = ContentFactory.getInstance().createContent(panel, "", false);
toolWindow.getContentManager().addContent(content);
}
Expand Down