use system independent path
[idea/community.git] / python / edu / src / com / jetbrains / python / edu / debugger / PyEduDebugRunner.java
1 package com.jetbrains.python.edu.debugger;
2
3 import com.intellij.execution.ExecutionResult;
4 import com.intellij.execution.Executor;
5 import com.intellij.execution.configurations.RunProfile;
6 import com.intellij.execution.configurations.RunProfileState;
7 import com.intellij.execution.filters.UrlFilter;
8 import com.intellij.execution.process.ProcessHandler;
9 import com.intellij.execution.runners.ExecutionEnvironment;
10 import com.intellij.execution.ui.ExecutionConsole;
11 import com.intellij.execution.ui.RunnerLayoutUi;
12 import com.intellij.execution.ui.actions.CloseAction;
13 import com.intellij.execution.ui.layout.PlaceInGrid;
14 import com.intellij.icons.AllIcons;
15 import com.intellij.ide.actions.ContextHelpAction;
16 import com.intellij.openapi.actionSystem.*;
17 import com.intellij.openapi.diagnostic.Logger;
18 import com.intellij.openapi.editor.Document;
19 import com.intellij.openapi.fileEditor.FileDocumentManager;
20 import com.intellij.openapi.module.ModuleManager;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.projectRoots.Sdk;
23 import com.intellij.openapi.util.io.FileUtil;
24 import com.intellij.openapi.vfs.VfsUtil;
25 import com.intellij.openapi.vfs.VirtualFile;
26 import com.intellij.ui.content.Content;
27 import com.intellij.ui.content.ContentManager;
28 import com.intellij.xdebugger.XDebugSession;
29 import com.intellij.xdebugger.XDebuggerBundle;
30 import com.intellij.xdebugger.impl.XDebugSessionImpl;
31 import com.intellij.xdebugger.impl.actions.XDebuggerActions;
32 import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
33 import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
34 import com.jetbrains.python.debugger.PyDebugProcess;
35 import com.jetbrains.python.debugger.PyDebugRunner;
36 import com.jetbrains.python.debugger.PyLineBreakpointType;
37 import com.jetbrains.python.run.PythonCommandLineState;
38 import com.jetbrains.python.run.PythonRunConfiguration;
39 import com.jetbrains.python.run.PythonTracebackFilter;
40 import com.jetbrains.python.sdk.PythonSdkType;
41 import org.jetbrains.annotations.NotNull;
42 import org.jetbrains.annotations.Nullable;
43
44 import java.io.File;
45 import java.net.ServerSocket;
46
47 public class PyEduDebugRunner extends PyDebugRunner {
48   private static final Logger LOG = Logger.getInstance(PyEduDebugRunner.class);
49   public static final int NO_LINE = -1;
50
51   @Override
52   public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
53     return executorId.equals(PyEduDebugExecutor.ID);
54   }
55
56   @NotNull
57   @Override
58   protected PyDebugProcess createDebugProcess(@NotNull XDebugSession session,
59                                               ServerSocket serverSocket,
60                                               ExecutionResult result,
61                                               PythonCommandLineState pyState) {
62     ExecutionConsole executionConsole = result.getExecutionConsole();
63     ProcessHandler processHandler = result.getProcessHandler();
64     boolean isMultiProcess = pyState.isMultiprocessDebug();
65     String scriptName = getScriptName(pyState);
66     if (scriptName != null) {
67       VirtualFile file = VfsUtil.findFileByIoFile(new File(scriptName), true);
68       if (file != null) {
69         int line = getBreakpointLineNumber(file, session.getProject());
70         if (line != NO_LINE) {
71           return new PyEduDebugProcess(session, serverSocket,
72                                        executionConsole, processHandler,
73                                        isMultiProcess, scriptName, line + 1);
74         }
75       }
76     }
77     LOG.info("Failed to create PyEduDebugProcess. PyDebugProcess created instead.");
78     return new PyDebugProcess(session, serverSocket, executionConsole,
79                               processHandler, isMultiProcess);
80   }
81
82   @Nullable
83   private static String getScriptName(PythonCommandLineState pyState) {
84     ExecutionEnvironment environment = pyState.getEnvironment();
85     if (environment == null) {
86       return null;
87     }
88     RunProfile runProfile = environment.getRunProfile();
89     if (runProfile instanceof PythonRunConfiguration) {
90       return FileUtil.toSystemIndependentName(((PythonRunConfiguration)runProfile).getScriptName());
91     }
92     return null;
93   }
94
95   /**
96    * @return the smallest line (from 0 to line number) suitable to set breakpoint on it, NO_LINE if there is no such line in the file
97    */
98   private static int getBreakpointLineNumber(@NotNull final VirtualFile file, @NotNull final Project project) {
99     Document document = FileDocumentManager.getInstance().getDocument(file);
100     if (document == null) {
101       return NO_LINE;
102     }
103     PyLineBreakpointType lineBreakpointType = new PyLineBreakpointType();
104     for (int line = 0; line < document.getLineCount(); line++) {
105       if (lineBreakpointType.canPutAt(file, line, project)) {
106         return line;
107       }
108     }
109     return NO_LINE;
110   }
111
112
113   @Override
114   protected void initSession(XDebugSession session, RunProfileState state, Executor executor) {
115     XDebugSessionTab tab = ((XDebugSessionImpl)session).getSessionTab();
116     if (tab != null) {
117       RunnerLayoutUi ui = tab.getUi();
118       ContentManager contentManager = ui.getContentManager();
119       Content content = findContent(contentManager, XDebuggerBundle.message("debugger.session.tab.watches.title"));
120       if (content != null) {
121         contentManager.removeContent(content, true);
122       }
123       content = findContent(contentManager, XDebuggerBundle.message("debugger.session.tab.console.content.name"));
124       if (content != null) {
125         contentManager.removeContent(content, true);
126       }
127       initEduConsole(session, ui);
128     }
129   }
130
131   private static void initEduConsole(@NotNull final XDebugSession session,
132                                      @NotNull final RunnerLayoutUi ui) {
133     Project project = session.getProject();
134     final Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
135     final PythonDebugLanguageConsoleView view = new PythonDebugLanguageConsoleView(project, sdk);
136     final ProcessHandler processHandler = session.getDebugProcess().getProcessHandler();
137
138     view.attachToProcess(processHandler);
139     view.addMessageFilter(new PythonTracebackFilter(project));
140     view.addMessageFilter(new UrlFilter());
141
142     view.enableConsole(false);
143
144     Content eduConsole =
145       ui.createContent("EduConsole", view.getComponent(),
146                        XDebuggerBundle.message("debugger.session.tab.console.content.name"),
147                        AllIcons.Debugger.ToolConsole, view.getPreferredFocusableComponent());
148     eduConsole.setCloseable(false);
149     ui.addContent(eduConsole, 0, PlaceInGrid.right, false);
150
151     PyDebugProcess process = (PyDebugProcess)session.getDebugProcess();
152     PyDebugRunner.initDebugConsoleView(project, process, view, processHandler, session);
153
154     patchLeftToolbar(session, ui);
155   }
156
157   private static void patchLeftToolbar(@NotNull XDebugSession session, @NotNull RunnerLayoutUi ui) {
158     DefaultActionGroup newLeftToolbar = new DefaultActionGroup();
159
160     DefaultActionGroup firstGroup = new DefaultActionGroup();
161     addActionToGroup(firstGroup, XDebuggerActions.RESUME);
162     addActionToGroup(firstGroup, IdeActions.ACTION_STOP_PROGRAM);
163     newLeftToolbar.addAll(firstGroup);
164
165     newLeftToolbar.addSeparator();
166
167     Executor executor = PyEduDebugExecutor.getInstance();
168     newLeftToolbar.add(new CloseAction(executor, session.getRunContentDescriptor(), session.getProject()));
169     //TODO: return proper helpID
170     newLeftToolbar.add(new ContextHelpAction(executor.getHelpId()));
171
172     ui.getOptions().setLeftToolbar(newLeftToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
173   }
174
175   private static void addActionToGroup(DefaultActionGroup group, String actionId) {
176     AnAction action = ActionManager.getInstance().getAction(actionId);
177     if (action != null) {
178       action.getTemplatePresentation().setEnabled(true);
179       group.add(action, Constraints.LAST);
180     }
181   }
182
183   @Nullable
184   private static Content findContent(ContentManager manager, String name) {
185     for (Content content : manager.getContents()) {
186       if (content.getDisplayName().equals(name)) {
187         return content;
188       }
189     }
190     return null;
191   }
192 }