### Eclipse Workspace Patch 1.0
#P org.eclipse.cdt.ui
Index: META-INF/MANIFEST.MF
===================================================================
RCS file: /home/tools/org.eclipse.cdt-core/org.eclipse.cdt.ui/META-INF/MANIFEST.MF,v
retrieving revision 1.10
diff -u -r1.10 MANIFEST.MF
--- META-INF/MANIFEST.MF 5 Jul 2006 14:23:52 -0000 1.10
+++ META-INF/MANIFEST.MF 15 Jul 2006 05:33:46 -0000
@@ -69,6 +69,7 @@
org.eclipse.help,
org.eclipse.ui.navigator,
org.eclipse.core.expressions,
- org.eclipse.ui.navigator.resources
+ org.eclipse.ui.navigator.resources,
+ com.ibm.icu
Eclipse-LazyStart: true
Bundle-RequiredExecutionEnvironment: J2SE-1.4
Index: src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties
===================================================================
RCS file: /home/tools/org.eclipse.cdt-core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties,v
retrieving revision 1.44
diff -u -r1.44 PreferencesMessages.properties
--- src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties 14 Jul 2006 13:21:46 -0000 1.44
+++ src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties 15 Jul 2006 05:33:46 -0000
@@ -108,6 +108,7 @@
CEditorPreferencePage.colorPage.preview=Preview:
CEditorPreferencePage.behaviorPage.tabSpace=&Insert space for tabs
CEditorPreferencePage.behaviorPage.matchingBrackets=Highlight &matching brackets
+CEditorPreferencePage.behaviorPage.subWordNavigation=Smart &caret positioning in identifiers
CEditorPreferencePage.behaviorPage.inactiveCode=Highlight &inactive code
CEditorPreferencePage.behaviorPage.appearanceColorOptions=Appearance color options:
CEditorPreferencePage.behaviorPage.matchingBracketColor=Matching brackets highlight
Index: src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt-core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java,v
retrieving revision 1.56
diff -u -r1.56 CEditorPreferencePage.java
--- src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java 14 Jul 2006 13:21:46 -0000 1.56
+++ src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java 15 Jul 2006 05:33:46 -0000
@@ -118,6 +118,7 @@
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, ICColorConstants.C_NUMBER + "_bold")); //$NON-NLS-1$
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, ICColorConstants.C_OPERATOR));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, ICColorConstants.C_OPERATOR + "_bold")); //$NON-NLS-1$
+ overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, CEditor.SUB_WORD_NAVIGATION));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, CEditor.MATCHING_BRACKETS_COLOR));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, CEditor.MATCHING_BRACKETS));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, CEditor.INACTIVE_CODE_COLOR));
@@ -147,6 +148,8 @@
// JDT also enables this feature.
store.setDefault(AbstractTextEditor.PREFERENCE_NAVIGATION_SMART_HOME_END, true);
+ store.setDefault(CEditor.SUB_WORD_NAVIGATION, true);
+
store.setDefault(CEditor.MATCHING_BRACKETS, true);
PreferenceConverter.setDefault(store, CEditor.MATCHING_BRACKETS_COLOR, new RGB(170,170,170));
@@ -336,7 +339,10 @@
layout.numColumns = 2;
behaviorComposite.setLayout(layout);
- String label = PreferencesMessages.getString("CEditorPreferencePage.behaviorPage.matchingBrackets"); //$NON-NLS-1$
+ String label= PreferencesMessages.getString("CEditorPreferencePage.behaviorPage.subWordNavigation"); //$NON-NLS-1$;
+ addCheckBox(behaviorComposite, label, CEditor.SUB_WORD_NAVIGATION, 0);
+
+ label = PreferencesMessages.getString("CEditorPreferencePage.behaviorPage.matchingBrackets"); //$NON-NLS-1$
addCheckBox(behaviorComposite, label, CEditor.MATCHING_BRACKETS, 0);
label = PreferencesMessages.getString("CEditorPreferencePage.behaviorPage.inactiveCode"); //$NON-NLS-1$
Index: src/org/eclipse/cdt/internal/ui/editor/CEditor.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt-core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java,v
retrieving revision 1.105
diff -u -r1.105 CEditor.java
--- src/org/eclipse/cdt/internal/ui/editor/CEditor.java 14 Jul 2006 13:21:46 -0000 1.105
+++ src/org/eclipse/cdt/internal/ui/editor/CEditor.java 15 Jul 2006 05:33:46 -0000
@@ -10,10 +10,12 @@
* QNX Software System
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
+ * Sergey Prigogin, Google
*******************************************************************************/
package org.eclipse.cdt.internal.ui.editor;
+import java.text.CharacterIterator;
import java.util.Iterator;
import java.util.ResourceBundle;
@@ -21,6 +23,7 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.preference.IPreferenceStore;
@@ -72,6 +75,7 @@
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.search.ui.actions.TextSearchGroup;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ST;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
@@ -104,12 +108,16 @@
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.ITextEditorDropTargetListener;
+import org.eclipse.ui.texteditor.IUpdate;
import org.eclipse.ui.texteditor.ResourceAction;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.TextEditorAction;
+import org.eclipse.ui.texteditor.TextNavigationAction;
import org.eclipse.ui.texteditor.TextOperationAction;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+import com.ibm.icu.text.BreakIterator;
+
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CCorePreferenceConstants;
import org.eclipse.cdt.core.model.CModelException;
@@ -138,6 +146,8 @@
import org.eclipse.cdt.internal.ui.text.CPairMatcher;
import org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration;
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.ICPartitions;
import org.eclipse.cdt.internal.ui.text.c.hover.SourceViewerInformationControl;
@@ -512,6 +522,8 @@
/** Listener to annotation model changes that updates the error tick in the tab image */
private CEditorErrorTickUpdater fCEditorErrorTickUpdater;
+ /** Preference key for sub-word navigation, aka smart caret positioning */
+ public final static String SUB_WORD_NAVIGATION= "subWordNavigation"; //$NON-NLS-1$
/** Preference key for matching brackets */
public final static String MATCHING_BRACKETS = "matchingBrackets"; //$NON-NLS-1$
/** Preference key for matching brackets color */
@@ -1396,6 +1408,47 @@
return store.getBoolean(SPACES_FOR_TABS);
}
+ /*
+ * @see org.eclipse.ui.texteditor.AbstractTextEditor#createNavigationActions()
+ */
+ protected void createNavigationActions() {
+ super.createNavigationActions();
+
+ final StyledText textWidget = getSourceViewer().getTextWidget();
+
+ IAction action = new NavigatePreviousSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_PREVIOUS);
+ setAction(ITextEditorActionDefinitionIds.WORD_PREVIOUS, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_LEFT, SWT.NULL);
+
+ action = new NavigateNextSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.WORD_NEXT);
+ setAction(ITextEditorActionDefinitionIds.WORD_NEXT, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.ARROW_RIGHT, SWT.NULL);
+
+ action = new SelectPreviousSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS);
+ setAction(ITextEditorActionDefinitionIds.SELECT_WORD_PREVIOUS, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_LEFT, SWT.NULL);
+
+ action = new SelectNextSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT);
+ setAction(ITextEditorActionDefinitionIds.SELECT_WORD_NEXT, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.SHIFT | SWT.ARROW_RIGHT, SWT.NULL);
+
+ action= new DeletePreviousSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD);
+ setAction(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.BS, SWT.NULL);
+ markAsStateDependentAction(ITextEditorActionDefinitionIds.DELETE_PREVIOUS_WORD, true);
+
+ action= new DeleteNextSubWordAction();
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD);
+ setAction(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, action);
+ textWidget.setKeyBinding(SWT.CTRL | SWT.DEL, SWT.NULL);
+ markAsStateDependentAction(ITextEditorActionDefinitionIds.DELETE_NEXT_WORD, true);
+ }
+
interface ITextConverter {
void customizeDocumentCommand(IDocument document, DocumentCommand command);
}
@@ -1669,4 +1722,365 @@
System.arraycopy(parentPrefPageIds, 0, prefPageIds, nIds, parentPrefPageIds.length);
return prefPageIds;
}
+
+ /**
+ * Text navigation action to navigate to the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected abstract class NextSubWordAction extends TextNavigationAction {
+
+ protected CWordIterator fIterator = new CWordIterator();
+
+ /**
+ * Creates a new next sub-word action.
+ *
+ * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
+ */
+ protected NextSubWordAction(int code) {
+ super(getSourceViewer().getTextWidget(), code);
+ }
+
+ /*
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ public void run() {
+ // Check whether sub word navigation is enabled.
+ final IPreferenceStore store = getPreferenceStore();
+ if (!store.getBoolean(SUB_WORD_NAVIGATION)) {
+ super.run();
+ return;
+ }
+
+ final ISourceViewer viewer = getSourceViewer();
+ final IDocument document = viewer.getDocument();
+ fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
+ int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+ if (position == -1)
+ return;
+
+ int next = findNextPosition(position);
+ if (next != BreakIterator.DONE) {
+ setCaretPosition(next);
+ getTextWidget().showSelection();
+ fireSelectionChanged();
+ }
+
+ }
+
+ /**
+ * Finds the next position after the given position.
+ *
+ * @param position the current position
+ * @return the next position
+ */
+ protected int findNextPosition(int position) {
+ ISourceViewer viewer = getSourceViewer();
+ int widget = -1;
+ while (position != BreakIterator.DONE && widget == -1) { // TODO: optimize
+ position = fIterator.following(position);
+ if (position != BreakIterator.DONE)
+ widget = modelOffset2WidgetOffset(viewer, position);
+ }
+ return position;
+ }
+
+ /**
+ * Sets the caret position to the sub-word boundary given with position
.
+ *
+ * @param position Position where the action should move the caret
+ */
+ protected abstract void setCaretPosition(int position);
+ }
+
+ /**
+ * Text navigation action to navigate to the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected class NavigateNextSubWordAction extends NextSubWordAction {
+
+ /**
+ * Creates a new navigate next sub-word action.
+ */
+ public NavigateNextSubWordAction() {
+ super(ST.WORD_NEXT);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+ */
+ protected void setCaretPosition(final int position) {
+ getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
+ }
+ }
+
+ /**
+ * Text operation action to delete the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected class DeleteNextSubWordAction extends NextSubWordAction implements IUpdate {
+
+ /**
+ * Creates a new delete next sub-word action.
+ */
+ public DeleteNextSubWordAction() {
+ super(ST.DELETE_WORD_NEXT);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+ */
+ protected void setCaretPosition(final int position) {
+ if (!validateEditorInputState())
+ return;
+
+ final ISourceViewer viewer = getSourceViewer();
+ final int caret, length;
+ Point selection = viewer.getSelectedRange();
+ if (selection.y != 0) {
+ caret = selection.x;
+ length = selection.y;
+ } else {
+ caret = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+ length = position - caret;
+ }
+
+ try {
+ viewer.getDocument().replace(caret, length, ""); //$NON-NLS-1$
+ } catch (BadLocationException exception) {
+ // Should not happen
+ }
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#findNextPosition(int)
+ */
+ protected int findNextPosition(int position) {
+ return fIterator.following(position);
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.IUpdate#update()
+ */
+ public void update() {
+ setEnabled(isEditorInputModifiable());
+ }
+ }
+
+ /**
+ * Text operation action to select the next sub-word.
+ *
+ * @since 3.0
+ */
+ protected class SelectNextSubWordAction extends NextSubWordAction {
+
+ /**
+ * Creates a new select next sub-word action.
+ */
+ public SelectNextSubWordAction() {
+ super(ST.SELECT_WORD_NEXT);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.NextSubWordAction#setCaretPosition(int)
+ */
+ protected void setCaretPosition(final int position) {
+ final ISourceViewer viewer = getSourceViewer();
+
+ final StyledText text = viewer.getTextWidget();
+ if (text != null && !text.isDisposed()) {
+
+ final Point selection = text.getSelection();
+ final int caret = text.getCaretOffset();
+ final int offset = modelOffset2WidgetOffset(viewer, position);
+
+ if (caret == selection.x)
+ text.setSelectionRange(selection.y, offset - selection.y);
+ else
+ text.setSelectionRange(selection.x, offset - selection.x);
+ }
+ }
+ }
+
+ /**
+ * Text navigation action to navigate to the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected abstract class PreviousSubWordAction extends TextNavigationAction {
+
+ protected CWordIterator fIterator = new CWordIterator();
+
+ /**
+ * Creates a new previous sub-word action.
+ *
+ * @param code Action code for the default operation. Must be an action code from @see org.eclipse.swt.custom.ST.
+ */
+ protected PreviousSubWordAction(final int code) {
+ super(getSourceViewer().getTextWidget(), code);
+ }
+
+ /*
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ public void run() {
+ // Check whether sub word navigation is enabled.
+ final IPreferenceStore store = getPreferenceStore();
+ if (!store.getBoolean(SUB_WORD_NAVIGATION)) {
+ super.run();
+ return;
+ }
+
+ final ISourceViewer viewer = getSourceViewer();
+ final IDocument document = viewer.getDocument();
+ fIterator.setText((CharacterIterator) new DocumentCharacterIterator(document));
+ int position = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset());
+ if (position == -1)
+ return;
+
+ int previous = findPreviousPosition(position);
+ if (previous != BreakIterator.DONE) {
+ setCaretPosition(previous);
+ getTextWidget().showSelection();
+ fireSelectionChanged();
+ }
+
+ }
+
+ /**
+ * Finds the previous position before the given position.
+ *
+ * @param position the current position
+ * @return the previous position
+ */
+ protected int findPreviousPosition(int position) {
+ ISourceViewer viewer = getSourceViewer();
+ int widget = -1;
+ while (position != BreakIterator.DONE && widget == -1) { // TODO: optimize
+ position = fIterator.preceding(position);
+ if (position != BreakIterator.DONE)
+ widget = modelOffset2WidgetOffset(viewer, position);
+ }
+ return position;
+ }
+
+ /**
+ * Sets the caret position to the sub-word boundary given with position
.
+ *
+ * @param position Position where the action should move the caret
+ */
+ protected abstract void setCaretPosition(int position);
+ }
+
+ /**
+ * Text navigation action to navigate to the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected class NavigatePreviousSubWordAction extends PreviousSubWordAction {
+
+ /**
+ * Creates a new navigate previous sub-word action.
+ */
+ public NavigatePreviousSubWordAction() {
+ super(ST.WORD_PREVIOUS);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+ */
+ protected void setCaretPosition(final int position) {
+ getTextWidget().setCaretOffset(modelOffset2WidgetOffset(getSourceViewer(), position));
+ }
+ }
+
+ /**
+ * Text operation action to delete the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected class DeletePreviousSubWordAction extends PreviousSubWordAction implements IUpdate {
+
+ /**
+ * Creates a new delete previous sub-word action.
+ */
+ public DeletePreviousSubWordAction() {
+ super(ST.DELETE_WORD_PREVIOUS);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+ */
+ protected void setCaretPosition(int position) {
+ if (!validateEditorInputState())
+ return;
+
+ final int length;
+ final ISourceViewer viewer = getSourceViewer();
+ Point selection = viewer.getSelectedRange();
+ if (selection.y != 0) {
+ position = selection.x;
+ length = selection.y;
+ } else {
+ length = widgetOffset2ModelOffset(viewer, viewer.getTextWidget().getCaretOffset()) - position;
+ }
+
+ try {
+ viewer.getDocument().replace(position, length, ""); //$NON-NLS-1$
+ } catch (BadLocationException exception) {
+ // Should not happen
+ }
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#findPreviousPosition(int)
+ */
+ protected int findPreviousPosition(int position) {
+ return fIterator.preceding(position);
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.IUpdate#update()
+ */
+ public void update() {
+ setEnabled(isEditorInputModifiable());
+ }
+ }
+
+ /**
+ * Text operation action to select the previous sub-word.
+ *
+ * @since 3.0
+ */
+ protected class SelectPreviousSubWordAction extends PreviousSubWordAction {
+
+ /**
+ * Creates a new select previous sub-word action.
+ */
+ public SelectPreviousSubWordAction() {
+ super(ST.SELECT_WORD_PREVIOUS);
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor.PreviousSubWordAction#setCaretPosition(int)
+ */
+ protected void setCaretPosition(final int position) {
+ final ISourceViewer viewer = getSourceViewer();
+
+ final StyledText text = viewer.getTextWidget();
+ if (text != null && !text.isDisposed()) {
+
+ final Point selection = text.getSelection();
+ final int caret = text.getCaretOffset();
+ final int offset = modelOffset2WidgetOffset(viewer, position);
+
+ if (caret == selection.x)
+ text.setSelectionRange(selection.y, offset - selection.y);
+ else
+ text.setSelectionRange(selection.x, offset - selection.x);
+ }
+ }
+ }
}
Index: src/org/eclipse/cdt/internal/ui/text/CBreakIterator.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/text/CBreakIterator.java
diff -N src/org/eclipse/cdt/internal/ui/text/CBreakIterator.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/text/CBreakIterator.java 1 Jan 1970 00:00:00 -0000
@@ -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
+ * Sergey Prigogin, Google
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.text;
+
+import com.ibm.icu.text.BreakIterator;
+import java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+
+
+/**
+ * A C break iterator. It returns all breaks, including before and after
+ * whitespace, and it returns all camel case breaks.
+ *
+ * A line break may be any of "\n", "\r", "\r\n", "\n\r". + *
+ * + * @since 3.0 + */ +public class CBreakIterator extends BreakIterator { + + /** + * A run of common characters. + */ + protected static abstract class Run { + /** The length of this run. */ + protected int length; + + public Run() { + init(); + } + + /** + * Returnstrue
if this run consumes ch
,
+ * false
otherwise. If true
is returned,
+ * the length of the receiver is adjusted accordingly.
+ *
+ * @param ch the character to test
+ * @return true
if ch
was consumed
+ */
+ protected boolean consume(char ch) {
+ if (isValid(ch)) {
+ length++;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Whether this run accepts that character; does not update state. Called
+ * from the default implementation of consume
.
+ *
+ * @param ch the character to test
+ * @return true
if ch
is accepted
+ */
+ protected abstract boolean isValid(char ch);
+
+ /**
+ * Resets this run to the initial state.
+ */
+ protected void init() {
+ length= 0;
+ }
+ }
+
+ static final class Whitespace extends Run {
+ protected boolean isValid(char ch) {
+ return Character.isWhitespace(ch) && ch != '\n' && ch != '\r';
+ }
+ }
+
+ static final class LineDelimiter extends Run {
+ /** State: INIT -> delimiter -> EXIT. */
+ private char fState;
+ private static final char INIT= '\0';
+ private static final char EXIT= '\1';
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#init()
+ */
+ protected void init() {
+ super.init();
+ fState= INIT;
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#consume(char)
+ */
+ protected boolean consume(char ch) {
+ if (!isValid(ch) || fState == EXIT)
+ return false;
+
+ if (fState == INIT) {
+ fState= ch;
+ length++;
+ return true;
+ } else if (fState != ch) {
+ fState= EXIT;
+ length++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected boolean isValid(char ch) {
+ return ch == '\n' || ch == '\r';
+ }
+ }
+
+ static final class Identifier extends Run {
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#isValid(char)
+ */
+ protected boolean isValid(char ch) {
+ return Character.isJavaIdentifierPart(ch);
+ }
+ }
+
+ static final class CamelCaseIdentifier extends Run {
+ /* states */
+ private static final int S_INIT= 0;
+ private static final int S_LOWER= 1;
+ private static final int S_ONE_CAP= 2;
+ private static final int S_ALL_CAPS= 3;
+ private static final int S_UNDERSCORE= 4;
+ private static final int S_EXIT= 5;
+ private static final int S_EXIT_MINUS_ONE= 6;
+
+ /* character types */
+ private static final int K_INVALID= 0;
+ private static final int K_LOWER= 1;
+ private static final int K_UPPER= 2;
+ private static final int K_UNDERSCORE= 3;
+ private static final int K_OTHER= 4;
+
+ private int fState;
+
+ private final static int[][] MATRIX= new int[][] {
+ // K_INVALID, K_LOWER, K_UPPER, K_UNDERSCORE, K_OTHER
+ { S_EXIT, S_LOWER, S_ONE_CAP, S_UNDERSCORE, S_LOWER }, // S_INIT
+ { S_EXIT, S_LOWER, S_EXIT, S_UNDERSCORE, S_LOWER }, // S_LOWER
+ { S_EXIT, S_LOWER, S_ALL_CAPS, S_UNDERSCORE, S_LOWER }, // S_ONE_CAP
+ { S_EXIT, S_EXIT_MINUS_ONE, S_ALL_CAPS, S_UNDERSCORE, S_LOWER }, // S_ALL_CAPS
+ { S_EXIT, S_EXIT, S_EXIT, S_UNDERSCORE, S_EXIT }, // S_UNDERSCORE
+ };
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#init()
+ */
+ protected void init() {
+ super.init();
+ fState= S_INIT;
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#consumes(char)
+ */
+ protected boolean consume(char ch) {
+ int kind= getKind(ch);
+ fState= MATRIX[fState][kind];
+ switch (fState) {
+ case S_LOWER:
+ case S_ONE_CAP:
+ case S_ALL_CAPS:
+ case S_UNDERSCORE:
+ length++;
+ return true;
+ case S_EXIT:
+ return false;
+ case S_EXIT_MINUS_ONE:
+ length--;
+ return false;
+ default:
+ Assert.isTrue(false);
+ return false;
+ }
+ }
+
+ /**
+ * Determines the kind of a character.
+ *
+ * @param ch the character to test
+ */
+ private int getKind(char ch) {
+ if (Character.isUpperCase(ch))
+ return K_UPPER;
+ if (Character.isLowerCase(ch))
+ return K_LOWER;
+ if (ch == '_')
+ return K_UNDERSCORE;
+ if (Character.isJavaIdentifierPart(ch)) // digits...
+ return K_OTHER;
+ return K_INVALID;
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#isValid(char)
+ */
+ protected boolean isValid(char ch) {
+ return Character.isJavaIdentifierPart(ch);
+ }
+ }
+
+ static final class Other extends Run {
+ /*
+ * @see org.eclipse.jdt.internal.ui.text.CBreakIterator.Run#isValid(char)
+ */
+ protected boolean isValid(char ch) {
+ return !Character.isWhitespace(ch) && !Character.isJavaIdentifierPart(ch);
+ }
+ }
+
+ private static final Run WHITESPACE= new Whitespace();
+ private static final Run DELIMITER= new LineDelimiter();
+ private static final Run IDENTIFIER= new Identifier();
+ private static final Run CAMELCASE= new CamelCaseIdentifier();
+ private static final Run OTHER= new Other();
+
+ /** The platform break iterator (word instance) used as a base. */
+ protected final BreakIterator fIterator;
+ /** The text we operate on. */
+ protected CharSequence fText;
+ /** our current position for the stateful methods. */
+ private int fIndex;
+ /** Break on camel case word boundaries */
+ private boolean fCamelCaseBreakEnabled = true;
+
+
+ /**
+ * Creates a new break iterator.
+ */
+ public CBreakIterator() {
+ fIterator= BreakIterator.getWordInstance();
+ fIndex= fIterator.current();
+ }
+
+ /*
+ * @see java.text.BreakIterator#current()
+ */
+ public int current() {
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.BreakIterator#first()
+ */
+ public int first() {
+ fIndex= fIterator.first();
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.BreakIterator#following(int)
+ */
+ public int following(int offset) {
+ // work around too eager IAEs in standard implementation
+ if (offset == getText().getEndIndex())
+ return DONE;
+
+ int next= fIterator.following(offset);
+ if (next == DONE)
+ return DONE;
+
+ // TODO deal with complex script word boundaries
+ // Math.min(offset + run.length, next) does not work
+ // since BreakIterator.getWordInstance considers _ as boundaries
+ // seems to work fine, however
+ Run run= consumeRun(offset);
+ return offset + run.length;
+
+ }
+
+ /**
+ * Consumes a run of characters at the limits of which we introduce a break.
+ * @param offset the offset to start at
+ * @return the run that was consumed
+ */
+ private Run consumeRun(int offset) {
+ // assert offset < length
+
+ char ch= fText.charAt(offset);
+ int length= fText.length();
+ Run run= getRun(ch);
+ while (run.consume(ch) && offset < length - 1) {
+ offset++;
+ ch= fText.charAt(offset);
+ }
+
+ return run;
+ }
+
+ /**
+ * Returns a run based on a character.
+ *
+ * @param ch the character to test
+ * @return the correct character given ch
+ */
+ private Run getRun(char ch) {
+ Run run;
+ if (WHITESPACE.isValid(ch))
+ run= WHITESPACE;
+ else if (DELIMITER.isValid(ch))
+ run= DELIMITER;
+ else if (IDENTIFIER.isValid(ch)) {
+ if (fCamelCaseBreakEnabled)
+ run= CAMELCASE;
+ else
+ run= IDENTIFIER;
+ }
+ else if (OTHER.isValid(ch))
+ run= OTHER;
+ else {
+ Assert.isTrue(false);
+ return null;
+ }
+
+ run.init();
+ return run;
+ }
+
+ /*
+ * @see java.text.BreakIterator#getText()
+ */
+ public CharacterIterator getText() {
+ return fIterator.getText();
+ }
+
+ /*
+ * @see java.text.BreakIterator#isBoundary(int)
+ */
+ public boolean isBoundary(int offset) {
+ if (offset == getText().getBeginIndex())
+ return true;
+ else
+ return following(offset - 1) == offset;
+ }
+
+ /*
+ * @see java.text.BreakIterator#last()
+ */
+ public int last() {
+ fIndex= fIterator.last();
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.BreakIterator#next()
+ */
+ public int next() {
+ fIndex= following(fIndex);
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.BreakIterator#next(int)
+ */
+ public int next(int n) {
+ return fIterator.next(n);
+ }
+
+ /*
+ * @see java.text.BreakIterator#preceding(int)
+ */
+ public int preceding(int offset) {
+ if (offset == getText().getBeginIndex())
+ return DONE;
+
+ if (isBoundary(offset - 1))
+ return offset - 1;
+
+ int previous= offset - 1;
+ do {
+ previous= fIterator.preceding(previous);
+ } while (!isBoundary(previous));
+
+ int last= DONE;
+ while (previous < offset) {
+ last= previous;
+ previous= following(previous);
+ }
+
+ return last;
+ }
+
+ /*
+ * @see java.text.BreakIterator#previous()
+ */
+ public int previous() {
+ fIndex= preceding(fIndex);
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.BreakIterator#setText(java.lang.String)
+ */
+ public void setText(String newText) {
+ setText((CharSequence) newText);
+ }
+
+ /**
+ * Creates a break iterator given a char sequence.
+ * @param newText the new text
+ */
+ public void setText(CharSequence newText) {
+ fText= newText;
+ fIterator.setText(new SequenceCharacterIterator(newText));
+ first();
+ }
+
+ /*
+ * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
+ */
+ public void setText(CharacterIterator newText) {
+ if (newText instanceof CharSequence) {
+ fText= (CharSequence) newText;
+ fIterator.setText(newText);
+ first();
+ } else {
+ throw new UnsupportedOperationException("CharacterIterator not supported"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Enables breaks at word boundaries inside a camel case identifier.
+ *
+ * @param enable true
to enable, false
to disable.
+ */
+ public void setCamelCaseBreakEnabled(boolean camelCaseBreakEnabled) {
+ fCamelCaseBreakEnabled = camelCaseBreakEnabled;
+ }
+
+ /**
+ * @return true
if breaks at word boundaries inside
+ * a camel case identifier are enabled.
+ */
+ public boolean isCamelCaseBreakEnabled() {
+ return fCamelCaseBreakEnabled;
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/text/DocumentCharacterIterator.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/text/DocumentCharacterIterator.java
diff -N src/org/eclipse/cdt/internal/ui/text/DocumentCharacterIterator.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/text/DocumentCharacterIterator.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * 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.text;
+
+import java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+
+/**
+ * An IDocument
based implementation of
+ * CharacterIterator
and CharSequence
. Note that
+ * the supplied document is not copied; if the document is modified during the
+ * lifetime of a DocumentCharacterIterator
, the methods
+ * returning document content may not always return the same values. Also, if
+ * accessing the document fails with a {@link BadLocationException}, any of
+ * CharacterIterator
methods as well as charAt
may
+ * return {@link CharacterIterator#DONE}.
+ *
+ * @since 3.0
+ */
+public class DocumentCharacterIterator implements CharacterIterator, CharSequence {
+
+ private int fIndex= -1;
+ private final IDocument fDocument;
+ private final int fFirst;
+ private final int fLast;
+
+ private void invariant() {
+ Assert.isTrue(fIndex >= fFirst);
+ Assert.isTrue(fIndex <= fLast);
+ }
+
+ /**
+ * Creates an iterator for the entire document.
+ *
+ * @param document the document backing this iterator
+ */
+ public DocumentCharacterIterator(IDocument document) {
+ this(document, 0);
+ }
+
+ /**
+ * Creates an iterator, starting at offset first
.
+ *
+ * @param document the document backing this iterator
+ * @param first the first character to consider
+ * @throws IllegalArgumentException if the indices are out of bounds
+ */
+ public DocumentCharacterIterator(IDocument document, int first) throws IllegalArgumentException {
+ this(document, first, document.getLength());
+ }
+
+ /**
+ * Creates an iterator for the document contents from first
+ * (inclusive) to last
(exclusive).
+ *
+ * @param document the document backing this iterator
+ * @param first the first character to consider
+ * @param last the last character index to consider
+ * @throws IllegalArgumentException if the indices are out of bounds
+ */
+ public DocumentCharacterIterator(IDocument document, int first, int last) throws IllegalArgumentException {
+ if (document == null)
+ throw new NullPointerException();
+ if (first < 0 || first > last)
+ throw new IllegalArgumentException();
+ if (last > document.getLength())
+ throw new IllegalArgumentException();
+ fDocument= document;
+ fFirst= first;
+ fLast= last;
+ fIndex= first;
+ invariant();
+ }
+
+ /*
+ * @see java.text.CharacterIterator#first()
+ */
+ public char first() {
+ return setIndex(getBeginIndex());
+ }
+
+ /*
+ * @see java.text.CharacterIterator#last()
+ */
+ public char last() {
+ if (fFirst == fLast)
+ return setIndex(getEndIndex());
+ else
+ return setIndex(getEndIndex() - 1);
+ }
+
+ /*
+ * @see java.text.CharacterIterator#current()
+ */
+ public char current() {
+ if (fIndex >= fFirst && fIndex < fLast)
+ try {
+ return fDocument.getChar(fIndex);
+ } catch (BadLocationException e) {
+ // ignore
+ }
+ return DONE;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#next()
+ */
+ public char next() {
+ return setIndex(Math.min(fIndex + 1, getEndIndex()));
+ }
+
+ /*
+ * @see java.text.CharacterIterator#previous()
+ */
+ public char previous() {
+ if (fIndex > getBeginIndex()) {
+ return setIndex(fIndex - 1);
+ } else {
+ return DONE;
+ }
+ }
+
+ /*
+ * @see java.text.CharacterIterator#setIndex(int)
+ */
+ public char setIndex(int position) {
+ if (position >= getBeginIndex() && position <= getEndIndex())
+ fIndex= position;
+ else
+ throw new IllegalArgumentException();
+
+ invariant();
+ return current();
+ }
+
+ /*
+ * @see java.text.CharacterIterator#getBeginIndex()
+ */
+ public int getBeginIndex() {
+ return fFirst;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#getEndIndex()
+ */
+ public int getEndIndex() {
+ return fLast;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#getIndex()
+ */
+ public int getIndex() {
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#clone()
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ /*
+ * @see java.lang.CharSequence#length()
+ */
+ public int length() {
+ return getEndIndex() - getBeginIndex();
+ }
+
+ /**
+ * {@inheritDoc}
+ * + * Note that, if the document is modified concurrently, this method may + * return {@link CharacterIterator#DONE} if a {@link BadLocationException} + * was thrown when accessing the backing document. + *
+ * + * @param index {@inheritDoc} + * @return {@inheritDoc} + */ + public char charAt(int index) { + if (index >= 0 && index < length()) + try { + return fDocument.getChar(getBeginIndex() + index); + } catch (BadLocationException e) { + // ignore and return DONE + return DONE; + } + else + throw new IndexOutOfBoundsException(); + } + + /* + * @see java.lang.CharSequence#subSequence(int, int) + */ + public CharSequence subSequence(int start, int end) { + if (start < 0) + throw new IndexOutOfBoundsException(); + if (end < start) + throw new IndexOutOfBoundsException(); + if (end > length()) + throw new IndexOutOfBoundsException(); + return new DocumentCharacterIterator(fDocument, getBeginIndex() + start, getBeginIndex() + end); + } +} Index: src/org/eclipse/cdt/internal/ui/text/CWordIterator.java =================================================================== RCS file: src/org/eclipse/cdt/internal/ui/text/CWordIterator.java diff -N src/org/eclipse/cdt/internal/ui/text/CWordIterator.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/cdt/internal/ui/text/CWordIterator.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,239 @@ +/******************************************************************************* + * 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 + * Sergey Prigogin, Google + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.text; + +import com.ibm.icu.text.BreakIterator; +import java.text.CharacterIterator; + +import org.eclipse.jface.text.Assert; + + +/** + * Breaks C text into word starts, also stops at line start and end. No + * direction dependency. + * + * @since 3.0 + */ +public class CWordIterator extends BreakIterator { + + /** + * The underlying java break iterator. It returns all breaks, including + * before and after every whitespace. + */ + private CBreakIterator fIterator; + /** The current index for the stateful operations. */ + private int fIndex; + + /** + * Creates a new word iterator. + */ + public CWordIterator() { + fIterator= new CBreakIterator(); + first(); + } + + /* + * @see java.text.BreakIterator#first() + */ + public int first() { + fIndex= fIterator.first(); + return fIndex; + } + + /* + * @see java.text.BreakIterator#last() + */ + public int last() { + fIndex= fIterator.last(); + return fIndex; + } + + /* + * @see java.text.BreakIterator#next(int) + */ + public int next(int n) { + int next= 0; + while (--n > 0 && next != DONE) { + next= next(); + } + return next; + } + + /* + * @see java.text.BreakIterator#next() + */ + public int next() { + fIndex= following(fIndex); + return fIndex; + } + + /* + * @see java.text.BreakIterator#previous() + */ + public int previous() { + fIndex= preceding(fIndex); + return fIndex; + } + + + /* + * @see java.text.BreakIterator#preceding(int) + */ + public int preceding(int offset) { + int first= fIterator.preceding(offset); + if (isWhitespace(first, offset)) { + int second= fIterator.preceding(first); + if (second != DONE && !isDelimiter(second, first)) + return second; + } + return first; + } + + /* + * @see java.text.BreakIterator#following(int) + */ + public int following(int offset) { + int first= fIterator.following(offset); + if (eatFollowingWhitespace(offset, first)) { + int second= fIterator.following(first); + if (isWhitespace(first, second)) + return second; + } + return first; + } + + private boolean eatFollowingWhitespace(int offset, int exclusiveEnd) { + if (exclusiveEnd == DONE || offset == DONE) + return false; + + if (isWhitespace(offset, exclusiveEnd)) + return false; + if (isDelimiter(offset, exclusiveEnd)) + return false; + + return true; + } + + /** + * Returnstrue
if the given sequence into the underlying text
+ * represents a delimiter, false
otherwise.
+ *
+ * @param offset the offset
+ * @param exclusiveEnd the end offset
+ * @return true
if the given range is a delimiter
+ */
+ private boolean isDelimiter(int offset, int exclusiveEnd) {
+ if (exclusiveEnd == DONE || offset == DONE)
+ return false;
+
+ Assert.isTrue(offset >= 0);
+ Assert.isTrue(exclusiveEnd <= getText().getEndIndex());
+ Assert.isTrue(exclusiveEnd > offset);
+
+ CharSequence seq= fIterator.fText;
+
+ while (offset < exclusiveEnd) {
+ char ch= seq.charAt(offset);
+ if (ch != '\n' && ch != '\r')
+ return false;
+ offset++;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true
if the given sequence into the underlying text
+ * represents whitespace, but not a delimiter, false
otherwise.
+ *
+ * @param offset the offset
+ * @param exclusiveEnd the end offset
+ * @return true
if the given range is whitespace
+ */
+ private boolean isWhitespace(int offset, int exclusiveEnd) {
+ if (exclusiveEnd == DONE || offset == DONE)
+ return false;
+
+ Assert.isTrue(offset >= 0);
+ Assert.isTrue(exclusiveEnd <= getText().getEndIndex());
+ Assert.isTrue(exclusiveEnd > offset);
+
+ CharSequence seq= fIterator.fText;
+
+ while (offset < exclusiveEnd) {
+ char ch= seq.charAt(offset);
+ if (!Character.isWhitespace(ch))
+ return false;
+ if (ch == '\n' || ch == '\r')
+ return false;
+ offset++;
+ }
+
+ return true;
+ }
+
+ /*
+ * @see java.text.BreakIterator#current()
+ */
+ public int current() {
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.BreakIterator#getText()
+ */
+ public CharacterIterator getText() {
+ return fIterator.getText();
+ }
+
+ /**
+ * Sets the text as CharSequence
.
+ * @param newText the new text
+ */
+ public void setText(CharSequence newText) {
+ fIterator.setText(newText);
+ first();
+ }
+
+ /*
+ * @see java.text.BreakIterator#setText(java.text.CharacterIterator)
+ */
+ public void setText(CharacterIterator newText) {
+ fIterator.setText(newText);
+ first();
+ }
+
+ /*
+ * @see java.text.BreakIterator#setText(java.lang.String)
+ */
+ public void setText(String newText) {
+ setText((CharSequence) newText);
+ }
+
+ /**
+ * Enables breaks at word boundaries inside a camel case identifier.
+ *
+ * @param camelCaseBreakEnabled true
to enable,
+ * false
to disable.
+ */
+ public void setCamelCaseBreakEnabled(boolean camelCaseBreakEnabled) {
+ fIterator.setCamelCaseBreakEnabled(camelCaseBreakEnabled);
+ }
+
+ /**
+ * @return true
if breaks at word boundaries inside
+ * a camel case identifier are enabled.
+ */
+ public boolean isCamelCaseBreakEnabled() {
+ return fIterator.isCamelCaseBreakEnabled();
+ }
+}
Index: src/org/eclipse/cdt/internal/ui/text/SequenceCharacterIterator.java
===================================================================
RCS file: src/org/eclipse/cdt/internal/ui/text/SequenceCharacterIterator.java
diff -N src/org/eclipse/cdt/internal/ui/text/SequenceCharacterIterator.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/cdt/internal/ui/text/SequenceCharacterIterator.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * 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.text;
+
+import java.text.CharacterIterator;
+
+import org.eclipse.jface.text.Assert;
+
+
+/**
+ * A CharSequence
based implementation of CharacterIterator
.
+ *
+ * @since 3.0
+ */
+public class SequenceCharacterIterator implements CharacterIterator {
+
+ private int fIndex= -1;
+ private final CharSequence fSequence;
+ private final int fFirst;
+ private final int fLast;
+
+ private void invariant() {
+ Assert.isTrue(fIndex >= fFirst);
+ Assert.isTrue(fIndex <= fLast);
+ }
+
+ /**
+ * Creates an iterator for the entire sequence.
+ *
+ * @param sequence the sequence backing this iterator
+ */
+ public SequenceCharacterIterator(CharSequence sequence) {
+ this(sequence, 0);
+ }
+
+ /**
+ * Creates an iterator.
+ *
+ * @param sequence the sequence backing this iterator
+ * @param first the first character to consider
+ * @throws IllegalArgumentException if the indices are out of bounds
+ */
+ public SequenceCharacterIterator(CharSequence sequence, int first) throws IllegalArgumentException {
+ this(sequence, first, sequence.length());
+ }
+
+ /**
+ * Creates an iterator.
+ *
+ * @param sequence the sequence backing this iterator
+ * @param first the first character to consider
+ * @param last the last character index to consider
+ * @throws IllegalArgumentException if the indices are out of bounds
+ */
+ public SequenceCharacterIterator(CharSequence sequence, int first, int last) throws IllegalArgumentException {
+ if (sequence == null)
+ throw new NullPointerException();
+ if (first < 0 || first > last)
+ throw new IllegalArgumentException();
+ if (last > sequence.length())
+ throw new IllegalArgumentException();
+ fSequence= sequence;
+ fFirst= first;
+ fLast= last;
+ fIndex= first;
+ invariant();
+ }
+
+ /*
+ * @see java.text.CharacterIterator#first()
+ */
+ public char first() {
+ return setIndex(getBeginIndex());
+ }
+
+ /*
+ * @see java.text.CharacterIterator#last()
+ */
+ public char last() {
+ if (fFirst == fLast)
+ return setIndex(getEndIndex());
+ else
+ return setIndex(getEndIndex() - 1);
+ }
+
+ /*
+ * @see java.text.CharacterIterator#current()
+ */
+ public char current() {
+ if (fIndex >= fFirst && fIndex < fLast)
+ return fSequence.charAt(fIndex);
+ else
+ return DONE;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#next()
+ */
+ public char next() {
+ return setIndex(Math.min(fIndex + 1, getEndIndex()));
+ }
+
+ /*
+ * @see java.text.CharacterIterator#previous()
+ */
+ public char previous() {
+ if (fIndex > getBeginIndex()) {
+ return setIndex(fIndex - 1);
+ } else {
+ return DONE;
+ }
+ }
+
+ /*
+ * @see java.text.CharacterIterator#setIndex(int)
+ */
+ public char setIndex(int position) {
+ if (position >= getBeginIndex() && position <= getEndIndex())
+ fIndex= position;
+ else
+ throw new IllegalArgumentException();
+
+ invariant();
+ return current();
+ }
+
+ /*
+ * @see java.text.CharacterIterator#getBeginIndex()
+ */
+ public int getBeginIndex() {
+ return fFirst;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#getEndIndex()
+ */
+ public int getEndIndex() {
+ return fLast;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#getIndex()
+ */
+ public int getIndex() {
+ return fIndex;
+ }
+
+ /*
+ * @see java.text.CharacterIterator#clone()
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+}
#P org.eclipse.cdt.ui.tests
Index: ui/org/eclipse/cdt/ui/tests/AutomatedSuite.java
===================================================================
RCS file: /home/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/AutomatedSuite.java,v
retrieving revision 1.35
diff -u -r1.35 AutomatedSuite.java
--- ui/org/eclipse/cdt/ui/tests/AutomatedSuite.java 3 Jul 2006 13:01:42 -0000 1.35
+++ ui/org/eclipse/cdt/ui/tests/AutomatedSuite.java 15 Jul 2006 05:33:47 -0000
@@ -15,6 +15,8 @@
import junit.framework.TestSuite;
import org.eclipse.cdt.ui.tests.text.CAutoIndentTest;
+import org.eclipse.cdt.ui.tests.text.CBreakIteratorTest;
+import org.eclipse.cdt.ui.tests.text.CWordIteratorTest;
import org.eclipse.cdt.ui.tests.text.NumberRuleTest;
import org.eclipse.cdt.ui.tests.text.contentassist.CompletionFailedTest_MemberReference_Arrow_Prefix2;
import org.eclipse.cdt.ui.tests.text.contentassist.CompletionTest_ArgumentType_NoPrefix;
@@ -136,6 +138,10 @@
addTest( CSelectionTestsDOMIndexer.suite() );
addTest( CPPSelectionTestsCTagsIndexer.suite() );
addTest( CSelectionTestsCTagsIndexer.suite() );
+
+ // Break iterator tests.
+ addTest(CBreakIteratorTest.suite());
+ addTest(CWordIteratorTest.suite());
}
}
Index: META-INF/MANIFEST.MF
===================================================================
RCS file: /home/tools/org.eclipse.cdt/all/org.eclipse.cdt.ui.tests/META-INF/MANIFEST.MF,v
retrieving revision 1.5
diff -u -r1.5 MANIFEST.MF
--- META-INF/MANIFEST.MF 24 May 2006 18:54:03 -0000 1.5
+++ META-INF/MANIFEST.MF 15 Jul 2006 05:33:47 -0000
@@ -32,6 +32,7 @@
org.eclipse.compare,
org.eclipse.ui.console,
org.eclipse.core.expressions,
- org.eclipse.cdt.make.core
+ org.eclipse.cdt.make.core,
+ com.ibm.icu
Eclipse-LazyStart: true
Bundle-Vendor: Eclipse.org
Index: ui/org/eclipse/cdt/ui/tests/text/CBreakIteratorTest.java
===================================================================
RCS file: ui/org/eclipse/cdt/ui/tests/text/CBreakIteratorTest.java
diff -N ui/org/eclipse/cdt/ui/tests/text/CBreakIteratorTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ui/org/eclipse/cdt/ui/tests/text/CBreakIteratorTest.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * 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
+ * Sergey Prigogin, Google
+ *******************************************************************************/
+package org.eclipse.cdt.ui.tests.text;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.cdt.internal.ui.text.CBreakIterator;
+
+
+public class CBreakIteratorTest extends BreakIteratorTest {
+
+ public static Test suite() {
+ return new TestSuite(CBreakIteratorTest.class);
+ }
+
+ /*
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ fBreakIterator= new CBreakIterator();
+ }
+
+ public void testNext1() {
+ assertNextPositions("word word", new int[] { 4, 5, 9 });
+ }
+
+ public void testNext2() {
+ assertNextPositions("wordWord word", new int[] { 4, 8, 9, 13 });
+ }
+
+ public void testNextSpace() {
+ assertNextPositions(" word ", new int[] { 1, 5, 6 });
+ }
+
+ public void testNextParen() {
+ assertNextPositions("word(params)", new int[] { 4, 5, 11, 12 });
+ }
+
+ public void testNextLn() {
+ String s= new String("word \n" +
+ " word2");
+ assertNextPositions(s, new int[] { 4, 5, 6, 8, 13 });
+ }
+
+ public void testMultiNextLn() {
+ String s= new String("word \n" +
+ "\n" +
+ "\n" +
+ " word2");
+ assertNextPositions(s, new int[] { 4, 5, 6, 7, 8, 10, 15 });
+ }
+
+ public void testMultiNextLn2() {
+ String s= new String("word \r\n" +
+ "\r\n" +
+ "\r\n" +
+ " word2");
+ assertNextPositions(s, new int[] { 4, 5, 7, 9, 11, 13, 18 });
+ }
+
+ public void testNextCamelCaseWord() {
+ String s= new String(" _isURLConnection_pool ");
+ assertNextPositions(s, new int[] { 3, 4, 6, 9, 20, 24, 27 });
+ }
+
+ public void testPrevious1() {
+ String s= new String("word word");
+ assertPreviousPositions(s, new int[] { 0, 4, 5 });
+ }
+
+ public void testPrevious2() {
+ String s= new String("wordWord word");
+ assertPreviousPositions(s, new int[] { 0, 4, 8, 9 });
+ }
+
+ public void testPreviousSpace() {
+ String s= new String(" word ");
+ assertPreviousPositions(s, new int[] { 1, 5 });
+ }
+
+ public void testPreviousParen() {
+ String s= new String("word(params)");
+ assertPreviousPositions(s, new int[] { 0, 4, 5, 11 });
+ }
+
+ public void testPreviousLn() {
+ String s= new String("word \n" +
+ " word2");
+ assertPreviousPositions(s, new int[] { 0, 4, 5, 6, 8 });
+ }
+
+ public void testMultiPreviousLn() {
+ String s= new String("word \n" +
+ "\n" +
+ "\n" +
+ " word2");
+ assertPreviousPositions(s, new int[] { 0, 4, 5, 6, 7, 8, 10 });
+ }
+
+ public void testMultiPreviousLn2() {
+ String s= new String("word \r\n" +
+ "\r\n" +
+ "\r\n" +
+ " word2");
+ assertPreviousPositions(s, new int[] { 0, 4, 5, 7, 9, 11, 13 });
+ }
+
+ public void testPreviousCamelCaseWord() {
+ String s= new String(" _isURLConnection_pool ");
+ assertPreviousPositions(s, new int[] { 0, 3, 4, 6, 9, 20, 24 });
+ }
+}
Index: ui/org/eclipse/cdt/ui/tests/text/BreakIteratorTest.java
===================================================================
RCS file: ui/org/eclipse/cdt/ui/tests/text/BreakIteratorTest.java
diff -N ui/org/eclipse/cdt/ui/tests/text/BreakIteratorTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ui/org/eclipse/cdt/ui/tests/text/BreakIteratorTest.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * 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
+ * Sergey Prigogin, Google
+ *******************************************************************************/
+package org.eclipse.cdt.ui.tests.text;
+
+import com.ibm.icu.text.BreakIterator;
+
+import junit.framework.TestCase;
+
+
+public class BreakIteratorTest extends TestCase {
+
+ protected BreakIterator fBreakIterator;
+
+ public void assertNextPositions(CharSequence ci, int position) {
+ assertNextPositions(ci, new int[] {position});
+ }
+
+ public void assertNextPositions(CharSequence ci, int[] positions) {
+ fBreakIterator.setText(ci.toString());
+
+ // test next()
+ for (int i = 0; i < positions.length; i++) {
+ int pos= fBreakIterator.next();
+ assertEquals(positions[i], pos);
+ }
+
+ // test following()
+ int idx= 0;
+ for (int i = 0; i < positions.length; i++) {
+ int position= positions[i];
+ while (idx < position) {
+ if (!illegalPos(ci, idx))
+ assertEquals(position, fBreakIterator.following(idx));
+ idx++;
+ }
+ }
+
+ }
+
+ /**
+ * Check if we are in a multibyte delimiter
+ * @param idx
+ * @return
+ */
+ private boolean illegalPos(CharSequence seq, int idx) {
+ String DELIMS= "\n\r";
+ if (idx == 0 || idx == seq.length())
+ return false;
+ char one= seq.charAt(idx - 1);
+ char two= seq.charAt(idx);
+ return one != two && DELIMS.indexOf(one) != -1 && DELIMS.indexOf(two) != -1;
+ }
+
+ public void assertPreviousPositions(CharSequence ci, int position) {
+ assertPreviousPositions(ci, new int[] {position});
+ }
+
+ public void assertPreviousPositions(CharSequence ci, int[] positions) {
+ fBreakIterator.setText(ci.toString());
+ fBreakIterator.last();
+
+ for (int i = positions.length - 1; i >= 0; i--) {
+ int pos= fBreakIterator.previous();
+ assertEquals(positions[i], pos);
+ }
+
+ // test preceding()
+ int idx= ci.length();
+ for (int i = positions.length - 1; i >= 0; i--) {
+ int position= positions[i];
+ while (idx > position) {
+ if (!illegalPos(ci, idx))
+ assertEquals(position, fBreakIterator.preceding(idx));
+ idx--;
+ }
+ }
+ }
+
+}
Index: ui/org/eclipse/cdt/ui/tests/text/CWordIteratorTest.java
===================================================================
RCS file: ui/org/eclipse/cdt/ui/tests/text/CWordIteratorTest.java
diff -N ui/org/eclipse/cdt/ui/tests/text/CWordIteratorTest.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ui/org/eclipse/cdt/ui/tests/text/CWordIteratorTest.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * 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
+ * Sergey Prigogin, Google
+******************************************************************************/
+package org.eclipse.cdt.ui.tests.text;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.cdt.internal.ui.text.CWordIterator;
+
+
+public class CWordIteratorTest extends BreakIteratorTest {
+
+ public static Test suite() {
+ return new TestSuite(CBreakIteratorTest.class);
+ }
+
+ /*
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ fBreakIterator= new CWordIterator();
+ }
+
+ public void testNext1() {
+ assertNextPositions("word word", new int[] { 5, 9 });
+ }
+
+ public void testNext2() {
+ assertNextPositions("wordWord word", new int[] { 4, 9, 13 });
+ }
+
+ public void testNextSpace() {
+ assertNextPositions(" word ", new int[] { 1, 6 });
+ }
+
+ public void testNextParen() {
+ assertNextPositions("word(params)", new int[] { 4, 5, 11, 12 });
+ }
+
+ public void testNextLn() {
+ String s= new String("word \n" +
+ " word2");
+ assertNextPositions(s, new int[] { 5, 6, 8, 13 });
+ }
+
+ public void testMultiNextLn() {
+ String s= new String("word \n" +
+ "\n" +
+ "\n" +
+ " word2");
+ assertNextPositions(s, new int[] { 5, 6, 7, 8, 10, 15 });
+ }
+
+ public void testMultiNextLn2() {
+ String s= new String("word \r\n" +
+ "\r\n" +
+ "\r\n" +
+ " word2");
+ assertNextPositions(s, new int[] { 5, 7, 9, 11, 13, 18 });
+ }
+
+ public void testNextCamelCaseWord() {
+ String s= new String(" _isURLConnection_pool ");
+ assertNextPositions(s, new int[] { 3, 4, 6, 9, 20, 27 });
+ }
+
+ public void testPrevious1() {
+ String s= new String("word word");
+ assertPreviousPositions(s, new int[] { 0, 5 });
+ }
+
+ public void testPrevious2() {
+ String s= new String("wordWord word");
+ assertPreviousPositions(s, new int[] { 0, 4, 9 });
+ }
+
+ public void testPreviousSpace() {
+ String s= new String(" word ");
+ assertPreviousPositions(s, new int[] { 1 });
+ }
+
+ public void testPreviousParen() {
+ String s= new String("word(params)");
+ assertPreviousPositions(s, new int[] { 0, 4, 5, 11 });
+ }
+
+ public void testPreviousLn() {
+ String s= new String("word \n" +
+ " word2");
+ assertPreviousPositions(s, new int[] { 0, 5, 6, 8 });
+ }
+
+ public void testMultiPreviousLn() {
+ String s= new String("word \n" +
+ "\n" +
+ "\n" +
+ " word2");
+ assertPreviousPositions(s, new int[] { 0, 5, 6, 7, 8, 10 });
+ }
+
+ public void testMultiPreviousLn2() {
+ String s= new String("word \r\n" +
+ "\r\n" +
+ "\r\n" +
+ " word2");
+ assertPreviousPositions(s, new int[] { 0, 5, 7, 9, 11, 13 });
+ }
+
+ public void testPreviousCamelCaseWord() {
+ String s= new String(" _isURLConnection_pool ");
+ assertPreviousPositions(s, new int[] { 0, 3, 4, 6, 9, 20 });
+ }
+
+}