package krasa.grepconsole.tail; import com.intellij.execution.DefaultExecutionResult; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionManager; import com.intellij.execution.Executor; import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfileState; import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.ui.RunnerLayoutUi; import com.intellij.execution.ui.actions.CloseAction; import com.intellij.execution.ui.layout.PlaceInGrid; import com.intellij.icons.AllIcons; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.ui.content.Content; import krasa.grepconsole.plugin.GrepProjectComponent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.io.File; import java.util.ArrayList; import java.util.List; /** * Copy of com.intellij.execution.RunContentExecutor Runs a process and prints the output in a content tab within the * Run toolwindow. * * @author yole */ public class TailContentExecutor implements Disposable { private final Project myProject; private final ProcessHandler myProcess; private final List<Filter> myFilterList = new ArrayList<>(); private Runnable myRerunAction; private Runnable myStopAction; private Runnable myAfterCompletion; private Computable<Boolean> myStopEnabled; private String myTitle = "Output"; private String myHelpId = null; private boolean myActivateToolWindow = true; private File file; public TailContentExecutor(@NotNull Project project, @NotNull ProcessHandler process) { myProject = project; myProcess = process; } public TailContentExecutor withFilter(Filter filter) { myFilterList.add(filter); return this; } public TailContentExecutor withTitle(String title) { myTitle = title; return this; } public TailContentExecutor withRerun(Runnable rerun) { myRerunAction = rerun; return this; } public TailContentExecutor withStop(@NotNull Runnable stop, @NotNull Computable<Boolean> stopEnabled) { myStopAction = stop; myStopEnabled = stopEnabled; return this; } public TailContentExecutor withAfterCompletion(Runnable afterCompletion) { myAfterCompletion = afterCompletion; return this; } public TailContentExecutor withHelpId(String helpId) { myHelpId = helpId; return this; } public TailContentExecutor withActivateToolWindow(boolean activateToolWindow) { myActivateToolWindow = activateToolWindow; return this; } private ConsoleView createConsole(@NotNull Project project, @NotNull ProcessHandler processHandler) { TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project); consoleBuilder.filters(myFilterList); ConsoleView console = consoleBuilder.getConsole(); console.attachToProcess(processHandler); return console; } public void run() { FileDocumentManager.getInstance().saveAllDocuments(); ConsoleView consoleView = createConsole(myProject, myProcess); if (myHelpId != null) { consoleView.setHelpId(myHelpId); } Executor executor = TailRunExecutor.getRunExecutorInstance(); DefaultActionGroup actions = new DefaultActionGroup(); // Create runner UI layout final RunnerLayoutUi.Factory factory = RunnerLayoutUi.Factory.getInstance(myProject); final RunnerLayoutUi layoutUi = factory.create("Tail", "Tail", "Tail", myProject); final JComponent consolePanel = createConsolePanel(consoleView, actions); RunContentDescriptor descriptor = new RunContentDescriptor(new RunProfile() { @Nullable @Override public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment executionEnvironment) throws ExecutionException { return null; } @Override public String getName() { return myTitle; } @Nullable @Override public Icon getIcon() { return null; } }, new DefaultExecutionResult(consoleView, myProcess), layoutUi); final Content content = layoutUi.createContent("ConsoleContent", consolePanel, myTitle, AllIcons.Debugger.Console, consolePanel); layoutUi.addContent(content, 0, PlaceInGrid.right, false); layoutUi.getOptions().setLeftToolbar( createActionToolbar(consolePanel, consoleView, layoutUi, descriptor, executor), "RunnerToolbar"); Disposer.register(this, descriptor); Disposer.register(descriptor, content); Disposer.register(content, consoleView); if (myStopAction != null) { Disposer.register(consoleView, new Disposable() { @Override public void dispose() { myStopAction.run(); } }); } for (AnAction action : consoleView.createConsoleActions()) { actions.add(action); } ExecutionManager.getInstance(myProject).getContentManager().showRunContent(executor, descriptor); if (myActivateToolWindow) { activateToolWindow(); } if (myAfterCompletion != null) { myProcess.addProcessListener(new ProcessAdapter() { @Override public void processTerminated(ProcessEvent event) { SwingUtilities.invokeLater(myAfterCompletion); } }); } myProcess.startNotify(); } @NotNull private ActionGroup createActionToolbar(JComponent consolePanel, ConsoleView consoleView, @NotNull final RunnerLayoutUi myUi, RunContentDescriptor contentDescriptor, Executor runExecutorInstance) { final DefaultActionGroup actionGroup = new DefaultActionGroup(); actionGroup.add(new RerunAction(consolePanel, consoleView)); actionGroup.add(new StopAction()); actionGroup.add(new PinAction()); actionGroup.add(myUi.getOptions().getLayoutActions()); CloseAction closeAction = new CloseAction(runExecutorInstance, contentDescriptor, myProject) { @Override public void actionPerformed(AnActionEvent e) { super.actionPerformed(e); GrepProjectComponent.getInstance(myProject).unpin(file); } }; GrepProjectComponent.getInstance(myProject).register(closeAction); actionGroup.add(closeAction); actionGroup.add(new CloseAll()); return actionGroup; } public void activateToolWindow() { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { ToolWindowManager.getInstance(myProject).getToolWindow(TailRunExecutor.TOOLWINDOWS_ID).activate(null); } }); } private static JComponent createConsolePanel(ConsoleView view, ActionGroup actions) { JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(view.getComponent(), BorderLayout.CENTER); panel.add(createToolbar(actions), BorderLayout.WEST); return panel; } private static JComponent createToolbar(ActionGroup actions) { ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actions, false); return actionToolbar.getComponent(); } @Override public void dispose() { Disposer.dispose(this); } public void forFile(File file) { this.file = file; } private class RerunAction extends AnAction implements DumbAware { private final ConsoleView consoleView; public RerunAction(JComponent consolePanel, ConsoleView consoleView) { super("Rerun", "Rerun", AllIcons.Actions.Restart); this.consoleView = consoleView; registerCustomShortcutSet(CommonShortcuts.getRerun(), consolePanel); } @Override public void actionPerformed(AnActionEvent e) { Disposer.dispose(consoleView); myRerunAction.run(); } @Override public void update(AnActionEvent e) { e.getPresentation().setVisible(myRerunAction != null); } } private class StopAction extends AnAction implements DumbAware { public StopAction() { super("Stop", "Stop", AllIcons.Actions.Suspend); } @Override public void actionPerformed(AnActionEvent e) { myStopAction.run(); } @Override public void update(AnActionEvent e) { e.getPresentation().setVisible(myStopAction != null); e.getPresentation().setEnabled(myStopEnabled != null && myStopEnabled.compute()); } } private class CloseAll extends AnAction implements DumbAware { public CloseAll() { super("Close All", "Close All", AllIcons.Actions.Exit); } @Override public void actionPerformed(AnActionEvent e) { GrepProjectComponent.getInstance(myProject).closeAllTails(e); } } public class PinAction extends ToggleAction implements DumbAware { private boolean pinned; public PinAction() { super("Pin", "Reopen with project", AllIcons.General.Pin_tab); GrepProjectComponent projectComponent = GrepProjectComponent.getInstance(myProject); projectComponent.register(this); pinned = projectComponent.isPinned(file.getAbsoluteFile()); } @Override public boolean isSelected(AnActionEvent anActionEvent) { return pinned; } public void refreshPinStatus(GrepProjectComponent projectComponent) { pinned = projectComponent.isPinned(file.getAbsoluteFile()); } @Override public void setSelected(AnActionEvent anActionEvent, boolean b) { pinned = b; GrepProjectComponent projectComponent = GrepProjectComponent.getInstance(myProject); if (pinned) { projectComponent.pin(file); } else { projectComponent.unpin(file); } } } }