Skip to content

Issue #2: Support for debugging TypeScript with JavaScript Debugger. #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion eclipse/jsdt/ts.eclipse.ide.jsdt.ui/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.ui.ide,
ts.eclipse.ide.core,
ts.eclipse.ide.ui,
org.eclipse.ui.workbench.texteditor
org.eclipse.ui.workbench.texteditor,
org.eclipse.debug.ui,
org.eclipse.wst.jsdt.debug.ui,
org.eclipse.wst.jsdt.debug.core
Bundle-ActivationPolicy: lazy
Bundle-Activator: ts.eclipse.ide.jsdt.internal.ui.JSDTTypeScriptUIPlugin
Import-Package: com.eclipsesource.json;version="[0.9.4,0.9.5)"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions eclipse/jsdt/ts.eclipse.ide.jsdt.ui/plugin.properties
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,13 @@ ActionDefinition.format.description= Format the selected text

ActionDefinition.referencesInProject.name= References in Project
ActionDefinition.referencesInProject.description= Search for references to the selected element in the enclosing project

##########################################################################
# Debugging support
##########################################################################
togglebreakpointRulerAction.name = Toggle Breakpoint
breakpointpropertiesRulerAction.name = Breakpoint &Properties
breakpointpropertiesRulerAction.tooltip = Displays the properties dialog for the selected breakpoint
togglebreakpointenablementRulerAction.name = To&ggle Breakpoint Enablement
togglebreakpointenablementRulerAction.tooltip = Allows the enabled state of the breakpoint to be changed

62 changes: 62 additions & 0 deletions eclipse/jsdt/ts.eclipse.ide.jsdt.ui/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,66 @@
point="org.eclipse.ui.startup">
<startup class="ts.eclipse.ide.jsdt.internal.ui.JSDTTypeScriptStartup" />
</extension>

<!-- debugging support -->
<extension
point="org.eclipse.core.runtime.adapters">
<factory
adaptableType="ts.eclipse.ide.jsdt.internal.ui.editor.TypeScriptEditor"
class="ts.eclipse.ide.jsdt.internal.ui.editor.breakpoints.TypeScriptAdapterFactory">
<adapter
type="org.eclipse.debug.ui.actions.IToggleBreakpointsTarget">
</adapter>
</factory>
</extension>

<extension
point="org.eclipse.ui.editorActions">
<editorContribution
id="ts.eclipse.ide.jsdt.debug.ui.togglebreakpoint"
targetID="ts.eclipse.ide.jsdt.ui.editor.TypeScriptEditor">
<action
actionID="RulerDoubleClick"
class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
helpContextId="editor_toggle_breakpoint_action_context"
icon="icons/full/obj16/brkp_obj.gif"
id="org.eclipse.wst.jsdt.debug.ui.RulerToggleBreakpoint"
label="%togglebreakpointRulerAction.name">
</action>
</editorContribution>
</extension>


<extension
point="org.eclipse.ui.popupMenus">
<viewerContribution
id="ts.eclipse.ide.jsdt.debug.ui.ruler.popup.actions"
targetID="ts.eclipse.ide.jsdt.ui.editor.TypeScriptEditor.RulerContext">
<action
class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
helpContextId="editor_toggle_breakpoint_action_context"
icon="icons/full/obj16/brkp_obj.gif"
id="org.eclipse.wst.jsdt.debug.ui.toggle.breakpoint.ruler.delegate"
label="%togglebreakpointRulerAction.name"
menubarPath="debug">
</action>
<action
class="org.eclipse.wst.jsdt.debug.internal.ui.breakpoints.BreakpointPropertiesEditorActionDelegate"
helpContextId="breakpoint_properties_editor_ruler_context"
id="org.eclipse.wst.jsdt.debug.ui.ruler.breakpoint.properties"
label="%breakpointpropertiesRulerAction.name"
menubarPath="group.properties"
tooltip="%breakpointpropertiesRulerAction.tooltip">
</action>
<action
class="org.eclipse.wst.jsdt.debug.internal.ui.breakpoints.ToggleBreakpointEnablementEditorDelegate"
helpContextId="toggle_breakpoint_anablement_ruler_context"
id="org.eclipse.wst.jsdt.debug.ui.toggle.breakpoint.enablement"
label="%togglebreakpointenablementRulerAction.name"
menubarPath="debug"
tooltip="%togglebreakpointenablementRulerAction.tooltip">
</action>
</viewerContribution>
</extension>

</plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/*******************************************************************************
* Copyright (c) 2010-2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Genuitec LLC - adapted for TypeScript editor
*******************************************************************************/
package ts.eclipse.ide.jsdt.internal.ui.editor.breakpoints;

import java.util.HashMap;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptBreakpoint;
import org.eclipse.wst.jsdt.debug.core.breakpoints.IJavaScriptLineBreakpoint;
import org.eclipse.wst.jsdt.debug.core.model.JavaScriptDebugModel;

/**
* Adapter for toggling JavaScript breakpoints in the TypeScript editor
*/
public class ToggleBreakpointAdapter implements IToggleBreakpointsTargetExtension {

public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) {
return selection instanceof ITextSelection;
}

public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
return selection instanceof ITextSelection;
}

public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) {
return false;
}

public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) {
return false;
}

public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
//do nothing
}

public void toggleMethodBreakpoints(final IWorkbenchPart part, final ISelection selection) throws CoreException {
//do nothing
}

public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
if(selection instanceof ITextSelection) {
ITextEditor textEditor = getTextEditor(part);
if(textEditor == null) {
reportToStatusLine(part, "No editor could be found for the associated part");
return;
}
toggleLineBreakpoint(part, (ITextSelection) selection, ((TextSelection)selection).getStartLine()+1);
}
}

public void toggleLineBreakpoints(final IWorkbenchPart part, final ISelection selection) throws CoreException {
if (!(part instanceof IEditorPart) || !(selection instanceof ITextSelection)) {
return;
}

ITextEditor textEditor = (ITextEditor) part.getAdapter(ITextEditor.class);
if (textEditor != null) {
IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput());
if (document != null) {
int lineNumber;
try {
lineNumber = document.getLineOfOffset(((ITextSelection) selection).getOffset());
IResource res = getResource((IEditorPart) part);
if (res != null) {
addBreakpoint(res, document, lineNumber + 1);
}
}
catch (BadLocationException e) {
e.printStackTrace();
}
}
}
}

void toggleLineBreakpoint(final IWorkbenchPart part, final ITextSelection selection, final int linenumber) {
Job job = new Job("Toggle Line Breakpoints") {
protected IStatus run(IProgressMonitor monitor) {
try {
ITextEditor editor = getTextEditor(part);
if(editor != null && part instanceof IEditorPart) {
IResource resource = getResource((IEditorPart)part);
if(resource == null) {
resource = getResource((IEditorPart)part);
reportToStatusLine(part, "Failed to create Javascript line breakpoint - the resource could no be computed");
return Status.CANCEL_STATUS;
}
IBreakpoint bp = lineBreakpointExists(resource, linenumber);
if(bp != null) {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint(bp, true);
return Status.OK_STATUS;
}
IDocumentProvider documentProvider = editor.getDocumentProvider();
IDocument document = documentProvider.getDocument(editor.getEditorInput());
int charstart = -1, charend = -1;
try {
IRegion line = document.getLineInformation(linenumber - 1);
charstart = line.getOffset();
charend = charstart + line.getLength();
}
catch (BadLocationException ble) {}
HashMap<String, String> attributes = new HashMap<String, String>();
attributes.put(IJavaScriptBreakpoint.TYPE_NAME, null);
attributes.put(IJavaScriptBreakpoint.SCRIPT_PATH, resource.getFullPath().makeAbsolute().toString());
attributes.put(IJavaScriptBreakpoint.ELEMENT_HANDLE, null);
JavaScriptDebugModel.createLineBreakpoint(resource, linenumber, charstart, charend, attributes, true);
return Status.OK_STATUS;
}
reportToStatusLine(part, "Failed to create Javascript line breakpoint");
return Status.CANCEL_STATUS;
}
catch(CoreException ce) {
return ce.getStatus();
}
}
};
job.setPriority(Job.INTERACTIVE);
job.setSystem(true);
job.schedule();
}

