blob: 84803058d245a9ef58791124c74a60f3142930d1 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.debug.core.breakpoints;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.statet.r.debug.core.breakpoints.IRLineBreakpoint;
public abstract class RGenericLineBreakpoint extends RBreakpoint implements IRLineBreakpoint {
public static final String ELEMENT_TYPE_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.ElementTypeAttribute"; //$NON-NLS-1$
public static final String ELEMENT_ID_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.ElementIdAttribute"; //$NON-NLS-1$
public static final String ELEMENT_LABEL_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.ElementLabelAttribute"; //$NON-NLS-1$
public static final String SUB_LABEL_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.SubLabelAttribute"; //$NON-NLS-1$
// public static final String REXPR_INDEX_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.RExprIndexAttribute"; //$NON-NLS-1$
public static final String CONDITION_ENABLED_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.ConditionEnabledAttribute"; //$NON-NLS-1$
public static final String CONDITION_EXPR_MARKER_ATTR= "org.eclipse.statet.r.resourceMarkers.ConditionExprAttribute"; //$NON-NLS-1$
public static class CachedData {
private final long stamp;
private final String elementId;
private final int[] rExpressionIndex;
public CachedData(final long stamp, final String elementId, final int[] rExpressionIndex) {
this.stamp= stamp;
this.elementId= elementId;
this.rExpressionIndex= rExpressionIndex;
}
public long getStamp() {
return this.stamp;
}
public String getElementId() {
return this.elementId;
}
public int[] getRExpressionIndex() {
return this.rExpressionIndex;
}
}
private static final String[] POSITION_ATTRIBUTES= new String[] {
IMarker.LINE_NUMBER, IMarker.CHAR_START, IMarker.CHAR_END };
private static final String[] ELEMENT_ATTRIBUTES= new String[] {
ELEMENT_TYPE_MARKER_ATTR, ELEMENT_ID_MARKER_ATTR, ELEMENT_LABEL_MARKER_ATTR };
public static void updatePosition(final IMarker marker,
final int lineNumber, final int charStart, final int charEnd)
throws CoreException {
if (lineNumber != marker.getAttribute(IMarker.LINE_NUMBER, -1)
|| charStart != marker.getAttribute(IMarker.CHAR_START, -1)
|| charEnd != marker.getAttribute(IMarker.CHAR_END, -1) ) {
marker.setAttributes(POSITION_ATTRIBUTES, new Object[] {
Integer.valueOf(lineNumber), Integer.valueOf(charStart), Integer.valueOf(charEnd)
});
}
}
public static void updateElementInfo(final IMarker marker,
final int elementType, final String elementId,
final String elementLabel, final String subLabel)
throws CoreException {
if (elementType != marker.getAttribute(ELEMENT_TYPE_MARKER_ATTR, -1)
|| ((elementId != null) ? !elementId.equals(marker.getAttribute(ELEMENT_ID_MARKER_ATTR, null)) :
null != marker.getAttribute(ELEMENT_ID_MARKER_ATTR, null))
|| ((elementLabel != null) ? !elementLabel.equals(marker.getAttribute(ELEMENT_LABEL_MARKER_ATTR, null)) :
null != marker.getAttribute(ELEMENT_LABEL_MARKER_ATTR, null)) ) {
marker.setAttributes(ELEMENT_ATTRIBUTES, new Object[] {
Integer.valueOf(elementType), elementId, elementLabel
});
}
if ((subLabel != null) ? !subLabel.equals(marker.getAttribute(SUB_LABEL_MARKER_ATTR, null)) :
null != marker.getAttribute(SUB_LABEL_MARKER_ATTR, null) ) {
marker.setAttribute(SUB_LABEL_MARKER_ATTR, subLabel);
}
// if (rExpressionIndex != null) {
// final String value= encodeIntArray(rExpressionIndex);
// if (!value.equals(marker.getAttribute(REXPR_INDEX_MARKER_ATTR, null)) ) {
// marker.setAttribute(REXPR_INDEX_MARKER_ATTR, value);
// }
// }
// else if (marker.getAttribute(REXPR_INDEX_MARKER_ATTR, null) != null) {
// marker.setAttribute(REXPR_INDEX_MARKER_ATTR, null);
// }
}
// private static String encodeIntArray(int[] path) {
// final StringBuilder sb= new StringBuilder(path.length*3);
// sb.append(path.length);
// sb.append('[');
// if (path.length > 0) {
// sb.append(path[0]);
// for (int i= 1; i < path.length; i++) {
// sb.append(',');
// sb.append(path[i]);
// }
// }
// return sb.toString();
// }
//
// private static int[] parseIntArray(final String s) {
// int idx1;
// int idx2;
// idx1= s.indexOf('[');
// final int[] index= new int[Integer.parseInt(s.substring(0, idx1))];
// final int last= index.length-1;
// if (last >= 0) {
// idx1++;
// for (int i= 0; i < last; i++) {
// idx2= s.indexOf(',', idx1);
// index[i]= Integer.parseInt(s.substring(idx1, idx2));
// idx1= idx2+1;
// }
// index[last]= Integer.parseInt(s.substring(idx1, s.length()));
// }
// return index;
// }
private final AtomicReference<CachedData> cachedData= new AtomicReference<>();
protected RGenericLineBreakpoint() {
}
/**
* Adds the standard attributes of a line breakpoint to the given attribute map.
* The standard attributes are:
* <ol>
* <li>IBreakpoint.ID</li>
* <li>IBreakpoint.ENABLED</li>
* <li>IMarker.LINE_NUMBER</li>
* <li>IMarker.CHAR_START</li>
* <li>IMarker.CHAR_END</li>
* <li>ELEMENT_LABEL_MARKER_ATTR</li>
* </ol>
*/
protected void addStandardLineBreakpointAttributes(final Map<String, Object> attributes,
final boolean enabled,
final int lineNumber, final int charStart, final int charEnd,
final int elementType, final String elementId, final String elementLabel, final String subLabel) {
attributes.put(IBreakpoint.ID, getModelIdentifier());
attributes.put(IBreakpoint.ENABLED, Boolean.valueOf(enabled));
attributes.put(IMarker.LINE_NUMBER, new Integer(lineNumber));
attributes.put(IMarker.CHAR_START, new Integer(charStart));
attributes.put(IMarker.CHAR_END, new Integer(charEnd));
attributes.put(ELEMENT_TYPE_MARKER_ATTR, new Integer(elementType));
if (elementId != null) {
attributes.put(ELEMENT_ID_MARKER_ATTR, elementId);
}
if (elementLabel != null) {
attributes.put(ELEMENT_LABEL_MARKER_ATTR, elementLabel);
}
if (subLabel != null) {
attributes.put(SUB_LABEL_MARKER_ATTR, elementLabel);
}
// if (rExpressionIndex != null) {
// attributes.put(REXPR_INDEX_MARKER_ATTR, encodeIntArray(rExpressionIndex));
// }
}
@Override
public int getLineNumber() throws CoreException {
return ensureMarker().getAttribute(IMarker.LINE_NUMBER, -1);
}
@Override
public int getCharStart() throws CoreException {
return ensureMarker().getAttribute(IMarker.CHAR_START, -1);
}
@Override
public int getCharEnd() throws CoreException {
return ensureMarker().getAttribute(IMarker.CHAR_END, -1);
}
@Override
public int getElementType() throws CoreException {
return ensureMarker().getAttribute(ELEMENT_TYPE_MARKER_ATTR, -1);
}
public String getElementId() throws CoreException {
return ensureMarker().getAttribute(ELEMENT_ID_MARKER_ATTR, null);
}
@Override
public String getElementLabel() throws CoreException {
return ensureMarker().getAttribute(ELEMENT_LABEL_MARKER_ATTR, null);
}
@Override
public String getSubLabel() throws CoreException {
return ensureMarker().getAttribute(SUB_LABEL_MARKER_ATTR, null);
}
@Override
public void setConditionEnabled(final boolean enabled) throws CoreException {
ensureMarker().setAttribute(CONDITION_ENABLED_MARKER_ATTR, enabled);
}
@Override
public boolean isConditionEnabled() throws CoreException {
return ensureMarker().getAttribute(CONDITION_ENABLED_MARKER_ATTR, false);
}
@Override
public void setConditionExpr(final String code) throws CoreException {
final IMarker marker= ensureMarker();
if (code != null && code.trim().length() > 0) {
marker.setAttribute(CONDITION_EXPR_MARKER_ATTR, code);
}
else {
if (marker.getAttribute(CONDITION_EXPR_MARKER_ATTR, (String) null) != null) {
marker.setAttribute(CONDITION_ENABLED_MARKER_ATTR, false);
}
ensureMarker().setAttribute(CONDITION_EXPR_MARKER_ATTR, (String) null);
}
}
@Override
public String getConditionExpr() throws CoreException {
return ensureMarker().getAttribute(CONDITION_EXPR_MARKER_ATTR, ""); //$NON-NLS-1$
}
public void setCachedData(final CachedData data) {
if (checkTimestamp(data)) {
this.cachedData.set(data);
}
}
public CachedData getCachedData() {
final CachedData cachedData= this.cachedData.get();
if (cachedData != null && !checkTimestamp(cachedData)) {
this.cachedData.compareAndSet(cachedData, null);
}
return cachedData;
}
private boolean checkTimestamp(final CachedData data) {
final IMarker marker= getMarker();
if (marker != null) {
final IResource resource= marker.getResource();
if (resource != null) {
return (data.getStamp() == resource.getModificationStamp());
}
}
return false;
}
}