package com.intellij.javascript.karma.server; import com.intellij.execution.actions.StopProcessAction; import com.intellij.execution.filters.TextConsoleBuilderImpl; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.javascript.karma.util.ArchivedOutputListener; import com.intellij.javascript.karma.util.KarmaUtil; import com.intellij.javascript.nodejs.NodeStackTraceFilter; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentWithActions; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.content.Content; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; public class KarmaServerLogComponent implements ComponentWithActions { private final ConsoleView myConsole; private final KarmaServer myServer; private ActionGroup myActionGroup; private KarmaServerLogComponent(@NotNull ConsoleView console, @NotNull KarmaServer server) { myConsole = console; myServer = server; } @Nullable @Override public ActionGroup getToolbarActions() { if (myActionGroup != null) { return myActionGroup; } DefaultActionGroup group = new DefaultActionGroup(); group.add(new StopProcessAction("Stop Karma Server", null, myServer.getProcessHandler())); final AnAction[] actions = myConsole.createConsoleActions(); for (AnAction action : actions) { group.add(action); } group.addSeparator(); myActionGroup = group; return myActionGroup; } @Nullable @Override public JComponent getSearchComponent() { return null; } @Nullable @Override public String getToolbarPlace() { return ActionPlaces.UNKNOWN; } @Nullable @Override public JComponent getToolbarContextComponent() { return myConsole.getComponent(); } @NotNull @Override public JComponent getComponent() { return myConsole.getComponent(); } @Override public boolean isContentBuiltIn() { return false; } @NotNull private static ConsoleView createConsole(@NotNull Project project) { GlobalSearchScope scope = GlobalSearchScope.allScope(project); TextConsoleBuilderImpl builder = new TextConsoleBuilderImpl(project, scope); builder.setUsePredefinedMessageFilter(false); builder.addFilter(new NodeStackTraceFilter(project)); return builder.getConsole(); } public static void register(@NotNull Project project, @NotNull final KarmaServer server, @NotNull final RunnerLayoutUi ui, boolean requestFocus) { final ConsoleView console = createConsole(project); KarmaServerLogComponent component = new KarmaServerLogComponent(console, server); final Content content = ui.createContent("KarmaServer", component, "Karma Server", null, console.getPreferredFocusableComponent()); content.setCloseable(false); ui.addContent(content, 4, PlaceInGrid.bottom, false); if (requestFocus && !server.isPortBound()) { ui.selectAndFocus(content, false, false); } final KarmaServerTerminatedListener terminationCallback = new KarmaServerTerminatedListener() { @Override public void onTerminated(int exitCode) { KarmaUtil.selectAndFocusIfNotDisposed(ui, content, false, false); } }; server.onTerminated(terminationCallback); final ArchivedOutputListener outputListener = new ArchivedOutputListener() { @Override public void onOutputAvailable(@NotNull String text, Key outputType, boolean archived) { ConsoleViewContentType contentType = ConsoleViewContentType.getConsoleViewType(outputType); console.print(text, contentType); if (!archived && text.startsWith("ERROR ")) { ApplicationManager.getApplication().invokeLater(() -> content.fireAlert(), ModalityState.any()); } } }; server.getProcessOutputManager().addOutputListener(outputListener); Disposer.register(content, console); Disposer.register(console, new Disposable() { @Override public void dispose() { server.removeTerminatedListener(terminationCallback); server.getProcessOutputManager().removeOutputListener(outputListener); } }); } }