void addBreakpoint(IResource resource, IDocument document, int linenumber) throws CoreException {
IBreakpoint bp = lineBreakpointExists(resource, linenumber);
if(bp != null) {
DebugPlugin.getDefault().getBreakpointManager().removeBreakpoint(bp, true);
}
int charstart = -1, charend = -1;
try {
IRegion line = document.getLineInformation(linenumber - 1);
charstart = line.getOffset();
charend = charstart + line.getLength();
}
catch (BadLocationException ble) {}
HashMap<String, String> attributes = new HashMap<String, String>();
attributes.put(IJavaScriptBreakpoint.TYPE_NAME, null);
attributes.put(IJavaScriptBreakpoint.SCRIPT_PATH, resource.getFullPath().makeAbsolute().toString());
attributes.put(IJavaScriptBreakpoint.ELEMENT_HANDLE, null);
JavaScriptDebugModel.createLineBreakpoint(resource, linenumber, charstart, charend, attributes, true);
}

void reportToStatusLine(final IWorkbenchPart part, final String message) {
getStandardDisplay().asyncExec(new Runnable() {
public void run() {
IEditorStatusLine statusLine = (IEditorStatusLine) part.getAdapter(IEditorStatusLine.class);
if (statusLine != null) {
if (message != null) {
statusLine.setMessage(true, message, null);
} else {
statusLine.setMessage(true, null, null);
}
}
}
});
}

Display getStandardDisplay() {
Display display;
display = Display.getCurrent();
if (display == null) {
display = Display.getDefault();
}
return display;
}

IBreakpoint lineBreakpointExists(IResource resource, int linenumber) {
IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(JavaScriptDebugModel.MODEL_ID);
IJavaScriptLineBreakpoint breakpoint = null;
for (int i = 0; i < breakpoints.length; i++) {
if(breakpoints[i] instanceof IJavaScriptLineBreakpoint) {
breakpoint = (IJavaScriptLineBreakpoint) breakpoints[i];
try {
if(IJavaScriptLineBreakpoint.MARKER_ID.equals(breakpoint.getMarker().getType()) &&
resource.equals(breakpoint.getMarker().getResource()) &&
linenumber == breakpoint.getLineNumber()) {
return breakpoint;
}
} catch (CoreException e) {}
}
}
return null;
}

IResource getResource(IEditorPart editor) {
IEditorInput editorInput = editor.getEditorInput();
return (IResource) editorInput.getAdapter(IFile.class);
}

ITextEditor getTextEditor(IWorkbenchPart part) {
if (part instanceof ITextEditor) {
return (ITextEditor) part;
}
return (ITextEditor) part.getAdapter(ITextEditor.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ts.eclipse.ide.jsdt.internal.ui.editor.breakpoints;

import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;

/**
* Adapter factory for breakpoints
*/
public class TypeScriptAdapterFactory implements IAdapterFactory {

static ToggleBreakpointAdapter tbadapter = null;

public Object getAdapter(Object adaptableObject, Class adapterType) {
if (adapterType.equals(IToggleBreakpointsTarget.class)) {
return getToggleBreakpointAdapter();
}
return null;
}

public Class[] getAdapterList() {
return new Class[] { IToggleBreakpointsTarget.class };
}

public static synchronized ToggleBreakpointAdapter getToggleBreakpointAdapter() {
if (tbadapter == null) {
tbadapter = new ToggleBreakpointAdapter();
}
return tbadapter;
}

}