|
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style license that can be |
|
3 // found in the LICENSE file. |
|
4 |
|
5 package org.chromium.debug.core.model; |
|
6 |
|
7 import java.util.Collection; |
|
8 |
|
9 import org.chromium.debug.core.ChromiumDebugPlugin; |
|
10 import org.chromium.debug.core.util.ChromiumDebugPluginUtil; |
|
11 import org.chromium.sdk.Breakpoint; |
|
12 import org.chromium.sdk.CallFrame; |
|
13 import org.chromium.sdk.JavascriptVm; |
|
14 import org.chromium.sdk.Script; |
|
15 import org.chromium.sdk.JavascriptVm.BreakpointCallback; |
|
16 import org.chromium.sdk.JavascriptVm.ScriptsCallback; |
|
17 import org.eclipse.core.resources.IFile; |
|
18 import org.eclipse.core.resources.IMarkerDelta; |
|
19 import org.eclipse.core.resources.IProject; |
|
20 import org.eclipse.core.runtime.CoreException; |
|
21 import org.eclipse.debug.core.DebugException; |
|
22 import org.eclipse.debug.core.DebugPlugin; |
|
23 import org.eclipse.debug.core.IBreakpointManager; |
|
24 import org.eclipse.debug.core.ILaunch; |
|
25 import org.eclipse.debug.core.model.IBreakpoint; |
|
26 import org.eclipse.debug.core.model.ISourceLocator; |
|
27 import org.eclipse.debug.core.model.IStackFrame; |
|
28 import org.eclipse.osgi.util.NLS; |
|
29 |
|
30 /** |
|
31 * Virtual project-supporting implementation of {@link WorkspaceBridge}. |
|
32 */ |
|
33 public class VProjectWorkspaceBridge implements WorkspaceBridge { |
|
34 /** The debug model ID. */ |
|
35 public static final String DEBUG_MODEL_ID = "org.chromium.debug"; //$NON-NLS-1$ |
|
36 |
|
37 public static class FactoryImpl implements Factory { |
|
38 private final String projectNameBase; |
|
39 |
|
40 public FactoryImpl(String projectNameBase) { |
|
41 this.projectNameBase = projectNameBase; |
|
42 } |
|
43 |
|
44 public WorkspaceBridge attachedToVm(DebugTargetImpl debugTargetImpl, |
|
45 JavascriptVm javascriptVm) { |
|
46 // We might want to add URL or something to project name. |
|
47 return new VProjectWorkspaceBridge(projectNameBase, debugTargetImpl, javascriptVm); |
|
48 } |
|
49 |
|
50 public String getDebugModelIdentifier() { |
|
51 return DEBUG_MODEL_ID; |
|
52 } |
|
53 |
|
54 public JsLabelProvider getLabelProvider() { |
|
55 return LABEL_PROVIDER; |
|
56 } |
|
57 } |
|
58 |
|
59 private final IProject debugProject; |
|
60 private final JavascriptVm javascriptVm; |
|
61 private final ResourceManager resourceManager; |
|
62 private final BreakpointRegistry breakpointRegistry = new BreakpointRegistry(); |
|
63 private final DebugTargetImpl debugTargetImpl; |
|
64 |
|
65 public VProjectWorkspaceBridge(String projectName, DebugTargetImpl debugTargetImpl, |
|
66 JavascriptVm javascriptVm) { |
|
67 this.debugTargetImpl = debugTargetImpl; |
|
68 this.javascriptVm = javascriptVm; |
|
69 this.debugProject = ChromiumDebugPluginUtil.createEmptyProject(projectName); |
|
70 this.resourceManager = new ResourceManager(debugProject, breakpointRegistry); |
|
71 ILaunch launch = debugTargetImpl.getLaunch(); |
|
72 launch.setSourceLocator(sourceLocator); |
|
73 } |
|
74 |
|
75 public void launchRemoved() { |
|
76 if (debugProject != null) { |
|
77 ChromiumDebugPluginUtil.deleteVirtualProjectAsync(debugProject); |
|
78 } |
|
79 } |
|
80 |
|
81 public void beforeDetach() { |
|
82 IBreakpointManager breakpointManager = DebugPlugin.getDefault().getBreakpointManager(); |
|
83 IBreakpoint[] breakpoints = |
|
84 breakpointManager.getBreakpoints(DEBUG_MODEL_ID); |
|
85 for (IBreakpoint bp : breakpoints) { |
|
86 ChromiumLineBreakpoint clb = (ChromiumLineBreakpoint) bp; |
|
87 if (clb.getBrowserBreakpoint() != null && |
|
88 clb.getBrowserBreakpoint().getId() != Breakpoint.INVALID_ID) { |
|
89 clb.getBrowserBreakpoint().clear(null); |
|
90 } |
|
91 } |
|
92 try { |
|
93 breakpointManager.removeBreakpoints(breakpoints, true); |
|
94 } catch (CoreException e) { |
|
95 ChromiumDebugPlugin.log(e); |
|
96 } |
|
97 } |
|
98 |
|
99 public void handleVmResetEvent() { |
|
100 resourceManager.clear(); |
|
101 } |
|
102 |
|
103 public void scriptLoaded(Script newScript) { |
|
104 resourceManager.addScript(newScript); |
|
105 } |
|
106 |
|
107 public void reloadScriptsAtStart() { |
|
108 javascriptVm.getScripts(new ScriptsCallback() { |
|
109 public void failure(String errorMessage) { |
|
110 ChromiumDebugPlugin.logError(errorMessage); |
|
111 } |
|
112 |
|
113 public void success(Collection<Script> scripts) { |
|
114 if (!javascriptVm.isAttached()) { |
|
115 return; |
|
116 } |
|
117 for (Script script : scripts) { |
|
118 resourceManager.addScript(script); |
|
119 } |
|
120 } |
|
121 }); |
|
122 } |
|
123 |
|
124 public IFile getScriptResource(Script script) { |
|
125 return resourceManager.getResource(script); |
|
126 } |
|
127 |
|
128 public BreakpointHandler getBreakpointHandler() { |
|
129 return breakpointHandler; |
|
130 } |
|
131 |
|
132 private final BreakpointHandler breakpointHandler = new BreakpointHandler() { |
|
133 public boolean supportsBreakpoint(IBreakpoint breakpoint) { |
|
134 return DEBUG_MODEL_ID.equals(breakpoint.getModelIdentifier()) && |
|
135 !debugTargetImpl.isDisconnected(); |
|
136 } |
|
137 public void breakpointAdded(IBreakpoint breakpoint) { |
|
138 if (!supportsBreakpoint(breakpoint)) { |
|
139 return; |
|
140 } |
|
141 try { |
|
142 if (breakpoint.isEnabled()) { |
|
143 // Class cast is ensured by the supportsBreakpoint implementation |
|
144 final ChromiumLineBreakpoint lineBreakpoint = (ChromiumLineBreakpoint) breakpoint; |
|
145 IFile file = (IFile) breakpoint.getMarker().getResource(); |
|
146 if (resourceManager.isAddingFile(file)) { |
|
147 return; // restoring breakpoints in progress |
|
148 } |
|
149 final Script script = resourceManager.getScript(file); |
|
150 if (script == null) { |
|
151 // Might be a script from a different debug target |
|
152 return; |
|
153 } |
|
154 // ILineBreakpoint lines are 1-based while V8 lines are 0-based |
|
155 final int line = (lineBreakpoint.getLineNumber() - 1) + script.getStartLine(); |
|
156 BreakpointCallback callback = new BreakpointCallback() { |
|
157 public void success(Breakpoint breakpoint) { |
|
158 lineBreakpoint.setBreakpoint(breakpoint); |
|
159 breakpointRegistry.add(script, line, breakpoint); |
|
160 } |
|
161 |
|
162 public void failure(String errorMessage) { |
|
163 ChromiumDebugPlugin.logError(errorMessage); |
|
164 } |
|
165 }; |
|
166 if (script.getName() != null) { |
|
167 javascriptVm.setBreakpoint(Breakpoint.Type.SCRIPT_NAME, |
|
168 script.getName(), |
|
169 line, |
|
170 Breakpoint.EMPTY_VALUE, |
|
171 breakpoint.isEnabled(), |
|
172 lineBreakpoint.getCondition(), |
|
173 lineBreakpoint.getIgnoreCount(), |
|
174 callback); |
|
175 } else { |
|
176 javascriptVm.setBreakpoint(Breakpoint.Type.SCRIPT_ID, |
|
177 String.valueOf(script.getId()), |
|
178 line, |
|
179 Breakpoint.EMPTY_VALUE, |
|
180 breakpoint.isEnabled(), |
|
181 lineBreakpoint.getCondition(), |
|
182 lineBreakpoint.getIgnoreCount(), |
|
183 callback); |
|
184 } |
|
185 } |
|
186 } catch (CoreException e) { |
|
187 ChromiumDebugPlugin.log(e); |
|
188 } |
|
189 } |
|
190 |
|
191 public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { |
|
192 if (!supportsBreakpoint(breakpoint)) { |
|
193 return; |
|
194 } |
|
195 // Class cast is ensured by the supportsBreakpoint implementation |
|
196 ((ChromiumLineBreakpoint) breakpoint).changed(); |
|
197 } |
|
198 |
|
199 public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { |
|
200 if (!supportsBreakpoint(breakpoint)) { |
|
201 return; |
|
202 } |
|
203 try { |
|
204 if (breakpoint.isEnabled()) { |
|
205 // Class cast is ensured by the supportsBreakpoint implementation |
|
206 ChromiumLineBreakpoint lineBreakpoint = (ChromiumLineBreakpoint) breakpoint; |
|
207 lineBreakpoint.clear(); |
|
208 breakpointRegistry.remove( |
|
209 resourceManager.getScript((IFile) breakpoint.getMarker().getResource()), |
|
210 lineBreakpoint.getLineNumber() - 1, |
|
211 lineBreakpoint.getBrowserBreakpoint()); |
|
212 } |
|
213 } catch (CoreException e) { |
|
214 ChromiumDebugPlugin.log(e); |
|
215 } |
|
216 } |
|
217 |
|
218 public void breakpointsHit(Collection<? extends Breakpoint> breakpointsHit) { |
|
219 if (breakpointsHit.isEmpty()) { |
|
220 return; |
|
221 } |
|
222 IBreakpoint[] breakpoints = |
|
223 DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(DEBUG_MODEL_ID); |
|
224 for (IBreakpoint breakpoint : breakpoints) { |
|
225 ChromiumLineBreakpoint jsBreakpoint = (ChromiumLineBreakpoint) breakpoint; |
|
226 if (breakpointsHit.contains(jsBreakpoint.getBrowserBreakpoint())) { |
|
227 jsBreakpoint.setIgnoreCount(-1); // reset ignore count as we've hit it |
|
228 } |
|
229 } |
|
230 } |
|
231 }; |
|
232 |
|
233 /** |
|
234 * This very simple source locator works because we provide our own source files. |
|
235 * We'll have to try harder, once we link with resource js files. |
|
236 */ |
|
237 private final ISourceLocator sourceLocator = new ISourceLocator() { |
|
238 public Object getSourceElement(IStackFrame stackFrame) { |
|
239 if (stackFrame instanceof StackFrame == false) { |
|
240 return null; |
|
241 } |
|
242 StackFrame jsStackFrame = (StackFrame) stackFrame; |
|
243 |
|
244 Script script = jsStackFrame.getCallFrame().getScript(); |
|
245 if (script == null) { |
|
246 return null; |
|
247 } |
|
248 |
|
249 return resourceManager.getResource(script); |
|
250 } |
|
251 }; |
|
252 |
|
253 private final static JsLabelProvider LABEL_PROVIDER = new JsLabelProvider() { |
|
254 public String getTargetLabel(DebugTargetImpl debugTarget) { |
|
255 JavascriptVmEmbedder vmEmbedder = debugTarget.getJavascriptEmbedder(); |
|
256 if (vmEmbedder == null) { |
|
257 return ""; //$NON-NLS-1$ |
|
258 } |
|
259 return vmEmbedder.getTargetName(); |
|
260 } |
|
261 |
|
262 public String getThreadLabel(JavascriptThread thread) { |
|
263 String url = thread.getDebugTarget().getJavascriptEmbedder().getThreadName(); |
|
264 return NLS.bind(Messages.JsThread_ThreadLabelFormat, (thread.isSuspended() |
|
265 ? Messages.JsThread_ThreadLabelSuspended |
|
266 : Messages.JsThread_ThreadLabelRunning), (url.length() > 0 |
|
267 ? (" : " + url) : "")); //$NON-NLS-1$ //$NON-NLS-2$ |
|
268 } |
|
269 |
|
270 public String getStackFrameLabel(StackFrame stackFrame) throws DebugException { |
|
271 CallFrame callFrame = stackFrame.getCallFrame(); |
|
272 String name = callFrame.getFunctionName(); |
|
273 Script script = callFrame.getScript(); |
|
274 if (script == null) { |
|
275 return Messages.StackFrame_UnknownScriptName; |
|
276 } |
|
277 int line = script.getStartLine() + stackFrame.getLineNumber(); |
|
278 if (line != -1) { |
|
279 name = NLS.bind(Messages.StackFrame_NameFormat, |
|
280 new Object[] {name, script.getName(), line}); |
|
281 } |
|
282 return name; |
|
283 } |
|
284 }; |
|
285 } |