1
0
Fork 0
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:
Anton Leherbauer 2006-08-28 12:46:34 +00:00
parent 3a46db2f34
commit 487bac0828
32 changed files with 8604 additions and 300 deletions

View file

@ -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;
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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 &lt; 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 &lt; 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 &lt; 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 &lt; 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();
}
}

View file

@ -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);
}
}
}

View file

@ -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) {
}
}
}
}
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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">

View file

@ -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();
}
}

View file

@ -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.
*/

View file

@ -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();
}
}

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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.

View file

@ -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.