blob: 3cfc0cbd744637b63d3c2cb5a2ffd3d355107e17 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.debug.ui.breakpoints;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
import org.eclipse.dltk.core.IField;
import org.eclipse.dltk.core.IMember;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.debug.core.model.IScriptVariable;
import org.eclipse.dltk.debug.ui.DLTKDebugUIPlugin;
import org.eclipse.dltk.internal.ui.editor.WorkingCopyManager;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.IWorkingCopyManager;
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.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.IEditorStatusLine;
import org.eclipse.ui.texteditor.ITextEditor;
public abstract class ScriptToggleBreakpointAdapter
implements IToggleBreakpointsTargetExtension {
protected boolean isRemote(IWorkbenchPart part, ISelection selection) {
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection) selection;
Object element = ss.getFirstElement();
if (element instanceof IMember) {
IMember member = (IMember) element;
return !member.getScriptProject().getProject().exists();
}
}
ITextEditor editor = getTextEditor(part);
if (editor != null) {
IEditorInput input = editor.getEditorInput();
Object adapter = Platform.getAdapterManager().getAdapter(input,
"org.eclipse.team.core.history.IFileRevision"); //$NON-NLS-1$
return adapter != null;
}
return false;
}
protected String getSelectedFirstLine(ITextEditor editor,
ITextSelection selection) {
try {
IDocument doc = editor.getDocumentProvider().getDocument(null);
final int line = selection.getStartLine();
IRegion region = doc.getLineInformation(line /* - 1 */);
return doc.get(region.getOffset(), region.getLength());
} catch (BadLocationException e) {
DLTKUIPlugin.log(e);
}
return null;
}
protected String getSelectedText(ITextEditor editor,
ITextSelection selection) {
try {
IDocument doc = editor.getDocumentProvider().getDocument(null);
return doc.get(selection.getOffset(), selection.getLength());
} catch (BadLocationException e) {
DLTKUIPlugin.log(e);
}
return null;
}
protected void report(final String message, final IWorkbenchPart part) {
DLTKDebugUIPlugin.getStandardDisplay().asyncExec(() -> {
IEditorStatusLine statusLine = part
.getAdapter(IEditorStatusLine.class);
if (statusLine != null) {
if (message != null) {
statusLine.setMessage(true, message, null);
} else {
statusLine.setMessage(true, null, null);
}
}
if (message != null
&& DLTKDebugUIPlugin.getActiveWorkbenchShell() != null) {
DLTKDebugUIPlugin.getActiveWorkbenchShell().getDisplay().beep();
}
});
}
protected ITextEditor getTextEditor(IWorkbenchPart part) {
if (part instanceof ITextEditor) {
return (ITextEditor) part;
}
return part.getAdapter(ITextEditor.class);
}
protected static final int BREAKPOINT_LINE_NOT_FOUND = -1;
protected static int findBreakpointLine(IDocument document, int startLine,
IScriptBreakpointLineValidator validator) {
String line = null;
int lineNumber = startLine;
int numberOfLines = document.getNumberOfLines();
if (lineNumber < 0 || lineNumber >= numberOfLines) {
return BREAKPOINT_LINE_NOT_FOUND;
}
while (lineNumber < numberOfLines) {
try {
IRegion region = document.getLineInformation(lineNumber);
line = document.get(region.getOffset(), region.getLength());
if (validator.isValid(line, lineNumber)) {
return lineNumber;
}
lineNumber++;
} catch (BadLocationException e) {
DLTKDebugUIPlugin.log(e);
}
}
return BREAKPOINT_LINE_NOT_FOUND;
}
public ScriptToggleBreakpointAdapter() {
}
@Override
public boolean canToggleLineBreakpoints(IWorkbenchPart part,
ISelection selection) {
if (isRemote(part, selection)) {
return false;
}
return selection instanceof ITextSelection;
}
/**
* Returns a selection of the member in the given text selection, or the
* original selection if none.
*
* @param part
* @param selection
* @return a structured selection of the member in the given text selection,
* or the original selection if none
* @exception CoreException
* if an exception occurs
*/
protected ISelection translateToMembers(IWorkbenchPart part,
ISelection selection) throws CoreException {
ITextEditor textEditor = getTextEditor(part);
if (textEditor != null && selection instanceof ITextSelection) {
ITextSelection textSelection = (ITextSelection) selection;
IEditorInput editorInput = textEditor.getEditorInput();
IDocumentProvider documentProvider = textEditor
.getDocumentProvider();
if (documentProvider == null) {
throw new CoreException(Status.CANCEL_STATUS);
}
IDocument document = documentProvider.getDocument(editorInput);
int offset = textSelection.getOffset();
if (document != null) {
try {
IRegion region = document
.getLineInformationOfOffset(offset);
int end = region.getOffset() + region.getLength();
while (Character.isWhitespace(document.getChar(offset))
&& offset < end) {
offset++;
}
} catch (BadLocationException e) {
}
}
IMember m = null;
IWorkingCopyManager manager = DLTKUIPlugin.getDefault()
.getWorkingCopyManager();
ISourceModule unit = manager.getWorkingCopy(editorInput);
if (unit != null) {
synchronized (unit) {
unit.reconcile(false, null, null);
}
}
IModelElement e = unit.getElementAt(offset);
if (e instanceof IMember) {
m = (IMember) e;
}
if (m != null) {
return new StructuredSelection(m);
}
}
return selection;
}
@Override
public void toggleLineBreakpoints(final IWorkbenchPart part,
final ISelection selection) throws CoreException {
Job job = new Job("Script Toggle Line Breakpoint") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
final ITextEditor editor = getTextEditor(part);
if (editor != null && selection instanceof ITextSelection) {
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
try {
report(null, part);
int lineNumber = ((ITextSelection) selection)
.getStartLine() + 1;
final String debugModelId = getDebugModelId();
final IBreakpoint breakpoint = BreakpointUtils
.findLineBreakpoint(editor, lineNumber,
debugModelId);
if (breakpoint != null) {
// if breakpoint already exists, delete it
breakpoint.delete();
} else {
final IDocumentProvider documentProvider = editor
.getDocumentProvider();
if (documentProvider == null) {
return Status.CANCEL_STATUS;
}
final IDocument document = documentProvider
.getDocument(editor.getEditorInput());
lineNumber = findBreakpointLine(document,
lineNumber - 1, getValidator()) + 1;
if (lineNumber != BREAKPOINT_LINE_NOT_FOUND) {
// Check if already breakpoint set to the same
// location
if (BreakpointUtils.findLineBreakpoint(editor,
lineNumber, debugModelId) == null) {
BreakpointUtils.addLineBreakpoint(editor,
lineNumber, debugModelId);
} else {
report(NLS.bind(
Messages.ScriptToggleBreakpointAdapter_breakpointAlreadySetAtLine,
lineNumber), part);
}
} else {
report(Messages.ScriptToggleBreakpointAdapter_invalidBreakpointPosition,
part);
}
}
} catch (CoreException e) {
DLTKDebugUIPlugin.log(e);
}
}
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
/**
* gets the <code>IJavaElement</code> from the editor input
*
* @param input
* the current editor input
* @return the corresponding <code>IJavaElement</code>
*/
protected IModelElement getModelElement(IEditorInput input) {
IModelElement je = DLTKUIPlugin.getEditorInputModelElement(input);
if (je != null) {
return je;
}
// try to get from the working copy manager
return ((WorkingCopyManager) DLTKUIPlugin.getDefault()
.getWorkingCopyManager()).getWorkingCopy(input, false);
}
/**
* Returns if the text selection is a field selection or not
*
* @param selection
* the text selection
* @param part
* the associated workbench part
* @return true if the text selection is a valid field for a watchpoint,
* false otherwise
* @since 3.3
*/
protected boolean isField(ITextSelection selection, IWorkbenchPart part) {
ITextEditor editor = getTextEditor(part);
if (editor != null) {
IModelElement element = getModelElement(editor.getEditorInput());
if (element != null) {
try {
if (element instanceof ISourceModule) {
element = ((ISourceModule) element)
.getElementAt(selection.getOffset());
}
return element != null
&& element.getElementType() == IModelElement.FIELD;
} catch (ModelException e) {
return false;
}
}
}
return false;
}
/**
* Determines if the selection is a field or not
*
* @param selection
* the current selection
* @return true if the selection is a field false otherwise
*/
protected boolean isFields(IStructuredSelection selection) {
if (!selection.isEmpty()) {
for (Iterator<?> i = selection.iterator(); i.hasNext();) {
Object thing = i.next();
if (thing instanceof IField) {
return true;
} else if (thing instanceof IScriptVariable) {
return true;
}
}
}
return false;
}
/**
* Returns a list of <code>IField</code> and <code>IJavaFieldVariable</code>
* in the given selection. When an <code>IField</code> can be resolved for
* an <code>IJavaFieldVariable</code>, it is returned in favour of the
* variable.
*
* @param selection
* @return list of <code>IField</code> and <code>IJavaFieldVariable</code>,
* possibly empty
* @throws CoreException
*/
protected List<?> getFields(IStructuredSelection selection)
throws CoreException {
if (selection.isEmpty()) {
return Collections.EMPTY_LIST;
}
List<Object> fields = new ArrayList<>(selection.size());
Iterator<?> iterator = selection.iterator();
while (iterator.hasNext()) {
Object thing = iterator.next();
if (thing instanceof IField) {
fields.add(thing);
} else if (thing instanceof IScriptVariable) {
fields.add(thing);
}
}
return fields;
}
protected abstract String getDebugModelId();
protected IScriptBreakpointLineValidator getValidator() {
return ScriptBreakpointLineValidatorFactory.NON_EMPTY_VALIDATOR;
}
}