/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others. All rights reserved. This
* program and the accompanying materials are made available under the terms of
* the Common Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/cpl-v10.html Contributors: IBM
* Corporation - initial API and implementation Bjorn Freeman-Benson - initial
* API and implementation
******************************************************************************/
package org.jactr.eclipse.runtime.ui.model;
import java.util.Collection;
import org.antlr.runtime.tree.CommonTree;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.texteditor.ITextEditor;
import org.jactr.eclipse.core.comp.CompilationUnitManager;
import org.jactr.eclipse.core.comp.ICompilationUnit;
import org.jactr.eclipse.runtime.debug.marker.ACTRBreakpoint;
import org.jactr.eclipse.runtime.launching.norm.ACTRSession;
import org.jactr.io.antlr3.builder.JACTRBuilder;
import org.jactr.io.antlr3.misc.ASTSupport;
/**
* Adapter to create breakpoints in jactr files.
*/
public class ACTRBreakpointAdapter implements IToggleBreakpointsTarget
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(ACTRBreakpointAdapter.class);
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleLineBreakpoints
* (org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection)
throws CoreException
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Attempting to toggle breakpoint at " + selection);
ITextEditor textEditor = getEditor(part);
if (textEditor != null)
{
IResource resource = (IResource) textEditor.getEditorInput().getAdapter(
IResource.class);
ITextSelection textSelection = (ITextSelection) selection;
int lineNumber = textSelection.getStartLine();
ICompilationUnit compUnit = CompilationUnitManager.acquire(resource);
if (compUnit == null) return;
CommonTree modelDescriptor = compUnit.getModelDescriptor();
CompilationUnitManager.release(compUnit);
// compilation errors - can't set break point
if (modelDescriptor == null)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(resource.getName()
+ " has compilation errors, can't mark breakpoints");
return;
}
CommonTree topLevel = findNearestTopLevelElement(modelDescriptor,
lineNumber);
// nothing was found.. bummer
if (topLevel == null)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("No top level element was found near " + lineNumber);
return;
}
if (LOGGER.isDebugEnabled())
LOGGER.debug(topLevel.toStringTree() + " is the closest element near "
+ lineNumber);
lineNumber = getLowestValidLineNumber(topLevel);
if (LOGGER.isDebugEnabled())
LOGGER.debug(lineNumber + " is the nearest valid line number near "
+ topLevel.toStringTree());
String type = getTypeString(topLevel);
String name = topLevel.getFirstChildWithType(JACTRBuilder.NAME).getText();
if (LOGGER.isDebugEnabled())
LOGGER.debug("break point type: " + type + " name:" + name);
IBreakpoint[] breakpoints = DebugPlugin.getDefault()
.getBreakpointManager().getBreakpoints(ACTRSession.ACTR_DEBUG_MODEL);
for (IBreakpoint breakpoint : breakpoints)
{
if (resource.equals(breakpoint.getMarker().getResource()))
{
ACTRBreakpoint bp = (ACTRBreakpoint) breakpoint;
if (bp.getLineNumber() == lineNumber
&& bp.getBreakpointName().equals(name)
&& bp.getBreakpointType().equals(type))
{
// remove
if (LOGGER.isDebugEnabled()) LOGGER.debug("removing");
breakpoint.delete();
return;
}
}
}
// create line breakpoint (doc line numbers start at 0)
ACTRBreakpoint lineBreakpoint = new ACTRBreakpoint(resource, type, name,
lineNumber);
if (LOGGER.isDebugEnabled()) LOGGER.debug("Adding breakpoint");
DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(
lineBreakpoint);
}
}
protected CommonTree findNearestTopLevelElement(CommonTree modelDescriptor,
int referenceLine)
{
Collection<CommonTree> topLevels = ASTSupport.getAllDescendantsWithType(
modelDescriptor, JACTRBuilder.PRODUCTION);
// topLevels.addAll(ASTSupport.getAllDescendantsWithType(modelDescriptor,
// JACTRBuilderTreeParser.CHUNK));
// topLevels.addAll(ASTSupport.getAllDescendantsWithType(modelDescriptor,
// JACTRBuilderTreeParser.CHUNK_TYPE));
// topLevels.addAll(ASTSupport.getAllDescendantsWithType(modelDescriptor,
// JACTRBuilderTreeParser.BUFFER));
int bestLine = Integer.MAX_VALUE;
CommonTree bestNode = null;
for (CommonTree node : topLevels)
{
int currentLine = getLowestValidLineNumber(node);
if (Math.abs(referenceLine - currentLine) < Math.abs(bestLine
- referenceLine))
{
bestNode = node;
bestLine = currentLine;
}
}
return bestNode;
}
protected int getLowestValidLineNumber(CommonTree commonTree)
{
int rtn = Integer.MAX_VALUE;
if (commonTree.getLine() != 0) rtn = commonTree.getLine();
// zip through the childre
for (int i = 0; i < commonTree.getChildCount(); i++)
rtn = Math.min(getLowestValidLineNumber((CommonTree) commonTree
.getChild(i)), rtn);
return rtn;
}
protected String getTypeString(CommonTree nearest)
{
switch (nearest.getType())
{
case JACTRBuilder.PRODUCTION:
return ACTRBreakpoint.PRODUCTION;
// case JACTRBuilderTreeParser.CHUNK:
// return org.jactr.eclipse.runtime.debug.marker.CHUNK;
// case JACTRBuilderTreeParser.CHUNK_TYPE:
// return org.jactr.eclipse.runtime.debug.marker.CHUNK_TYPE;
// case JACTRBuilderTreeParser.BUFFER:
// return org.jactr.eclipse.runtime.debug.marker.BUFFER;
}
return "unknown";
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleLineBreakpoints
* (org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleLineBreakpoints(IWorkbenchPart part,
ISelection selection)
{
return getEditor(part) != null;
}
/**
* Returns the editor being used to edit a PDA file, associated with the given
* part, or <code>null</code> if none.
*
* @param part
* workbench part
* @return the editor being used to edit a PDA file, associated with the given
* part, or <code>null</code> if none
*/
private ITextEditor getEditor(IWorkbenchPart part)
{
if (part instanceof ITextEditor)
{
ITextEditor editorPart = (ITextEditor) part;
IResource resource = (IResource) editorPart.getEditorInput().getAdapter(
IResource.class);
if (resource != null)
{
String extension = resource.getFileExtension();
if (extension != null
&& (extension.equalsIgnoreCase("jactr") || extension
.equalsIgnoreCase("lisp"))) return editorPart;
}
}
return null;
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleMethodBreakpoints
* (org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection)
throws CoreException
{
}
/*
* (non-Javadoc)
* @seeorg.eclipse.debug.ui.actions.IToggleBreakpointsTarget#
* canToggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart,
* org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleMethodBreakpoints(IWorkbenchPart part,
ISelection selection)
{
return false;
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleWatchpoints
* (org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void toggleWatchpoints(IWorkbenchPart part, ISelection selection)
throws CoreException
{
}
/*
* (non-Javadoc)
* @see
* org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleWatchpoints
* (org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection)
{
return false;
}
}