mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-06 17:26:01 +02:00
Semantic Highlighting (140335)
This commit is contained in:
parent
3a46db2f34
commit
487bac0828
32 changed files with 8604 additions and 300 deletions
|
@ -0,0 +1,120 @@
|
|||
#define SIMPLE_MACRO
|
||||
#define FUNCTION_MACRO(arg) globalFunc(arg)
|
||||
|
||||
enum Enumeration {
|
||||
enumerator
|
||||
};
|
||||
|
||||
const int globalConstant = 0;
|
||||
int globalVariable = 0;
|
||||
static int globalStaticVariable;
|
||||
|
||||
void globalFunc(int a);
|
||||
static void globalStaticFunc() {
|
||||
};
|
||||
|
||||
class Base1 {};
|
||||
class Base2 {};
|
||||
|
||||
class ClassContainer : Base1, Base2 {
|
||||
friend void friendFunc();
|
||||
friend class FriendClass;
|
||||
|
||||
public:
|
||||
static int staticPubField;
|
||||
const int constPubField;
|
||||
const static int constStaticPubField;
|
||||
int pubField;
|
||||
|
||||
static int staticPubMethod(int arg) {
|
||||
FUNCTION_MACRO(arg);
|
||||
globalFunc(arg);
|
||||
}
|
||||
int pubMethod();
|
||||
|
||||
enum pubEnumeration {pubEnumerator};
|
||||
class pubClass{};
|
||||
class pubStruct{};
|
||||
class pubUnion{};
|
||||
typedef pubClass pubTypedef;
|
||||
|
||||
protected:
|
||||
static const int constStaticProtField = 12;
|
||||
static int staticProtField;
|
||||
const int constProtField;
|
||||
int protField;
|
||||
|
||||
static int staticProtMethod();
|
||||
int protMethod();
|
||||
|
||||
enum protEnumeration {protEnumerator};
|
||||
class protClass{};
|
||||
class protStruct{};
|
||||
class protUnion{};
|
||||
typedef protClass protTypedef;
|
||||
|
||||
private:
|
||||
static const int constStaticPrivField = 12;
|
||||
static int staticPrivField;
|
||||
const int constPrivField;
|
||||
int privField;
|
||||
|
||||
static int staticPrivMethod();
|
||||
int privMethod();
|
||||
|
||||
enum privEnumeration {privEnumerator};
|
||||
class privClass{};
|
||||
class privStruct{};
|
||||
class privUnion{};
|
||||
typedef privClass privTypedef;
|
||||
|
||||
|
||||
};
|
||||
|
||||
template<T1,T2> class TemplateClass {
|
||||
T1 tArg1;
|
||||
T2 tArg2;
|
||||
TemplateClass(T1 arg1, T2 arg2) {
|
||||
tArg1 = arg1;
|
||||
tArg2 = arg2;
|
||||
}
|
||||
};
|
||||
|
||||
template<T1> class PartialInstantiatedClass : TemplateClass<T1,Base1> {};
|
||||
|
||||
|
||||
struct CppStruct {
|
||||
int structField;
|
||||
};
|
||||
|
||||
union CppUnion {
|
||||
int unionField;
|
||||
};
|
||||
|
||||
typedef CppUnion TUnion;
|
||||
|
||||
namespace ns {
|
||||
int namespaceField = 0;
|
||||
int namespaceFunc() {
|
||||
}
|
||||
}
|
||||
|
||||
int ClassContainer::protMethod() {
|
||||
return protField;
|
||||
}
|
||||
|
||||
int ClassContainer::pubMethod() {
|
||||
int localVar;
|
||||
return pubField;
|
||||
}
|
||||
|
||||
int ClassContainer::staticPrivMethod() {
|
||||
CppStruct st= new CppStruct();
|
||||
st.structField= 1;
|
||||
CppUnion un= new CppUnion();
|
||||
un.unionField= 2;
|
||||
staticPubMethod(staticPrivField);
|
||||
label:
|
||||
FUNCTION_MACRO(0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2005 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import junit.extensions.TestSetup;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.BadPositionCategoryException;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.SourceViewer;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.CEditor;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlighting;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingPresenter;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightings;
|
||||
|
||||
/**
|
||||
* Derived from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class AbstractSemanticHighlightingTest extends TestCase {
|
||||
|
||||
protected static class SemanticHighlightingTestSetup extends TestSetup {
|
||||
|
||||
private ICProject fCProject;
|
||||
private final String fTestFilename;
|
||||
|
||||
public SemanticHighlightingTestSetup(Test test, String testFilename) {
|
||||
super(test);
|
||||
fTestFilename= testFilename;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
fCProject= EditorTestHelper.createCProject(PROJECT, LINKED_FOLDER);
|
||||
|
||||
disableAllSemanticHighlightings();
|
||||
|
||||
fEditor= (CEditor) EditorTestHelper.openInEditor(ResourceTestHelper.findFile(fTestFilename), true);
|
||||
fSourceViewer= EditorTestHelper.getSourceViewer(fEditor);
|
||||
assertTrue(EditorTestHelper.joinReconciler(fSourceViewer, 0, 10000, 100));
|
||||
}
|
||||
|
||||
protected String getTestFilename() {
|
||||
return "/SHTest/src/SHTest.cpp";
|
||||
}
|
||||
|
||||
protected void tearDown () throws Exception {
|
||||
EditorTestHelper.closeEditor(fEditor);
|
||||
|
||||
IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore();
|
||||
|
||||
SemanticHighlighting[] semanticHighlightings= SemanticHighlightings.getSemanticHighlightings();
|
||||
for (int i= 0, n= semanticHighlightings.length; i < n; i++) {
|
||||
String enabledPreferenceKey= SemanticHighlightings.getEnabledPreferenceKey(semanticHighlightings[i]);
|
||||
if (!store.isDefault(enabledPreferenceKey))
|
||||
store.setToDefault(enabledPreferenceKey);
|
||||
}
|
||||
|
||||
if (fCProject != null)
|
||||
CProjectHelper.delete(fCProject);
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
public static final String LINKED_FOLDER= "resources/semanticHighlighting";
|
||||
|
||||
public static final String PROJECT= "SHTest";
|
||||
|
||||
private static CEditor fEditor;
|
||||
|
||||
private static SourceViewer fSourceViewer;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
disableAllSemanticHighlightings();
|
||||
}
|
||||
|
||||
protected void assertEqualPositions(Position[] expected, Position[] actual) {
|
||||
assertEquals(expected.length, actual.length);
|
||||
for (int i= 0, n= expected.length; i < n; i++) {
|
||||
assertEquals(expected[i].isDeleted(), actual[i].isDeleted());
|
||||
assertEquals(expected[i].getOffset(), actual[i].getOffset());
|
||||
assertEquals(expected[i].getLength(), actual[i].getLength());
|
||||
}
|
||||
}
|
||||
|
||||
protected Position createPosition(int line, int column, int length) throws BadLocationException {
|
||||
IDocument document= fSourceViewer.getDocument();
|
||||
return new Position(document.getLineOffset(line) + column, length);
|
||||
}
|
||||
|
||||
String toString(Position[] positions) throws BadLocationException {
|
||||
StringBuffer buf= new StringBuffer();
|
||||
IDocument document= fSourceViewer.getDocument();
|
||||
buf.append("Position[] expected= new Position[] {\n");
|
||||
for (int i= 0, n= positions.length; i < n; i++) {
|
||||
Position position= positions[i];
|
||||
int line= document.getLineOfOffset(position.getOffset());
|
||||
int column= position.getOffset() - document.getLineOffset(line);
|
||||
buf.append("\tcreatePosition(" + line + ", " + column + ", " + position.getLength() + "),\n");
|
||||
}
|
||||
buf.append("};\n");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected Position[] getSemanticHighlightingPositions() throws BadPositionCategoryException {
|
||||
SemanticHighlightingManager manager= (SemanticHighlightingManager) new Accessor(fEditor, CEditor.class).get("fSemanticManager");
|
||||
SemanticHighlightingPresenter presenter= (SemanticHighlightingPresenter) new Accessor(manager, manager.getClass()).get("fPresenter");
|
||||
String positionCategory= (String) new Accessor(presenter, presenter.getClass()).invoke("getPositionCategory", new Object[0]);
|
||||
IDocument document= fSourceViewer.getDocument();
|
||||
return document.getPositions(positionCategory);
|
||||
}
|
||||
|
||||
protected void setUpSemanticHighlighting(String semanticHighlighting) {
|
||||
enableSemanticHighlighting(semanticHighlighting);
|
||||
EditorTestHelper.forceReconcile(fSourceViewer);
|
||||
assertTrue(EditorTestHelper.joinReconciler(fSourceViewer, 0, 10000, 100));
|
||||
EditorTestHelper.runEventQueue(100);
|
||||
}
|
||||
|
||||
private void enableSemanticHighlighting(String preferenceKey) {
|
||||
IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore();
|
||||
store.setValue(getEnabledPreferenceKey(preferenceKey), true);
|
||||
}
|
||||
|
||||
private String getEnabledPreferenceKey(String preferenceKey) {
|
||||
return PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + preferenceKey + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_SUFFIX;
|
||||
}
|
||||
|
||||
private static void disableAllSemanticHighlightings() {
|
||||
IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore();
|
||||
store.setValue(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED, true);
|
||||
SemanticHighlighting[] semanticHilightings= SemanticHighlightings.getSemanticHighlightings();
|
||||
for (int i= 0, n= semanticHilightings.length; i < n; i++) {
|
||||
SemanticHighlighting semanticHilighting= semanticHilightings[i];
|
||||
if (store.getBoolean(SemanticHighlightings.getEnabledPreferenceKey(semanticHilighting)))
|
||||
store.setValue(SemanticHighlightings.getEnabledPreferenceKey(semanticHilighting), false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
/**
|
||||
* Helper class for accessing classes and members which cannot
|
||||
* be accessed using standard Java access control like private
|
||||
* or package visible elements.
|
||||
*
|
||||
* <p>Copied from JDT.</p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class Accessor extends Assert {
|
||||
|
||||
/** The class to access. */
|
||||
private Class fClass;
|
||||
/** The instance to access. */
|
||||
private Object fInstance;
|
||||
|
||||
/**
|
||||
* Creates an accessor for the given <code>instance</code> and
|
||||
* <code>class</code>. Only non-inherited members that particular
|
||||
* <code>class</code> can be accessed.
|
||||
*
|
||||
* @param instance the instance
|
||||
* @param clazz the class
|
||||
*/
|
||||
public Accessor(Object instance, Class clazz) {
|
||||
assertNotNull(instance);
|
||||
assertNotNull(clazz);
|
||||
fInstance= instance;
|
||||
fClass= clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an accessor for the given <code>instance</code> and
|
||||
* <code>class</code>. Only non-inherited members that particular
|
||||
* <code>class</code> can be accessed.
|
||||
*
|
||||
* @param instance the instance
|
||||
* @param className the name of the class
|
||||
* @param classLoader the class loader to use i.e. <code>getClass().getClassLoader()</code>
|
||||
*/
|
||||
public Accessor(Object instance, String className, ClassLoader classLoader) {
|
||||
assertNotNull(instance);
|
||||
assertNotNull(className);
|
||||
assertNotNull(classLoader);
|
||||
fInstance= instance;
|
||||
try {
|
||||
fClass= Class.forName(className, true, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
fail();
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an accessor for the given class.
|
||||
* <p>
|
||||
* In order to get the type information from the given
|
||||
* arguments they must all be instanc eof Object. Use
|
||||
* {@link #Accessor(String, ClassLoader, Class[], Object[])} if this
|
||||
* is not the case.</p>
|
||||
*
|
||||
* @param className the name of the class
|
||||
* @param classLoader the class loader to use i.e. <code>getClass().getClassLoader()</code>
|
||||
* @param constructorArgs the constructor arguments which must all be instance of Object
|
||||
*/
|
||||
public Accessor(String className, ClassLoader classLoader, Object[] constructorArgs) {
|
||||
this(className, classLoader, getTypes(constructorArgs), constructorArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an accessor for the given class.
|
||||
*
|
||||
* @param className the name of the class
|
||||
* @param classLoader the class loader to use i.e. <code>getClass().getClassLoader()</code>
|
||||
* @param constructorTypes the types of the constructor arguments
|
||||
* @param constructorArgs the constructor arguments
|
||||
*/
|
||||
public Accessor(String className, ClassLoader classLoader, Class[] constructorTypes, Object[] constructorArgs) {
|
||||
try {
|
||||
fClass= Class.forName(className, true, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
fail();
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
fail();
|
||||
}
|
||||
Constructor constructor= null;
|
||||
try {
|
||||
constructor= fClass.getDeclaredConstructor(constructorTypes);
|
||||
} catch (SecurityException e2) {
|
||||
fail();
|
||||
} catch (NoSuchMethodException e2) {
|
||||
fail();
|
||||
}
|
||||
assertNotNull(constructor);
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
fInstance= constructor.newInstance(constructorArgs);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (InvocationTargetException e) {
|
||||
fail();
|
||||
} catch (InstantiationException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an accessor for the given class.
|
||||
* <p>
|
||||
* This constructor is used to access static stuff.
|
||||
* </p>
|
||||
*
|
||||
* @param className the name of the class
|
||||
* @param classLoader the class loader to use i.e. <code>getClass().getClassLoader()</code>
|
||||
*/
|
||||
public Accessor(String className, ClassLoader classLoader) {
|
||||
try {
|
||||
fClass= Class.forName(className, true, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
fail();
|
||||
} catch (ExceptionInInitializerError e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the method with the given method name and arguments.
|
||||
* <p>
|
||||
* In order to get the type information from the given
|
||||
* arguments all those arguments must be instance of Object. Use
|
||||
* {@link #invoke(String, Class[], Object[])} if this
|
||||
* is not the case.</p>
|
||||
*
|
||||
* @param methodName the method name
|
||||
* @param arguments the method arguments which must all be instance of Object
|
||||
* @return the method return value
|
||||
*/
|
||||
public Object invoke(String methodName, Object[] arguments) {
|
||||
return invoke(methodName, getTypes(arguments), arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the method with the given method name and arguments.
|
||||
*
|
||||
* @param methodName the method name
|
||||
* @param types the argument types
|
||||
* @param arguments the method arguments
|
||||
* @return the method return value
|
||||
*/
|
||||
public Object invoke(String methodName, Class[] types, Object[] arguments) {
|
||||
Method method= null;
|
||||
try {
|
||||
method= fClass.getDeclaredMethod(methodName, types);
|
||||
} catch (SecurityException e) {
|
||||
fail();
|
||||
} catch (NoSuchMethodException ex) {
|
||||
fail();
|
||||
}
|
||||
assertNotNull(method);
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
return method.invoke(fInstance, arguments);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (InvocationTargetException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given value to the field with the given name.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @param value the value to assign to the field
|
||||
*/
|
||||
public void set(String fieldName, Object value) {
|
||||
Field field= getField(fieldName);
|
||||
try {
|
||||
field.set(fInstance, value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given value to the field with the given name.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @param value the value to assign to the field
|
||||
*/
|
||||
public void set(String fieldName, boolean value) {
|
||||
Field field= getField(fieldName);
|
||||
try {
|
||||
field.setBoolean(fInstance, value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the given value to the field with the given name.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @param value the value to assign to the field
|
||||
*/
|
||||
public void set(String fieldName, int value) {
|
||||
Field field= getField(fieldName);
|
||||
try {
|
||||
field.setInt(fInstance, value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the field with the given name.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @return the value of the field
|
||||
*/
|
||||
public Object get(String fieldName) {
|
||||
Field field= getField(fieldName);
|
||||
try {
|
||||
return field.get(fInstance);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
// Unreachable code
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the field with the given name.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @return the value of the field
|
||||
*/
|
||||
public boolean getBoolean(String fieldName) {
|
||||
Field field= getField(fieldName);
|
||||
try {
|
||||
return field.getBoolean(fInstance);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
// Unreachable code
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the field with the given name.
|
||||
*
|
||||
* @param fieldName the field name
|
||||
* @return the value of the field
|
||||
*/
|
||||
public int getInt(String fieldName) {
|
||||
Field field= getField(fieldName);
|
||||
try {
|
||||
return field.getInt(fInstance);
|
||||
} catch (IllegalArgumentException e) {
|
||||
fail();
|
||||
} catch (IllegalAccessException e) {
|
||||
fail();
|
||||
}
|
||||
// Unreachable code
|
||||
return 0;
|
||||
}
|
||||
|
||||
private Field getField(String fieldName) {
|
||||
Field field= null;
|
||||
try {
|
||||
field= fClass.getDeclaredField(fieldName);
|
||||
} catch (SecurityException e) {
|
||||
fail();
|
||||
} catch (NoSuchFieldException e) {
|
||||
fail();
|
||||
}
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
}
|
||||
|
||||
private static Class[] getTypes(Object[] objects) {
|
||||
if (objects == null)
|
||||
return null;
|
||||
|
||||
int length= objects.length;
|
||||
Class[] classes= new Class[length];
|
||||
for (int i= 0; i < length; i++) {
|
||||
assertNotNull(objects[i]);
|
||||
classes[i]= objects[i].getClass();
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,621 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
|
||||
/**
|
||||
* Runs the event loop of the given display until {@link #condition()} becomes
|
||||
* <code>true</code> or no events have occurred for the supplied timeout.
|
||||
* Between running the event loop, {@link Display#sleep()} is called.
|
||||
* <p>
|
||||
* There is a caveat: the given timeouts must be long enough that the calling
|
||||
* thread can enter <code>Display.sleep()</code> before the timeout elapses,
|
||||
* otherwise, the waiter may time out before <code>sleep</code> is called and
|
||||
* the sleeping thread may never be waken up.
|
||||
* </p>
|
||||
*
|
||||
* <p>Copied from org.eclipse.jdt.testplugin.util.</p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class DisplayHelper {
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
protected DisplayHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Until {@link #condition()} becomes <code>true</code> or the timeout
|
||||
* elapses, call {@link Display#sleep()} and run the event loop.
|
||||
* <p>
|
||||
* If <code>timeout < 0</code>, the event loop is never driven and
|
||||
* only the condition is checked. If <code>timeout == 0</code>, the event
|
||||
* loop is driven at most once, but <code>Display.sleep()</code> is never
|
||||
* invoked.
|
||||
* </p>
|
||||
*
|
||||
* @param display the display to run the event loop of
|
||||
* @param timeout the timeout in milliseconds
|
||||
* @return <code>true</code> if the condition became <code>true</code>,
|
||||
* <code>false</code> if the timeout elapsed
|
||||
*/
|
||||
public final boolean waitForCondition(Display display, long timeout) {
|
||||
// if the condition already holds, succeed
|
||||
if (condition())
|
||||
return true;
|
||||
|
||||
if (timeout < 0)
|
||||
return false;
|
||||
|
||||
// if driving the event loop once makes the condition hold, succeed
|
||||
// without spawning a thread.
|
||||
driveEventQueue(display);
|
||||
if (condition())
|
||||
return true;
|
||||
|
||||
// if the timeout is negative or zero, fail
|
||||
if (timeout == 0)
|
||||
return false;
|
||||
|
||||
// repeatedly sleep until condition becomes true or timeout elapses
|
||||
DisplayWaiter waiter= new DisplayWaiter(display);
|
||||
DisplayWaiter.Timeout timeoutState= waiter.start(timeout);
|
||||
boolean condition;
|
||||
try {
|
||||
do {
|
||||
if (display.sleep())
|
||||
driveEventQueue(display);
|
||||
condition= condition();
|
||||
} while (!condition && !timeoutState.hasTimedOut());
|
||||
} finally {
|
||||
waiter.stop();
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link Display#sleep()} and run the event loop until the given
|
||||
* timeout has elapsed.
|
||||
* <p>
|
||||
* If <code>timeout < 0</code>, nothing happens. If
|
||||
* <code>timeout == 0</code>, the event loop is driven exactly once, but
|
||||
* <code>Display.sleep()</code> is never invoked.
|
||||
* </p>
|
||||
*
|
||||
* @param display the display to run the event loop of
|
||||
* @param millis the timeout in milliseconds
|
||||
*/
|
||||
public static void sleep(Display display, long millis) {
|
||||
new DisplayHelper() {
|
||||
public boolean condition() {
|
||||
return false;
|
||||
}
|
||||
}.waitForCondition(display, millis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link Display#sleep()} and run the event loop once if
|
||||
* <code>sleep</code> returns before the timeout elapses. Returns
|
||||
* <code>true</code> if any events were processed, <code>false</code> if
|
||||
* not.
|
||||
* <p>
|
||||
* If <code>timeout < 0</code>, nothing happens and false is returned.
|
||||
* If <code>timeout == 0</code>, the event loop is driven exactly once,
|
||||
* but <code>Display.sleep()</code> is never invoked.
|
||||
* </p>
|
||||
*
|
||||
* @param display the display to run the event loop of
|
||||
* @param timeout the timeout in milliseconds
|
||||
* @return <code>true</code> if any event was taken off the event queue,
|
||||
* <code>false</code> if not
|
||||
*/
|
||||
public static boolean runEventLoop(Display display, long timeout) {
|
||||
if (timeout < 0)
|
||||
return false;
|
||||
|
||||
if (timeout == 0)
|
||||
return driveEventQueue(display);
|
||||
|
||||
// repeatedly sleep until condition becomes true or timeout elapses
|
||||
DisplayWaiter waiter= new DisplayWaiter(display);
|
||||
DisplayWaiter.Timeout timeoutState= waiter.start(timeout);
|
||||
boolean events= false;
|
||||
if (display.sleep() && !timeoutState.hasTimedOut()) {
|
||||
driveEventQueue(display);
|
||||
events= true;
|
||||
}
|
||||
waiter.stop();
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* The condition which has to be met in order for
|
||||
* {@link #waitForCondition(Display, int)} to return before the timeout
|
||||
* elapses.
|
||||
*
|
||||
* @return <code>true</code> if the condition is met, <code>false</code>
|
||||
* if the event loop should be driven some more
|
||||
*/
|
||||
protected abstract boolean condition();
|
||||
|
||||
/**
|
||||
* Runs the event loop on the given display.
|
||||
*
|
||||
* @param display the display
|
||||
* @return if <code>display.readAndDispatch</code> returned
|
||||
* <code>true</code> at least once
|
||||
*/
|
||||
private static boolean driveEventQueue(Display display) {
|
||||
boolean events= false;
|
||||
while (display.readAndDispatch()) {
|
||||
events= true;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Until {@link #condition()} becomes <code>true</code> or the timeout
|
||||
* elapses, call {@link Display#sleep()} and run the event loop.
|
||||
* <p>
|
||||
* If <code>timeout < 0</code>, the event loop is never driven and
|
||||
* only the condition is checked. If <code>timeout == 0</code>, the event
|
||||
* loop is driven at most once, but <code>Display.sleep()</code> is never
|
||||
* invoked.
|
||||
* </p>
|
||||
* <p>
|
||||
* The condition gets rechecked every <code>interval</code> milliseconds, even
|
||||
* if no events were read from the queue.
|
||||
* </p>
|
||||
*
|
||||
* @param display the display to run the event loop of
|
||||
* @param timeout the timeout in milliseconds
|
||||
* @param interval the interval to re-check the condition in milliseconds
|
||||
* @return <code>true</code> if the condition became <code>true</code>,
|
||||
* <code>false</code> if the timeout elapsed
|
||||
*/
|
||||
public final boolean waitForCondition(Display display, long timeout, long interval) {
|
||||
// if the condition already holds, succeed
|
||||
if (condition())
|
||||
return true;
|
||||
|
||||
if (timeout < 0)
|
||||
return false;
|
||||
|
||||
// if driving the event loop once makes the condition hold, succeed
|
||||
// without spawning a thread.
|
||||
driveEventQueue(display);
|
||||
if (condition())
|
||||
return true;
|
||||
|
||||
// if the timeout is negative or zero, fail
|
||||
if (timeout == 0)
|
||||
return false;
|
||||
|
||||
// repeatedly sleep until condition becomes true or timeout elapses
|
||||
DisplayWaiter waiter= new DisplayWaiter(display, true);
|
||||
long currentTimeMillis= System.currentTimeMillis();
|
||||
long finalTimeout= timeout + currentTimeMillis;
|
||||
if (finalTimeout < currentTimeMillis)
|
||||
finalTimeout= Long.MAX_VALUE;
|
||||
boolean condition;
|
||||
try {
|
||||
do {
|
||||
waiter.restart(interval);
|
||||
if (display.sleep())
|
||||
driveEventQueue(display);
|
||||
condition= condition();
|
||||
} while (!condition && finalTimeout > System.currentTimeMillis());
|
||||
} finally {
|
||||
waiter.stop();
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the thread that will wait for the timeout and wake up the display
|
||||
* so it does not wait forever. The thread may be restarted after it was stopped
|
||||
* or timed out.
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
final class DisplayWaiter {
|
||||
/**
|
||||
* Timeout state of a display waiter thread.
|
||||
*/
|
||||
public final class Timeout {
|
||||
private boolean fTimeoutState= false;
|
||||
/**
|
||||
* Returns <code>true</code> if the timeout has been reached,
|
||||
* <code>false</code> if not.
|
||||
*
|
||||
* @return <code>true</code> if the timeout has been reached,
|
||||
* <code>false</code> if not
|
||||
*/
|
||||
public boolean hasTimedOut() {
|
||||
synchronized (fMutex) {
|
||||
return fTimeoutState;
|
||||
}
|
||||
}
|
||||
void setTimedOut(boolean timedOut) {
|
||||
fTimeoutState= timedOut;
|
||||
}
|
||||
Timeout(boolean initialState) {
|
||||
fTimeoutState= initialState;
|
||||
}
|
||||
}
|
||||
|
||||
// configuration
|
||||
private final Display fDisplay;
|
||||
private final Object fMutex= new Object();
|
||||
private final boolean fKeepRunningOnTimeout;
|
||||
|
||||
/* State -- possible transitions:
|
||||
*
|
||||
* STOPPED -> RUNNING
|
||||
* RUNNING -> STOPPED
|
||||
* RUNNING -> IDLE
|
||||
* IDLE -> RUNNING
|
||||
* IDLE -> STOPPED
|
||||
*/
|
||||
private static final int RUNNING= 1 << 1;
|
||||
private static final int STOPPED= 1 << 2;
|
||||
private static final int IDLE= 1 << 3;
|
||||
|
||||
/** The current state. */
|
||||
private int fState;
|
||||
/** The time in milliseconds (see Date) that the timeout will occur. */
|
||||
private long fNextTimeout;
|
||||
/** The thread. */
|
||||
private Thread fCurrentThread;
|
||||
/** The timeout state of the current thread. */
|
||||
private Timeout fCurrentTimeoutState;
|
||||
|
||||
/**
|
||||
* Creates a new instance on the given display and timeout.
|
||||
*
|
||||
* @param display the display to run the event loop of
|
||||
*/
|
||||
public DisplayWaiter(Display display) {
|
||||
this(display, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance on the given display and timeout.
|
||||
*
|
||||
* @param display the display to run the event loop of
|
||||
* @param keepRunning <code>true</code> if the thread should be kept
|
||||
* running after timing out
|
||||
*/
|
||||
public DisplayWaiter(Display display, boolean keepRunning) {
|
||||
Assert.assertNotNull(display);
|
||||
fDisplay= display;
|
||||
fState= STOPPED;
|
||||
fKeepRunningOnTimeout= keepRunning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timeout thread if it is not currently running. Nothing happens
|
||||
* if a thread is already running.
|
||||
*
|
||||
* @param delay the delay from now in milliseconds
|
||||
* @return the timeout state which can be queried for its timed out status
|
||||
*/
|
||||
public Timeout start(long delay) {
|
||||
Assert.assertTrue(delay > 0);
|
||||
synchronized (fMutex) {
|
||||
switch (fState) {
|
||||
case STOPPED:
|
||||
startThread();
|
||||
setNextTimeout(delay);
|
||||
break;
|
||||
case IDLE:
|
||||
unhold();
|
||||
setNextTimeout(delay);
|
||||
break;
|
||||
}
|
||||
|
||||
return fCurrentTimeoutState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the next timeout to <em>current time</em> plus <code>delay</code>.
|
||||
*
|
||||
* @param delay the delay until the next timeout occurs in milliseconds from
|
||||
* now
|
||||
*/
|
||||
private void setNextTimeout(long delay) {
|
||||
long currentTimeMillis= System.currentTimeMillis();
|
||||
long next= currentTimeMillis + delay;
|
||||
if (next > currentTimeMillis)
|
||||
fNextTimeout= next;
|
||||
else
|
||||
fNextTimeout= Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the thread if it is not currently running; resets the timeout if
|
||||
* it is.
|
||||
*
|
||||
* @param delay the delay from now in milliseconds
|
||||
* @return the timeout state which can be queried for its timed out status
|
||||
*/
|
||||
public Timeout restart(long delay) {
|
||||
Assert.assertTrue(delay > 0);
|
||||
synchronized (fMutex) {
|
||||
switch (fState) {
|
||||
case STOPPED:
|
||||
startThread();
|
||||
break;
|
||||
case IDLE:
|
||||
unhold();
|
||||
break;
|
||||
}
|
||||
setNextTimeout(delay);
|
||||
|
||||
return fCurrentTimeoutState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the thread if it is running. If not, nothing happens. Another
|
||||
* thread may be started by calling {@link #start(long)} or
|
||||
* {@link #restart(long)}.
|
||||
*/
|
||||
public void stop() {
|
||||
synchronized (fMutex) {
|
||||
if (tryTransition(RUNNING | IDLE, STOPPED))
|
||||
fMutex.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the reaper thread on hold but does not stop it. It may be restarted
|
||||
* by calling {@link #start(long)} or {@link #restart(long)}.
|
||||
*/
|
||||
public void hold() {
|
||||
synchronized (fMutex) {
|
||||
// nothing to do if there is no thread
|
||||
if (tryTransition(RUNNING, IDLE))
|
||||
fMutex.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transition to <code>RUNNING</code> and clear the timed out flag. Assume
|
||||
* current state is <code>IDLE</code>.
|
||||
*/
|
||||
private void unhold() {
|
||||
checkedTransition(IDLE, RUNNING);
|
||||
fCurrentTimeoutState= new Timeout(false);
|
||||
fMutex.notifyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the thread. Assume the current state is <code>STOPPED</code>.
|
||||
*/
|
||||
private void startThread() {
|
||||
checkedTransition(STOPPED, RUNNING);
|
||||
fCurrentTimeoutState= new Timeout(false);
|
||||
fCurrentThread= new Thread() {
|
||||
/**
|
||||
* Exception thrown when a thread notices that it has been stopped
|
||||
* and a new thread has been started.
|
||||
*/
|
||||
final class ThreadChangedException extends Exception {
|
||||
private static final long serialVersionUID= 1L;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
run2();
|
||||
} catch (InterruptedException e) {
|
||||
// ignore and end the thread - we never interrupt ourselves,
|
||||
// so it must be an external entity that interrupted us
|
||||
Logger.global.log(Level.FINE, "", e);
|
||||
} catch (ThreadChangedException e) {
|
||||
// the thread was stopped and restarted before we got out
|
||||
// of a wait - we're no longer used
|
||||
// we might have been notified instead of the current thread,
|
||||
// so wake it up
|
||||
Logger.global.log(Level.FINE, "", e);
|
||||
synchronized (fMutex) {
|
||||
fMutex.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the thread.
|
||||
*
|
||||
* @throws InterruptedException if the thread was interrupted
|
||||
* @throws ThreadChangedException if the thread changed
|
||||
*/
|
||||
private void run2() throws InterruptedException, ThreadChangedException {
|
||||
synchronized (fMutex) {
|
||||
checkThread();
|
||||
tryHold(); // wait / potential state change
|
||||
assertStates(STOPPED | RUNNING);
|
||||
|
||||
while (isState(RUNNING)) {
|
||||
waitForTimeout(); // wait / potential state change
|
||||
|
||||
if (isState(RUNNING))
|
||||
timedOut(); // state change
|
||||
assertStates(STOPPED | IDLE);
|
||||
|
||||
tryHold(); // wait / potential state change
|
||||
assertStates(STOPPED | RUNNING);
|
||||
}
|
||||
assertStates(STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current thread is this thread, throw an
|
||||
* exception otherwise.
|
||||
*
|
||||
* @throws ThreadChangedException if the current thread changed
|
||||
*/
|
||||
private void checkThread() throws ThreadChangedException {
|
||||
if (fCurrentThread != this)
|
||||
throw new ThreadChangedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the next timeout occurs.
|
||||
*
|
||||
* @throws InterruptedException if the thread was interrupted
|
||||
* @throws ThreadChangedException if the thread changed
|
||||
*/
|
||||
private void waitForTimeout() throws InterruptedException, ThreadChangedException {
|
||||
long delta;
|
||||
while (isState(RUNNING) && (delta = fNextTimeout - System.currentTimeMillis()) > 0) {
|
||||
delta= Math.max(delta, 50); // wait at least 50ms in order to avoid timing out before the display is going to sleep
|
||||
Logger.global.finest("sleeping for " + delta + "ms");
|
||||
fMutex.wait(delta);
|
||||
checkThread();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timed out flag and wakes up the display. Transitions to
|
||||
* <code>IDLE</code> (if in keep-running mode) or
|
||||
* <code>STOPPED</code>.
|
||||
*/
|
||||
private void timedOut() {
|
||||
Logger.global.finer("timed out");
|
||||
fCurrentTimeoutState.setTimedOut(true);
|
||||
fDisplay.wake(); // wake up call!
|
||||
if (fKeepRunningOnTimeout)
|
||||
checkedTransition(RUNNING, IDLE);
|
||||
else
|
||||
checkedTransition(RUNNING, STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits while the state is <code>IDLE</code>, then returns. The
|
||||
* state must not be <code>RUNNING</code> when calling this
|
||||
* method. The state is either <code>STOPPED</code> or
|
||||
* <code>RUNNING</code> when the method returns.
|
||||
*
|
||||
* @throws InterruptedException if the thread was interrupted
|
||||
* @throws ThreadChangedException if the thread has changed while on
|
||||
* hold
|
||||
*/
|
||||
private void tryHold() throws InterruptedException, ThreadChangedException {
|
||||
while (isState(IDLE)) {
|
||||
fMutex.wait(0);
|
||||
checkThread();
|
||||
}
|
||||
assertStates(STOPPED | RUNNING);
|
||||
}
|
||||
};
|
||||
|
||||
fCurrentThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transitions to <code>nextState</code> if the current state is one of
|
||||
* <code>possibleStates</code>. Returns <code>true</code> if the
|
||||
* transition happened, <code>false</code> otherwise.
|
||||
*
|
||||
* @param possibleStates the states which trigger a transition
|
||||
* @param nextState the state to transition to
|
||||
* @return <code>true</code> if the transition happened,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
private boolean tryTransition(int possibleStates, int nextState) {
|
||||
if (isState(possibleStates)) {
|
||||
Logger.global.finer(name(fState) + " > " + name(nextState) + " (" + name(possibleStates) + ")");
|
||||
fState= nextState;
|
||||
return true;
|
||||
}
|
||||
Logger.global.finest("noTransition" + name(fState) + " !> " + name(nextState) + " (" + name(possibleStates) + ")");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the <code>possibleStates</code> and throws an assertion if it is
|
||||
* not met, then transitions to <code>nextState</code>.
|
||||
*
|
||||
* @param possibleStates the allowed states
|
||||
* @param nextState the state to transition to
|
||||
*/
|
||||
private void checkedTransition(int possibleStates, int nextState) {
|
||||
assertStates(possibleStates);
|
||||
Logger.global.finer(name(fState) + " > " + name(nextState));
|
||||
fState= nextState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements state consistency checking.
|
||||
*
|
||||
* @param states the allowed states
|
||||
* @throws junit.framework.AssertionFailedError if the current state is not
|
||||
* in <code>states</code>
|
||||
*/
|
||||
private void assertStates(int states) {
|
||||
Assert.assertTrue("illegal state", isState(states));
|
||||
}
|
||||
|
||||
/**
|
||||
* Answers <code>true</code> if the current state is in the given
|
||||
* <code>states</code>.
|
||||
*
|
||||
* @param states the possible states
|
||||
* @return <code>true</code> if the current state is in the given states,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
private boolean isState(int states) {
|
||||
return (states & fState) == fState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty print the given states.
|
||||
*
|
||||
* @param states the states
|
||||
* @return a string representation of the states
|
||||
*/
|
||||
private String name(int states) {
|
||||
StringBuffer buf= new StringBuffer();
|
||||
boolean comma= false;
|
||||
if ((states & RUNNING) == RUNNING) {
|
||||
buf.append("RUNNING");
|
||||
comma= true;
|
||||
}
|
||||
if ((states & STOPPED) == STOPPED) {
|
||||
if (comma)
|
||||
buf.append(",");
|
||||
buf.append("STOPPED");
|
||||
comma= true;
|
||||
}
|
||||
if ((states & IDLE) == IDLE) {
|
||||
if (comma)
|
||||
buf.append(",");
|
||||
buf.append("IDLE");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,508 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.IJobManager;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IWidgetTokenKeeper;
|
||||
import org.eclipse.jface.text.IWidgetTokenOwner;
|
||||
import org.eclipse.jface.text.reconciler.AbstractReconciler;
|
||||
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
|
||||
import org.eclipse.jface.text.reconciler.MonoReconciler;
|
||||
import org.eclipse.jface.text.source.SourceViewer;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.IEditorInput;
|
||||
import org.eclipse.ui.IEditorPart;
|
||||
import org.eclipse.ui.IEditorReference;
|
||||
import org.eclipse.ui.IViewReference;
|
||||
import org.eclipse.ui.IWorkbench;
|
||||
import org.eclipse.ui.IWorkbenchPage;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.IWorkbenchPartSite;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PartInitException;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.WorkbenchException;
|
||||
import org.eclipse.ui.dialogs.IOverwriteQuery;
|
||||
import org.eclipse.ui.ide.IDE;
|
||||
import org.eclipse.ui.texteditor.AbstractTextEditor;
|
||||
import org.eclipse.ui.texteditor.IDocumentProvider;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider;
|
||||
import org.eclipse.ui.wizards.datatransfer.IImportStructureProvider;
|
||||
import org.eclipse.ui.wizards.datatransfer.ImportOperation;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||
import org.eclipse.cdt.ui.testplugin.CTestPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.text.CReconcilingStrategy;
|
||||
|
||||
|
||||
/**
|
||||
* Copied from org.eclipse.jdt.text.tests.performance.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class EditorTestHelper {
|
||||
|
||||
private static class ImportOverwriteQuery implements IOverwriteQuery {
|
||||
public String queryOverwrite(String file) {
|
||||
return ALL;
|
||||
}
|
||||
}
|
||||
|
||||
public static final String TEXT_EDITOR_ID= "org.eclipse.ui.DefaultTextEditor";
|
||||
|
||||
public static final String C_EDITOR_ID= "org.eclipse.cdt.ui.editor.CEditor";
|
||||
|
||||
public static final String RESOURCE_PERSPECTIVE_ID= "org.eclipse.ui.resourcePerspective";
|
||||
|
||||
public static final String C_PERSPECTIVE_ID= "org.eclipse.cdt.ui.CPerspective";
|
||||
|
||||
public static final String OUTLINE_VIEW_ID= "org.eclipse.ui.views.ContentOutline";
|
||||
|
||||
public static final String C_VIEW_ID= "org.eclipse.cdt.ui.CView";
|
||||
|
||||
public static final String NAVIGATOR_VIEW_ID= "org.eclipse.ui.views.ResourceNavigator";
|
||||
|
||||
public static final String INTRO_VIEW_ID= "org.eclipse.ui.internal.introview";
|
||||
|
||||
public static IEditorPart openInEditor(IFile file, boolean runEventLoop) throws PartInitException {
|
||||
IEditorPart part= IDE.openEditor(getActivePage(), file);
|
||||
if (runEventLoop)
|
||||
runEventQueue(part);
|
||||
return part;
|
||||
}
|
||||
|
||||
public static IEditorPart openInEditor(IFile file, String editorId, boolean runEventLoop) throws PartInitException {
|
||||
IEditorPart part= IDE.openEditor(getActivePage(), file, editorId);
|
||||
if (runEventLoop)
|
||||
runEventQueue(part);
|
||||
return part;
|
||||
}
|
||||
|
||||
public static AbstractTextEditor[] openInEditor(IFile[] files, String editorId) throws PartInitException {
|
||||
AbstractTextEditor editors[]= new AbstractTextEditor[files.length];
|
||||
for (int i= 0; i < files.length; i++) {
|
||||
editors[i]= (AbstractTextEditor) openInEditor(files[i], editorId, true);
|
||||
joinReconciler(getSourceViewer(editors[i]), 100, 10000, 100);
|
||||
}
|
||||
return editors;
|
||||
}
|
||||
|
||||
public static IDocument getDocument(ITextEditor editor) {
|
||||
IDocumentProvider provider= editor.getDocumentProvider();
|
||||
IEditorInput input= editor.getEditorInput();
|
||||
return provider.getDocument(input);
|
||||
}
|
||||
|
||||
public static void revertEditor(ITextEditor editor, boolean runEventQueue) {
|
||||
editor.doRevertToSaved();
|
||||
if (runEventQueue)
|
||||
runEventQueue(editor);
|
||||
}
|
||||
|
||||
public static void closeEditor(IEditorPart editor) {
|
||||
IWorkbenchPartSite site;
|
||||
IWorkbenchPage page;
|
||||
if (editor != null && (site= editor.getSite()) != null && (page= site.getPage()) != null)
|
||||
page.closeEditor(editor, false);
|
||||
}
|
||||
|
||||
public static void closeAllEditors() {
|
||||
IWorkbenchWindow[] windows= PlatformUI.getWorkbench().getWorkbenchWindows();
|
||||
for (int i= 0; i < windows.length; i++) {
|
||||
IWorkbenchPage[] pages= windows[i].getPages();
|
||||
for (int j= 0; j < pages.length; j++) {
|
||||
IEditorReference[] editorReferences= pages[j].getEditorReferences();
|
||||
for (int k= 0; k < editorReferences.length; k++)
|
||||
closeEditor(editorReferences[k].getEditor(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the event queue on the current display until it is empty.
|
||||
*/
|
||||
public static void runEventQueue() {
|
||||
IWorkbenchWindow window= getActiveWorkbenchWindow();
|
||||
if (window != null)
|
||||
runEventQueue(window.getShell());
|
||||
}
|
||||
|
||||
public static void runEventQueue(IWorkbenchPart part) {
|
||||
runEventQueue(part.getSite().getShell());
|
||||
}
|
||||
|
||||
public static void runEventQueue(Shell shell) {
|
||||
runEventQueue(shell.getDisplay());
|
||||
}
|
||||
|
||||
public static void runEventQueue(Display display) {
|
||||
while (display.readAndDispatch()) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the event queue on the current display and lets it sleep until the
|
||||
* timeout elapses.
|
||||
*
|
||||
* @param millis the timeout in milliseconds
|
||||
*/
|
||||
public static void runEventQueue(long millis) {
|
||||
runEventQueue(getActiveDisplay(), millis);
|
||||
}
|
||||
|
||||
public static void runEventQueue(IWorkbenchPart part, long millis) {
|
||||
runEventQueue(part.getSite().getShell(), millis);
|
||||
}
|
||||
|
||||
public static void runEventQueue(Shell shell, long millis) {
|
||||
runEventQueue(shell.getDisplay(), millis);
|
||||
}
|
||||
|
||||
public static void runEventQueue(Display display, long minTime) {
|
||||
if (display != null) {
|
||||
DisplayHelper.sleep(display, minTime);
|
||||
} else {
|
||||
sleep((int) minTime);
|
||||
}
|
||||
}
|
||||
|
||||
public static IWorkbenchWindow getActiveWorkbenchWindow() {
|
||||
return PlatformUI.getWorkbench().getActiveWorkbenchWindow();
|
||||
}
|
||||
|
||||
public static void forceFocus() {
|
||||
IWorkbenchWindow window= getActiveWorkbenchWindow();
|
||||
if (window == null) {
|
||||
IWorkbenchWindow[] wbWindows= PlatformUI.getWorkbench().getWorkbenchWindows();
|
||||
if (wbWindows.length == 0)
|
||||
return;
|
||||
window= wbWindows[0];
|
||||
}
|
||||
Shell shell= window.getShell();
|
||||
if (shell != null && !shell.isDisposed()) {
|
||||
shell.forceActive();
|
||||
shell.forceFocus();
|
||||
}
|
||||
}
|
||||
|
||||
public static IWorkbenchPage getActivePage() {
|
||||
IWorkbenchWindow window= getActiveWorkbenchWindow();
|
||||
return window != null ? window.getActivePage() : null;
|
||||
}
|
||||
|
||||
public static Display getActiveDisplay() {
|
||||
IWorkbenchWindow window= getActiveWorkbenchWindow();
|
||||
return window != null ? window.getShell().getDisplay() : null;
|
||||
}
|
||||
|
||||
public static void joinBackgroundActivities(AbstractTextEditor editor) throws CoreException {
|
||||
joinBackgroundActivities(getSourceViewer(editor));
|
||||
}
|
||||
|
||||
public static void joinBackgroundActivities(SourceViewer sourceViewer) throws CoreException {
|
||||
joinBackgroundActivities();
|
||||
joinReconciler(sourceViewer, 500, 0, 500);
|
||||
}
|
||||
|
||||
public static void joinBackgroundActivities() throws CoreException {
|
||||
// Join Building
|
||||
Logger.global.entering("EditorTestHelper", "joinBackgroundActivities");
|
||||
Logger.global.finer("join builder");
|
||||
boolean interrupted= true;
|
||||
while (interrupted) {
|
||||
try {
|
||||
Platform.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, null);
|
||||
interrupted= false;
|
||||
} catch (InterruptedException e) {
|
||||
interrupted= true;
|
||||
}
|
||||
}
|
||||
// Join indexing
|
||||
Logger.global.finer("join indexer");
|
||||
// new SearchEngine().searchAllTypeNames(
|
||||
// null,
|
||||
// "XXXXXXXXX".toCharArray(), // make sure we search a concrete name. This is faster according to Kent
|
||||
// SearchPattern.R_EXACT_MATCH,
|
||||
// IJavaSearchConstants.CLASS,
|
||||
// SearchEngine.createJavaSearchScope(new ICElement[0]),
|
||||
// new Requestor(),
|
||||
// IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
|
||||
// null);
|
||||
// Join jobs
|
||||
joinJobs(0, 0, 500);
|
||||
Logger.global.exiting("EditorTestHelper", "joinBackgroundActivities");
|
||||
}
|
||||
|
||||
public static boolean joinJobs(long minTime, long maxTime, long intervalTime) {
|
||||
Logger.global.entering("EditorTestHelper", "joinJobs");
|
||||
runEventQueue(minTime);
|
||||
|
||||
DisplayHelper helper= new DisplayHelper() {
|
||||
public boolean condition() {
|
||||
return allJobsQuiet();
|
||||
}
|
||||
};
|
||||
boolean quiet= helper.waitForCondition(getActiveDisplay(), maxTime > 0 ? maxTime : Long.MAX_VALUE, intervalTime);
|
||||
Logger.global.exiting("EditorTestHelper", "joinJobs", new Boolean(quiet));
|
||||
return quiet;
|
||||
}
|
||||
|
||||
public static void sleep(int intervalTime) {
|
||||
try {
|
||||
Thread.sleep(intervalTime);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean allJobsQuiet() {
|
||||
IJobManager jobManager= Platform.getJobManager();
|
||||
Job[] jobs= jobManager.find(null);
|
||||
for (int i= 0; i < jobs.length; i++) {
|
||||
Job job= jobs[i];
|
||||
int state= job.getState();
|
||||
if (state == Job.RUNNING || state == Job.WAITING) {
|
||||
Logger.global.finest(job.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isViewShown(String viewId) {
|
||||
return getActivePage().findViewReference(viewId) != null;
|
||||
}
|
||||
|
||||
public static boolean showView(String viewId, boolean show) throws PartInitException {
|
||||
IWorkbenchPage activePage= getActivePage();
|
||||
IViewReference view= activePage.findViewReference(viewId);
|
||||
boolean shown= view != null;
|
||||
if (shown != show)
|
||||
if (show)
|
||||
activePage.showView(viewId);
|
||||
else
|
||||
activePage.hideView(view);
|
||||
return shown;
|
||||
}
|
||||
|
||||
public static void bringToTop() {
|
||||
getActiveWorkbenchWindow().getShell().forceActive();
|
||||
}
|
||||
|
||||
public static void forceReconcile(SourceViewer sourceViewer) {
|
||||
Accessor reconcilerAccessor= new Accessor(getReconciler(sourceViewer), AbstractReconciler.class);
|
||||
reconcilerAccessor.invoke("forceReconciling", new Object[0]);
|
||||
}
|
||||
|
||||
public static boolean joinReconciler(SourceViewer sourceViewer, long minTime, long maxTime, long intervalTime) {
|
||||
Logger.global.entering("EditorTestHelper", "joinReconciler");
|
||||
runEventQueue(minTime);
|
||||
|
||||
AbstractReconciler reconciler= getReconciler(sourceViewer);
|
||||
if (reconciler == null)
|
||||
return true;
|
||||
final Accessor backgroundThreadAccessor= getBackgroundThreadAccessor(reconciler);
|
||||
final Accessor cReconcilerAccessor;
|
||||
if (reconciler instanceof MonoReconciler) {
|
||||
IReconcilingStrategy strategy= reconciler.getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE);
|
||||
if (strategy instanceof CReconcilingStrategy) {
|
||||
cReconcilerAccessor= new Accessor(strategy, CReconcilingStrategy.class);
|
||||
} else {
|
||||
cReconcilerAccessor= null;
|
||||
}
|
||||
} else {
|
||||
cReconcilerAccessor= null;
|
||||
}
|
||||
DisplayHelper helper= new DisplayHelper() {
|
||||
public boolean condition() {
|
||||
return !isRunning(cReconcilerAccessor, backgroundThreadAccessor);
|
||||
}
|
||||
};
|
||||
boolean finished= helper.waitForCondition(getActiveDisplay(), maxTime > 0 ? maxTime : Long.MAX_VALUE, intervalTime);
|
||||
Logger.global.exiting("EditorTestHelper", "joinReconciler", new Boolean(finished));
|
||||
return finished;
|
||||
}
|
||||
|
||||
public static AbstractReconciler getReconciler(SourceViewer sourceViewer) {
|
||||
return (AbstractReconciler) new Accessor(sourceViewer, SourceViewer.class).get("fReconciler");
|
||||
}
|
||||
|
||||
public static SourceViewer getSourceViewer(AbstractTextEditor editor) {
|
||||
SourceViewer sourceViewer= (SourceViewer) new Accessor(editor, AbstractTextEditor.class).invoke("getSourceViewer", new Object[0]);
|
||||
return sourceViewer;
|
||||
}
|
||||
|
||||
private static Accessor getBackgroundThreadAccessor(AbstractReconciler reconciler) {
|
||||
Object backgroundThread= new Accessor(reconciler, AbstractReconciler.class).get("fThread");
|
||||
return new Accessor(backgroundThread, backgroundThread.getClass());
|
||||
}
|
||||
|
||||
private static boolean isRunning(Accessor cReconcilerAccessor, Accessor backgroundThreadAccessor) {
|
||||
return (cReconcilerAccessor != null ? !isInitialProcessDone(cReconcilerAccessor) : false) || isDirty(backgroundThreadAccessor) || isActive(backgroundThreadAccessor);
|
||||
}
|
||||
|
||||
private static boolean isInitialProcessDone(Accessor cReconcilerAccessor) {
|
||||
return ((Boolean) cReconcilerAccessor.get("fInitialProcessDone")).booleanValue();
|
||||
}
|
||||
|
||||
private static boolean isDirty(Accessor backgroundThreadAccessor) {
|
||||
return ((Boolean) backgroundThreadAccessor.invoke("isDirty", new Object[0])).booleanValue();
|
||||
}
|
||||
|
||||
private static boolean isActive(Accessor backgroundThreadAccessor) {
|
||||
return ((Boolean) backgroundThreadAccessor.invoke("isActive", new Object[0])).booleanValue();
|
||||
}
|
||||
|
||||
public static String showPerspective(String perspective) throws WorkbenchException {
|
||||
String shownPerspective= getActivePage().getPerspective().getId();
|
||||
if (!perspective.equals(shownPerspective)) {
|
||||
IWorkbench workbench= PlatformUI.getWorkbench();
|
||||
IWorkbenchWindow activeWindow= workbench.getActiveWorkbenchWindow();
|
||||
workbench.showPerspective(perspective, activeWindow);
|
||||
}
|
||||
return shownPerspective;
|
||||
}
|
||||
|
||||
public static void closeAllPopUps(SourceViewer sourceViewer) {
|
||||
IWidgetTokenKeeper tokenKeeper= new IWidgetTokenKeeper() {
|
||||
public boolean requestWidgetToken(IWidgetTokenOwner owner) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
sourceViewer.requestWidgetToken(tokenKeeper, Integer.MAX_VALUE);
|
||||
sourceViewer.releaseWidgetToken(tokenKeeper);
|
||||
}
|
||||
|
||||
public static void resetFolding() {
|
||||
CUIPlugin.getDefault().getPreferenceStore().setToDefault(PreferenceConstants.EDITOR_FOLDING_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean enableFolding(boolean value) {
|
||||
IPreferenceStore preferenceStore= CUIPlugin.getDefault().getPreferenceStore();
|
||||
boolean oldValue= preferenceStore.getBoolean(PreferenceConstants.EDITOR_FOLDING_ENABLED);
|
||||
if (value != oldValue)
|
||||
preferenceStore.setValue(PreferenceConstants.EDITOR_FOLDING_ENABLED, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public static ICProject createCProject(String project, String externalSourceFolder) throws CoreException {
|
||||
return createCProject(project, externalSourceFolder, false);
|
||||
}
|
||||
|
||||
public static ICProject createCProject(String project, String externalSourceFolder, boolean linkSourceFolder) throws CoreException {
|
||||
ICProject cProject= CProjectHelper.createCProject(project, "bin");
|
||||
IFolder folder;
|
||||
if (linkSourceFolder)
|
||||
folder= ResourceHelper.createLinkedFolder((IProject) cProject.getUnderlyingResource(), new Path("src"), CTestPlugin.getDefault(), new Path(externalSourceFolder));
|
||||
else {
|
||||
folder= ((IProject) cProject.getUnderlyingResource()).getFolder("src");
|
||||
importFilesFromDirectory(FileTool.getFileInPlugin(CTestPlugin.getDefault(), new Path(externalSourceFolder)), folder.getFullPath(), null);
|
||||
}
|
||||
Assert.assertNotNull(folder);
|
||||
Assert.assertTrue(folder.exists());
|
||||
CProjectHelper.addCContainer(cProject, "src");
|
||||
return cProject;
|
||||
}
|
||||
|
||||
public static IFile[] findFiles(IResource resource) throws CoreException {
|
||||
List files= new ArrayList();
|
||||
findFiles(resource, files);
|
||||
return (IFile[]) files.toArray(new IFile[files.size()]);
|
||||
}
|
||||
|
||||
private static void findFiles(IResource resource, List files) throws CoreException {
|
||||
if (resource instanceof IFile) {
|
||||
files.add(resource);
|
||||
return;
|
||||
}
|
||||
if (resource instanceof IContainer) {
|
||||
IResource[] resources= ((IContainer) resource).members();
|
||||
for (int i= 0; i < resources.length; i++)
|
||||
findFiles(resources[i], files);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean setDialogEnabled(String id, boolean enabled) {
|
||||
// boolean wasEnabled= OptionalMessageDialog.isDialogEnabled(id);
|
||||
// if (wasEnabled != enabled)
|
||||
// OptionalMessageDialog.setDialogEnabled(id, enabled);
|
||||
// return wasEnabled;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void importFilesFromDirectory(File rootDir, IPath destPath, IProgressMonitor monitor) throws CoreException {
|
||||
try {
|
||||
IImportStructureProvider structureProvider= FileSystemStructureProvider.INSTANCE;
|
||||
List files= new ArrayList(100);
|
||||
addFiles(rootDir, files);
|
||||
ImportOperation op= new ImportOperation(destPath, rootDir, structureProvider, new ImportOverwriteQuery(), files);
|
||||
op.setCreateContainerStructure(false);
|
||||
op.run(monitor);
|
||||
} catch (Exception x) {
|
||||
throw newCoreException(x);
|
||||
}
|
||||
}
|
||||
|
||||
private static CoreException newCoreException(Throwable x) {
|
||||
return new CoreException(new Status(IStatus.ERROR, CTestPlugin.PLUGIN_ID, -1, "", x));
|
||||
}
|
||||
|
||||
private static void addFiles(File dir, List collection) throws IOException {
|
||||
File[] files= dir.listFiles();
|
||||
List subDirs= new ArrayList(2);
|
||||
for (int i= 0; i < files.length; i++) {
|
||||
if (files[i].isFile()) {
|
||||
collection.add(files[i]);
|
||||
} else if (files[i].isDirectory()) {
|
||||
subDirs.add(files[i]);
|
||||
}
|
||||
}
|
||||
Iterator iter= subDirs.iterator();
|
||||
while (iter.hasNext()) {
|
||||
File subDir= (File)iter.next();
|
||||
addFiles(subDir, collection);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
|
||||
import org.eclipse.core.filebuffers.FileBuffers;
|
||||
|
||||
/**
|
||||
* Copied from org.eclipse.core.filebuffers.tests.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class FileTool {
|
||||
|
||||
private final static int MAX_RETRY= 5;
|
||||
|
||||
/**
|
||||
* A buffer.
|
||||
*/
|
||||
private static byte[] buffer = new byte[8192];
|
||||
|
||||
/**
|
||||
* Unzips the given zip file to the given destination directory
|
||||
* extracting only those entries the pass through the given
|
||||
* filter.
|
||||
*
|
||||
* @param zipFile the zip file to unzip
|
||||
* @param dstDir the destination directory
|
||||
* @throws IOException in case of problem
|
||||
*/
|
||||
public static void unzip(ZipFile zipFile, File dstDir) throws IOException {
|
||||
unzip(zipFile, dstDir, dstDir, 0);
|
||||
}
|
||||
|
||||
private static void unzip(ZipFile zipFile, File rootDstDir, File dstDir, int depth) throws IOException {
|
||||
|
||||
Enumeration entries = zipFile.entries();
|
||||
|
||||
try {
|
||||
while(entries.hasMoreElements()){
|
||||
ZipEntry entry = (ZipEntry)entries.nextElement();
|
||||
if(entry.isDirectory()){
|
||||
continue;
|
||||
}
|
||||
String entryName = entry.getName();
|
||||
File file = new File(dstDir, changeSeparator(entryName, '/', File.separatorChar));
|
||||
file.getParentFile().mkdirs();
|
||||
InputStream src = null;
|
||||
OutputStream dst = null;
|
||||
try {
|
||||
src = zipFile.getInputStream(entry);
|
||||
dst = new FileOutputStream(file);
|
||||
transferData(src, dst);
|
||||
} finally {
|
||||
if(dst != null){
|
||||
try {
|
||||
dst.close();
|
||||
} catch(IOException e){
|
||||
}
|
||||
}
|
||||
if(src != null){
|
||||
try {
|
||||
src.close();
|
||||
} catch(IOException e){
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
zipFile.close();
|
||||
} catch(IOException e){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given file path with its separator
|
||||
* character changed from the given old separator to the
|
||||
* given new separator.
|
||||
*
|
||||
* @param path a file path
|
||||
* @param oldSeparator a path separator character
|
||||
* @param newSeparator a path separator character
|
||||
* @return the file path with its separator character
|
||||
* changed from the given old separator to the given new
|
||||
* separator
|
||||
*/
|
||||
public static String changeSeparator(String path, char oldSeparator, char newSeparator){
|
||||
return path.replace(oldSeparator, newSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all bytes in the given source file to
|
||||
* the given destination file.
|
||||
*
|
||||
* @param source the given source file
|
||||
* @param destination the given destination file
|
||||
* @throws IOException in case of error
|
||||
*/
|
||||
public static void transferData(File source, File destination) throws IOException {
|
||||
destination.getParentFile().mkdirs();
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
is = new FileInputStream(source);
|
||||
os = new FileOutputStream(destination);
|
||||
transferData(is, os);
|
||||
} finally {
|
||||
if(os != null)
|
||||
os.close();
|
||||
if(is != null)
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all bytes in the given source stream to
|
||||
* the given destination stream. Neither streams
|
||||
* are closed.
|
||||
*
|
||||
* @param source the given source stream
|
||||
* @param destination the given destination stream
|
||||
* @throws IOException in case of error
|
||||
*/
|
||||
public static void transferData(InputStream source, OutputStream destination) throws IOException {
|
||||
int bytesRead = 0;
|
||||
while(bytesRead != -1){
|
||||
bytesRead = source.read(buffer, 0, buffer.length);
|
||||
if(bytesRead != -1){
|
||||
destination.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the given source file to the given destination file.
|
||||
*
|
||||
* @param src the given source file
|
||||
* @param dst the given destination file
|
||||
* @throws IOException in case of error
|
||||
*/
|
||||
public static void copy(File src, File dst) throws IOException {
|
||||
if(src.isDirectory()){
|
||||
String[] srcChildren = src.list();
|
||||
for(int i = 0; i < srcChildren.length; ++i){
|
||||
File srcChild= new File(src, srcChildren[i]);
|
||||
File dstChild= new File(dst, srcChildren[i]);
|
||||
copy(srcChild, dstChild);
|
||||
}
|
||||
} else
|
||||
transferData(src, dst);
|
||||
}
|
||||
|
||||
public static File getFileInPlugin(Plugin plugin, IPath path) {
|
||||
try {
|
||||
URL installURL= plugin.getBundle().getEntry(path.toString());
|
||||
URL localURL= Platform.asLocalURL(installURL);
|
||||
return new File(localURL.getFile());
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static File createTempFileInPlugin(Plugin plugin, IPath path) {
|
||||
IPath stateLocation= plugin.getStateLocation();
|
||||
stateLocation= stateLocation.append(path);
|
||||
return stateLocation.toFile();
|
||||
}
|
||||
|
||||
public static StringBuffer read(String fileName) throws IOException {
|
||||
return read(new FileReader(fileName));
|
||||
}
|
||||
|
||||
public static StringBuffer read(Reader reader) throws IOException {
|
||||
StringBuffer s= new StringBuffer();
|
||||
try {
|
||||
char[] charBuffer= new char[8196];
|
||||
int chars= reader.read(charBuffer);
|
||||
while (chars != -1) {
|
||||
s.append(charBuffer, 0, chars);
|
||||
chars= reader.read(charBuffer);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void write(String fileName, StringBuffer content) throws IOException {
|
||||
Writer writer= new FileWriter(fileName);
|
||||
try {
|
||||
writer.write(content.toString());
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void delete(IPath path) throws CoreException {
|
||||
File file= FileBuffers.getSystemFileAtLocation(path);
|
||||
delete(file);
|
||||
}
|
||||
|
||||
public static void delete(File file) throws CoreException {
|
||||
if (file.exists()) {
|
||||
for (int i= 0; i < MAX_RETRY; i++) {
|
||||
if (file.delete())
|
||||
i= MAX_RETRY;
|
||||
else {
|
||||
try {
|
||||
Thread.sleep(1000); // sleep a second
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.eclipse.core.filebuffers.manipulation.ContainerCreator;
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IProjectDescription;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
|
||||
import org.eclipse.cdt.ui.testplugin.CTestPlugin;
|
||||
|
||||
/**
|
||||
* Copied from org.eclipse.core.filebuffers.tests.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ResourceHelper {
|
||||
|
||||
private final static IProgressMonitor NULL_MONITOR= new NullProgressMonitor();
|
||||
private static final int MAX_RETRY= 5;
|
||||
|
||||
public static IProject createProject(String projectName) throws CoreException {
|
||||
|
||||
IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
|
||||
IProject project= root.getProject(projectName);
|
||||
if (!project.exists())
|
||||
project.create(NULL_MONITOR);
|
||||
else
|
||||
project.refreshLocal(IResource.DEPTH_INFINITE, null);
|
||||
|
||||
if (!project.isOpen())
|
||||
project.open(NULL_MONITOR);
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
public static void deleteProject(String projectName) throws CoreException {
|
||||
IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
|
||||
IProject project= root.getProject(projectName);
|
||||
if (project.exists())
|
||||
delete(project);
|
||||
}
|
||||
|
||||
public static void delete(final IProject project) throws CoreException {
|
||||
delete(project, true);
|
||||
}
|
||||
|
||||
public static void delete(final IProject project, boolean deleteContent) throws CoreException {
|
||||
for (int i= 0; i < MAX_RETRY; i++) {
|
||||
try {
|
||||
project.delete(deleteContent, true, NULL_MONITOR);
|
||||
i= MAX_RETRY;
|
||||
} catch (CoreException x) {
|
||||
if (i == MAX_RETRY - 1) {
|
||||
CTestPlugin.getDefault().getLog().log(x.getStatus());
|
||||
// throw x;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000); // sleep a second
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IFolder createFolder(String portableFolderPath) throws CoreException {
|
||||
ContainerCreator creator= new ContainerCreator(ResourcesPlugin.getWorkspace(), new Path(portableFolderPath));
|
||||
IContainer container= creator.createContainer(NULL_MONITOR);
|
||||
if (container instanceof IFolder)
|
||||
return (IFolder) container;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IFile createFile(IFolder folder, String name, String contents) throws CoreException {
|
||||
return createFile(folder.getFile(name), name, contents);
|
||||
}
|
||||
|
||||
public static IFile createFile(IProject project, String name, String contents) throws CoreException {
|
||||
return createFile(project.getFile(name), name, contents);
|
||||
}
|
||||
|
||||
private static IFile createFile(IFile file, String name, String contents) throws CoreException {
|
||||
if (contents == null)
|
||||
contents= "";
|
||||
InputStream inputStream= new java.io.StringBufferInputStream(contents);
|
||||
file.create(inputStream, true, NULL_MONITOR);
|
||||
return file;
|
||||
}
|
||||
|
||||
public static IFile createLinkedFile(IContainer container, IPath linkPath, File linkedFileTarget) throws CoreException {
|
||||
IFile iFile= container.getFile(linkPath);
|
||||
iFile.createLink(new Path(linkedFileTarget.getAbsolutePath()), IResource.ALLOW_MISSING_LOCAL, NULL_MONITOR);
|
||||
return iFile;
|
||||
}
|
||||
|
||||
public static IFile createLinkedFile(IContainer container, IPath linkPath, Plugin plugin, IPath linkedFileTargetPath) throws CoreException {
|
||||
File file= FileTool.getFileInPlugin(plugin, linkedFileTargetPath);
|
||||
IFile iFile= container.getFile(linkPath);
|
||||
iFile.createLink(new Path(file.getAbsolutePath()), IResource.ALLOW_MISSING_LOCAL, NULL_MONITOR);
|
||||
return iFile;
|
||||
}
|
||||
|
||||
public static IFolder createLinkedFolder(IContainer container, IPath linkPath, File linkedFolderTarget) throws CoreException {
|
||||
IFolder folder= container.getFolder(linkPath);
|
||||
folder.createLink(new Path(linkedFolderTarget.getAbsolutePath()), IResource.ALLOW_MISSING_LOCAL, NULL_MONITOR);
|
||||
return folder;
|
||||
}
|
||||
|
||||
public static IFolder createLinkedFolder(IContainer container, IPath linkPath, Plugin plugin, IPath linkedFolderTargetPath) throws CoreException {
|
||||
File file= FileTool.getFileInPlugin(plugin, linkedFolderTargetPath);
|
||||
IFolder iFolder= container.getFolder(linkPath);
|
||||
iFolder.createLink(new Path(file.getAbsolutePath()), IResource.ALLOW_MISSING_LOCAL, NULL_MONITOR);
|
||||
return iFolder;
|
||||
}
|
||||
|
||||
public static IProject createLinkedProject(String projectName, Plugin plugin, IPath linkPath) throws CoreException {
|
||||
IWorkspace workspace= ResourcesPlugin.getWorkspace();
|
||||
IProject project= workspace.getRoot().getProject(projectName);
|
||||
|
||||
IProjectDescription desc= workspace.newProjectDescription(projectName);
|
||||
File file= FileTool.getFileInPlugin(plugin, linkPath);
|
||||
IPath projectLocation= new Path(file.getAbsolutePath());
|
||||
if (Platform.getLocation().equals(projectLocation))
|
||||
projectLocation= null;
|
||||
desc.setLocation(projectLocation);
|
||||
|
||||
project.create(desc, NULL_MONITOR);
|
||||
if (!project.isOpen())
|
||||
project.open(NULL_MONITOR);
|
||||
|
||||
return project;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IProjectDescription;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Plugin;
|
||||
import org.eclipse.core.runtime.Preferences;
|
||||
|
||||
/**
|
||||
* Copied from org.eclipse.jdt.text.tests.performance.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ResourceTestHelper {
|
||||
|
||||
public static final int FAIL_IF_EXISTS= 0;
|
||||
|
||||
public static final int OVERWRITE_IF_EXISTS= 1;
|
||||
|
||||
public static final int SKIP_IF_EXISTS= 2;
|
||||
|
||||
private static final int DELETE_MAX_RETRY= 5;
|
||||
|
||||
private static final long DELETE_RETRY_DELAY= 1000;
|
||||
|
||||
public static void replicate(String src, String destPrefix, String destSuffix, int n, int ifExists) throws CoreException {
|
||||
for (int i= 0; i < n; i++)
|
||||
copy(src, destPrefix + i + destSuffix, ifExists);
|
||||
}
|
||||
|
||||
public static void copy(String src, String dest) throws CoreException {
|
||||
copy(src, dest, FAIL_IF_EXISTS);
|
||||
}
|
||||
|
||||
public static void copy(String src, String dest, int ifExists) throws CoreException {
|
||||
if (handleExisting(dest, ifExists))
|
||||
getFile(src).copy(new Path(dest), true, null);
|
||||
}
|
||||
|
||||
private static boolean handleExisting(String dest, int ifExists) throws CoreException {
|
||||
IFile destFile= getFile(dest);
|
||||
switch (ifExists) {
|
||||
case FAIL_IF_EXISTS:
|
||||
if (destFile.exists())
|
||||
throw new IllegalArgumentException("Destination file exists: " + dest);
|
||||
return true;
|
||||
case OVERWRITE_IF_EXISTS:
|
||||
if (destFile.exists())
|
||||
delete(destFile);
|
||||
return true;
|
||||
case SKIP_IF_EXISTS:
|
||||
if (destFile.exists())
|
||||
return false;
|
||||
return true;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private static IFile getFile(String path) {
|
||||
return getRoot().getFile(new Path(path));
|
||||
}
|
||||
|
||||
public static void delete(String file) throws CoreException {
|
||||
delete(getFile(file));
|
||||
}
|
||||
|
||||
private static void delete(IFile file) throws CoreException {
|
||||
CoreException x= null;
|
||||
for (int i= 0; i < DELETE_MAX_RETRY; i++) {
|
||||
try {
|
||||
file.delete(true, null);
|
||||
return;
|
||||
} catch (CoreException x0) {
|
||||
x= x0;
|
||||
try {
|
||||
Thread.sleep(DELETE_RETRY_DELAY);
|
||||
} catch (InterruptedException x1) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
}
|
||||
throw x;
|
||||
}
|
||||
|
||||
public static void delete(String prefix, String suffix, int n) throws CoreException {
|
||||
for (int i= 0; i < n; i++)
|
||||
delete(prefix + i + suffix);
|
||||
}
|
||||
|
||||
public static IFile findFile(String pathStr) {
|
||||
IFile file= getFile(pathStr);
|
||||
Assert.assertTrue(file != null && file.exists());
|
||||
return file;
|
||||
}
|
||||
|
||||
public static IFile[] findFiles(String prefix, String suffix, int i, int n) {
|
||||
List files= new ArrayList(n);
|
||||
for (int j= i; j < i + n; j++) {
|
||||
String path= prefix + j + suffix;
|
||||
files.add(findFile(path));
|
||||
}
|
||||
return (IFile[]) files.toArray(new IFile[files.size()]);
|
||||
}
|
||||
|
||||
public static StringBuffer read(String src) throws IOException, CoreException {
|
||||
return FileTool.read(new InputStreamReader(getFile(src).getContents()));
|
||||
}
|
||||
|
||||
public static void write(String dest, final String content) throws IOException, CoreException {
|
||||
InputStream stream= new InputStream() {
|
||||
private Reader fReader= new StringReader(content);
|
||||
public int read() throws IOException {
|
||||
return fReader.read();
|
||||
}
|
||||
};
|
||||
getFile(dest).create(stream, true, null);
|
||||
}
|
||||
|
||||
|
||||
public static void replicate(String src, String destPrefix, String destSuffix, int n, String srcName, String destNamePrefix, int ifExists) throws IOException, CoreException {
|
||||
StringBuffer s= read(src);
|
||||
List positions= identifierPositions(s, srcName);
|
||||
for (int j= 0; j < n; j++) {
|
||||
String dest= destPrefix + j + destSuffix;
|
||||
if (handleExisting(dest, ifExists)) {
|
||||
StringBuffer c= new StringBuffer(s.toString());
|
||||
replacePositions(c, srcName.length(), destNamePrefix + j, positions);
|
||||
write(dest, c.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copy(String src, String dest, String srcName, String destName, int ifExists) throws IOException, CoreException {
|
||||
if (handleExisting(dest, ifExists)) {
|
||||
StringBuffer buf= read(src);
|
||||
List positions= identifierPositions(buf, srcName);
|
||||
replacePositions(buf, srcName.length(), destName, positions);
|
||||
write(dest, buf.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void replacePositions(StringBuffer c, int origLength, String string, List positions) {
|
||||
int offset= 0;
|
||||
for (Iterator iter= positions.iterator(); iter.hasNext();) {
|
||||
int position= ((Integer) iter.next()).intValue();
|
||||
c.replace(offset + position, offset + position + origLength, string);
|
||||
offset += string.length() - origLength;
|
||||
}
|
||||
}
|
||||
|
||||
private static List identifierPositions(StringBuffer buffer, String identifier) {
|
||||
List positions= new ArrayList();
|
||||
int i= -1;
|
||||
while (true) {
|
||||
i= buffer.indexOf(identifier, i + 1);
|
||||
if (i == -1)
|
||||
break;
|
||||
if (i > 0 && Character.isJavaIdentifierPart(buffer.charAt(i - 1)))
|
||||
continue;
|
||||
if (i < buffer.length() - 1 && Character.isJavaIdentifierPart(buffer.charAt(i + identifier.length())))
|
||||
continue;
|
||||
positions.add(new Integer(i));
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
private static IWorkspaceRoot getRoot() {
|
||||
return ResourcesPlugin.getWorkspace().getRoot();
|
||||
}
|
||||
|
||||
public static void incrementalBuild() throws CoreException {
|
||||
ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null);
|
||||
}
|
||||
|
||||
public static void fullBuild() throws CoreException {
|
||||
ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
|
||||
}
|
||||
|
||||
public static boolean disableAutoBuilding() {
|
||||
return setAutoBuilding(false);
|
||||
}
|
||||
|
||||
public static boolean enableAutoBuilding() {
|
||||
return setAutoBuilding(true);
|
||||
}
|
||||
|
||||
public static boolean setAutoBuilding(boolean value) {
|
||||
Preferences preferences= ResourcesPlugin.getPlugin().getPluginPreferences();
|
||||
boolean oldValue= preferences.getBoolean(ResourcesPlugin.PREF_AUTO_BUILDING);
|
||||
if (value != oldValue)
|
||||
preferences.setValue(ResourcesPlugin.PREF_AUTO_BUILDING, value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public static IProject createExistingProject(String projectName) throws CoreException {
|
||||
IWorkspace workspace= ResourcesPlugin.getWorkspace();
|
||||
IProject project= workspace.getRoot().getProject(projectName);
|
||||
IProjectDescription description= workspace.newProjectDescription(projectName);
|
||||
description.setLocation(null);
|
||||
|
||||
project.create(description, null);
|
||||
project.open(null);
|
||||
return project;
|
||||
}
|
||||
|
||||
public static IProject createProjectFromZip(Plugin installationPlugin, String projectZip, String projectName) throws IOException, ZipException, CoreException {
|
||||
String workspacePath= ResourcesPlugin.getWorkspace().getRoot().getLocation().toString() + "/";
|
||||
FileTool.unzip(new ZipFile(FileTool.getFileInPlugin(installationPlugin, new Path(projectZip))), new File(workspacePath));
|
||||
return createExistingProject(projectName);
|
||||
}
|
||||
|
||||
public static IProject getProject(String projectName) {
|
||||
IWorkspace workspace= ResourcesPlugin.getWorkspace();
|
||||
return workspace.getRoot().getProject(projectName);
|
||||
}
|
||||
|
||||
public static boolean projectExists(String projectName) {
|
||||
return getProject(projectName).exists();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,391 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.ui.tests.text;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.eclipse.jface.text.Position;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightings;
|
||||
|
||||
/**
|
||||
* Semantic highlighting tests.
|
||||
*
|
||||
* <p>Derived from JDT.<p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SemanticHighlightingTest extends AbstractSemanticHighlightingTest {
|
||||
|
||||
private static final Class THIS= SemanticHighlightingTest.class;
|
||||
|
||||
public static Test suite() {
|
||||
return new SemanticHighlightingTestSetup(new TestSuite(THIS), "/SHTest/src/SHTest.cpp");
|
||||
}
|
||||
|
||||
// public void testStaticConstFieldHighlighting() throws Exception {
|
||||
// setUpSemanticHighlighting(SemanticHighlightings.STATIC_CONST_FIELD);
|
||||
// Position[] expected= new Position[] {
|
||||
// createPosition(6, 18, 16),
|
||||
// createPosition(35, 37, 16),
|
||||
// };
|
||||
// Position[] actual= getSemanticHighlightingPositions();
|
||||
//// System.out.println(toString(actual));
|
||||
// assertEqualPositions(expected, actual);
|
||||
// }
|
||||
|
||||
public void testStaticFieldHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.STATIC_FIELD);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(23, 15, 14),
|
||||
createPosition(25, 21, 19),
|
||||
createPosition(41, 21, 20),
|
||||
createPosition(42, 15, 15),
|
||||
createPosition(56, 21, 20),
|
||||
createPosition(57, 15, 15),
|
||||
createPosition(115, 20, 15),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testFieldHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.FIELD);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(24, 14, 13),
|
||||
createPosition(26, 8, 8),
|
||||
createPosition(43, 15, 14),
|
||||
createPosition(44, 8, 9),
|
||||
createPosition(58, 15, 14),
|
||||
createPosition(59, 8, 9),
|
||||
createPosition(74, 7, 5),
|
||||
createPosition(75, 7, 5),
|
||||
createPosition(77, 8, 5),
|
||||
createPosition(78, 8, 5),
|
||||
createPosition(86, 8, 11),
|
||||
createPosition(90, 8, 10),
|
||||
createPosition(102, 11, 9),
|
||||
createPosition(107, 11, 8),
|
||||
createPosition(112, 7, 11),
|
||||
createPosition(114, 7, 10),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testMethodDeclarationHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.METHOD_DECLARATION);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(28, 15, 15),
|
||||
createPosition(32, 8, 9),
|
||||
createPosition(46, 15, 16),
|
||||
createPosition(47, 8, 10),
|
||||
createPosition(61, 15, 16),
|
||||
createPosition(62, 8, 10),
|
||||
createPosition(76, 4, 13),
|
||||
createPosition(101, 4, 26),
|
||||
createPosition(101, 20, 10),
|
||||
createPosition(105, 4, 25),
|
||||
createPosition(105, 20, 9),
|
||||
createPosition(110, 4, 32),
|
||||
createPosition(110, 20, 16),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testMethodInvocationHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.METHOD_INVOCATION);
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(111, 22, 9),
|
||||
createPosition(113, 21, 8),
|
||||
createPosition(115, 4, 15),
|
||||
};
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
// public void testStaticMethodInvocationHighlighting() throws Exception {
|
||||
// setUpSemanticHighlighting(SemanticHighlightings.STATIC_METHOD_INVOCATION);
|
||||
// Position[] expected= new Position[] {
|
||||
// };
|
||||
// Position[] actual= getSemanticHighlightingPositions();
|
||||
// System.out.println(toString(actual));
|
||||
// assertEqualPositions(expected, actual);
|
||||
// }
|
||||
|
||||
/*
|
||||
*/
|
||||
// public void testVirtualMethodInvocationHighlighting() throws Exception {
|
||||
// setUpSemanticHighlighting(SemanticHighlightings.VIRTUAL_METHOD_INVOCATION);
|
||||
// Position[] expected= new Position[] {
|
||||
// createPosition(11, 2, 14),
|
||||
// };
|
||||
// Position[] actual= getSemanticHighlightingPositions();
|
||||
//// System.out.println(toString(actual));
|
||||
// assertEqualPositions(expected, actual);
|
||||
// }
|
||||
|
||||
// public void testInheritedMethodInvocationHighlighting() throws Exception {
|
||||
// setUpSemanticHighlighting(SemanticHighlightings.INHERITED_METHOD_INVOCATION);
|
||||
// Position[] expected= new Position[] {
|
||||
// createPosition(12, 2, 8),
|
||||
// createPosition(15, 17, 8),
|
||||
// };
|
||||
// Position[] actual= getSemanticHighlightingPositions();
|
||||
//// System.out.println(toString(actual));
|
||||
// assertEqualPositions(expected, actual);
|
||||
// }
|
||||
|
||||
public void testLocalVariableDeclarationHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.LOCAL_VARIABLE_DECLARATION);
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(106, 8, 8),
|
||||
createPosition(111, 14, 2),
|
||||
createPosition(113, 13, 2),
|
||||
};
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testLocalVariableHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.LOCAL_VARIABLE);
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(112, 4, 2),
|
||||
createPosition(114, 4, 2),
|
||||
};
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testParameterVariableHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.PARAMETER_VARIABLE);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(11, 20, 1),
|
||||
createPosition(28, 35, 3),
|
||||
createPosition(29, 8, 19),
|
||||
createPosition(30, 19, 3),
|
||||
createPosition(76, 21, 4),
|
||||
createPosition(76, 30, 4),
|
||||
createPosition(77, 16, 4),
|
||||
createPosition(78, 16, 4),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testTemplateParameterHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.TEMPLATE_PARAMETER);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
// public void testTemplateArgumentHighlighting() throws Exception {
|
||||
// setUpSemanticHighlighting(SemanticHighlightings.TEMPLATE_ARGUMENT);
|
||||
// Position[] actual= getSemanticHighlightingPositions();
|
||||
// Position[] expected= new Position[] {
|
||||
// createPosition(41, 8, 6),
|
||||
// };
|
||||
//// System.out.println(toString(actual));
|
||||
// assertEqualPositions(expected, actual);
|
||||
// }
|
||||
|
||||
public void testEnumHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.ENUM);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(3, 5, 11),
|
||||
createPosition(34, 9, 14),
|
||||
createPosition(49, 9, 15),
|
||||
createPosition(64, 9, 15),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testClassHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.CLASS);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(15, 6, 5),
|
||||
createPosition(16, 6, 5),
|
||||
createPosition(18, 6, 14),
|
||||
createPosition(18, 23, 5),
|
||||
createPosition(18, 30, 5),
|
||||
createPosition(20, 17, 11),
|
||||
createPosition(35, 10, 8),
|
||||
createPosition(36, 10, 9),
|
||||
createPosition(37, 10, 8),
|
||||
createPosition(38, 12, 8),
|
||||
createPosition(50, 10, 9),
|
||||
createPosition(51, 10, 10),
|
||||
createPosition(52, 10, 9),
|
||||
createPosition(53, 12, 9),
|
||||
createPosition(65, 10, 9),
|
||||
createPosition(66, 10, 10),
|
||||
createPosition(67, 10, 9),
|
||||
createPosition(68, 12, 9),
|
||||
createPosition(73, 22, 13),
|
||||
createPosition(82, 19, 24),
|
||||
createPosition(82, 46, 13),
|
||||
createPosition(82, 63, 5),
|
||||
createPosition(85, 7, 9),
|
||||
createPosition(89, 6, 8),
|
||||
createPosition(93, 8, 8),
|
||||
createPosition(111, 4, 9),
|
||||
createPosition(113, 4, 8),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testFunctionDeclarationHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.FUNCTION_DECLARATION);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(11, 5, 10),
|
||||
createPosition(12, 12, 16),
|
||||
createPosition(19, 16, 10),
|
||||
createPosition(28, 15, 15),
|
||||
createPosition(32, 8, 9),
|
||||
createPosition(46, 15, 16),
|
||||
createPosition(47, 8, 10),
|
||||
createPosition(61, 15, 16),
|
||||
createPosition(62, 8, 10),
|
||||
createPosition(76, 4, 13),
|
||||
createPosition(97, 8, 13),
|
||||
createPosition(101, 4, 26),
|
||||
createPosition(101, 20, 10),
|
||||
createPosition(105, 4, 25),
|
||||
createPosition(105, 20, 9),
|
||||
createPosition(110, 4, 32),
|
||||
createPosition(110, 20, 16),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testFunctionInvocationHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.FUNCTION_INVOCATION);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(29, 8, 19),
|
||||
createPosition(30, 8, 10),
|
||||
createPosition(111, 22, 9),
|
||||
createPosition(113, 21, 8),
|
||||
createPosition(115, 4, 15),
|
||||
createPosition(117, 4, 17),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
|
||||
public void testGlobalVariableHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.GLOBAL_VARIABLE);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(7, 10, 14),
|
||||
createPosition(8, 4, 14),
|
||||
createPosition(9, 11, 20),
|
||||
createPosition(96, 8, 14),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testMacroSubstitutionHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.MACRO_SUBSTITUTION);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(29, 8, 19),
|
||||
createPosition(117, 4, 17),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testTypedefHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.TYPEDEF);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(38, 21, 10),
|
||||
createPosition(53, 22, 11),
|
||||
createPosition(68, 22, 11),
|
||||
createPosition(93, 17, 6),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testNamespaceHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.NAMESPACE);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(95, 10, 2),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testLabelHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.LABEL);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(116, 0, 5),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testEnumeratorHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.ENUMERATOR);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(4, 4, 10),
|
||||
createPosition(34, 25, 13),
|
||||
createPosition(49, 26, 14),
|
||||
createPosition(64, 26, 14),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
public void testProblemHighlighting() throws Exception {
|
||||
setUpSemanticHighlighting(SemanticHighlightings.PROBLEM);
|
||||
Position[] actual= getSemanticHighlightingPositions();
|
||||
Position[] expected= new Position[] {
|
||||
createPosition(73, 9, 2),
|
||||
createPosition(73, 12, 2),
|
||||
createPosition(74, 4, 2),
|
||||
createPosition(75, 4, 2),
|
||||
createPosition(76, 18, 2),
|
||||
createPosition(76, 27, 2),
|
||||
createPosition(82, 9, 2),
|
||||
createPosition(82, 60, 2),
|
||||
};
|
||||
// System.out.println(toString(actual));
|
||||
assertEqualPositions(expected, actual);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,3 +3,8 @@ org.eclipse.cdt.ui/debug=true
|
|||
# Reports contentAssist activity
|
||||
org.eclipse.cdt.ui/debug/contentassist=false
|
||||
|
||||
# Prints debug information related to the AST provider
|
||||
org.eclipse.cdt.ui/debug/ASTProvider=false
|
||||
|
||||
# Enables all semantic highlighting types
|
||||
org.eclipse.cdt.ui/debug/SemanticHighlighting=false
|
||||
|
|
|
@ -621,12 +621,12 @@
|
|||
class="org.eclipse.cdt.internal.ui.preferences.IndexerPreferencePage"
|
||||
id="org.eclipse.cdt.ui.preferences.IndexerPreferencePage"
|
||||
name="%indexerPrefName"/>
|
||||
<!--page
|
||||
<page
|
||||
name="%WorkInProgress.name"
|
||||
category="org.eclipse.cdt.ui.preferences.CPluginPreferencePage"
|
||||
class="org.eclipse.cdt.internal.ui.preferences.WorkInProgressPreferencePage"
|
||||
id="org.eclipse.cdt.ui.preferneces.WorkInProgressPreferencePage">
|
||||
</page-->
|
||||
</page>
|
||||
</extension>
|
||||
<extension
|
||||
point="org.eclipse.ui.editorActions">
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006 Wind River Systems, Inc. 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:
|
||||
* Anton Leherbauer (Wind River Systems) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.corext.util;
|
||||
|
||||
import org.eclipse.jface.text.DocumentEvent;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IPositionUpdater;
|
||||
|
||||
import org.eclipse.cdt.internal.core.PositionTracker;
|
||||
|
||||
/**
|
||||
* A simple general purpose position tracker.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SimplePositionTracker extends PositionTracker implements
|
||||
IPositionUpdater {
|
||||
|
||||
private IDocument fDocument;
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IPositionUpdater#update(org.eclipse.jface.text.DocumentEvent)
|
||||
*/
|
||||
public void update(DocumentEvent event) {
|
||||
String text = event.getText();
|
||||
int insertLen = text != null ? text.length() : 0;
|
||||
update(event.getOffset(), event.getLength(), insertLen);
|
||||
}
|
||||
|
||||
private void update(int offset, int deleteLen, int insertLen) {
|
||||
if (insertLen > deleteLen) {
|
||||
insert(offset + deleteLen, insertLen - deleteLen);
|
||||
} else if (insertLen < deleteLen) {
|
||||
delete(offset+insertLen, deleteLen - insertLen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking on the given document.
|
||||
*
|
||||
* @param doc
|
||||
*/
|
||||
public synchronized void startTracking(IDocument doc) {
|
||||
stopTracking();
|
||||
fDocument= doc;
|
||||
if (fDocument != null) {
|
||||
fDocument.addPositionUpdater(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop tracking.
|
||||
*/
|
||||
public synchronized void stopTracking() {
|
||||
if (fDocument != null) {
|
||||
fDocument.removePositionUpdater(this);
|
||||
fDocument= null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the tracker.
|
||||
*/
|
||||
public void dispose() {
|
||||
stopTracking();
|
||||
}
|
||||
|
||||
}
|
|
@ -127,7 +127,7 @@ public class LineBackgroundPainter implements IPainter, LineBackgroundListener {
|
|||
|
||||
/**
|
||||
* Set highlight positions. It is assumed that all positions
|
||||
* are up-to-date with respect to the text viewers document.
|
||||
* are up-to-date with respect to the text viewer document.
|
||||
*
|
||||
* @param positions a list of <code>Position</code>s
|
||||
*/
|
||||
|
@ -142,6 +142,51 @@ public class LineBackgroundPainter implements IPainter, LineBackgroundListener {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add highlight positions. It is assumed that all positions
|
||||
* are up-to-date with respect to the text viewer document.
|
||||
*
|
||||
* @param positions a list of <code>Position</code>s
|
||||
*/
|
||||
public void addHighlightPositions(List positions) {
|
||||
boolean isActive= fIsActive;
|
||||
deactivate(isActive);
|
||||
fPositions.addAll(positions);
|
||||
if (isActive) {
|
||||
activate(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove highlight positions by identity.
|
||||
*
|
||||
* @param positions a list of <code>Position</code>s
|
||||
*/
|
||||
public void removeHighlightPositions(List positions) {
|
||||
boolean isActive= fIsActive;
|
||||
deactivate(isActive);
|
||||
fPositions.removeAll(positions);
|
||||
if (isActive) {
|
||||
activate(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace given highlight positions in one step.
|
||||
*
|
||||
* @param removePositions a list of <code>Position</code>s to remove
|
||||
* @param addPositions a list of <code>Position</code>s to add
|
||||
*/
|
||||
public void replaceHighlightPositions(List removePositions, List addPositions) {
|
||||
boolean isActive= fIsActive;
|
||||
deactivate(isActive);
|
||||
fPositions.removeAll(removePositions);
|
||||
fPositions.addAll(addPositions);
|
||||
if (isActive) {
|
||||
activate(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger redraw of managed positions.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,640 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.ISafeRunnable;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.SafeRunner;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.text.Assert;
|
||||
import org.eclipse.ui.IPartListener2;
|
||||
import org.eclipse.ui.IWindowListener;
|
||||
import org.eclipse.ui.IWorkbenchPart;
|
||||
import org.eclipse.ui.IWorkbenchPartReference;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ILanguage;
|
||||
import org.eclipse.cdt.core.model.ISourceReference;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a shared AST for clients. The shared AST is
|
||||
* the AST of the active CEditor's input element.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public final class ASTProvider {
|
||||
|
||||
/**
|
||||
* Wait flag.
|
||||
*/
|
||||
public static final class WAIT_FLAG {
|
||||
|
||||
String fName;
|
||||
|
||||
private WAIT_FLAG(String name) {
|
||||
fName= name;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return fName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait flag indicating that a client requesting an AST
|
||||
* wants to wait until an AST is ready.
|
||||
* <p>
|
||||
* An AST will be created by this AST provider if the shared
|
||||
* AST is not for the given C element.
|
||||
* </p>
|
||||
*/
|
||||
public static final WAIT_FLAG WAIT_YES= new WAIT_FLAG("wait yes"); //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Wait flag indicating that a client requesting an AST
|
||||
* only wants to wait for the shared AST of the active editor.
|
||||
* <p>
|
||||
* No AST will be created by the AST provider.
|
||||
* </p>
|
||||
*/
|
||||
public static final WAIT_FLAG WAIT_ACTIVE_ONLY= new WAIT_FLAG("wait active only"); //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Wait flag indicating that a client requesting an AST
|
||||
* only wants the already available shared AST.
|
||||
* <p>
|
||||
* No AST will be created by the AST provider.
|
||||
* </p>
|
||||
*/
|
||||
public static final WAIT_FLAG WAIT_NO= new WAIT_FLAG("don't wait"); //$NON-NLS-1$
|
||||
|
||||
public static int PARSE_MODE_FULL= ILanguage.AST_SKIP_IF_NO_BUILD_INFO;
|
||||
public static int PARSE_MODE_FAST= ILanguage.AST_SKIP_IF_NO_BUILD_INFO | ILanguage.AST_SKIP_INDEXED_HEADERS;
|
||||
public static int PARSE_MODE_FAST_INDEX= ILanguage.AST_SKIP_IF_NO_BUILD_INFO | ILanguage.AST_SKIP_INDEXED_HEADERS | ILanguage.AST_USE_INDEX;
|
||||
public static int PARSE_MODE_INDEX= ILanguage.AST_SKIP_IF_NO_BUILD_INFO | ILanguage.AST_USE_INDEX;
|
||||
|
||||
public static int PARSE_MODE= PARSE_MODE_FULL;
|
||||
|
||||
/**
|
||||
* Tells whether this class is in debug mode.
|
||||
*/
|
||||
private static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.cdt.ui/debug/ASTProvider")); //$NON-NLS-1$//$NON-NLS-2$
|
||||
|
||||
/**
|
||||
* Internal activation listener.
|
||||
*/
|
||||
private class ActivationListener implements IPartListener2, IWindowListener {
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partActivated(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partActivated(IWorkbenchPartReference ref) {
|
||||
if (isCEditor(ref) && !isActiveEditor(ref))
|
||||
activeEditorChanged(ref.getPart(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partBroughtToTop(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partBroughtToTop(IWorkbenchPartReference ref) {
|
||||
if (isCEditor(ref) && !isActiveEditor(ref))
|
||||
activeEditorChanged(ref.getPart(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partClosed(IWorkbenchPartReference ref) {
|
||||
if (isActiveEditor(ref)) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "closed active editor: " + ref.getTitle()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
activeEditorChanged(null);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partDeactivated(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partDeactivated(IWorkbenchPartReference ref) {
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partOpened(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partOpened(IWorkbenchPartReference ref) {
|
||||
if (isCEditor(ref) && !isActiveEditor(ref))
|
||||
activeEditorChanged(ref.getPart(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partHidden(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partHidden(IWorkbenchPartReference ref) {
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partVisible(IWorkbenchPartReference ref) {
|
||||
if (isCEditor(ref) && !isActiveEditor(ref))
|
||||
activeEditorChanged(ref.getPart(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.IWorkbenchPartReference)
|
||||
*/
|
||||
public void partInputChanged(IWorkbenchPartReference ref) {
|
||||
if (isCEditor(ref) && isActiveEditor(ref))
|
||||
activeEditorChanged(ref.getPart(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow)
|
||||
*/
|
||||
public void windowActivated(IWorkbenchWindow window) {
|
||||
IWorkbenchPartReference ref= window.getPartService().getActivePartReference();
|
||||
if (isCEditor(ref) && !isActiveEditor(ref))
|
||||
activeEditorChanged(ref.getPart(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow)
|
||||
*/
|
||||
public void windowDeactivated(IWorkbenchWindow window) {
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow)
|
||||
*/
|
||||
public void windowClosed(IWorkbenchWindow window) {
|
||||
if (fActiveEditor != null && fActiveEditor.getSite() != null && window == fActiveEditor.getSite().getWorkbenchWindow()) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "closed active editor: " + fActiveEditor.getTitle()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
activeEditorChanged(null);
|
||||
}
|
||||
window.getPartService().removePartListener(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow)
|
||||
*/
|
||||
public void windowOpened(IWorkbenchWindow window) {
|
||||
window.getPartService().addPartListener(this);
|
||||
}
|
||||
|
||||
private boolean isActiveEditor(IWorkbenchPartReference ref) {
|
||||
return ref != null && isActiveEditor(ref.getPart(false));
|
||||
}
|
||||
|
||||
private boolean isActiveEditor(IWorkbenchPart part) {
|
||||
return part != null && (part == fActiveEditor);
|
||||
}
|
||||
|
||||
private boolean isCEditor(IWorkbenchPartReference ref) {
|
||||
if (ref == null)
|
||||
return false;
|
||||
|
||||
String id= ref.getId();
|
||||
|
||||
return CUIPlugin.EDITOR_ID.equals(id) || ref.getPart(false) instanceof CEditor;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DEBUG_PREFIX= "ASTProvider > "; //$NON-NLS-1$
|
||||
|
||||
|
||||
private ICElement fReconcilingCElement;
|
||||
private ICElement fActiveCElement;
|
||||
private IASTTranslationUnit fAST;
|
||||
private ActivationListener fActivationListener;
|
||||
private Object fReconcileLock= new Object();
|
||||
private Object fWaitLock= new Object();
|
||||
private boolean fIsReconciling;
|
||||
private IWorkbenchPart fActiveEditor;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the C plug-in's AST provider.
|
||||
*
|
||||
* @return the AST provider
|
||||
*/
|
||||
public static ASTProvider getASTProvider() {
|
||||
return CUIPlugin.getDefault().getASTProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AST provider.
|
||||
*/
|
||||
public ASTProvider() {
|
||||
install();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs this AST provider.
|
||||
*/
|
||||
void install() {
|
||||
// Create and register activation listener
|
||||
fActivationListener= new ActivationListener();
|
||||
PlatformUI.getWorkbench().addWindowListener(fActivationListener);
|
||||
|
||||
// Ensure existing windows get connected
|
||||
IWorkbenchWindow[] windows= PlatformUI.getWorkbench().getWorkbenchWindows();
|
||||
for (int i= 0, length= windows.length; i < length; i++)
|
||||
windows[i].getPartService().addPartListener(fActivationListener);
|
||||
}
|
||||
|
||||
private void activeEditorChanged(IWorkbenchPart editor) {
|
||||
|
||||
ICElement cElement= null;
|
||||
if (editor instanceof CEditor) {
|
||||
cElement= ((CEditor)editor).getInputCElement();
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
fActiveEditor= editor;
|
||||
fActiveCElement= cElement;
|
||||
cache(null, cElement);
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "active editor is: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
synchronized (fReconcileLock) {
|
||||
if (fIsReconciling && (fReconcilingCElement == null || !fReconcilingCElement.equals(cElement))) {
|
||||
fIsReconciling= false;
|
||||
fReconcilingCElement= null;
|
||||
} else if (cElement == null) {
|
||||
fIsReconciling= false;
|
||||
fReconcilingCElement= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given translation unit AST is
|
||||
* cached by this AST provided.
|
||||
*
|
||||
* @param ast the translation unit AST
|
||||
* @return <code>true</code> if the given AST is the cached one
|
||||
*/
|
||||
public boolean isCached(IASTTranslationUnit ast) {
|
||||
return ast != null && fAST == ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this AST provider is active on the given
|
||||
* translation unit.
|
||||
*
|
||||
* @param tu the translation unit
|
||||
* @return <code>true</code> if the given translation unit is the active one
|
||||
*/
|
||||
public boolean isActive(ITranslationUnit tu) {
|
||||
return tu != null && tu.equals(fActiveCElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs that reconciling for the given element is about to be started.
|
||||
*
|
||||
* @param cElement the C element
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
|
||||
*/
|
||||
void aboutToBeReconciled(ICElement cElement) {
|
||||
|
||||
if (cElement == null)
|
||||
return;
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "about to reconcile: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
synchronized (fReconcileLock) {
|
||||
fIsReconciling= true;
|
||||
fReconcilingCElement= cElement;
|
||||
}
|
||||
cache(null, cElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes the cached AST.
|
||||
*/
|
||||
private synchronized void disposeAST() {
|
||||
|
||||
if (fAST == null)
|
||||
return;
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "disposing AST: " + toString(fAST) + " for: " + toString(fActiveCElement)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
fAST= null;
|
||||
|
||||
cache(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for the given C element used for debugging.
|
||||
*
|
||||
* @param cElement the translation unit AST
|
||||
* @return a string used for debugging
|
||||
*/
|
||||
private String toString(ICElement cElement) {
|
||||
if (cElement == null)
|
||||
return "null"; //$NON-NLS-1$
|
||||
else
|
||||
return cElement.getElementName();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string for the given AST used for debugging.
|
||||
*
|
||||
* @param ast the translation unit AST
|
||||
* @return a string used for debugging
|
||||
*/
|
||||
private String toString(IASTTranslationUnit ast) {
|
||||
if (ast == null)
|
||||
return "null"; //$NON-NLS-1$
|
||||
|
||||
IASTNode[] nodes= ast.getDeclarations();
|
||||
if (nodes != null && nodes.length > 0)
|
||||
return nodes[0].getRawSignature();
|
||||
else
|
||||
return "AST without any declaration"; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the given translation unit AST for the given C element.
|
||||
*
|
||||
* @param ast
|
||||
* @param cElement
|
||||
*/
|
||||
private synchronized void cache(IASTTranslationUnit ast, ICElement cElement) {
|
||||
|
||||
if (fActiveCElement != null && !fActiveCElement.equals(cElement)) {
|
||||
if (DEBUG && cElement != null) // don't report call from disposeAST()
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "don't cache AST for inactive: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG && (cElement != null || ast != null)) // don't report call from disposeAST()
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "caching AST: " + toString(ast) + " for: " + toString(cElement)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
if (fAST != null)
|
||||
disposeAST();
|
||||
|
||||
fAST= ast;
|
||||
|
||||
// Signal AST change
|
||||
synchronized (fWaitLock) {
|
||||
fWaitLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shared translation unit AST for the given
|
||||
* C element.
|
||||
* <p>
|
||||
* Clients are not allowed to modify the AST and must
|
||||
* synchronize all access to its nodes.
|
||||
* </p>
|
||||
*
|
||||
* @param cElement the C element
|
||||
* @param waitFlag {@link #WAIT_YES}, {@link #WAIT_NO} or {@link #WAIT_ACTIVE_ONLY}
|
||||
* @param progressMonitor the progress monitor or <code>null</code>
|
||||
* @return the AST or <code>null</code> if the AST is not available
|
||||
*/
|
||||
public IASTTranslationUnit getAST(ICElement cElement, WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) {
|
||||
if (cElement == null)
|
||||
return null;
|
||||
|
||||
Assert.isTrue(cElement instanceof ITranslationUnit);
|
||||
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
return null;
|
||||
|
||||
boolean isActiveElement;
|
||||
synchronized (this) {
|
||||
isActiveElement= cElement.equals(fActiveCElement);
|
||||
if (isActiveElement) {
|
||||
if (fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning cached AST:" + toString(fAST) + " for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
return fAST;
|
||||
}
|
||||
if (waitFlag == WAIT_NO) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning null (WAIT_NO) for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isActiveElement && isReconciling(cElement)) {
|
||||
try {
|
||||
final ICElement activeElement= fReconcilingCElement;
|
||||
|
||||
// Wait for AST
|
||||
synchronized (fWaitLock) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "waiting for AST for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
fWaitLock.wait();
|
||||
}
|
||||
|
||||
// Check whether active element is still valid
|
||||
synchronized (this) {
|
||||
if (activeElement == fActiveCElement && fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "...got AST for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
return fAST;
|
||||
}
|
||||
}
|
||||
return getAST(cElement, waitFlag, progressMonitor);
|
||||
} catch (InterruptedException e) {
|
||||
return null; // thread has been interrupted don't compute AST
|
||||
}
|
||||
} else if (waitFlag == WAIT_NO || (waitFlag == WAIT_ACTIVE_ONLY && !(isActiveElement && fAST == null)))
|
||||
return null;
|
||||
|
||||
if (isActiveElement)
|
||||
aboutToBeReconciled(cElement);
|
||||
|
||||
if (DEBUG)
|
||||
System.err.println(getThreadName() + " - " + DEBUG_PREFIX + "creating AST for " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
IASTTranslationUnit ast= null;
|
||||
try {
|
||||
ast= createAST(cElement, progressMonitor);
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
ast= null;
|
||||
else if (DEBUG && ast != null)
|
||||
System.err.println(getThreadName() + " - " + DEBUG_PREFIX + "created AST for: " + cElement.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
} finally {
|
||||
if (isActiveElement) {
|
||||
if (fAST != null) {
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "Ignore created AST for " + cElement.getElementName() + "- AST from reconciler is newer"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
reconciled(fAST, cElement, null);
|
||||
} else
|
||||
reconciled(ast, cElement, null);
|
||||
}
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given C element is the one
|
||||
* reported as currently being reconciled.
|
||||
*
|
||||
* @param cElement the C element
|
||||
* @return <code>true</code> if reported as currently being reconciled
|
||||
*/
|
||||
private boolean isReconciling(ICElement cElement) {
|
||||
synchronized (fReconcileLock) {
|
||||
return cElement != null && cElement.equals(fReconcilingCElement) && fIsReconciling;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new translation unit AST.
|
||||
*
|
||||
* @param cElement the C element for which to create the AST
|
||||
* @param progressMonitor the progress monitor
|
||||
* @return AST
|
||||
*/
|
||||
IASTTranslationUnit createAST(ICElement cElement, final IProgressMonitor progressMonitor) {
|
||||
if (!hasSource(cElement))
|
||||
return null;
|
||||
|
||||
if (progressMonitor != null && progressMonitor.isCanceled())
|
||||
return null;
|
||||
|
||||
if (!(cElement instanceof ITranslationUnit))
|
||||
return null;
|
||||
|
||||
final ITranslationUnit tu= (ITranslationUnit)cElement;
|
||||
final IASTTranslationUnit root[]= new IASTTranslationUnit[1];
|
||||
|
||||
SafeRunner.run(new ISafeRunnable() {
|
||||
public void run() throws CoreException {
|
||||
try {
|
||||
if (progressMonitor != null && progressMonitor.isCanceled()) {
|
||||
root[0]= null;
|
||||
} else {
|
||||
root[0]= tu.getLanguage().getASTTranslationUnit(tu, PARSE_MODE);
|
||||
}
|
||||
} catch (OperationCanceledException ex) {
|
||||
root[0]= null;
|
||||
}
|
||||
}
|
||||
public void handleException(Throwable ex) {
|
||||
IStatus status= new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, IStatus.OK, "Error in CDT Core during AST creation", ex); //$NON-NLS-1$
|
||||
CUIPlugin.getDefault().getLog().log(status);
|
||||
}
|
||||
});
|
||||
|
||||
return root[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given C element has accessible source.
|
||||
*
|
||||
* @param cElement the C element to test
|
||||
* @return <code>true</code> if the element has source
|
||||
*/
|
||||
private boolean hasSource(ICElement cElement) {
|
||||
if (cElement == null || !cElement.exists())
|
||||
return false;
|
||||
|
||||
try {
|
||||
return cElement instanceof ISourceReference /* && ((ISourceReference)cElement).getSource() != null */;
|
||||
} catch (Exception ex) {
|
||||
IStatus status= new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, IStatus.OK, "Error in CDT Core during AST creation", ex); //$NON-NLS-1$
|
||||
CUIPlugin.getDefault().getLog().log(status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes this AST provider.
|
||||
*/
|
||||
public void dispose() {
|
||||
|
||||
// Dispose activation listener
|
||||
PlatformUI.getWorkbench().removeWindowListener(fActivationListener);
|
||||
fActivationListener= null;
|
||||
|
||||
disposeAST();
|
||||
|
||||
synchronized (fWaitLock) {
|
||||
fWaitLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled(org.eclipse.cdt.core.dom.IASTTranslationUnit)
|
||||
*/
|
||||
void reconciled(IASTTranslationUnit ast, ICElement cElement, IProgressMonitor progressMonitor) {
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "reconciled: " + toString(cElement) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
|
||||
synchronized (fReconcileLock) {
|
||||
|
||||
fIsReconciling= progressMonitor != null && progressMonitor.isCanceled();
|
||||
if (cElement == null || !cElement.equals(fReconcilingCElement)) {
|
||||
|
||||
if (DEBUG)
|
||||
System.out.println(getThreadName() + " - " + DEBUG_PREFIX + " ignoring AST of out-dated editor"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// Signal - threads might wait for wrong element
|
||||
synchronized (fWaitLock) {
|
||||
fWaitLock.notifyAll();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cache(ast, cElement);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getThreadName() {
|
||||
String name= Thread.currentThread().getName();
|
||||
if (name != null)
|
||||
return name;
|
||||
else
|
||||
return Thread.currentThread().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,6 +21,8 @@ import java.util.ResourceBundle;
|
|||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.ListenerList;
|
||||
import org.eclipse.core.runtime.content.IContentType;
|
||||
import org.eclipse.jface.action.Action;
|
||||
import org.eclipse.jface.action.IAction;
|
||||
|
@ -119,6 +121,8 @@ import com.ibm.icu.text.BreakIterator;
|
|||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ISourceRange;
|
||||
|
@ -132,6 +136,8 @@ import org.eclipse.cdt.ui.actions.ShowInCViewAction;
|
|||
import org.eclipse.cdt.ui.text.ICPartitions;
|
||||
import org.eclipse.cdt.ui.text.folding.ICFoldingStructureProvider;
|
||||
|
||||
import org.eclipse.cdt.internal.corext.util.SimplePositionTracker;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.ICHelpContextIds;
|
||||
import org.eclipse.cdt.internal.ui.IContextMenuConstants;
|
||||
import org.eclipse.cdt.internal.ui.actions.AddBlockCommentAction;
|
||||
|
@ -150,6 +156,7 @@ import org.eclipse.cdt.internal.ui.text.CTextTools;
|
|||
import org.eclipse.cdt.internal.ui.text.CWordIterator;
|
||||
import org.eclipse.cdt.internal.ui.text.DocumentCharacterIterator;
|
||||
import org.eclipse.cdt.internal.ui.text.HTMLTextPresenter;
|
||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
import org.eclipse.cdt.internal.ui.text.c.hover.SourceViewerInformationControl;
|
||||
import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference;
|
||||
import org.eclipse.cdt.internal.ui.util.CUIHelp;
|
||||
|
@ -158,9 +165,8 @@ import org.eclipse.cdt.internal.ui.util.CUIHelp;
|
|||
/**
|
||||
* C specific text editor.
|
||||
*/
|
||||
public class CEditor extends TextEditor implements ISelectionChangedListener, IShowInSource , IReconcilingParticipant{
|
||||
public class CEditor extends TextEditor implements ISelectionChangedListener, IShowInSource, IReconcilingParticipant, ICReconcilingListener {
|
||||
|
||||
|
||||
/**
|
||||
* The information provider used to present focusable information
|
||||
* shells.
|
||||
|
@ -554,6 +560,19 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
*/
|
||||
private FoldingActionGroup fFoldingGroup;
|
||||
|
||||
/**
|
||||
* AST reconciling listeners.
|
||||
* @since 4.0
|
||||
*/
|
||||
private ListenerList fReconcilingListeners= new ListenerList(ListenerList.IDENTITY);
|
||||
|
||||
/**
|
||||
* Semantic highlighting manager
|
||||
* @since 4.0
|
||||
*/
|
||||
private SemanticHighlightingManager fSemanticManager;
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
|
@ -590,11 +609,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
if (fCEditorErrorTickUpdater != null) {
|
||||
fCEditorErrorTickUpdater.updateEditorImage(getInputCElement());
|
||||
}
|
||||
|
||||
if (getSourceViewer() != null) {
|
||||
CSourceViewerDecorationSupport decoSupport = (CSourceViewerDecorationSupport) getSourceViewerDecorationSupport(getSourceViewer());
|
||||
decoSupport.editorInputChanged(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -732,6 +746,16 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
return;
|
||||
}
|
||||
|
||||
if (SemanticHighlightings.affectsEnablement(getPreferenceStore(), event)) {
|
||||
if (isSemanticHighlightingEnabled()) {
|
||||
installSemanticHighlighting();
|
||||
fSemanticManager.refresh();
|
||||
} else {
|
||||
uninstallSemanticHighlighting();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
IContentAssistant c= asv.getContentAssistant();
|
||||
if (c instanceof ContentAssistant) {
|
||||
ContentAssistPreference.changeConfiguration((ContentAssistant) c, getPreferenceStore(), event);
|
||||
|
@ -1211,7 +1235,10 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
|
||||
if (isTabConversionEnabled())
|
||||
startTabConversion();
|
||||
|
||||
|
||||
if (isSemanticHighlightingEnabled())
|
||||
installSemanticHighlighting();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1234,12 +1261,12 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#getSourceViewerDecorationSupport(org.eclipse.jface.text.source.ISourceViewer)
|
||||
* @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#getSourceViewerDecorationSupport(ISourceViewer)
|
||||
*/
|
||||
protected SourceViewerDecorationSupport getSourceViewerDecorationSupport(
|
||||
ISourceViewer viewer) {
|
||||
if (fSourceViewerDecorationSupport == null) {
|
||||
fSourceViewerDecorationSupport= new CSourceViewerDecorationSupport(viewer, getOverviewRuler(), getAnnotationAccess(), getSharedColors());
|
||||
fSourceViewerDecorationSupport= new CSourceViewerDecorationSupport(this, viewer, getOverviewRuler(), getAnnotationAccess(), getSharedColors());
|
||||
configureSourceViewerDecorationSupport(fSourceViewerDecorationSupport);
|
||||
}
|
||||
return fSourceViewerDecorationSupport;
|
||||
|
@ -1557,11 +1584,10 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
getOverviewRuler(),
|
||||
isOverviewRulerVisible());
|
||||
|
||||
CSourceViewerDecorationSupport decoSupport = (CSourceViewerDecorationSupport) getSourceViewerDecorationSupport(sourceViewer);
|
||||
decoSupport.editorInputChanged(getEditorInput());
|
||||
|
||||
CUIHelp.setHelp(this, sourceViewer.getTextWidget(), ICHelpContextIds.CEDITOR_VIEW);
|
||||
|
||||
getSourceViewerDecorationSupport(sourceViewer);
|
||||
|
||||
return sourceViewer;
|
||||
}
|
||||
|
||||
|
@ -1701,16 +1727,36 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.editor.IReconcilingParticipant#reconciled()
|
||||
*/
|
||||
public void reconciled(boolean somethingHasChanged) {
|
||||
// Do nothing the outliner is listener to the
|
||||
// CoreModel WorkingCopy changes instead.
|
||||
// It will allow more fined grained.
|
||||
if (somethingHasChanged && getSourceViewer() != null) {
|
||||
CSourceViewerDecorationSupport decoSupport = (CSourceViewerDecorationSupport) getSourceViewerDecorationSupport(getSourceViewer());
|
||||
decoSupport.editorInputChanged(getEditorInput());
|
||||
if (getSourceViewer() == null) {
|
||||
return;
|
||||
}
|
||||
// this method must be called in a background thread
|
||||
assert getSourceViewer().getTextWidget().getDisplay().getThread() != Thread.currentThread();
|
||||
|
||||
if (fReconcilingListeners.size() > 0) {
|
||||
// create AST and notify ICReconcilingListeners
|
||||
ICElement cElement= getInputCElement();
|
||||
if (cElement == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
aboutToBeReconciled();
|
||||
|
||||
// track changes to the document while parsing
|
||||
IDocument doc= getDocumentProvider().getDocument(getEditorInput());
|
||||
SimplePositionTracker positionTracker= new SimplePositionTracker();
|
||||
positionTracker.startTracking(doc);
|
||||
|
||||
try {
|
||||
IASTTranslationUnit ast= CUIPlugin.getDefault().getASTProvider().createAST(cElement, null);
|
||||
reconciled(ast, positionTracker, null);
|
||||
} finally {
|
||||
positionTracker.stopTracking();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2099,4 +2145,101 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IS
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
|
||||
* @since 4.0
|
||||
*/
|
||||
public void aboutToBeReconciled() {
|
||||
|
||||
// Notify AST provider
|
||||
CUIPlugin.getDefault().getASTProvider().aboutToBeReconciled(getInputCElement());
|
||||
|
||||
// Notify listeners
|
||||
Object[] listeners = fReconcilingListeners.getListeners();
|
||||
for (int i = 0, length= listeners.length; i < length; ++i) {
|
||||
((ICReconcilingListener)listeners[i]).aboutToBeReconciled();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled(IASTTranslationUnit, IPositionConverter, IProgressMonitor)
|
||||
* @since 4.0
|
||||
*/
|
||||
public void reconciled(IASTTranslationUnit ast, IPositionConverter positionTracker, IProgressMonitor progressMonitor) {
|
||||
|
||||
CUIPlugin cuiPlugin= CUIPlugin.getDefault();
|
||||
if (cuiPlugin == null)
|
||||
return;
|
||||
|
||||
// Always notify AST provider
|
||||
cuiPlugin.getASTProvider().reconciled(ast, getInputCElement(), progressMonitor);
|
||||
|
||||
// Notify listeners
|
||||
Object[] listeners = fReconcilingListeners.getListeners();
|
||||
for (int i = 0, length= listeners.length; i < length; ++i) {
|
||||
((ICReconcilingListener)listeners[i]).reconciled(ast, positionTracker, progressMonitor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given listener.
|
||||
* Has no effect if an identical listener was not already registered.
|
||||
*
|
||||
* @param listener The reconcile listener to be added
|
||||
* @since 4.0
|
||||
*/
|
||||
final void addReconcileListener(ICReconcilingListener listener) {
|
||||
synchronized (fReconcilingListeners) {
|
||||
fReconcilingListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given listener.
|
||||
* Has no effect if an identical listener was not already registered.
|
||||
*
|
||||
* @param listener the reconcile listener to be removed
|
||||
* @since 4.0
|
||||
*/
|
||||
final void removeReconcileListener(ICReconcilingListener listener) {
|
||||
synchronized (fReconcilingListeners) {
|
||||
fReconcilingListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if Semantic Highlighting is enabled.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
private boolean isSemanticHighlightingEnabled() {
|
||||
return SemanticHighlightings.isEnabled(getPreferenceStore());
|
||||
}
|
||||
|
||||
/**
|
||||
* Install Semantic Highlighting.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
private void installSemanticHighlighting() {
|
||||
if (fSemanticManager == null) {
|
||||
fSemanticManager= new SemanticHighlightingManager();
|
||||
fSemanticManager.install(this, (CSourceViewer) getSourceViewer(), CUIPlugin.getDefault().getTextTools().getColorManager(), getPreferenceStore());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall Semantic Highlighting.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
private void uninstallSemanticHighlighting() {
|
||||
if (fSemanticManager != null) {
|
||||
fSemanticManager.uninstall();
|
||||
fSemanticManager= null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#########################################
|
||||
# Copyright (c) 2005 IBM Corporation and others.
|
||||
# Copyright (c) 2005, 2006 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
|
||||
|
@ -8,6 +8,7 @@
|
|||
# Contributors:
|
||||
# IBM Corporation - initial API and implementation
|
||||
# QNX Software System
|
||||
# Anton Leherbauer (Wind River Systems)
|
||||
#########################################
|
||||
|
||||
AddIncludeOnSelection.description=Add include statement on selection
|
||||
|
@ -201,3 +202,33 @@ ShowToolTip.label=Show T&ooltip Description
|
|||
|
||||
ToggleComment_error_title=Comment/Uncomment
|
||||
ToggleComment_error_message=An error occurred while commenting/uncommenting.
|
||||
|
||||
InactiveCodeHighlighting_job= Inactive Code Highlighting
|
||||
|
||||
Reconciling_job= Reconciling
|
||||
|
||||
SemanticHighlighting_job= Semantic Highlighting
|
||||
SemanticHighlighting_field= Fields
|
||||
SemanticHighlighting_staticField= Static fields
|
||||
SemanticHighlighting_staticConstField= Constants
|
||||
SemanticHighlighting_methodDeclaration= Method declarations
|
||||
SemanticHighlighting_staticMethodInvocation= Static method invocations
|
||||
SemanticHighlighting_virtualMethodInvocation= Virtual method invocations
|
||||
SemanticHighlighting_inheritedMethodInvocation= Inherited method invocations
|
||||
SemanticHighlighting_localVariableDeclaration= Local variable declarations
|
||||
SemanticHighlighting_localVariable= Local variable references
|
||||
SemanticHighlighting_globalVariable= Global variables
|
||||
SemanticHighlighting_parameterVariable= Parameter variables
|
||||
SemanticHighlighting_TemplateVariables= Template variables
|
||||
SemanticHighlighting_method= Methods
|
||||
SemanticHighlighting_classes= Classes
|
||||
SemanticHighlighting_enums= Enums
|
||||
SemanticHighlighting_templateArguments= Template arguments
|
||||
SemanticHighlighting_functionDeclaration= Function declarations
|
||||
SemanticHighlighting_functionInvocation= Function invocations
|
||||
SemanticHighlighting_macroSubstitions= Macro references
|
||||
SemanticHighlighting_macroDefintion= Macro definitions
|
||||
SemanticHighlighting_typeDef= Typedefs
|
||||
SemanticHighlighting_namespace= Namespaces
|
||||
SemanticHighlighting_label= Labels
|
||||
SemanticHighlighting_problem= Problems
|
||||
|
|
|
@ -10,23 +10,9 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
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.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.preference.PreferenceConverter;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.ITextViewerExtension2;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.source.IAnnotationAccess;
|
||||
import org.eclipse.jface.text.source.IOverviewRuler;
|
||||
import org.eclipse.jface.text.source.ISharedTextColors;
|
||||
|
@ -34,24 +20,8 @@ import org.eclipse.jface.text.source.ISourceViewer;
|
|||
import org.eclipse.jface.util.PropertyChangeEvent;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
import org.eclipse.ui.IEditorInput;
|
||||
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorEndifStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.model.ILanguage;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.LineBackgroundPainter;
|
||||
|
||||
/**
|
||||
|
@ -64,69 +34,10 @@ import org.eclipse.cdt.internal.ui.LineBackgroundPainter;
|
|||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class CSourceViewerDecorationSupport
|
||||
extends SourceViewerDecorationSupport {
|
||||
public class CSourceViewerDecorationSupport extends SourceViewerDecorationSupport {
|
||||
|
||||
/**
|
||||
* This job takes the current translation unit and produces an
|
||||
* AST in the background. Upon completion, {@link #inactiveCodePositionsChanged}
|
||||
* is called in the display thread.
|
||||
*/
|
||||
private class UpdateJob extends Job {
|
||||
|
||||
/**
|
||||
* @param name
|
||||
*/
|
||||
public UpdateJob(String name) {
|
||||
super(name);
|
||||
setSystem(true);
|
||||
setPriority(Job.DECORATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
IStatus result = Status.OK_STATUS;
|
||||
if (fASTTranslationUnit == null && fTranslationUnit != null) {
|
||||
try {
|
||||
fParseTimeStamp = System.currentTimeMillis();
|
||||
int style = ILanguage.AST_SKIP_IF_NO_BUILD_INFO | ILanguage.AST_SKIP_INDEXED_HEADERS;
|
||||
fASTTranslationUnit = fTranslationUnit.getLanguage().getASTTranslationUnit(fTranslationUnit, style);
|
||||
} catch (CoreException exc) {
|
||||
result = exc.getStatus();
|
||||
}
|
||||
}
|
||||
if (monitor.isCanceled() || fViewer == null) {
|
||||
result = Status.CANCEL_STATUS;
|
||||
} else {
|
||||
final List inactiveCodePositions = collectInactiveCodePositions(fASTTranslationUnit);
|
||||
Runnable updater = new Runnable() {
|
||||
public void run() {
|
||||
inactiveCodePositionsChanged(inactiveCodePositions);
|
||||
}
|
||||
};
|
||||
if (fViewer != null && !monitor.isCanceled()) {
|
||||
fViewer.getTextWidget().getDisplay().asyncExec(updater);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of <code>IRegion</code> that can be reused
|
||||
* by setting the offset and the length.
|
||||
*/
|
||||
private static class ReusableRegion extends Position implements IRegion {
|
||||
public ReusableRegion(int offset, int length) {
|
||||
super(offset, length);
|
||||
}
|
||||
public ReusableRegion(IRegion region) {
|
||||
super(region.getOffset(), region.getLength());
|
||||
}
|
||||
}
|
||||
/** The key to use for the {@link LineBackgroundPainter} */
|
||||
private static final String INACTIVE_CODE_KEY = "inactiveCode"; //$NON-NLS-1$
|
||||
|
||||
/** The preference key for the inactive code highlight color */
|
||||
private String fInactiveCodeColorKey;
|
||||
|
@ -144,14 +55,10 @@ public class CSourceViewerDecorationSupport
|
|||
private String fCLPEnableKey;
|
||||
/** The source viewer (duplicate of private base class member) */
|
||||
protected ISourceViewer fViewer;
|
||||
/** The current translation unit */
|
||||
private ITranslationUnit fTranslationUnit;
|
||||
/** The corresponding AST translation unit */
|
||||
private IASTTranslationUnit fASTTranslationUnit;
|
||||
/** The time stamp when the parsing was initiated */
|
||||
private long fParseTimeStamp;
|
||||
/** The background job doing the AST parsing */
|
||||
private Job fUpdateJob;
|
||||
/** The editor we are associated with */
|
||||
private CEditor fEditor;
|
||||
/** The inactive code highlighting */
|
||||
private InactiveCodeHighlighting fInactiveCodeHighlighting;
|
||||
|
||||
/**
|
||||
* Inherited constructor.
|
||||
|
@ -162,55 +69,22 @@ public class CSourceViewerDecorationSupport
|
|||
* @param sharedTextColors
|
||||
*/
|
||||
CSourceViewerDecorationSupport(
|
||||
CEditor editor,
|
||||
ISourceViewer sourceViewer,
|
||||
IOverviewRuler overviewRuler,
|
||||
IAnnotationAccess annotationAccess,
|
||||
ISharedTextColors sharedTextColors) {
|
||||
super(sourceViewer, overviewRuler, annotationAccess, sharedTextColors);
|
||||
// we have to save our own reference, because super class members are all private
|
||||
fEditor = editor;
|
||||
// we have to save our own references, because super class members are all private
|
||||
fViewer = sourceViewer;
|
||||
fSharedColors = sharedTextColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that the associated editor got a new input.
|
||||
* This is currently also used to notify of a reconcilation
|
||||
* to update the inactive code while editing.
|
||||
*
|
||||
* @param input the new editor input
|
||||
*/
|
||||
void editorInputChanged(IEditorInput input) {
|
||||
if (fUpdateJob != null) {
|
||||
fUpdateJob.cancel();
|
||||
}
|
||||
fTranslationUnit = CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(input);
|
||||
fASTTranslationUnit = null;
|
||||
if (isInactiveCodePositionsActive()) {
|
||||
updateInactiveCodePositions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule update of the AST in the background.
|
||||
*/
|
||||
private void updateInactiveCodePositions() {
|
||||
if (fUpdateJob == null) {
|
||||
fUpdateJob = new UpdateJob("Update Inactive Code Positions"); //$NON-NLS-1$
|
||||
}
|
||||
if (fUpdateJob.getState() == Job.NONE) {
|
||||
fUpdateJob.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.texteditor.SourceViewerDecorationSupport#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
if (fUpdateJob != null) {
|
||||
fUpdateJob.cancel();
|
||||
}
|
||||
fTranslationUnit = null;
|
||||
fASTTranslationUnit = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -229,7 +103,7 @@ public class CSourceViewerDecorationSupport
|
|||
updateCLPColor();
|
||||
} else if (p.equals(fInactiveCodeEnableKey)) {
|
||||
if (isInactiveCodePositionsActive()) {
|
||||
showInactiveCodePositions();
|
||||
showInactiveCodePositions(true);
|
||||
} else {
|
||||
hideInactiveCodePositions();
|
||||
}
|
||||
|
@ -244,7 +118,7 @@ public class CSourceViewerDecorationSupport
|
|||
*/
|
||||
private void updateInactiveCodeColor() {
|
||||
if (fLineBackgroundPainter != null) {
|
||||
fLineBackgroundPainter.setDefaultColor(getColor(fInactiveCodeColorKey));
|
||||
fLineBackgroundPainter.setBackgroundColor(INACTIVE_CODE_KEY, getColor(fInactiveCodeColorKey));
|
||||
if (isInactiveCodePositionsActive()) {
|
||||
fLineBackgroundPainter.redraw();
|
||||
}
|
||||
|
@ -342,7 +216,7 @@ public class CSourceViewerDecorationSupport
|
|||
showCLP();
|
||||
}
|
||||
if (isInactiveCodePositionsActive()) {
|
||||
showInactiveCodePositions();
|
||||
showInactiveCodePositions(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,6 +224,10 @@ public class CSourceViewerDecorationSupport
|
|||
* @see org.eclipse.ui.texteditor.SourceViewerDecorationSupport#uninstall()
|
||||
*/
|
||||
public void uninstall() {
|
||||
if (fInactiveCodeHighlighting != null) {
|
||||
fInactiveCodeHighlighting.dispose();
|
||||
fInactiveCodeHighlighting= null;
|
||||
}
|
||||
uninstallLineBackgroundPainter();
|
||||
super.uninstall();
|
||||
}
|
||||
|
@ -361,7 +239,7 @@ public class CSourceViewerDecorationSupport
|
|||
if (fLineBackgroundPainter == null) {
|
||||
if (fViewer instanceof ITextViewerExtension2) {
|
||||
fLineBackgroundPainter = new LineBackgroundPainter(fViewer);
|
||||
fLineBackgroundPainter.setDefaultColor(getColor(fInactiveCodeColorKey));
|
||||
fLineBackgroundPainter.setBackgroundColor(INACTIVE_CODE_KEY, getColor(fInactiveCodeColorKey));
|
||||
fLineBackgroundPainter.setCursorLineColor(getColor(fCLPColorKey));
|
||||
fLineBackgroundPainter.enableCursorLine(isCLPActive());
|
||||
((ITextViewerExtension2)fViewer).addPainter(fLineBackgroundPainter);
|
||||
|
@ -385,10 +263,18 @@ public class CSourceViewerDecorationSupport
|
|||
|
||||
/**
|
||||
* Show inactive code positions.
|
||||
*
|
||||
* @param refresh trigger a refresh of the positions
|
||||
*/
|
||||
private void showInactiveCodePositions() {
|
||||
private void showInactiveCodePositions(boolean refresh) {
|
||||
installLineBackgroundPainter();
|
||||
updateInactiveCodePositions();
|
||||
if (fLineBackgroundPainter != null) {
|
||||
fInactiveCodeHighlighting= new InactiveCodeHighlighting(fLineBackgroundPainter, INACTIVE_CODE_KEY);
|
||||
fInactiveCodeHighlighting.install(fEditor);
|
||||
if (refresh) {
|
||||
fInactiveCodeHighlighting.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -396,133 +282,16 @@ public class CSourceViewerDecorationSupport
|
|||
*/
|
||||
private void hideInactiveCodePositions() {
|
||||
if (fLineBackgroundPainter != null) {
|
||||
if (fInactiveCodeHighlighting != null) {
|
||||
fInactiveCodeHighlighting.dispose();
|
||||
fInactiveCodeHighlighting= null;
|
||||
}
|
||||
if (!isCLPActive()) {
|
||||
uninstallLineBackgroundPainter();
|
||||
} else {
|
||||
fLineBackgroundPainter.setHighlightPositions(Collections.EMPTY_LIST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void inactiveCodePositionsChanged(List inactiveCodePositions) {
|
||||
if (fLineBackgroundPainter != null) {
|
||||
if (!inactiveCodePositions.isEmpty()) {
|
||||
IPositionConverter pt = CCorePlugin.getPositionTrackerManager().findPositionConverter(fTranslationUnit.getPath(), fParseTimeStamp);
|
||||
if (pt != null) {
|
||||
List convertedPositions = new ArrayList(inactiveCodePositions.size());
|
||||
for (Iterator iter = inactiveCodePositions.iterator(); iter
|
||||
.hasNext();) {
|
||||
IRegion pos = (IRegion) iter.next();
|
||||
convertedPositions.add(new ReusableRegion(pt.historicToActual(pos)));
|
||||
}
|
||||
inactiveCodePositions = convertedPositions;
|
||||
}
|
||||
}
|
||||
fLineBackgroundPainter.setHighlightPositions(inactiveCodePositions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect source positions of preprocessor-hidden branches
|
||||
* in the given translation unit.
|
||||
*
|
||||
* @param translationUnit the {@link IASTTranslationUnit}, may be <code>null</code>
|
||||
* @return a {@link List} of {@link IRegion}s
|
||||
*/
|
||||
private static List collectInactiveCodePositions(IASTTranslationUnit translationUnit) {
|
||||
if (translationUnit == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
String fileName = translationUnit.getFilePath();
|
||||
if (fileName == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List positions = new ArrayList();
|
||||
int inactiveCodeStart = -1;
|
||||
boolean inInactiveCode = false;
|
||||
Stack inactiveCodeStack = new Stack();
|
||||
// TLETODO [performance] This does not look very efficient
|
||||
IASTPreprocessorStatement[] preprocStmts = translationUnit.getAllPreprocessorStatements();
|
||||
for (int i = 0; i < preprocStmts.length; i++) {
|
||||
IASTPreprocessorStatement statement = preprocStmts[i];
|
||||
if (!fileName.equals(statement.getContainingFilename())) {
|
||||
// preprocessor directive is from a different file
|
||||
continue;
|
||||
}
|
||||
if (statement instanceof IASTPreprocessorIfStatement) {
|
||||
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement;
|
||||
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
|
||||
if (!ifStmt.taken()) {
|
||||
if (!inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = ifStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorIfdefStatement) {
|
||||
IASTPreprocessorIfdefStatement ifdefStmt = (IASTPreprocessorIfdefStatement)statement;
|
||||
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
|
||||
if (!ifdefStmt.taken()) {
|
||||
if (!inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = ifdefStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorIfndefStatement) {
|
||||
IASTPreprocessorIfndefStatement ifndefStmt = (IASTPreprocessorIfndefStatement)statement;
|
||||
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
|
||||
if (!ifndefStmt.taken()) {
|
||||
if (!inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = ifndefStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorElseStatement) {
|
||||
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement;
|
||||
if (!elseStmt.taken() && !inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
} else if (elseStmt.taken() && inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0];
|
||||
int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
|
||||
positions.add(new ReusableRegion(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
|
||||
inInactiveCode = false;
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorElifStatement) {
|
||||
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement;
|
||||
if (!elifStmt.taken() && !inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
} else if (elifStmt.taken() && inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0];
|
||||
int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
|
||||
positions.add(new ReusableRegion(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
|
||||
inInactiveCode = false;
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorEndifStatement) {
|
||||
IASTPreprocessorEndifStatement endifStmt = (IASTPreprocessorEndifStatement)statement;
|
||||
try {
|
||||
boolean wasInInactiveCode = ((Boolean)inactiveCodeStack.pop()).booleanValue();
|
||||
if (inInactiveCode && !wasInInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = endifStmt.getNodeLocations()[0];
|
||||
int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
|
||||
positions.add(new ReusableRegion(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart));
|
||||
}
|
||||
inInactiveCode = wasInInactiveCode;
|
||||
}
|
||||
catch( EmptyStackException e) {}
|
||||
}
|
||||
}
|
||||
if (inInactiveCode) {
|
||||
// handle dangling #if?
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.texteditor.SourceViewerDecorationSupport#setCursorLinePainterPreferenceKeys(java.lang.String, java.lang.String)
|
||||
*/
|
||||
|
@ -543,4 +312,5 @@ public class CSourceViewerDecorationSupport
|
|||
fInactiveCodeEnableKey = enableKey;
|
||||
fInactiveCodeColorKey = colorKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006 Wind River Systems, Inc. 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:
|
||||
* Anton Leherbauer (Wind River Systems) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
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.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.TypedPosition;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorEndifStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.LineBackgroundPainter;
|
||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
|
||||
/**
|
||||
* TLETODO Document InactiveCodeHighlighting.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class InactiveCodeHighlighting implements ICReconcilingListener {
|
||||
|
||||
/**
|
||||
* Implementation of <code>IRegion</code> that can be reused
|
||||
* by setting the offset and the length.
|
||||
*/
|
||||
private static class HighlightPosition extends TypedPosition implements IRegion {
|
||||
public HighlightPosition(int offset, int length, String type) {
|
||||
super(offset, length, type);
|
||||
}
|
||||
public HighlightPosition(IRegion region, String type) {
|
||||
super(region.getOffset(), region.getLength(), type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** The line background painter */
|
||||
private LineBackgroundPainter fLineBackgroundPainter;
|
||||
/** The key for inactive code positions in the background painter */
|
||||
private String fHighlightKey;
|
||||
/** The current translation unit */
|
||||
private ITranslationUnit fTranslationUnit;
|
||||
/** The background job doing the AST parsing */
|
||||
private Job fUpdateJob;
|
||||
/** The lock for job manipulation */
|
||||
private Object fJobLock = new Object();
|
||||
/** The editor this is installed on */
|
||||
private CEditor fEditor;
|
||||
/** The list of currently highlighted positions */
|
||||
private List fInactiveCodePositions= Collections.EMPTY_LIST;
|
||||
|
||||
/**
|
||||
* @param lineBackgroundPainter
|
||||
*/
|
||||
public InactiveCodeHighlighting(LineBackgroundPainter lineBackgroundPainter, String highlightKey) {
|
||||
fLineBackgroundPainter= lineBackgroundPainter;
|
||||
fHighlightKey= highlightKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule update of the inactive code positions in the background.
|
||||
*/
|
||||
private void scheduleJob() {
|
||||
synchronized (fJobLock) {
|
||||
if (fUpdateJob == null) {
|
||||
fUpdateJob = new Job(CEditorMessages.getString("InactiveCodeHighlighting_job")) { //$NON-NLS-1$
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
IStatus result = Status.OK_STATUS;
|
||||
if (fTranslationUnit != null) {
|
||||
IASTTranslationUnit ast= CUIPlugin.getDefault().getASTProvider().getAST(fTranslationUnit, ASTProvider.WAIT_YES, monitor);
|
||||
reconciled(ast, null, monitor);
|
||||
}
|
||||
if (monitor.isCanceled()) {
|
||||
result = Status.CANCEL_STATUS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
fUpdateJob.setPriority(Job.DECORATE);
|
||||
}
|
||||
if (fUpdateJob.getState() == Job.NONE) {
|
||||
// schedule later if AST is not available yet
|
||||
fUpdateJob.schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param editor
|
||||
*/
|
||||
public void install(CEditor editor) {
|
||||
assert fEditor == null;
|
||||
fEditor= editor;
|
||||
fEditor.addReconcileListener(this);
|
||||
ICElement cElement= fEditor.getInputCElement();
|
||||
if (cElement instanceof ITranslationUnit) {
|
||||
fTranslationUnit = (ITranslationUnit)cElement;
|
||||
} else {
|
||||
fTranslationUnit = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void uninstall() {
|
||||
if (fLineBackgroundPainter != null) {
|
||||
fLineBackgroundPainter.removeHighlightPositions(fInactiveCodePositions);
|
||||
fInactiveCodePositions= Collections.EMPTY_LIST;
|
||||
}
|
||||
if (fEditor != null) {
|
||||
fEditor.removeReconcileListener(this);
|
||||
fEditor= null;
|
||||
fTranslationUnit= null;
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
uninstall();
|
||||
fLineBackgroundPainter= null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force refresh.
|
||||
*/
|
||||
public void refresh() {
|
||||
scheduleJob();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#aboutToBeReconciled()
|
||||
*/
|
||||
public void aboutToBeReconciled() {
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled(IASTTranslationUnit, IPositionConverter, IProgressMonitor)
|
||||
*/
|
||||
public void reconciled(IASTTranslationUnit ast, final IPositionConverter positionTracker, IProgressMonitor progressMonitor) {
|
||||
if (progressMonitor != null && progressMonitor.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final List newInactiveCodePositions = collectInactiveCodePositions(ast);
|
||||
if (positionTracker != null) {
|
||||
for (int i = 0, sz = newInactiveCodePositions.size(); i < sz; i++) {
|
||||
IRegion pos = (IRegion) newInactiveCodePositions.get(i);
|
||||
newInactiveCodePositions.set(i, new HighlightPosition(positionTracker.historicToActual(pos), fHighlightKey));
|
||||
}
|
||||
}
|
||||
Runnable updater = new Runnable() {
|
||||
public void run() {
|
||||
if (fEditor != null && fLineBackgroundPainter != null) {
|
||||
fLineBackgroundPainter.replaceHighlightPositions(fInactiveCodePositions, newInactiveCodePositions);
|
||||
fInactiveCodePositions= newInactiveCodePositions;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (fEditor != null) {
|
||||
Display.getDefault().asyncExec(updater);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect source positions of preprocessor-hidden branches
|
||||
* in the given translation unit.
|
||||
*
|
||||
* @param translationUnit the {@link IASTTranslationUnit}, may be <code>null</code>
|
||||
* @return a {@link List} of {@link IRegion}s
|
||||
*/
|
||||
private List collectInactiveCodePositions(IASTTranslationUnit translationUnit) {
|
||||
if (translationUnit == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
String fileName = translationUnit.getFilePath();
|
||||
if (fileName == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List positions = new ArrayList();
|
||||
int inactiveCodeStart = -1;
|
||||
boolean inInactiveCode = false;
|
||||
Stack inactiveCodeStack = new Stack();
|
||||
|
||||
IASTPreprocessorStatement[] preprocStmts = translationUnit.getAllPreprocessorStatements();
|
||||
|
||||
for (int i = 0; i < preprocStmts.length; i++) {
|
||||
IASTPreprocessorStatement statement = preprocStmts[i];
|
||||
if (!fileName.equals(statement.getContainingFilename())) {
|
||||
// preprocessor directive is from a different file
|
||||
continue;
|
||||
}
|
||||
if (statement instanceof IASTPreprocessorIfStatement) {
|
||||
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement;
|
||||
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
|
||||
if (!ifStmt.taken()) {
|
||||
if (!inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = ifStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorIfdefStatement) {
|
||||
IASTPreprocessorIfdefStatement ifdefStmt = (IASTPreprocessorIfdefStatement)statement;
|
||||
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
|
||||
if (!ifdefStmt.taken()) {
|
||||
if (!inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = ifdefStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorIfndefStatement) {
|
||||
IASTPreprocessorIfndefStatement ifndefStmt = (IASTPreprocessorIfndefStatement)statement;
|
||||
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
|
||||
if (!ifndefStmt.taken()) {
|
||||
if (!inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = ifndefStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
}
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorElseStatement) {
|
||||
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement;
|
||||
if (!elseStmt.taken() && !inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
} else if (elseStmt.taken() && inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elseStmt.getNodeLocations()[0];
|
||||
int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
|
||||
positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey));
|
||||
inInactiveCode = false;
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorElifStatement) {
|
||||
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement;
|
||||
if (!elifStmt.taken() && !inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0];
|
||||
inactiveCodeStart = nodeLocation.getNodeOffset();
|
||||
inInactiveCode = true;
|
||||
} else if (elifStmt.taken() && inInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = elifStmt.getNodeLocations()[0];
|
||||
int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
|
||||
positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey));
|
||||
inInactiveCode = false;
|
||||
}
|
||||
} else if (statement instanceof IASTPreprocessorEndifStatement) {
|
||||
IASTPreprocessorEndifStatement endifStmt = (IASTPreprocessorEndifStatement)statement;
|
||||
try {
|
||||
boolean wasInInactiveCode = ((Boolean)inactiveCodeStack.pop()).booleanValue();
|
||||
if (inInactiveCode && !wasInInactiveCode) {
|
||||
IASTNodeLocation nodeLocation = endifStmt.getNodeLocations()[0];
|
||||
int inactiveCodeEnd = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
|
||||
positions.add(new HighlightPosition(inactiveCodeStart, inactiveCodeEnd - inactiveCodeStart, fHighlightKey));
|
||||
}
|
||||
inInactiveCode = wasInInactiveCode;
|
||||
}
|
||||
catch( EmptyStackException e) {}
|
||||
}
|
||||
}
|
||||
if (inInactiveCode) {
|
||||
// handle dangling #if?
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
/**
|
||||
* Semantic highlighting.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public abstract class SemanticHighlighting {
|
||||
|
||||
/**
|
||||
* @return the preference key, will be augmented by a prefix and a suffix for each preference
|
||||
*/
|
||||
public abstract String getPreferenceKey();
|
||||
|
||||
/**
|
||||
* @return the default text color
|
||||
*/
|
||||
public RGB getDefaultTextColor() {
|
||||
return new RGB(0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the text attribute bold is set by default
|
||||
*/
|
||||
public boolean isBoldByDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the text attribute italic is set by default
|
||||
*/
|
||||
public boolean isItalicByDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the text attribute strikethrough is set by default
|
||||
*/
|
||||
public boolean isStrikethroughByDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the text attribute underline is set by default
|
||||
* @since 3.1
|
||||
*/
|
||||
public boolean isUnderlineByDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the text attribute italic is enabled by default
|
||||
*/
|
||||
public abstract boolean isEnabledByDefault();
|
||||
|
||||
/**
|
||||
* @return the display name
|
||||
*/
|
||||
public abstract String getDisplayName();
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> iff the semantic highlighting consumes the semantic token.
|
||||
* <p>
|
||||
* NOTE: Implementors are not allowed to keep a reference on the token or on any object
|
||||
* retrieved from the token.
|
||||
* </p>
|
||||
*
|
||||
* @param token the semantic token for a {@link org.eclipse.cdt.core.dom.ast.IASTName}
|
||||
* @return <code>true</code> iff the semantic highlighting consumes the semantic token
|
||||
*/
|
||||
public abstract boolean consumes(SemanticToken token);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> iff the semantic highlighting consumes the
|
||||
* semantic token.
|
||||
* <p>
|
||||
* NOTE: Implementors are not allowed to keep a reference on the token or on
|
||||
* any object retrieved from the token.
|
||||
* </p>
|
||||
* @param token the semantic token for a
|
||||
* {@link org.eclipse.cdt.core.dom.ast.IASTLiteralExpression}
|
||||
* @return <code>true</code> iff the semantic highlighting consumes the
|
||||
* semantic token
|
||||
*/
|
||||
public boolean consumesLiteral(SemanticToken token) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,632 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.preference.PreferenceConverter;
|
||||
import org.eclipse.jface.resource.StringConverter;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.text.TextAttribute;
|
||||
import org.eclipse.jface.util.IPropertyChangeListener;
|
||||
import org.eclipse.jface.util.PropertyChangeEvent;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.StyleRange;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.RGB;
|
||||
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.text.CPresentationReconciler;
|
||||
import org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration;
|
||||
import org.eclipse.cdt.internal.ui.text.IColorManager;
|
||||
import org.eclipse.cdt.internal.ui.text.IColorManagerExtension;
|
||||
|
||||
/**
|
||||
* Semantic highlighting manager.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SemanticHighlightingManager implements IPropertyChangeListener {
|
||||
|
||||
/**
|
||||
* Highlighting style.
|
||||
*/
|
||||
static class HighlightingStyle {
|
||||
|
||||
/** Text attribute */
|
||||
private TextAttribute fTextAttribute;
|
||||
/** Enabled state */
|
||||
private boolean fIsEnabled;
|
||||
|
||||
/**
|
||||
* Initialize with the given text attribute.
|
||||
* @param textAttribute The text attribute
|
||||
* @param isEnabled the enabled state
|
||||
*/
|
||||
public HighlightingStyle(TextAttribute textAttribute, boolean isEnabled) {
|
||||
setTextAttribute(textAttribute);
|
||||
setEnabled(isEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the text attribute.
|
||||
*/
|
||||
public TextAttribute getTextAttribute() {
|
||||
return fTextAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param textAttribute The background to set.
|
||||
*/
|
||||
public void setTextAttribute(TextAttribute textAttribute) {
|
||||
fTextAttribute= textAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the enabled state
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return fIsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isEnabled the new enabled state
|
||||
*/
|
||||
public void setEnabled(boolean isEnabled) {
|
||||
fIsEnabled= isEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlighted Positions.
|
||||
*/
|
||||
static class HighlightedPosition extends Position {
|
||||
|
||||
/** Highlighting of the position */
|
||||
private HighlightingStyle fStyle;
|
||||
|
||||
/** Lock object */
|
||||
private Object fLock;
|
||||
|
||||
/**
|
||||
* Initialize the styled positions with the given offset, length and foreground color.
|
||||
*
|
||||
* @param offset The position offset
|
||||
* @param length The position length
|
||||
* @param highlighting The position's highlighting
|
||||
* @param lock The lock object
|
||||
*/
|
||||
public HighlightedPosition(int offset, int length, HighlightingStyle highlighting, Object lock) {
|
||||
super(offset, length);
|
||||
fStyle= highlighting;
|
||||
fLock= lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns a corresponding style range.
|
||||
*/
|
||||
public StyleRange createStyleRange() {
|
||||
int len= 0;
|
||||
if (fStyle.isEnabled())
|
||||
len= getLength();
|
||||
|
||||
TextAttribute textAttribute= fStyle.getTextAttribute();
|
||||
int style= textAttribute.getStyle();
|
||||
int fontStyle= style & (SWT.ITALIC | SWT.BOLD | SWT.NORMAL);
|
||||
StyleRange styleRange= new StyleRange(getOffset(), len, textAttribute.getForeground(), textAttribute.getBackground(), fontStyle);
|
||||
styleRange.strikeout= (style & TextAttribute.STRIKETHROUGH) != 0;
|
||||
styleRange.underline= (style & TextAttribute.UNDERLINE) != 0;
|
||||
|
||||
return styleRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses reference equality for the highlighting.
|
||||
*
|
||||
* @param off The offset
|
||||
* @param len The length
|
||||
* @param highlighting The highlighting
|
||||
* @return <code>true</code> iff the given offset, length and highlighting are equal to the internal ones.
|
||||
*/
|
||||
public boolean isEqual(int off, int len, HighlightingStyle highlighting) {
|
||||
synchronized (fLock) {
|
||||
return !isDeleted() && getOffset() == off && getLength() == len && fStyle == highlighting;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this position contained in the given range (inclusive)? Synchronizes on position updater.
|
||||
*
|
||||
* @param off The range offset
|
||||
* @param len The range length
|
||||
* @return <code>true</code> iff this position is not delete and contained in the given range.
|
||||
*/
|
||||
public boolean isContained(int off, int len) {
|
||||
synchronized (fLock) {
|
||||
return !isDeleted() && off <= getOffset() && off + len >= getOffset() + getLength();
|
||||
}
|
||||
}
|
||||
|
||||
public void update(int off, int len) {
|
||||
synchronized (fLock) {
|
||||
super.setOffset(off);
|
||||
super.setLength(len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.Position#setLength(int)
|
||||
*/
|
||||
public void setLength(int length) {
|
||||
synchronized (fLock) {
|
||||
super.setLength(length);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.Position#setOffset(int)
|
||||
*/
|
||||
public void setOffset(int offset) {
|
||||
synchronized (fLock) {
|
||||
super.setOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.Position#delete()
|
||||
*/
|
||||
public void delete() {
|
||||
synchronized (fLock) {
|
||||
super.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.Position#undelete()
|
||||
*/
|
||||
public void undelete() {
|
||||
synchronized (fLock) {
|
||||
super.undelete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the highlighting.
|
||||
*/
|
||||
public HighlightingStyle getHighlighting() {
|
||||
return fStyle;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlighted ranges.
|
||||
*/
|
||||
public static class HighlightedRange extends Region {
|
||||
/** The highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}. */
|
||||
private String fKey;
|
||||
|
||||
/**
|
||||
* Initialize with the given offset, length and highlighting key.
|
||||
*
|
||||
* @param offset
|
||||
* @param length
|
||||
* @param key the highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}
|
||||
*/
|
||||
public HighlightedRange(int offset, int length, String key) {
|
||||
super(offset, length);
|
||||
fKey= key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}
|
||||
*/
|
||||
public String getKey() {
|
||||
return fKey;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.Region#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o) && o instanceof HighlightedRange && fKey.equals(((HighlightedRange)o).getKey());
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.Region#hashCode()
|
||||
*/
|
||||
public int hashCode() {
|
||||
return super.hashCode() | fKey.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/** Semantic highlighting presenter */
|
||||
private SemanticHighlightingPresenter fPresenter;
|
||||
/** Semantic highlighting reconciler */
|
||||
private SemanticHighlightingReconciler fReconciler;
|
||||
|
||||
/** Semantic highlightings */
|
||||
private SemanticHighlighting[] fSemanticHighlightings;
|
||||
/** Highlightings */
|
||||
private HighlightingStyle[] fHighlightings;
|
||||
|
||||
/** The editor */
|
||||
private CEditor fEditor;
|
||||
/** The source viewer */
|
||||
private CSourceViewer fSourceViewer;
|
||||
/** The color manager */
|
||||
private IColorManager fColorManager;
|
||||
/** The preference store */
|
||||
private IPreferenceStore fPreferenceStore;
|
||||
/** The source viewer configuration */
|
||||
private CSourceViewerConfiguration fConfiguration;
|
||||
/** The presentation reconciler */
|
||||
private CPresentationReconciler fPresentationReconciler;
|
||||
|
||||
/** The hard-coded ranges */
|
||||
private HighlightedRange[][] fHardcodedRanges;
|
||||
|
||||
/**
|
||||
* Install the semantic highlighting on the given editor infrastructure
|
||||
*
|
||||
* @param editor The C editor
|
||||
* @param sourceViewer The source viewer
|
||||
* @param colorManager The color manager
|
||||
* @param preferenceStore The preference store
|
||||
*/
|
||||
public void install(CEditor editor, CSourceViewer sourceViewer, IColorManager colorManager, IPreferenceStore preferenceStore) {
|
||||
fEditor= editor;
|
||||
fSourceViewer= sourceViewer;
|
||||
fColorManager= colorManager;
|
||||
fPreferenceStore= preferenceStore;
|
||||
if (fEditor != null) {
|
||||
fConfiguration= new CSourceViewerConfiguration(CUIPlugin.getDefault().getTextTools(), fEditor);
|
||||
// fConfiguration= new CSourceViewerConfiguration(colorManager, preferenceStore, editor, ICPartitions.C_PARTITIONING);
|
||||
fPresentationReconciler= (CPresentationReconciler) fConfiguration.getPresentationReconciler(sourceViewer);
|
||||
} else {
|
||||
fConfiguration= null;
|
||||
fPresentationReconciler= null;
|
||||
}
|
||||
|
||||
fPreferenceStore.addPropertyChangeListener(this);
|
||||
|
||||
if (isEnabled())
|
||||
enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the semantic highlighting on the given source viewer infrastructure. No reconciliation will be performed.
|
||||
*
|
||||
* @param sourceViewer the source viewer
|
||||
* @param colorManager the color manager
|
||||
* @param preferenceStore the preference store
|
||||
* @param hardcodedRanges the hard-coded ranges to be highlighted
|
||||
*/
|
||||
public void install(CSourceViewer sourceViewer, IColorManager colorManager, IPreferenceStore preferenceStore, HighlightedRange[][] hardcodedRanges) {
|
||||
fHardcodedRanges= hardcodedRanges;
|
||||
install(null, sourceViewer, colorManager, preferenceStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable semantic highlighting.
|
||||
*/
|
||||
private void enable() {
|
||||
initializeHighlightings();
|
||||
|
||||
fPresenter= new SemanticHighlightingPresenter();
|
||||
fPresenter.install(fSourceViewer, fPresentationReconciler);
|
||||
|
||||
if (fEditor != null) {
|
||||
fReconciler= new SemanticHighlightingReconciler();
|
||||
fReconciler.install(fEditor, fSourceViewer, fPresenter, fSemanticHighlightings, fHighlightings);
|
||||
} else {
|
||||
fPresenter.updatePresentation(null, createHardcodedPositions(), new HighlightedPosition[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the hard-coded positions from the hard-coded ranges
|
||||
*
|
||||
* @return the hard-coded positions
|
||||
*/
|
||||
private HighlightedPosition[] createHardcodedPositions() {
|
||||
List positions= new ArrayList();
|
||||
for (int i= 0; i < fHardcodedRanges.length; i++) {
|
||||
HighlightedRange range= null;
|
||||
HighlightingStyle hl= null;
|
||||
for (int j= 0; j < fHardcodedRanges[i].length; j++ ) {
|
||||
hl= getHighlighting(fHardcodedRanges[i][j].getKey());
|
||||
if (hl.isEnabled()) {
|
||||
range= fHardcodedRanges[i][j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (range != null)
|
||||
positions.add(fPresenter.createHighlightedPosition(range.getOffset(), range.getLength(), hl));
|
||||
}
|
||||
return (HighlightedPosition[]) positions.toArray(new HighlightedPosition[positions.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highlighting corresponding to the given key.
|
||||
*
|
||||
* @param key the highlighting key as returned by {@link SemanticHighlighting#getPreferenceKey()}
|
||||
* @return the corresponding highlighting
|
||||
*/
|
||||
private HighlightingStyle getHighlighting(String key) {
|
||||
for (int i= 0; i < fSemanticHighlightings.length; i++) {
|
||||
SemanticHighlighting semanticHighlighting= fSemanticHighlightings[i];
|
||||
if (key.equals(semanticHighlighting.getPreferenceKey()))
|
||||
return fHighlightings[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall the semantic highlighting
|
||||
*/
|
||||
public void uninstall() {
|
||||
disable();
|
||||
|
||||
if (fPreferenceStore != null) {
|
||||
fPreferenceStore.removePropertyChangeListener(this);
|
||||
fPreferenceStore= null;
|
||||
}
|
||||
|
||||
fEditor= null;
|
||||
fSourceViewer= null;
|
||||
fColorManager= null;
|
||||
fConfiguration= null;
|
||||
fPresentationReconciler= null;
|
||||
fHardcodedRanges= null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable semantic highlighting.
|
||||
*/
|
||||
private void disable() {
|
||||
if (fReconciler != null) {
|
||||
fReconciler.uninstall();
|
||||
fReconciler= null;
|
||||
}
|
||||
|
||||
if (fPresenter != null) {
|
||||
fPresenter.uninstall();
|
||||
fPresenter= null;
|
||||
}
|
||||
|
||||
if (fSemanticHighlightings != null)
|
||||
disposeHighlightings();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> iff semantic highlighting is enabled in the preferences
|
||||
*/
|
||||
private boolean isEnabled() {
|
||||
return SemanticHighlightings.isEnabled(fPreferenceStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize semantic highlightings.
|
||||
*/
|
||||
private void initializeHighlightings() {
|
||||
fSemanticHighlightings= SemanticHighlightings.getSemanticHighlightings();
|
||||
fHighlightings= new HighlightingStyle[fSemanticHighlightings.length];
|
||||
|
||||
for (int i= 0, n= fSemanticHighlightings.length; i < n; i++) {
|
||||
SemanticHighlighting semanticHighlighting= fSemanticHighlightings[i];
|
||||
String colorKey= SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
|
||||
addColor(colorKey);
|
||||
|
||||
String boldKey= SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
|
||||
int style= fPreferenceStore.getBoolean(boldKey) ? SWT.BOLD : SWT.NORMAL;
|
||||
|
||||
String italicKey= SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
|
||||
if (fPreferenceStore.getBoolean(italicKey))
|
||||
style |= SWT.ITALIC;
|
||||
|
||||
String strikethroughKey= SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
|
||||
if (fPreferenceStore.getBoolean(strikethroughKey))
|
||||
style |= TextAttribute.STRIKETHROUGH;
|
||||
|
||||
String underlineKey= SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
|
||||
if (fPreferenceStore.getBoolean(underlineKey))
|
||||
style |= TextAttribute.UNDERLINE;
|
||||
|
||||
boolean isEnabled= fPreferenceStore.getBoolean(SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting));
|
||||
|
||||
fHighlightings[i]= new HighlightingStyle(new TextAttribute(fColorManager.getColor(PreferenceConverter.getColor(fPreferenceStore, colorKey)), null, style), isEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the semantic highlightings.
|
||||
*/
|
||||
private void disposeHighlightings() {
|
||||
for (int i= 0, n= fSemanticHighlightings.length; i < n; i++)
|
||||
removeColor(SemanticHighlightings.getColorPreferenceKey(fSemanticHighlightings[i]));
|
||||
|
||||
fSemanticHighlightings= null;
|
||||
fHighlightings= null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
|
||||
*/
|
||||
public void propertyChange(PropertyChangeEvent event) {
|
||||
handlePropertyChangeEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given property change event
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
private void handlePropertyChangeEvent(PropertyChangeEvent event) {
|
||||
if (fPreferenceStore == null)
|
||||
return; // Uninstalled during event notification
|
||||
|
||||
if (fConfiguration != null)
|
||||
fConfiguration.handlePropertyChangeEvent(event);
|
||||
|
||||
if (SemanticHighlightings.affectsEnablement(fPreferenceStore, event)) {
|
||||
if (isEnabled())
|
||||
enable();
|
||||
else
|
||||
disable();
|
||||
}
|
||||
|
||||
if (!isEnabled())
|
||||
return;
|
||||
|
||||
boolean refreshNeeded= false;
|
||||
|
||||
for (int i= 0, n= fSemanticHighlightings.length; i < n; i++) {
|
||||
SemanticHighlighting semanticHighlighting= fSemanticHighlightings[i];
|
||||
|
||||
String colorKey= SemanticHighlightings.getColorPreferenceKey(semanticHighlighting);
|
||||
if (colorKey.equals(event.getProperty())) {
|
||||
adaptToTextForegroundChange(fHighlightings[i], event);
|
||||
fPresenter.highlightingStyleChanged(fHighlightings[i]);
|
||||
refreshNeeded= true;
|
||||
continue;
|
||||
}
|
||||
|
||||
String boldKey= SemanticHighlightings.getBoldPreferenceKey(semanticHighlighting);
|
||||
if (boldKey.equals(event.getProperty())) {
|
||||
adaptToTextStyleChange(fHighlightings[i], event, SWT.BOLD);
|
||||
fPresenter.highlightingStyleChanged(fHighlightings[i]);
|
||||
refreshNeeded= true;
|
||||
continue;
|
||||
}
|
||||
|
||||
String italicKey= SemanticHighlightings.getItalicPreferenceKey(semanticHighlighting);
|
||||
if (italicKey.equals(event.getProperty())) {
|
||||
adaptToTextStyleChange(fHighlightings[i], event, SWT.ITALIC);
|
||||
fPresenter.highlightingStyleChanged(fHighlightings[i]);
|
||||
refreshNeeded= true;
|
||||
continue;
|
||||
}
|
||||
|
||||
String strikethroughKey= SemanticHighlightings.getStrikethroughPreferenceKey(semanticHighlighting);
|
||||
if (strikethroughKey.equals(event.getProperty())) {
|
||||
adaptToTextStyleChange(fHighlightings[i], event, TextAttribute.STRIKETHROUGH);
|
||||
fPresenter.highlightingStyleChanged(fHighlightings[i]);
|
||||
refreshNeeded= true;
|
||||
continue;
|
||||
}
|
||||
|
||||
String underlineKey= SemanticHighlightings.getUnderlinePreferenceKey(semanticHighlighting);
|
||||
if (underlineKey.equals(event.getProperty())) {
|
||||
adaptToTextStyleChange(fHighlightings[i], event, TextAttribute.UNDERLINE);
|
||||
fPresenter.highlightingStyleChanged(fHighlightings[i]);
|
||||
refreshNeeded= true;
|
||||
continue;
|
||||
}
|
||||
|
||||
String enabledKey= SemanticHighlightings.getEnabledPreferenceKey(semanticHighlighting);
|
||||
if (enabledKey.equals(event.getProperty())) {
|
||||
adaptToEnablementChange(fHighlightings[i], event);
|
||||
fPresenter.highlightingStyleChanged(fHighlightings[i]);
|
||||
refreshNeeded= true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshNeeded && fReconciler != null)
|
||||
fReconciler.refresh();
|
||||
}
|
||||
|
||||
private void adaptToEnablementChange(HighlightingStyle highlighting, PropertyChangeEvent event) {
|
||||
Object value= event.getNewValue();
|
||||
boolean eventValue;
|
||||
if (value instanceof Boolean)
|
||||
eventValue= ((Boolean) value).booleanValue();
|
||||
else if (IPreferenceStore.TRUE.equals(value))
|
||||
eventValue= true;
|
||||
else
|
||||
eventValue= false;
|
||||
highlighting.setEnabled(eventValue);
|
||||
}
|
||||
|
||||
private void adaptToTextForegroundChange(HighlightingStyle highlighting, PropertyChangeEvent event) {
|
||||
RGB rgb= null;
|
||||
|
||||
Object value= event.getNewValue();
|
||||
if (value instanceof RGB)
|
||||
rgb= (RGB) value;
|
||||
else if (value instanceof String)
|
||||
rgb= StringConverter.asRGB((String) value);
|
||||
|
||||
if (rgb != null) {
|
||||
|
||||
String property= event.getProperty();
|
||||
Color color= fColorManager.getColor(property);
|
||||
|
||||
if ((color == null || !rgb.equals(color.getRGB())) && fColorManager instanceof IColorManagerExtension) {
|
||||
IColorManagerExtension ext= (IColorManagerExtension) fColorManager;
|
||||
ext.unbindColor(property);
|
||||
ext.bindColor(property, rgb);
|
||||
color= fColorManager.getColor(property);
|
||||
}
|
||||
|
||||
TextAttribute oldAttr= highlighting.getTextAttribute();
|
||||
highlighting.setTextAttribute(new TextAttribute(color, oldAttr.getBackground(), oldAttr.getStyle()));
|
||||
}
|
||||
}
|
||||
|
||||
private void adaptToTextStyleChange(HighlightingStyle highlighting, PropertyChangeEvent event, int styleAttribute) {
|
||||
boolean eventValue= false;
|
||||
Object value= event.getNewValue();
|
||||
if (value instanceof Boolean)
|
||||
eventValue= ((Boolean) value).booleanValue();
|
||||
else if (IPreferenceStore.TRUE.equals(value))
|
||||
eventValue= true;
|
||||
|
||||
TextAttribute oldAttr= highlighting.getTextAttribute();
|
||||
boolean activeValue= (oldAttr.getStyle() & styleAttribute) == styleAttribute;
|
||||
|
||||
if (activeValue != eventValue)
|
||||
highlighting.setTextAttribute(new TextAttribute(oldAttr.getForeground(), oldAttr.getBackground(), eventValue ? oldAttr.getStyle() | styleAttribute : oldAttr.getStyle() & ~styleAttribute));
|
||||
}
|
||||
|
||||
private void addColor(String colorKey) {
|
||||
if (fColorManager != null && colorKey != null && fColorManager.getColor(colorKey) == null) {
|
||||
RGB rgb= PreferenceConverter.getColor(fPreferenceStore, colorKey);
|
||||
if (fColorManager instanceof IColorManagerExtension) {
|
||||
IColorManagerExtension ext= (IColorManagerExtension) fColorManager;
|
||||
ext.unbindColor(colorKey);
|
||||
ext.bindColor(colorKey, rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeColor(String colorKey) {
|
||||
if (fColorManager instanceof IColorManagerExtension)
|
||||
((IColorManagerExtension) fColorManager).unbindColor(colorKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force refresh of highlighting.
|
||||
*/
|
||||
public void refresh() {
|
||||
if (fReconciler != null) {
|
||||
fReconciler.refresh();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,777 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.BadPositionCategoryException;
|
||||
import org.eclipse.jface.text.DocumentEvent;
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IDocumentListener;
|
||||
import org.eclipse.jface.text.IPositionUpdater;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.ISynchronizable;
|
||||
import org.eclipse.jface.text.ITextInputListener;
|
||||
import org.eclipse.jface.text.ITextPresentationListener;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.text.TextPresentation;
|
||||
import org.eclipse.swt.custom.StyleRange;
|
||||
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightedPosition;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle;
|
||||
import org.eclipse.cdt.internal.ui.text.CPresentationReconciler;
|
||||
|
||||
|
||||
/**
|
||||
* Semantic highlighting presenter - UI thread implementation.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SemanticHighlightingPresenter implements ITextPresentationListener, ITextInputListener, IDocumentListener {
|
||||
|
||||
/**
|
||||
* Semantic highlighting position updater.
|
||||
*/
|
||||
private class HighlightingPositionUpdater implements IPositionUpdater {
|
||||
|
||||
/** The position category. */
|
||||
private final String fCategory;
|
||||
|
||||
/**
|
||||
* Creates a new updater for the given <code>category</code>.
|
||||
*
|
||||
* @param category the new category.
|
||||
*/
|
||||
public HighlightingPositionUpdater(String category) {
|
||||
fCategory= category;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IPositionUpdater#update(org.eclipse.jface.text.DocumentEvent)
|
||||
*/
|
||||
public void update(DocumentEvent event) {
|
||||
|
||||
int eventOffset= event.getOffset();
|
||||
int eventOldLength= event.getLength();
|
||||
int eventEnd= eventOffset + eventOldLength;
|
||||
|
||||
try {
|
||||
Position[] positions= event.getDocument().getPositions(fCategory);
|
||||
|
||||
for (int i= 0; i != positions.length; i++) {
|
||||
|
||||
HighlightedPosition position= (HighlightedPosition) positions[i];
|
||||
|
||||
// Also update deleted positions because they get deleted by the background thread and removed/invalidated only in the UI runnable
|
||||
// if (position.isDeleted())
|
||||
// continue;
|
||||
|
||||
int offset= position.getOffset();
|
||||
int length= position.getLength();
|
||||
int end= offset + length;
|
||||
|
||||
if (offset > eventEnd)
|
||||
updateWithPrecedingEvent(position, event);
|
||||
else if (end < eventOffset)
|
||||
updateWithSucceedingEvent(position, event);
|
||||
else if (offset <= eventOffset && end >= eventEnd)
|
||||
updateWithIncludedEvent(position, event);
|
||||
else if (offset <= eventOffset)
|
||||
updateWithOverEndEvent(position, event);
|
||||
else if (end >= eventEnd)
|
||||
updateWithOverStartEvent(position, event);
|
||||
else
|
||||
updateWithIncludingEvent(position, event);
|
||||
}
|
||||
} catch (BadPositionCategoryException e) {
|
||||
// ignore and return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given position with the given event. The event precedes the position.
|
||||
*
|
||||
* @param position The position
|
||||
* @param event The event
|
||||
*/
|
||||
private void updateWithPrecedingEvent(HighlightedPosition position, DocumentEvent event) {
|
||||
String newText= event.getText();
|
||||
int eventNewLength= newText != null ? newText.length() : 0;
|
||||
int deltaLength= eventNewLength - event.getLength();
|
||||
|
||||
position.setOffset(position.getOffset() + deltaLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given position with the given event. The event succeeds the position.
|
||||
*
|
||||
* @param position The position
|
||||
* @param event The event
|
||||
*/
|
||||
private void updateWithSucceedingEvent(HighlightedPosition position, DocumentEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given position with the given event. The event is included by the position.
|
||||
*
|
||||
* @param position The position
|
||||
* @param event The event
|
||||
*/
|
||||
private void updateWithIncludedEvent(HighlightedPosition position, DocumentEvent event) {
|
||||
int eventOffset= event.getOffset();
|
||||
String newText= event.getText();
|
||||
if (newText == null)
|
||||
newText= ""; //$NON-NLS-1$
|
||||
int eventNewLength= newText.length();
|
||||
|
||||
int deltaLength= eventNewLength - event.getLength();
|
||||
|
||||
int offset= position.getOffset();
|
||||
int length= position.getLength();
|
||||
int end= offset + length;
|
||||
|
||||
int includedLength= 0;
|
||||
while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength)))
|
||||
includedLength++;
|
||||
if (includedLength == eventNewLength)
|
||||
position.setLength(length + deltaLength);
|
||||
else {
|
||||
int newLeftLength= eventOffset - offset + includedLength;
|
||||
|
||||
int excludedLength= eventNewLength;
|
||||
while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1)))
|
||||
excludedLength--;
|
||||
int newRightOffset= eventOffset + excludedLength;
|
||||
int newRightLength= end + deltaLength - newRightOffset;
|
||||
|
||||
if (newRightLength == 0) {
|
||||
position.setLength(newLeftLength);
|
||||
} else {
|
||||
if (newLeftLength == 0) {
|
||||
position.update(newRightOffset, newRightLength);
|
||||
} else {
|
||||
position.setLength(newLeftLength);
|
||||
addPositionFromUI(newRightOffset, newRightLength, position.getHighlighting());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given position with the given event. The event overlaps with the end of the position.
|
||||
*
|
||||
* @param position The position
|
||||
* @param event The event
|
||||
*/
|
||||
private void updateWithOverEndEvent(HighlightedPosition position, DocumentEvent event) {
|
||||
String newText= event.getText();
|
||||
if (newText == null)
|
||||
newText= ""; //$NON-NLS-1$
|
||||
int eventNewLength= newText.length();
|
||||
|
||||
int includedLength= 0;
|
||||
while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength)))
|
||||
includedLength++;
|
||||
position.setLength(event.getOffset() - position.getOffset() + includedLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given position with the given event. The event overlaps with the start of the position.
|
||||
*
|
||||
* @param position The position
|
||||
* @param event The event
|
||||
*/
|
||||
private void updateWithOverStartEvent(HighlightedPosition position, DocumentEvent event) {
|
||||
int eventOffset= event.getOffset();
|
||||
int eventEnd= eventOffset + event.getLength();
|
||||
|
||||
String newText= event.getText();
|
||||
if (newText == null)
|
||||
newText= ""; //$NON-NLS-1$
|
||||
int eventNewLength= newText.length();
|
||||
|
||||
int excludedLength= eventNewLength;
|
||||
while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1)))
|
||||
excludedLength--;
|
||||
int deleted= eventEnd - position.getOffset();
|
||||
int inserted= eventNewLength - excludedLength;
|
||||
position.update(eventOffset + excludedLength, position.getLength() - deleted + inserted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the given position with the given event. The event includes the position.
|
||||
*
|
||||
* @param position The position
|
||||
* @param event The event
|
||||
*/
|
||||
private void updateWithIncludingEvent(HighlightedPosition position, DocumentEvent event) {
|
||||
position.delete();
|
||||
position.update(event.getOffset(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Position updater */
|
||||
private IPositionUpdater fPositionUpdater= new HighlightingPositionUpdater(getPositionCategory());
|
||||
|
||||
/** The source viewer this semantic highlighting reconciler is installed on */
|
||||
private CSourceViewer fSourceViewer;
|
||||
/** The background presentation reconciler */
|
||||
private CPresentationReconciler fPresentationReconciler;
|
||||
|
||||
/** UI's current highlighted positions - can contain <code>null</code> elements */
|
||||
private List fPositions= new ArrayList();
|
||||
/** UI position lock */
|
||||
private Object fPositionLock= new Object();
|
||||
|
||||
/** <code>true</code> iff the current reconcile is canceled. */
|
||||
private boolean fIsCanceled= false;
|
||||
|
||||
/**
|
||||
* Creates and returns a new highlighted position with the given offset, length and highlighting.
|
||||
* <p>
|
||||
* NOTE: Also called from background thread.
|
||||
* </p>
|
||||
*
|
||||
* @param offset The offset
|
||||
* @param length The length
|
||||
* @param highlighting The highlighting
|
||||
* @return The new highlighted position
|
||||
*/
|
||||
public HighlightedPosition createHighlightedPosition(int offset, int length, HighlightingStyle highlighting) {
|
||||
// TODO: reuse deleted positions
|
||||
return new HighlightedPosition(offset, length, highlighting, fPositionUpdater);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all current positions to the given list.
|
||||
* <p>
|
||||
* NOTE: Called from background thread.
|
||||
* </p>
|
||||
*
|
||||
* @param list The list
|
||||
*/
|
||||
public void addAllPositions(List list) {
|
||||
synchronized (fPositionLock) {
|
||||
list.addAll(fPositions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a text presentation in the background.
|
||||
* <p>
|
||||
* NOTE: Called from background thread.
|
||||
* </p>
|
||||
*
|
||||
* @param addedPositions the added positions
|
||||
* @param removedPositions the removed positions
|
||||
* @return the text presentation or <code>null</code>, if reconciliation should be canceled
|
||||
*/
|
||||
public TextPresentation createPresentation(List addedPositions, List removedPositions) {
|
||||
CSourceViewer sourceViewer= fSourceViewer;
|
||||
CPresentationReconciler presentationReconciler= fPresentationReconciler;
|
||||
if (sourceViewer == null || presentationReconciler == null)
|
||||
return null;
|
||||
|
||||
if (isCanceled())
|
||||
return null;
|
||||
|
||||
IDocument document= sourceViewer.getDocument();
|
||||
if (document == null)
|
||||
return null;
|
||||
|
||||
int minStart= Integer.MAX_VALUE;
|
||||
int maxEnd= Integer.MIN_VALUE;
|
||||
for (int i= 0, n= removedPositions.size(); i < n; i++) {
|
||||
Position position= (Position) removedPositions.get(i);
|
||||
int offset= position.getOffset();
|
||||
minStart= Math.min(minStart, offset);
|
||||
maxEnd= Math.max(maxEnd, offset + position.getLength());
|
||||
}
|
||||
for (int i= 0, n= addedPositions.size(); i < n; i++) {
|
||||
Position position= (Position) addedPositions.get(i);
|
||||
int offset= position.getOffset();
|
||||
minStart= Math.min(minStart, offset);
|
||||
maxEnd= Math.max(maxEnd, offset + position.getLength());
|
||||
}
|
||||
|
||||
if (minStart < maxEnd)
|
||||
try {
|
||||
return presentationReconciler.createRepairDescription(new Region(minStart, maxEnd - minStart), document);
|
||||
} catch (RuntimeException e) {
|
||||
// Assume concurrent modification from UI thread
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a runnable for updating the presentation.
|
||||
* <p>
|
||||
* NOTE: Called from background thread.
|
||||
* </p>
|
||||
* @param textPresentation the text presentation
|
||||
* @param addedPositions the added positions
|
||||
* @param removedPositions the removed positions
|
||||
* @return the runnable or <code>null</code>, if reconciliation should be canceled
|
||||
*/
|
||||
public Runnable createUpdateRunnable(final TextPresentation textPresentation, List addedPositions, List removedPositions) {
|
||||
if (fSourceViewer == null || textPresentation == null)
|
||||
return null;
|
||||
|
||||
// TODO: do clustering of positions and post multiple fast runnables
|
||||
final HighlightedPosition[] added= new SemanticHighlightingManager.HighlightedPosition[addedPositions.size()];
|
||||
addedPositions.toArray(added);
|
||||
final SemanticHighlightingManager.HighlightedPosition[] removed= new SemanticHighlightingManager.HighlightedPosition[removedPositions.size()];
|
||||
removedPositions.toArray(removed);
|
||||
|
||||
if (isCanceled())
|
||||
return null;
|
||||
|
||||
Runnable runnable= new Runnable() {
|
||||
public void run() {
|
||||
updatePresentation(textPresentation, added, removed);
|
||||
}
|
||||
};
|
||||
return runnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the presentation of the positions based on the given added positions and the existing deleted positions.
|
||||
* Also unregisters the deleted positions from the document and patches the positions of this presenter.
|
||||
* <p>
|
||||
* NOTE: Indirectly called from background thread by UI runnable.
|
||||
* </p>
|
||||
* @param textPresentation the text presentation or <code>null</code>, if the presentation should computed in the UI thread
|
||||
* @param addedPositions the added positions
|
||||
* @param removedPositions the removed positions
|
||||
*/
|
||||
public void updatePresentation(TextPresentation textPresentation, HighlightedPosition[] addedPositions, HighlightedPosition[] removedPositions) {
|
||||
if (fSourceViewer == null)
|
||||
return;
|
||||
|
||||
// checkOrdering("added positions: ", Arrays.asList(addedPositions)); //$NON-NLS-1$
|
||||
// checkOrdering("removed positions: ", Arrays.asList(removedPositions)); //$NON-NLS-1$
|
||||
// checkOrdering("old positions: ", fPositions); //$NON-NLS-1$
|
||||
|
||||
// TODO: double-check consistency with document.getPositions(...)
|
||||
// TODO: reuse removed positions
|
||||
if (isCanceled())
|
||||
return;
|
||||
|
||||
IDocument document= fSourceViewer.getDocument();
|
||||
if (document == null)
|
||||
return;
|
||||
|
||||
String positionCategory= getPositionCategory();
|
||||
|
||||
List removedPositionsList= Arrays.asList(removedPositions);
|
||||
|
||||
try {
|
||||
synchronized (fPositionLock) {
|
||||
List oldPositions= fPositions;
|
||||
int newSize= Math.max(fPositions.size() + addedPositions.length - removedPositions.length, 10);
|
||||
|
||||
/*
|
||||
* The following loop is a kind of merge sort: it merges two List<Position>, each
|
||||
* sorted by position.offset, into one new list. The first of the two is the
|
||||
* previous list of positions (oldPositions), from which any deleted positions get
|
||||
* removed on the fly. The second of two is the list of added positions. The result
|
||||
* is stored in newPositions.
|
||||
*/
|
||||
List newPositions= new ArrayList(newSize);
|
||||
Position position= null;
|
||||
Position addedPosition= null;
|
||||
for (int i= 0, j= 0, n= oldPositions.size(), m= addedPositions.length; i < n || position != null || j < m || addedPosition != null;) {
|
||||
// loop variant: i + j < old(i + j)
|
||||
|
||||
// a) find the next non-deleted Position from the old list
|
||||
while (position == null && i < n) {
|
||||
position= (Position) oldPositions.get(i++);
|
||||
if (position.isDeleted() || contain(removedPositionsList, position)) {
|
||||
document.removePosition(positionCategory, position);
|
||||
position= null;
|
||||
}
|
||||
}
|
||||
|
||||
// b) find the next Position from the added list
|
||||
if (addedPosition == null && j < m) {
|
||||
addedPosition= addedPositions[j++];
|
||||
document.addPosition(positionCategory, addedPosition);
|
||||
}
|
||||
|
||||
// c) merge: add the next of position/addedPosition with the lower offset
|
||||
if (position != null) {
|
||||
if (addedPosition != null)
|
||||
if (position.getOffset() <= addedPosition.getOffset()) {
|
||||
newPositions.add(position);
|
||||
position= null;
|
||||
} else {
|
||||
newPositions.add(addedPosition);
|
||||
addedPosition= null;
|
||||
}
|
||||
else {
|
||||
newPositions.add(position);
|
||||
position= null;
|
||||
}
|
||||
} else if (addedPosition != null) {
|
||||
newPositions.add(addedPosition);
|
||||
addedPosition= null;
|
||||
}
|
||||
}
|
||||
fPositions= newPositions;
|
||||
}
|
||||
} catch (BadPositionCategoryException e) {
|
||||
// Should not happen
|
||||
CUIPlugin.getDefault().log(e);
|
||||
} catch (BadLocationException e) {
|
||||
// Should not happen
|
||||
CUIPlugin.getDefault().log(e);
|
||||
}
|
||||
// checkOrdering("new positions: ", fPositions); //$NON-NLS-1$
|
||||
|
||||
if (textPresentation != null)
|
||||
fSourceViewer.changeTextPresentation(textPresentation, false);
|
||||
else
|
||||
fSourceViewer.invalidateTextPresentation();
|
||||
}
|
||||
|
||||
// private void checkOrdering(String s, List positions) {
|
||||
// Position previous= null;
|
||||
// for (int i= 0, n= positions.size(); i < n; i++) {
|
||||
// Position current= (Position) positions.get(i);
|
||||
// if (previous != null && previous.getOffset() + previous.getLength() > current.getOffset())
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> iff the positions contain the position.
|
||||
* @param positions the positions, must be ordered by offset but may overlap
|
||||
* @param position the position
|
||||
* @return <code>true</code> iff the positions contain the position
|
||||
*/
|
||||
private boolean contain(List positions, Position position) {
|
||||
return indexOf(positions, position) != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns index of the position in the positions, <code>-1</code> if not found.
|
||||
* @param positions the positions, must be ordered by offset but may overlap
|
||||
* @param position the position
|
||||
* @return the index
|
||||
*/
|
||||
private int indexOf(List positions, Position position) {
|
||||
int index= computeIndexAtOffset(positions, position.getOffset());
|
||||
int size= positions.size();
|
||||
while (index < size) {
|
||||
if (positions.get(index) == position)
|
||||
return index;
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the given position in <code>fPositions</code>, s.t. the offsets remain in linear order.
|
||||
*
|
||||
* @param position The position for insertion
|
||||
*/
|
||||
private void insertPosition(Position position) {
|
||||
int i= computeIndexAfterOffset(fPositions, position.getOffset());
|
||||
fPositions.add(i, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first position with an offset greater than the given offset.
|
||||
*
|
||||
* @param positions the positions, must be ordered by offset and must not overlap
|
||||
* @param offset the offset
|
||||
* @return the index of the last position with an offset greater than the given offset
|
||||
*/
|
||||
private int computeIndexAfterOffset(List positions, int offset) {
|
||||
int i= -1;
|
||||
int j= positions.size();
|
||||
while (j - i > 1) {
|
||||
int k= (i + j) >> 1;
|
||||
Position position= (Position) positions.get(k);
|
||||
if (position.getOffset() > offset)
|
||||
j= k;
|
||||
else
|
||||
i= k;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first position with an offset equal or greater than the given offset.
|
||||
*
|
||||
* @param positions the positions, must be ordered by offset and must not overlap
|
||||
* @param offset the offset
|
||||
* @return the index of the last position with an offset equal or greater than the given offset
|
||||
*/
|
||||
private int computeIndexAtOffset(List positions, int offset) {
|
||||
int i= -1;
|
||||
int j= positions.size();
|
||||
while (j - i > 1) {
|
||||
int k= (i + j) >> 1;
|
||||
Position position= (Position) positions.get(k);
|
||||
if (position.getOffset() >= offset)
|
||||
j= k;
|
||||
else
|
||||
i= k;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation)
|
||||
*/
|
||||
public void applyTextPresentation(TextPresentation textPresentation) {
|
||||
IRegion region= textPresentation.getExtent();
|
||||
int i= computeIndexAtOffset(fPositions, region.getOffset()), n= computeIndexAtOffset(fPositions, region.getOffset() + region.getLength());
|
||||
if (n - i > 2) {
|
||||
List ranges= new ArrayList(n - i);
|
||||
for (; i < n; i++) {
|
||||
HighlightedPosition position= (HighlightedPosition) fPositions.get(i);
|
||||
if (!position.isDeleted())
|
||||
ranges.add(position.createStyleRange());
|
||||
}
|
||||
StyleRange[] array= new StyleRange[ranges.size()];
|
||||
array= (StyleRange[]) ranges.toArray(array);
|
||||
textPresentation.replaceStyleRanges(array);
|
||||
} else {
|
||||
for (; i < n; i++) {
|
||||
HighlightedPosition position= (HighlightedPosition) fPositions.get(i);
|
||||
if (!position.isDeleted())
|
||||
textPresentation.replaceStyleRange(position.createStyleRange());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
|
||||
*/
|
||||
public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) {
|
||||
setCanceled(true);
|
||||
releaseDocument(oldInput);
|
||||
resetState();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
|
||||
*/
|
||||
public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
|
||||
manageDocument(newInput);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
|
||||
*/
|
||||
public void documentAboutToBeChanged(DocumentEvent event) {
|
||||
setCanceled(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
|
||||
*/
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns <code>true</code> iff the current reconcile is canceled.
|
||||
* <p>
|
||||
* NOTE: Also called from background thread.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isCanceled() {
|
||||
IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null;
|
||||
if (document == null)
|
||||
return fIsCanceled;
|
||||
|
||||
synchronized (getLockObject(document)) {
|
||||
return fIsCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the current reconcile is canceled.
|
||||
*
|
||||
* @param isCanceled <code>true</code> iff the current reconcile is canceled
|
||||
*/
|
||||
public void setCanceled(boolean isCanceled) {
|
||||
IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null;
|
||||
if (document == null) {
|
||||
fIsCanceled= isCanceled;
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (getLockObject(document)) {
|
||||
fIsCanceled= isCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param document the document
|
||||
* @return the document's lock object
|
||||
*/
|
||||
private Object getLockObject(IDocument document) {
|
||||
if (document instanceof ISynchronizable) {
|
||||
Object lock= ((ISynchronizable)document).getLockObject();
|
||||
if (lock != null)
|
||||
return lock;
|
||||
}
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install this presenter on the given source viewer and background presentation
|
||||
* reconciler.
|
||||
*
|
||||
* @param sourceViewer the source viewer
|
||||
* @param backgroundPresentationReconciler the background presentation reconciler,
|
||||
* can be <code>null</code>, in that case {@link SemanticHighlightingPresenter#createPresentation(List, List)}
|
||||
* should not be called
|
||||
*/
|
||||
public void install(CSourceViewer sourceViewer, CPresentationReconciler backgroundPresentationReconciler) {
|
||||
fSourceViewer= sourceViewer;
|
||||
fPresentationReconciler= backgroundPresentationReconciler;
|
||||
|
||||
fSourceViewer.addTextPresentationListener(this);
|
||||
// fSourceViewer.prependTextPresentationListener(this);
|
||||
fSourceViewer.addTextInputListener(this);
|
||||
manageDocument(fSourceViewer.getDocument());
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall this presenter.
|
||||
*/
|
||||
public void uninstall() {
|
||||
setCanceled(true);
|
||||
|
||||
if (fSourceViewer != null) {
|
||||
fSourceViewer.removeTextPresentationListener(this);
|
||||
releaseDocument(fSourceViewer.getDocument());
|
||||
invalidateTextPresentation();
|
||||
resetState();
|
||||
|
||||
fSourceViewer.removeTextInputListener(this);
|
||||
fSourceViewer= null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate text presentation of positions with the given highlighting.
|
||||
*
|
||||
* @param highlighting The highlighting
|
||||
*/
|
||||
public void highlightingStyleChanged(HighlightingStyle highlighting) {
|
||||
for (int i= 0, n= fPositions.size(); i < n; i++) {
|
||||
HighlightedPosition position= (HighlightedPosition) fPositions.get(i);
|
||||
if (position.getHighlighting() == highlighting)
|
||||
fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate text presentation of all positions.
|
||||
*/
|
||||
private void invalidateTextPresentation() {
|
||||
for (int i= 0, n= fPositions.size(); i < n; i++) {
|
||||
Position position= (Position) fPositions.get(i);
|
||||
fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a position with the given range and highlighting unconditionally, only from UI thread.
|
||||
* The position will also be registered on the document. The text presentation is not invalidated.
|
||||
*
|
||||
* @param offset The range offset
|
||||
* @param length The range length
|
||||
* @param highlighting
|
||||
*/
|
||||
private void addPositionFromUI(int offset, int length, HighlightingStyle highlighting) {
|
||||
Position position= createHighlightedPosition(offset, length, highlighting);
|
||||
synchronized (fPositionLock) {
|
||||
insertPosition(position);
|
||||
}
|
||||
|
||||
IDocument document= fSourceViewer.getDocument();
|
||||
if (document == null)
|
||||
return;
|
||||
String positionCategory= getPositionCategory();
|
||||
try {
|
||||
document.addPosition(positionCategory, position);
|
||||
} catch (BadLocationException e) {
|
||||
// Should not happen
|
||||
CUIPlugin.getDefault().log(e);
|
||||
} catch (BadPositionCategoryException e) {
|
||||
// Should not happen
|
||||
CUIPlugin.getDefault().log(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to initial state.
|
||||
*/
|
||||
private void resetState() {
|
||||
synchronized (fPositionLock) {
|
||||
fPositions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start managing the given document.
|
||||
*
|
||||
* @param document The document
|
||||
*/
|
||||
private void manageDocument(IDocument document) {
|
||||
if (document != null) {
|
||||
document.addPositionCategory(getPositionCategory());
|
||||
document.addPositionUpdater(fPositionUpdater);
|
||||
document.addDocumentListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop managing the given document.
|
||||
*
|
||||
* @param document The document
|
||||
*/
|
||||
private void releaseDocument(IDocument document) {
|
||||
if (document != null) {
|
||||
document.removeDocumentListener(this);
|
||||
document.removePositionUpdater(fPositionUpdater);
|
||||
try {
|
||||
document.removePositionCategory(getPositionCategory());
|
||||
} catch (BadPositionCategoryException e) {
|
||||
// Should not happen
|
||||
CUIPlugin.getDefault().log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The semantic reconciler position's category.
|
||||
*/
|
||||
private String getPositionCategory() {
|
||||
return toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,449 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.text.TextPresentation;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.ui.IWorkbenchPartSite;
|
||||
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightedPosition;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle;
|
||||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
|
||||
|
||||
/**
|
||||
* Semantic highlighting reconciler - Background thread implementation.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class SemanticHighlightingReconciler implements ICReconcilingListener {
|
||||
|
||||
/**
|
||||
* Collects positions from the AST.
|
||||
*/
|
||||
private class PositionCollector extends ASTVisitor {
|
||||
{
|
||||
shouldVisitNames= true;
|
||||
shouldVisitDeclarations= true;
|
||||
shouldVisitExpressions= true;
|
||||
}
|
||||
|
||||
/** The semantic token */
|
||||
private SemanticToken fToken= new SemanticToken();
|
||||
private String fFilePath;
|
||||
private IPositionConverter fPositionTracker;
|
||||
|
||||
/**
|
||||
* @param filePath
|
||||
* @param positionTracker
|
||||
*/
|
||||
public PositionCollector(String filePath, IPositionConverter positionTracker) {
|
||||
fFilePath= filePath;
|
||||
fPositionTracker= positionTracker;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTDeclaration)
|
||||
*/
|
||||
public int visit(IASTDeclaration declaration) {
|
||||
if (!fFilePath.equals(declaration.getContainingFilename())) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTExpression)
|
||||
*/
|
||||
public int visit(IASTExpression expression) {
|
||||
if (!fFilePath.equals(expression.getContainingFilename())) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
IASTNodeLocation[] nodeLocations= expression.getNodeLocations();
|
||||
if (nodeLocations.length > 0 && nodeLocations[0] instanceof IASTMacroExpansion) {
|
||||
if (visitNode(expression)) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.core.dom.ast.ASTVisitor#visit(org.eclipse.cdt.core.dom.ast.IASTName)
|
||||
*/
|
||||
public int visit(IASTName node) {
|
||||
if (!fFilePath.equals(node.getContainingFilename())) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
visitNode(node);
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
private boolean visitNode(IASTNode node) {
|
||||
boolean consumed= false;
|
||||
fToken.update(node);
|
||||
for (int i= 0, n= fJobSemanticHighlightings.length; i < n; ++i) {
|
||||
SemanticHighlighting semanticHighlighting= fJobSemanticHighlightings[i];
|
||||
if (fJobHighlightings[i].isEnabled() && semanticHighlighting.consumes(fToken)) {
|
||||
IASTNodeLocation[] nodeLocations= node.getNodeLocations();
|
||||
if (nodeLocations.length > 0) {
|
||||
addNodeLocations(nodeLocations, fJobHighlightings[i]);
|
||||
}
|
||||
consumed= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fToken.clear();
|
||||
return consumed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all node locations for the given highlighting.
|
||||
*
|
||||
* @param nodeLocations The node locations
|
||||
* @param highlighting The highlighting
|
||||
*/
|
||||
private void addNodeLocations(IASTNodeLocation[] nodeLocations, HighlightingStyle highlighting) {
|
||||
for (int j = 0; j < nodeLocations.length; j++) {
|
||||
IASTNodeLocation nodeLocation = nodeLocations[j];
|
||||
if (nodeLocation instanceof IASTMacroExpansion) {
|
||||
IASTMacroExpansion macroExpansion= (IASTMacroExpansion)nodeLocation;
|
||||
IASTNodeLocation[] expansionLocations = macroExpansion.getExpansionLocations();
|
||||
addNodeLocations(expansionLocations, highlighting);
|
||||
} else {
|
||||
int offset= nodeLocation.getNodeOffset();
|
||||
int length= nodeLocation.getNodeLength();
|
||||
if (fPositionTracker != null) {
|
||||
IRegion actualPos= fPositionTracker.historicToActual(new Region(offset, length));
|
||||
offset= actualPos.getOffset();
|
||||
length= actualPos.getLength();
|
||||
}
|
||||
if (offset > -1 && length > 0) {
|
||||
addPosition(offset, length, highlighting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a position with the given range and highlighting iff it does not exist already.
|
||||
*
|
||||
* @param offset The range offset
|
||||
* @param length The range length
|
||||
* @param highlighting The highlighting
|
||||
*/
|
||||
private void addPosition(int offset, int length, HighlightingStyle highlighting) {
|
||||
boolean isExisting= false;
|
||||
// TODO: use binary search
|
||||
for (int i= 0, n= fRemovedPositions.size(); i < n; i++) {
|
||||
HighlightedPosition position= (HighlightedPosition) fRemovedPositions.get(i);
|
||||
if (position == null)
|
||||
continue;
|
||||
if (position.isEqual(offset, length, highlighting)) {
|
||||
isExisting= true;
|
||||
fRemovedPositions.set(i, null);
|
||||
fNOfRemovedPositions--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExisting) {
|
||||
Position position= fJobPresenter.createHighlightedPosition(offset, length, highlighting);
|
||||
fAddedPositions.add(position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The C editor this semantic highlighting reconciler is installed on */
|
||||
private CEditor fEditor;
|
||||
/** The semantic highlighting presenter */
|
||||
private SemanticHighlightingPresenter fPresenter;
|
||||
/** Semantic highlightings */
|
||||
private SemanticHighlighting[] fSemanticHighlightings;
|
||||
/** Highlightings */
|
||||
private HighlightingStyle[] fHighlightings;
|
||||
|
||||
/** Background job's added highlighted positions */
|
||||
private List fAddedPositions= new ArrayList();
|
||||
/** Background job's removed highlighted positions */
|
||||
private List fRemovedPositions= new ArrayList();
|
||||
/** Number of removed positions */
|
||||
private int fNOfRemovedPositions;
|
||||
|
||||
/** Background job */
|
||||
private Job fJob;
|
||||
/** Background job lock */
|
||||
private final Object fJobLock= new Object();
|
||||
/** Reconcile operation lock. */
|
||||
private final Object fReconcileLock= new Object();
|
||||
/**
|
||||
* <code>true</code> if any thread is executing
|
||||
* <code>reconcile</code>, <code>false</code> otherwise.
|
||||
*/
|
||||
private boolean fIsReconciling= false;
|
||||
|
||||
/** The semantic highlighting presenter - cache for background thread, only valid during {@link #reconciled(IASTTranslationUnit, boolean, IProgressMonitor)} */
|
||||
private SemanticHighlightingPresenter fJobPresenter;
|
||||
/** Semantic highlightings - cache for background thread, only valid during {@link #reconciled(IASTTranslationUnit, boolean, IProgressMonitor)} */
|
||||
private SemanticHighlighting[] fJobSemanticHighlightings;
|
||||
/** Highlightings - cache for background thread, only valid during {@link #reconciled(IASTTranslationUnit, boolean, IProgressMonitor)} */
|
||||
private HighlightingStyle[] fJobHighlightings;
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.java.ICReconcilingListener#aboutToBeReconciled()
|
||||
*/
|
||||
public void aboutToBeReconciled() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.cdt.internal.ui.text.ICReconcilingListener#reconciled(IASTTranslationUnit, IPositionConverter, IProgressMonitor)
|
||||
*/
|
||||
public void reconciled(IASTTranslationUnit ast, IPositionConverter positionTracker, IProgressMonitor progressMonitor) {
|
||||
// ensure at most one thread can be reconciling at any time
|
||||
synchronized (fReconcileLock) {
|
||||
if (fIsReconciling)
|
||||
return;
|
||||
else
|
||||
fIsReconciling= true;
|
||||
}
|
||||
fJobPresenter= fPresenter;
|
||||
fJobSemanticHighlightings= fSemanticHighlightings;
|
||||
fJobHighlightings= fHighlightings;
|
||||
|
||||
try {
|
||||
if (fJobPresenter == null || fJobSemanticHighlightings == null || fJobHighlightings == null)
|
||||
return;
|
||||
|
||||
fJobPresenter.setCanceled(progressMonitor != null && progressMonitor.isCanceled());
|
||||
|
||||
if (ast == null || fJobPresenter.isCanceled())
|
||||
return;
|
||||
|
||||
PositionCollector collector= new PositionCollector(ast.getFilePath(), positionTracker);
|
||||
IASTNode[] subtrees= getAffectedSubtrees(ast);
|
||||
if (subtrees.length == 0)
|
||||
return;
|
||||
|
||||
startReconcilingPositions();
|
||||
|
||||
if (!fJobPresenter.isCanceled())
|
||||
reconcilePositions(subtrees, collector);
|
||||
|
||||
TextPresentation textPresentation= null;
|
||||
if (!fJobPresenter.isCanceled())
|
||||
textPresentation= fJobPresenter.createPresentation(fAddedPositions, fRemovedPositions);
|
||||
|
||||
if (!fJobPresenter.isCanceled())
|
||||
updatePresentation(textPresentation, fAddedPositions, fRemovedPositions);
|
||||
|
||||
stopReconcilingPositions();
|
||||
} finally {
|
||||
fJobPresenter= null;
|
||||
fJobSemanticHighlightings= null;
|
||||
fJobHighlightings= null;
|
||||
synchronized (fReconcileLock) {
|
||||
fIsReconciling= false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node Root node
|
||||
* @return Array of subtrees that may be affected by past document changes
|
||||
*/
|
||||
private IASTNode[] getAffectedSubtrees(IASTNode node) {
|
||||
return new IASTNode[] { node };
|
||||
}
|
||||
|
||||
/**
|
||||
* Start reconciling positions.
|
||||
*/
|
||||
private void startReconcilingPositions() {
|
||||
fJobPresenter.addAllPositions(fRemovedPositions);
|
||||
fNOfRemovedPositions= fRemovedPositions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconcile positions based on the AST subtrees
|
||||
*
|
||||
* @param subtrees the AST subtrees
|
||||
*/
|
||||
private void reconcilePositions(IASTNode[] subtrees, ASTVisitor visitor) {
|
||||
// FIXME: remove positions not covered by subtrees
|
||||
for (int i= 0, n= subtrees.length; i < n; i++) {
|
||||
subtrees[i].accept(visitor);
|
||||
}
|
||||
List oldPositions= fRemovedPositions;
|
||||
List newPositions= new ArrayList(fNOfRemovedPositions);
|
||||
for (int i= 0, n= oldPositions.size(); i < n; i ++) {
|
||||
Object current= oldPositions.get(i);
|
||||
if (current != null)
|
||||
newPositions.add(current);
|
||||
}
|
||||
fRemovedPositions= newPositions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the presentation.
|
||||
*
|
||||
* @param textPresentation the text presentation
|
||||
* @param addedPositions the added positions
|
||||
* @param removedPositions the removed positions
|
||||
*/
|
||||
private void updatePresentation(TextPresentation textPresentation, List addedPositions, List removedPositions) {
|
||||
Runnable runnable= fJobPresenter.createUpdateRunnable(textPresentation, addedPositions, removedPositions);
|
||||
if (runnable == null)
|
||||
return;
|
||||
|
||||
CEditor editor= fEditor;
|
||||
if (editor == null)
|
||||
return;
|
||||
|
||||
IWorkbenchPartSite site= editor.getSite();
|
||||
if (site == null)
|
||||
return;
|
||||
|
||||
Shell shell= site.getShell();
|
||||
if (shell == null || shell.isDisposed())
|
||||
return;
|
||||
|
||||
Display display= shell.getDisplay();
|
||||
if (display == null || display.isDisposed())
|
||||
return;
|
||||
|
||||
display.asyncExec(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop reconciling positions.
|
||||
*/
|
||||
private void stopReconcilingPositions() {
|
||||
fRemovedPositions.clear();
|
||||
fNOfRemovedPositions= 0;
|
||||
fAddedPositions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Install this reconciler on the given editor, presenter and highlightings.
|
||||
* @param editor the editor
|
||||
* @param sourceViewer the source viewer
|
||||
* @param presenter the semantic highlighting presenter
|
||||
* @param semanticHighlightings the semantic highlightings
|
||||
* @param highlightings the highlightings
|
||||
*/
|
||||
public void install(CEditor editor, ISourceViewer sourceViewer, SemanticHighlightingPresenter presenter, SemanticHighlighting[] semanticHighlightings, HighlightingStyle[] highlightings) {
|
||||
fPresenter= presenter;
|
||||
fSemanticHighlightings= semanticHighlightings;
|
||||
fHighlightings= highlightings;
|
||||
|
||||
fEditor= editor;
|
||||
|
||||
if (fEditor != null) {
|
||||
fEditor.addReconcileListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall this reconciler from the editor
|
||||
*/
|
||||
public void uninstall() {
|
||||
if (fPresenter != null)
|
||||
fPresenter.setCanceled(true);
|
||||
|
||||
if (fEditor != null) {
|
||||
fEditor.removeReconcileListener(this);
|
||||
fEditor= null;
|
||||
}
|
||||
|
||||
fSemanticHighlightings= null;
|
||||
fHighlightings= null;
|
||||
fPresenter= null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a background job for retrieving the AST and reconciling the Semantic Highlighting model.
|
||||
*/
|
||||
private void scheduleJob() {
|
||||
final ICElement element= fEditor.getInputCElement();
|
||||
|
||||
synchronized (fJobLock) {
|
||||
final Job oldJob= fJob;
|
||||
if (fJob != null) {
|
||||
fJob.cancel();
|
||||
fJob= null;
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
fJob= new Job(CEditorMessages.getString("SemanticHighlighting_job")) { //$NON-NLS-1$
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
if (oldJob != null) {
|
||||
try {
|
||||
oldJob.join();
|
||||
} catch (InterruptedException e) {
|
||||
CUIPlugin.getDefault().log(e);
|
||||
return Status.CANCEL_STATUS;
|
||||
}
|
||||
}
|
||||
if (monitor.isCanceled())
|
||||
return Status.CANCEL_STATUS;
|
||||
IASTTranslationUnit ast= CUIPlugin.getDefault().getASTProvider().getAST(element, ASTProvider.WAIT_YES, monitor);
|
||||
reconciled(ast, null, monitor);
|
||||
synchronized (fJobLock) {
|
||||
// allow the job to be gc'ed
|
||||
if (fJob == this)
|
||||
fJob= null;
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
// fJob.setSystem(true);
|
||||
fJob.setPriority(Job.DECORATE);
|
||||
fJob.schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the highlighting.
|
||||
*/
|
||||
public void refresh() {
|
||||
scheduleJob();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,99 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
|
||||
/**
|
||||
* Semantic token.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public final class SemanticToken {
|
||||
|
||||
/** AST node */
|
||||
private IASTNode fNode;
|
||||
|
||||
/** Binding */
|
||||
private IBinding fBinding;
|
||||
/** Is the binding resolved? */
|
||||
private boolean fIsBindingResolved= false;
|
||||
|
||||
/** AST root */
|
||||
private IASTTranslationUnit fRoot;
|
||||
private boolean fIsRootResolved= false;
|
||||
|
||||
/**
|
||||
* @return Returns the binding, can be <code>null</code>.
|
||||
*/
|
||||
public IBinding getBinding() {
|
||||
if (!fIsBindingResolved) {
|
||||
fIsBindingResolved= true;
|
||||
if (fNode instanceof IASTName)
|
||||
fBinding= ((IASTName)fNode).resolveBinding();
|
||||
}
|
||||
|
||||
return fBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the AST node
|
||||
*/
|
||||
public IASTNode getNode() {
|
||||
return fNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the AST root
|
||||
*/
|
||||
public IASTTranslationUnit getRoot() {
|
||||
if (!fIsRootResolved) {
|
||||
fIsRootResolved= true;
|
||||
if (fNode != null) {
|
||||
fRoot= fNode.getTranslationUnit();
|
||||
}
|
||||
}
|
||||
return fRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this token with the given AST node.
|
||||
* <p>
|
||||
* NOTE: Allowed to be used by {@link SemanticHighlightingReconciler} only.
|
||||
* </p>
|
||||
*
|
||||
* @param node the AST node
|
||||
*/
|
||||
void update(IASTNode node) {
|
||||
clear();
|
||||
fNode= node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears this token.
|
||||
* <p>
|
||||
* NOTE: Allowed to be used by {@link SemanticHighlightingReconciler} only.
|
||||
* </p>
|
||||
*/
|
||||
void clear() {
|
||||
fNode= null;
|
||||
fBinding= null;
|
||||
fIsBindingResolved= false;
|
||||
fRoot= null;
|
||||
fIsRootResolved= false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2005 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.preferences;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jface.dialogs.IDialogConstants;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.preference.PreferencePage;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
import org.eclipse.ui.IWorkbench;
|
||||
import org.eclipse.ui.IWorkbenchPreferencePage;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||
|
||||
/**
|
||||
* Preference page for work in progress.
|
||||
*/
|
||||
public class WorkInProgressPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
|
||||
|
||||
private List fCheckBoxes;
|
||||
private List fRadioButtons;
|
||||
private List fTextControls;
|
||||
|
||||
/**
|
||||
* creates a new preference page.
|
||||
*/
|
||||
public WorkInProgressPreferencePage() {
|
||||
setPreferenceStore(getPreferenceStore());
|
||||
fRadioButtons= new ArrayList();
|
||||
fCheckBoxes= new ArrayList();
|
||||
fTextControls= new ArrayList();
|
||||
}
|
||||
|
||||
Button addCheckBox(Composite parent, String label, String key) {
|
||||
GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
|
||||
|
||||
Button button= new Button(parent, SWT.CHECK);
|
||||
button.setText(label);
|
||||
button.setData(key);
|
||||
button.setLayoutData(gd);
|
||||
|
||||
button.setSelection(getPreferenceStore().getBoolean(key));
|
||||
|
||||
fCheckBoxes.add(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see PreferencePage#createControl(Composite)
|
||||
*/
|
||||
public void createControl(Composite parent) {
|
||||
super.createControl(parent);
|
||||
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), "WORK_IN_PROGRESS_PREFERENCE_PAGE"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
protected Control createContents(Composite parent) {
|
||||
initializeDialogUnits(parent);
|
||||
|
||||
Composite result= new Composite(parent, SWT.NONE);
|
||||
GridLayout layout= new GridLayout();
|
||||
layout.marginHeight= convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
|
||||
layout.marginWidth= 0;
|
||||
layout.verticalSpacing= convertVerticalDLUsToPixels(10);
|
||||
layout.horizontalSpacing= convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
|
||||
result.setLayout(layout);
|
||||
|
||||
// Add your controls here
|
||||
addCheckBox(result, "Semantic Highlighting", PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED); //$NON-NLS-1$
|
||||
applyDialogFont(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
|
||||
*/
|
||||
public void init(IWorkbench workbench) {
|
||||
}
|
||||
|
||||
protected void createSpacer(Composite composite, int columnSpan) {
|
||||
Label label= new Label(composite, SWT.NONE);
|
||||
GridData gd= new GridData();
|
||||
gd.horizontalSpan= columnSpan;
|
||||
label.setLayoutData(gd);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.preference.PreferencePage#doGetPreferenceStore()
|
||||
*/
|
||||
protected IPreferenceStore doGetPreferenceStore() {
|
||||
return CUIPlugin.getDefault().getPreferenceStore();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see PreferencePage#performDefaults()
|
||||
*/
|
||||
protected void performDefaults() {
|
||||
IPreferenceStore store= getPreferenceStore();
|
||||
for (int i= 0; i < fCheckBoxes.size(); i++) {
|
||||
Button button= (Button) fCheckBoxes.get(i);
|
||||
String key= (String) button.getData();
|
||||
button.setSelection(store.getDefaultBoolean(key));
|
||||
}
|
||||
for (int i= 0; i < fRadioButtons.size(); i++) {
|
||||
Button button= (Button) fRadioButtons.get(i);
|
||||
String[] info= (String[]) button.getData();
|
||||
button.setSelection(info[1].equals(store.getDefaultString(info[0])));
|
||||
}
|
||||
for (int i= 0; i < fTextControls.size(); i++) {
|
||||
Text text= (Text) fTextControls.get(i);
|
||||
String key= (String) text.getData();
|
||||
text.setText(store.getDefaultString(key));
|
||||
}
|
||||
|
||||
super.performDefaults();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IPreferencePage#performOk()
|
||||
*/
|
||||
public boolean performOk() {
|
||||
IPreferenceStore store= getPreferenceStore();
|
||||
for (int i= 0; i < fCheckBoxes.size(); i++) {
|
||||
Button button= (Button) fCheckBoxes.get(i);
|
||||
String key= (String) button.getData();
|
||||
store.setValue(key, button.getSelection());
|
||||
}
|
||||
for (int i= 0; i < fRadioButtons.size(); i++) {
|
||||
Button button= (Button) fRadioButtons.get(i);
|
||||
if (button.getSelection()) {
|
||||
String[] info= (String[]) button.getData();
|
||||
store.setValue(info[0], info[1]);
|
||||
}
|
||||
}
|
||||
for (int i= 0; i < fTextControls.size(); i++) {
|
||||
Text text= (Text) fTextControls.get(i);
|
||||
String key= (String) text.getData();
|
||||
store.setValue(key, text.getText());
|
||||
}
|
||||
|
||||
CUIPlugin.getDefault().savePluginPreferences();
|
||||
return super.performOk();
|
||||
}
|
||||
|
||||
public static void initDefaults(IPreferenceStore store) {
|
||||
// Initialize your defaults here
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.internal.ui.text;
|
||||
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.TextPresentation;
|
||||
import org.eclipse.jface.text.presentation.PresentationReconciler;
|
||||
|
||||
|
||||
/**
|
||||
* Presentation reconciler, adding functionality for operation without a viewer.
|
||||
* Cloned from JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class CPresentationReconciler extends PresentationReconciler {
|
||||
|
||||
/** Last used document */
|
||||
private IDocument fLastDocument;
|
||||
|
||||
/**
|
||||
* Constructs a "repair description" for the given damage and returns
|
||||
* this description as a text presentation.
|
||||
* <p>
|
||||
* NOTE: Should not be used if this reconciler is installed on a viewer.
|
||||
* </p>
|
||||
*
|
||||
* @param damage the damage to be repaired
|
||||
* @param document the document whose presentation must be repaired
|
||||
* @return the presentation repair description as text presentation
|
||||
*/
|
||||
public TextPresentation createRepairDescription(IRegion damage, IDocument document) {
|
||||
if (document != fLastDocument) {
|
||||
setDocumentToDamagers(document);
|
||||
setDocumentToRepairers(document);
|
||||
fLastDocument= document;
|
||||
}
|
||||
return createPresentation(damage, document);
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* QNX Software System
|
||||
* Anton Leherbauer (Wind River Systems)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text;
|
||||
|
||||
|
@ -24,15 +25,18 @@ import org.eclipse.jface.text.IDocument;
|
|||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.reconciler.DirtyRegion;
|
||||
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
|
||||
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
|
||||
|
||||
public class CReconcilingStrategy implements IReconcilingStrategy {
|
||||
public class CReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
|
||||
|
||||
private ITextEditor fEditor;
|
||||
private IWorkingCopyManager fManager;
|
||||
private IProgressMonitor fProgressMonitor;
|
||||
private String txt = null;
|
||||
// used by tests
|
||||
protected boolean fInitialProcessDone;
|
||||
|
||||
public CReconcilingStrategy(CEditor editor) {
|
||||
fEditor= editor;
|
||||
|
@ -123,5 +127,16 @@ public class CReconcilingStrategy implements IReconcilingStrategy {
|
|||
} catch(CModelException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension#initialReconcile()
|
||||
*/
|
||||
public void initialReconcile() {
|
||||
if (fEditor instanceof IReconcilingParticipant) {
|
||||
IReconcilingParticipant p= (IReconcilingParticipant) fEditor;
|
||||
p.reconciled(true);
|
||||
}
|
||||
fInitialProcessDone= true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* QNX Software System
|
||||
* Anton Leherbauer (Wind River Systems)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text;
|
||||
|
||||
|
@ -33,7 +34,6 @@ import org.eclipse.jface.text.information.IInformationPresenter;
|
|||
import org.eclipse.jface.text.information.IInformationProvider;
|
||||
import org.eclipse.jface.text.information.InformationPresenter;
|
||||
import org.eclipse.jface.text.presentation.IPresentationReconciler;
|
||||
import org.eclipse.jface.text.presentation.PresentationReconciler;
|
||||
import org.eclipse.jface.text.reconciler.IReconciler;
|
||||
import org.eclipse.jface.text.reconciler.MonoReconciler;
|
||||
import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
|
||||
|
@ -163,7 +163,7 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration {
|
|||
*/
|
||||
public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
|
||||
|
||||
PresentationReconciler reconciler= new PresentationReconciler();
|
||||
CPresentationReconciler reconciler= new CPresentationReconciler();
|
||||
reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
|
||||
|
||||
RuleBasedScanner scanner = null;
|
||||
|
@ -529,5 +529,14 @@ public class CSourceViewerConfiguration extends TextSourceViewerConfiguration {
|
|||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt to the given preference change event.
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
public void handlePropertyChangeEvent(PropertyChangeEvent event) {
|
||||
fTextTools.adaptToPreferenceChange(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2006 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
|
||||
* Anton Leherbauer (Wind River Systems) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
import org.eclipse.cdt.core.IPositionConverter;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
|
||||
|
||||
/**
|
||||
* Interface of an object listening to (AST-) reconciling.
|
||||
* Inspired by JDT.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface ICReconcilingListener {
|
||||
|
||||
/**
|
||||
* Called before reconciling is started.
|
||||
*/
|
||||
void aboutToBeReconciled();
|
||||
|
||||
/**
|
||||
* Called after reconciling has been finished.
|
||||
*
|
||||
* @param ast
|
||||
* the translation unit AST or <code>null</code> if the working
|
||||
* copy was consistent or reconciliation has been cancelled
|
||||
* @param positionTracker
|
||||
* the position tracker to map AST positions to current document
|
||||
* positions; may be <code>null</code> which means positions
|
||||
* can be considered up-to-date
|
||||
* @param progressMonitor
|
||||
* the progress monitor
|
||||
*/
|
||||
void reconciled(IASTTranslationUnit ast, IPositionConverter positionTracker, IProgressMonitor progressMonitor);
|
||||
}
|
|
@ -68,6 +68,7 @@ import org.eclipse.cdt.internal.ui.ICStatusConstants;
|
|||
import org.eclipse.cdt.internal.ui.IContextMenuConstants;
|
||||
import org.eclipse.cdt.internal.ui.ResourceAdapterFactory;
|
||||
import org.eclipse.cdt.internal.ui.buildconsole.BuildConsoleManager;
|
||||
import org.eclipse.cdt.internal.ui.editor.ASTProvider;
|
||||
import org.eclipse.cdt.internal.ui.editor.CDocumentProvider;
|
||||
import org.eclipse.cdt.internal.ui.editor.CustomBufferFactory;
|
||||
import org.eclipse.cdt.internal.ui.editor.ExternalSearchDocumentProvider;
|
||||
|
@ -110,9 +111,8 @@ public class CUIPlugin extends AbstractUIPlugin {
|
|||
private CEditorTextHoverDescriptor[] fCEditorTextHoverDescriptors;
|
||||
|
||||
/**
|
||||
* The extension point registry for the <code>org.eclipse.jdt.ui.javaFoldingStructureProvider</code>
|
||||
* The extension point registry for the <code>org.eclipse.cdt.ui.foldingStructureProviders</code>
|
||||
* extension point.
|
||||
*
|
||||
*/
|
||||
private CFoldingStructureProviderRegistry fFoldingStructureProviderRegistry;
|
||||
|
||||
|
@ -338,17 +338,23 @@ public class CUIPlugin extends AbstractUIPlugin {
|
|||
private CElementAdapterFactory fCElementAdapterFactory;
|
||||
|
||||
/**
|
||||
* The template context type registry for the java editor.
|
||||
* The template context type registry for the C editor.
|
||||
* @since 3.0
|
||||
*/
|
||||
private ContributionContextTypeRegistry fContextTypeRegistry;
|
||||
|
||||
/**
|
||||
* The template store for the java editor.
|
||||
* The template store for the C editor.
|
||||
* @since 3.0
|
||||
*/
|
||||
private TemplateStore fTemplateStore;
|
||||
|
||||
/**
|
||||
* The AST provider.
|
||||
* @since 4.0
|
||||
*/
|
||||
private ASTProvider fASTProvider;
|
||||
|
||||
|
||||
public CUIPlugin() {
|
||||
fgCPlugin = this;
|
||||
|
@ -708,9 +714,9 @@ public class CUIPlugin extends AbstractUIPlugin {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the template context type registry for the java plugin.
|
||||
* Returns the template context type registry for the C plugin.
|
||||
*
|
||||
* @return the template context type registry for the java plugin
|
||||
* @return the template context type registry for the C plugin
|
||||
* @since 3.0
|
||||
*/
|
||||
public ContextTypeRegistry getTemplateContextRegistry() {
|
||||
|
@ -722,9 +728,9 @@ public class CUIPlugin extends AbstractUIPlugin {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the template store for the java editor templates.
|
||||
* Returns the template store for the C editor templates.
|
||||
*
|
||||
* @return the template store for the java editor templates
|
||||
* @return the template store for the C editor templates
|
||||
* @since 3.0
|
||||
*/
|
||||
public TemplateStore getTemplateStore() {
|
||||
|
@ -739,4 +745,17 @@ public class CUIPlugin extends AbstractUIPlugin {
|
|||
return fTemplateStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AST provider.
|
||||
*
|
||||
* @return the AST provider
|
||||
* @since 4.0
|
||||
*/
|
||||
public synchronized ASTProvider getASTProvider() {
|
||||
if (fASTProvider == null)
|
||||
fASTProvider= new ASTProvider();
|
||||
|
||||
return fASTProvider;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,11 +11,14 @@
|
|||
package org.eclipse.cdt.ui;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.cview.CView;
|
||||
import org.eclipse.cdt.internal.ui.editor.SemanticHighlightings;
|
||||
import org.eclipse.cdt.internal.ui.preferences.BuildConsolePreferencePage;
|
||||
import org.eclipse.cdt.internal.ui.preferences.CEditorPreferencePage;
|
||||
import org.eclipse.cdt.internal.ui.preferences.CParserPreferencePage;
|
||||
import org.eclipse.cdt.internal.ui.preferences.CPluginPreferencePage;
|
||||
import org.eclipse.cdt.internal.ui.preferences.CodeAssistPreferencePage;
|
||||
import org.eclipse.cdt.internal.ui.preferences.WorkInProgressPreferencePage;
|
||||
|
||||
import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.ui.editors.text.EditorsUI;
|
||||
|
@ -41,7 +44,9 @@ public class CUIPreferenceInitializer extends AbstractPreferenceInitializer {
|
|||
CParserPreferencePage.initDefaults(store);
|
||||
CEditorPreferencePage.initDefaults(store);
|
||||
CodeAssistPreferencePage.initDefaults(store);
|
||||
|
||||
SemanticHighlightings.initDefaults(store);
|
||||
WorkInProgressPreferencePage.initDefaults(store);
|
||||
|
||||
// We need to do this remove any keys that might have been
|
||||
// in the CUIPlugin store prior to the move of the CEditor setting
|
||||
// All of those settings are now in the workbench "All TextEditor" preference Page.
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
package org.eclipse.cdt.ui;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.text.ICColorConstants;
|
||||
|
||||
import org.eclipse.jface.action.Action;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.preference.PreferenceConverter;
|
||||
|
@ -432,6 +433,86 @@ public class PreferenceConstants {
|
|||
*/
|
||||
public static final String EDITOR_SHOW_TEXT_HOVER_AFFORDANCE= "PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference prefix for semantic highlighting preferences.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX="semanticHighlighting."; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference suffix that controls a semantic highlighting's color.
|
||||
* <p>
|
||||
* Value is of type <code>String</code>. A RGB color value encoded as a string
|
||||
* using class <code>PreferenceConverter</code>
|
||||
* </p>
|
||||
*
|
||||
* @see org.eclipse.jface.resource.StringConverter
|
||||
* @see org.eclipse.jface.preference.PreferenceConverter
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX=".color"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference suffix that controls if semantic highlighting has the text attribute bold.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>: <code>true</code> if bold.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_BOLD_SUFFIX=".bold"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference suffix that controls if semantic highlighting has the text attribute italic.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>: <code>true</code> if italic.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_ITALIC_SUFFIX=".italic"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference suffix that controls if semantic highlighting has the text attribute strikethrough.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>: <code>true</code> if strikethrough.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_STRIKETHROUGH_SUFFIX=".strikethrough"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference suffix that controls if semantic highlighting has the text attribute underline.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>: <code>true</code> if underline.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_UNDERLINE_SUFFIX=".underline"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference suffix that controls if semantic highlighting is enabled.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>: <code>true</code> if enabled.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_SUFFIX=".enabled"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference key that controls if semantic highlighting is enabled.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>: <code>true</code> if enabled.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public static final String EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED= "semanticHighlighting.enabled"; //$NON-NLS-1$
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the given preference store with the default values.
|
||||
|
|
Loading…
Add table
Reference in a new issue