-- get rid of inheritance from AbstractConsoleRunner with history. It adds no almost...
[idea/community.git] / platform / lang-impl / src / com / intellij / execution / runners / AbstractConsoleRunnerWithHistory.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.execution.runners;
17
18 import com.intellij.execution.ExecutionException;
19 import com.intellij.execution.ExecutionHelper;
20 import com.intellij.execution.ExecutionManager;
21 import com.intellij.execution.Executor;
22 import com.intellij.execution.console.ConsoleExecuteAction;
23 import com.intellij.execution.console.LanguageConsoleView;
24 import com.intellij.execution.console.ProcessBackedConsoleExecuteActionHandler;
25 import com.intellij.execution.executors.DefaultRunExecutor;
26 import com.intellij.execution.process.*;
27 import com.intellij.execution.ui.RunContentDescriptor;
28 import com.intellij.execution.ui.actions.CloseAction;
29 import com.intellij.ide.CommonActionsManager;
30 import com.intellij.openapi.actionSystem.*;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.ui.JBColor;
33 import com.intellij.ui.SideBorder;
34 import com.intellij.util.containers.ContainerUtil;
35 import com.intellij.util.ui.UIUtil;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38
39 import javax.swing.*;
40 import java.awt.*;
41 import java.util.List;
42 import java.util.stream.Collectors;
43
44 /**
45  * This class provides basic functionality for running consoles.
46  * It launches external process and handles line input with history
47  *
48  * @author oleg
49  */
50 public abstract class AbstractConsoleRunnerWithHistory<T extends LanguageConsoleView> {
51   private final String myConsoleTitle;
52
53   private ProcessHandler myProcessHandler;
54   private final String myWorkingDir;
55
56   private T myConsoleView;
57
58   @NotNull
59   private final Project myProject;
60
61   private ProcessBackedConsoleExecuteActionHandler myConsoleExecuteActionHandler;
62
63   public AbstractConsoleRunnerWithHistory(@NotNull Project project, @NotNull String consoleTitle, @Nullable String workingDir) {
64     myProject = project;
65     myConsoleTitle = consoleTitle;
66     myWorkingDir = workingDir;
67   }
68
69   /**
70    * Launch process, setup history, actions etc.
71    *
72    * @throws ExecutionException
73    */
74   public void initAndRun() throws ExecutionException {
75     // Create Server process
76     final Process process = createProcess();
77     UIUtil.invokeLaterIfNeeded(() -> {
78       // Init console view
79       myConsoleView = createConsoleView();
80       if (myConsoleView instanceof JComponent) {
81         ((JComponent)myConsoleView).setBorder(new SideBorder(JBColor.border(), SideBorder.LEFT));
82       }
83       myProcessHandler = createProcessHandler(process);
84
85       myConsoleExecuteActionHandler = createExecuteActionHandler();
86
87       ProcessTerminatedListener.attach(myProcessHandler);
88
89       myProcessHandler.addProcessListener(new ProcessAdapter() {
90         @Override
91         public void processTerminated(ProcessEvent event) {
92           finishConsole();
93         }
94       });
95
96       // Attach to process
97       myConsoleView.attachToProcess(myProcessHandler);
98
99       // Runner creating
100       createContentDescriptorAndActions();
101
102       // Run
103       myProcessHandler.startNotify();
104     });
105   }
106
107   protected Executor getExecutor() {
108     return DefaultRunExecutor.getRunExecutorInstance();
109   }
110
111   protected void createContentDescriptorAndActions() {
112     final Executor defaultExecutor = getExecutor();
113     final DefaultActionGroup toolbarActions = new DefaultActionGroup();
114     final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, toolbarActions, false);
115
116     // Runner creating
117     final JPanel panel = new JPanel(new BorderLayout());
118     panel.add(actionToolbar.getComponent(), BorderLayout.WEST);
119     panel.add(myConsoleView.getComponent(), BorderLayout.CENTER);
120
121     actionToolbar.setTargetComponent(panel);
122
123     final RunContentDescriptor contentDescriptor =
124       new RunContentDescriptor(myConsoleView, myProcessHandler, panel, constructConsoleTitle(myConsoleTitle), getConsoleIcon());
125
126     contentDescriptor.setFocusComputable(() -> getConsoleView().getConsoleEditor().getContentComponent());
127     contentDescriptor.setAutoFocusContent(isAutoFocusContent());
128
129
130     // tool bar actions
131     final List<AnAction> actions = fillToolBarActions(toolbarActions, defaultExecutor, contentDescriptor);
132     registerActionShortcuts(actions, getConsoleView().getConsoleEditor().getComponent());
133     registerActionShortcuts(actions, panel);
134
135     showConsole(defaultExecutor, contentDescriptor);
136   }
137
138   @Nullable
139   protected Icon getConsoleIcon() {
140     return null;
141   }
142
143   protected String constructConsoleTitle(final @NotNull String consoleTitle) {
144     return new ConsoleTitleGen(myProject, consoleTitle, shouldAddNumberToTitle()).makeTitle();
145   }
146
147   public boolean isAutoFocusContent() {
148     return true;
149   }
150
151   protected boolean shouldAddNumberToTitle() {
152     return false;
153   }
154
155   protected void showConsole(Executor defaultExecutor, @NotNull RunContentDescriptor contentDescriptor) {
156     // Show in run toolwindow
157     ExecutionManager.getInstance(myProject).getContentManager().showRunContent(defaultExecutor, contentDescriptor);
158   }
159
160   protected void finishConsole() {
161     myConsoleView.setEditable(false);
162   }
163
164   protected abstract T createConsoleView();
165
166   @Nullable
167   protected abstract Process createProcess() throws ExecutionException;
168
169   protected abstract OSProcessHandler createProcessHandler(final Process process);
170
171   public static void registerActionShortcuts(final List<AnAction> actions, final JComponent component) {
172     for (AnAction action : actions) {
173       if (action.getShortcutSet() != null) {
174         action.registerCustomShortcutSet(action.getShortcutSet(), component);
175       }
176     }
177   }
178
179   protected List<AnAction> fillToolBarActions(final DefaultActionGroup toolbarActions,
180                                               final Executor defaultExecutor,
181                                               final RunContentDescriptor contentDescriptor) {
182
183     List<AnAction> actionList = ContainerUtil.newArrayList();
184
185     //stop
186     actionList.add(createStopAction());
187
188     //close
189     actionList.add(createCloseAction(defaultExecutor, contentDescriptor));
190
191     // run action
192     actionList.add(createConsoleExecAction(myConsoleExecuteActionHandler));
193
194     // Help
195     actionList.add(CommonActionsManager.getInstance().createHelpAction("interactive_console"));
196
197     toolbarActions.addAll(actionList);
198
199     return actionList;
200   }
201
202   protected AnAction createCloseAction(final Executor defaultExecutor, final RunContentDescriptor myDescriptor) {
203     return new CloseAction(defaultExecutor, myDescriptor, myProject);
204   }
205
206   protected AnAction createStopAction() {
207     return ActionManager.getInstance().getAction(IdeActions.ACTION_STOP_PROGRAM);
208   }
209
210   protected AnAction createConsoleExecAction(@NotNull ProcessBackedConsoleExecuteActionHandler consoleExecuteActionHandler) {
211     String emptyAction = consoleExecuteActionHandler.getEmptyExecuteAction();
212     return new ConsoleExecuteAction(myConsoleView, consoleExecuteActionHandler, emptyAction, consoleExecuteActionHandler);
213   }
214
215   @NotNull
216   protected abstract ProcessBackedConsoleExecuteActionHandler createExecuteActionHandler();
217
218   public T getConsoleView() {
219     return myConsoleView;
220   }
221
222   @NotNull
223   public Project getProject() {
224     return myProject;
225   }
226
227   public String getConsoleTitle() {
228     return myConsoleTitle;
229   }
230
231   public String getWorkingDir() {
232     return myWorkingDir;
233   }
234
235   public ProcessHandler getProcessHandler() {
236     return myProcessHandler;
237   }
238
239   public ProcessBackedConsoleExecuteActionHandler getConsoleExecuteActionHandler() {
240     return myConsoleExecuteActionHandler;
241   }
242
243
244 }