### Eclipse Workspace Patch 1.0 #P org.eclipse.equinox.bidi Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/components/bundles/org.eclipse.equinox.bidi/META-INF/MANIFEST.MF,v retrieving revision 1.1 diff -u -r1.1 MANIFEST.MF --- META-INF/MANIFEST.MF 2 Feb 2010 21:55:26 -0000 1.1 +++ META-INF/MANIFEST.MF 3 Feb 2010 19:53:43 -0000 @@ -8,7 +8,13 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.4, CDC-1.1/Foundation-1.1 Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.equinox.bidi.complexp;version="1.0.0";x-internal:=true +Export-Package: org.eclipse.equinox.bidi.complexp, + org.eclipse.equinox.bidi.internal.complexp;x-internal:=true, + org.eclipse.equinox.bidi.internal.complexp.consumable;x-internal:=true Require-Bundle: org.eclipse.equinox.common;bundle-version="3.6.0", org.eclipse.equinox.registry;bundle-version="3.5.0" -Import-Package: org.eclipse.osgi.util;version="1.1.0" +Import-Package: org.eclipse.osgi.framework.log;version="1.0.0", + org.eclipse.osgi.util;version="1.1.0", + org.osgi.framework;version="1.5.0", + org.osgi.util.tracker;version="1.4.0" +Bundle-Activator: org.eclipse.equinox.bidi.internal.complexp.BiDiActivator Index: plugin.properties =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/components/bundles/org.eclipse.equinox.bidi/plugin.properties,v retrieving revision 1.1 diff -u -r1.1 plugin.properties --- plugin.properties 2 Feb 2010 21:55:25 -0000 1.1 +++ plugin.properties 3 Feb 2010 19:53:43 -0000 @@ -11,3 +11,15 @@ pluginName = Bidirectional Text Support providerName = Eclipse.org - Equinox bidiExpressionPointName = Add new complex expression type +bidiExtensionName = Default bi-directional processors +sqlProcessorName = Processor for SQL expressions +regexProcessorName = Processor for regular expressions +javaProcessorName = Processor for Java statements +commaProcessorName = Processor for comma-separated lists +emailProcessorName = Processor for E-mail addresses +fileProcessorName = Processor for file and directory names +propertyProcessorName = Processor for property file lines +systemProcessorName = Processor for System / user statements +underscoreProcessorName = Processor for names segmented by underscores +urlProcessorName = Processor for URLs +xpathProcessorName = Processor for XPath expressions Index: plugin.xml =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/components/bundles/org.eclipse.equinox.bidi/plugin.xml,v retrieving revision 1.1 diff -u -r1.1 plugin.xml --- plugin.xml 2 Feb 2010 21:55:25 -0000 1.1 +++ plugin.xml 3 Feb 2010 19:53:43 -0000 @@ -1,5 +1,70 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: schema/BiDiExpressionType.exsd =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/components/bundles/org.eclipse.equinox.bidi/schema/BiDiExpressionType.exsd,v retrieving revision 1.1 diff -u -r1.1 BiDiExpressionType.exsd --- schema/BiDiExpressionType.exsd 2 Feb 2010 21:55:26 -0000 1.1 +++ schema/BiDiExpressionType.exsd 3 Feb 2010 19:53:43 -0000 @@ -3,12 +3,11 @@ - + - This extension point provides guidelines about adding a new type of complex expression. Basically, such a new type is an extension of the ComplExpBasic class which specifies specific operators and, optionally, a number of special cases to handle. -<br> -See the javadoc for ComplExpBasic for explanations about constructors of ComplExpBasic and methods that an extension might override. + Use this extension point to describe processing for strings that need special Bi-directional handling, such as file paths, SQL expressions, or Java code. + @@ -19,6 +18,9 @@ + + + @@ -26,10 +28,10 @@ - + - + Unique identifier of this extension @@ -46,12 +48,44 @@ + + + + + + Type of the expression that this processor will work on. + + + + + + + The processor that provides specialized bi-directional handling for this type of strings. + + + + + + + + + + The description of the string type. + + + + + + + + + - 3.6 + 1.0 @@ -60,39 +94,18 @@ - Here is a most basic example. -<p> + A processor for the complex expressions that support "minus" delimiters can be described as: + <pre> -/* -* ComplExpSepMinus -*/ - -package example.complexpType; - -import org.eclipse.equinox.bidi.*; - -/** - * <code>ComplExpSepMinus</code> is a processor for complex expressions - * composed of text segments separated by minus signs. - * - */ public class ComplExpSepMinus extends ComplExpBasic { - /** - * Constructor for a complex expressions processor with support for - * minus delimiters. - * - */ public ComplExpSepMinus() { super("-"); } } </pre> -<p> -In the plug-in org.eclipse.equinox.bidi, the classes CompExpDelims, ComplExpDelimsEsc, ComplExpJava, ComplExpRegex, ComplExpSingle, ComplExpSql may be used as examples of extensions for ComplExpBasic. -<p> -Start with the very simple ComplExpSingle, then ComplExpDelims, ComplExpDelimsEsc, then all the rest. + Index: src/org/eclipse/equinox/bidi/complexp/ComplExpBasic.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpBasic.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpBasic.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpBasic.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,968 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpBasic is a - * complex expression processor for simple types of complex expressions. - * Normally, a group of operators is specified when creating a new - * instance. - * Lean text which is submitted to this processor is divided into - * segments by the operators. The processor adds directional formatting - * characters into the lean text to generate a full text where - * operators and text segments will be presented in left-to-right sequence. - * - * @see IComplExpProcessor - * - * @author Matitiahu Allouche - */ -public class ComplExpBasic implements IComplExpProcessor { - - final private static String EMPTY_STRING = ""; //$NON-NLS-1$ - - /** - * Flag specifying that a specific instance of complex expression should - * assume that the GUI is mirrored (globally going from right to left). - * This flag overrides the default flag mirroredDefault - * for the parent complex expression instance. - * @see #assumeMirrored - * @see #isMirrored - * @see ComplExpUtil#mirroredDefault - */ - protected boolean mirrored = ComplExpUtil.mirroredDefault; - - /** - * Orientation that should be assumed for the text component where the - * complex expression will be displayed. It can be specified using - * {@link #assumeOrientation}. - * It must be one of the values - * {@link IComplExpProcessor#ORIENT_LTR ORIENT_LTR}, - * {@link IComplExpProcessor#ORIENT_LTR ORIENT_RTL}, - * {@link IComplExpProcessor#ORIENT_CONTEXTUAL_LTR ORIENT_CONTEXTUAL_LTR} or - * {@link IComplExpProcessor#ORIENT_CONTEXTUAL_RTL ORIENT_CONTEXTUAL_RTL}. - * {@link IComplExpProcessor#ORIENT_UNKNOWN ORIENT_UNKNOWN}. - * {@link IComplExpProcessor#ORIENT_IGNORE ORIENT_IGNORE}. - * The default is ORIENT_LTR. - *

- * The orientation affects the addition of directional formatting - * characters as prefix and/or suffix when generating the full - * text of the complex expression. - * - * @see #assumeOrientation - * @see #recallOrientation - * @see #leanToFullText - */ - protected int orientation; - - /** - * Type of the complex expression processor specified when calling - * {@link ComplExpUtil#create} - */ - protected int type; - - /** - * Base direction of the complex expression. This is an array such that - *

- * Each of the elements in the array must be one of the values - * {@link IComplExpProcessor#DIRECTION_LTR DIRECTION_LTR}, - * {@link IComplExpProcessor#DIRECTION_LTR DIRECTION_RTL}. - * The default is DIRECTION_LTR. - * - * @see #setDirection(int) setDirection - * @see #getDirection getDirection - */ - protected int[][] direction = new int[2][2]; - - /** - * This field represents the final state achieved in a previous call to - * {@link IComplExpProcessor#leanToFullText leanToFullText} or - * {@link IComplExpProcessor#fullToLeanText fullToLeanText}, - * {@link IComplExpProcessor#leanBidiCharOffsets(java.lang.String text)} or - * {@link IComplExpProcessor#leanBidiCharOffsets(java.lang.String text, int initState)}. - * The state is an opaque value which makes sense only - * within calls to a same complex expression processor. - * The only externalized value is - * {@link IComplExpProcessor#STATE_NOTHING_GOING} which means that - * there is nothing to remember from the last call. - *

- * state should be used only for complex expressions - * which span more than one line, when the user makes a separate call to - * leanToFullText, fullToLeanText or - * leanBidiCharOffsets for each - * line in the expression. The final state value retrieved after the - * call for one line should be used as the initial state in the call - * which processes the next line. - *

- * If a line within a complex expression has already been processed by - * leanToFullText and the lean version of that line has - * not changed, and its initial state has not changed either, the user - * can be sure that the full version of that line is also - * identical to the result of the previous processing. - * - * @see IComplExpProcessor#getFinalState - * @see IComplExpProcessor#leanToFullText(String text, int initState) - * @see IComplExpProcessor#fullToLeanText(String text, int initState) - * @see IComplExpProcessor#leanBidiCharOffsets(String text, int initState) - */ - protected int state = STATE_NOTHING_GOING; - - private boolean ignoreArabic, ignoreHebrew; - - static final byte B = Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR; - static final byte L = Character.DIRECTIONALITY_LEFT_TO_RIGHT; - static final byte R = Character.DIRECTIONALITY_RIGHT_TO_LEFT; - static final byte AL = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC; - static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER; - static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER; - static final char LRM = 0x200E; - static final char RLM = 0x200F; - static final char LRE = 0x202A; - static final char RLE = 0x202B; - static final char PDF = 0x202C; - static final char[] MARKS = {LRM, RLM}; - static final char[] EMBEDS = {LRE, RLE}; - static final byte[] STRONGS = {L, R}; - static final int PREFIX_LENGTH = 2; - static final int SUFFIX_LENGTH = 2; - static final int FIXES_LENGTH = PREFIX_LENGTH + SUFFIX_LENGTH; - private byte curStrong = -1; - private char curMark; - private char curEmbed; - private int prefixLength; - char[] operators; - int operCount; - int[] locations; - int specialsCount; - int nextLocation; - int len; - private String leanText; - private int idxLocation; - private int[] offsets; - private int count, countLimit; - private int curPos; - // For positions where it has been looked up, the entry will receive - // the Character directionality + 2 (so that 0 indicates that the - // the directionality has not been looked up yet. - private byte[] dirProps; - // current UI orientation (after resolution if contextual) - private int curOrient = -1; - // Current expression base direction (after resolution if depending on - // script and/or on GUI mirroring (0=LTR, 1=RTL)) - private int curDirection = -1; - - /** - * Constructor specifying operators. The processor will add directional - * formatting characters to lean text to generate a full - * text so that the operators and the segments of text between operators - * are displayed from left to right, while each segment is displayed - * according to the UBA. - * - * @param operators string grouping one-character operators which - * separate the text of the complex expression into segments. - */ - public ComplExpBasic(String operators) { - this.operators = operators.toCharArray(); - operCount = this.operators.length; - locations = new int[operCount]; - } - - /** - * Constructor specifying operators and a number of special cases. - * In ComplExpBasic the special cases are implemented as - * doing nothing. Subclasses of ComplExpBasic may override - * methods indexOfSpecial and processSpecial - * to provide specific handling for the special cases. - * Examples of special cases are comments, literals, or anything which - * is not identified by a one-character operator. - *

- * Independently of the special cases, the processor will add directional - * formatting characters to lean text to generate a full - * text so that the operators and the segments of text between operators - * are displayed from left to right, while each segment is displayed - * according to the UBA. - * - * @param operators string grouping one-character operators which - * separate the text of the complex expression into segments. - * - * @param specialsCount number of special cases supported by this - * class. Handling of the special cases is implemented with - * methods indexOfSpecial and - * processSpecial. - * - * @see #indexOfSpecial indexOfSpecial - * @see #processSpecial processSpecial - */ - public ComplExpBasic(String operators, int specialsCount) { - this.operators = operators.toCharArray(); - operCount = this.operators.length; - this.specialsCount = specialsCount; - locations = new int[operCount + specialsCount]; - } - - public void selectBidiScript(boolean arabic, boolean hebrew) { - ignoreArabic = !arabic; - ignoreHebrew = !hebrew; - } - - public boolean handlesArabicScript() { - return !ignoreArabic; - } - - public boolean handlesHebrewScript() { - return !ignoreHebrew; - } - - void computeNextLocation() { - nextLocation = len; - // Start with special sequences to give them precedence over simple - // operators. This may apply to cases like slash+asterisk versus slash. - for (int i = 0; i < specialsCount; i++) { - int loc = locations[operCount + i]; - if (loc < curPos) { - loc = indexOfSpecial(i, leanText, curPos); - if (loc < 0) - loc = len; - locations[operCount + i] = loc; - } - if (loc < nextLocation) { - nextLocation = loc; - idxLocation = operCount + i; - } - } - for (int i = 0; i < operCount; i++) { - int loc = locations[i]; - if (loc < curPos) { - loc = leanText.indexOf(operators[i], curPos); - if (loc < 0) - loc = len; - locations[i] = loc; - } - if (loc < nextLocation) { - nextLocation = loc; - idxLocation = i; - } - } - } - - /** - * This method is called repeatedly by leanToFullText to - * locate all special cases specified in the constructor - * (see {@link #ComplExpBasic(String operators, int specialsCount)}), - * varying whichSpecial from zero to - * specialsCount - 1. It is meant to be overridden in - * subclasses of ComplExpBasic. - * Those subclasses may use methods - * {@link #getDirProp getDirProp}, - * {@link #setDirProp setDirProp} and - * {@link #insertMark insertMark} within indexOfSpecial. - * - * @param whichSpecial number of the special case to locate. The meaning - * of this number is internal to the class implementing - * indexOfSpecial. - * - * @param text text of the complex expression. - * - * @param fromIndex the index within leanText to start - * the search from. - * - * @return the position where the start of the special case was located. - * The method must return the first occurrence of whatever - * identifies the start of the special case after - * fromIndex. The method does not have to check if - * this occurrence appears within the scope of another special - * case (e.g. a comment starting delimiter within the scope of - * a literal or vice-versa). - * If no occurrence is found, the method must return -1. - *

- * In ComplExpBasic this method always returns -1. - * - */ - protected int indexOfSpecial(int whichSpecial, String text, int fromIndex) { - // This method must be overridden by all subclasses with special cases. - return -1; - } - - /** - * This method is called by leanToFullText - * when a special case occurrence is located by - * {@link #indexOfSpecial indexOfSpecial}. - * It is meant to be overridden in subclasses of ComplExpBasic. - * Those subclasses may use methods - * {@link #getDirProp getDirProp}, - * {@link #setDirProp setDirProp} and - * {@link #insertMark insertMark} within processSpecial. - *

- * If a special processing cannot be completed within a current call to - * processSpecial (for instance, a comment has been started - * in the current line but its end appears in a following line), - * processSpecial should put in the {@link #state} - * member of the class instance a number which characterizes this - * situation. On a later call to - * {@link IComplExpProcessor#leanToFullText(String text, int initState)} - * specifying that state value, processSpecial will be - * called with that value for parameter whichSpecial and - * -1 for parameter operLocation and should - * perform whatever initializations are required depending on the state. - * - * @param whichSpecial number of the special case to handle. - * - * @param text text of the complex expression. - * - * @param operLocation the position returned by indexOfSpecial. - * In calls to leanToFullText or - * fullToLeanText specifying an initState - * parameter, processSpecial is called when initializing - * the processing with the value of whichSpecial - * equal to initState and the value of - * operLocation equal to -1. - * - * @return the position after the scope of the special case ends. - * For instance, the position after the end of a comment, - * the position after the end of a literal. - *

- * In ComplExpBasic this method always returns - * operLocation + 1 (but it should never be called). - * - */ - protected int processSpecial(int whichSpecial, String text, int operLocation) { - // This method must be overridden by all subclasses with any special case. - return operLocation + 1; - } - - private int getCurOrient() { - if (curOrient >= 0) - return curOrient; - - if ((orientation & ORIENT_CONTEXTUAL_LTR) == 0) { - // absolute orientation - curOrient = orientation; - return curOrient; - } - // contextual orientation - byte dirProp; - for (int i = 0; i < len; i++) { - dirProp = dirProps[i]; - if (dirProp == 0) { - dirProp = Character.getDirectionality(leanText.charAt(i)); - if (dirProp == B) // B char resolves to L or R depending on orientation - continue; - dirProps[i] = (byte) (dirProp + 2); - } else { - dirProp -= 2; - } - if (dirProp == L) { - curOrient = ORIENT_LTR; - return curOrient; - } - if (dirProp == R || dirProp == AL) { - curOrient = ORIENT_RTL; - return curOrient; - } - } - curOrient = orientation & 1; - return curOrient; - } - - public int getCurDirection() { - if (curDirection >= 0) - return curDirection; - - curStrong = -1; - int idx2 = mirrored ? 1 : 0; - // same direction for Arabic and Hebrew? - if (direction[0][idx2] == direction[1][idx2]) { - curDirection = direction[0][idx2]; - return curDirection; - } - // check if Arabic or Hebrew letter comes first - byte dirProp; - for (int i = 0; i < len; i++) { - dirProp = getDirProp(i); - if (dirProp == AL) { - curDirection = direction[0][idx2]; - return curDirection; - } - if (dirProp == R) { - curDirection = direction[1][idx2]; - return curDirection; - } - } - // found no Arabic or Hebrew character - curDirection = DIRECTION_LTR; - return curDirection; - } - - private void setMarkAndFixes() { - int dir = getCurDirection(); - if (curStrong == STRONGS[dir]) - return; - curStrong = STRONGS[dir]; - curMark = MARKS[dir]; - curEmbed = EMBEDS[dir]; - } - - /** - * This method can be called from within {@link #indexOfSpecial indexOfSpecial} - * or {@link #processSpecial processSpecial} in subclasses of - * ComplExpBasic to retrieve the bidirectional class of - * characters in leanText. - * - * @param index position of the character in leanText. - * - * @return the bidirectional class of the character. It is one of the - * values which can be returned by - * java.lang.Character#getDirectionality. - * However, it is recommended to use getDirProp - * rather than java.lang.Character.getDirectionality - * since getDirProp manages a cache of character - * properties and so can be more efficient than calling the - * java.lang.Character method. - * - */ - protected byte getDirProp(int index) { - byte dirProp = dirProps[index]; - if (dirProp == 0) { - dirProp = Character.getDirectionality(leanText.charAt(index)); - if (dirProp == B) - dirProp = getCurOrient() == ORIENT_RTL ? R : L; - dirProps[index] = (byte) (dirProp + 2); - return dirProp; - } - return (byte) (dirProp - 2); - } - - /** - * This method can be called from within {@link #indexOfSpecial indexOfSpecial} - * or {@link #processSpecial processSpecial} in subclasses of - * ComplExpBasic to set or override the bidirectional - * class of characters in leanText. - * - * @param index position of the character in leanText. - * - * @param dirProp bidirectional class of the character. It is one of the - * values which can be returned by - * java.lang.Character.getDirectionality. - * - */ - protected void setDirProp(int index, byte dirProp) { - dirProps[index] = (byte) (dirProp + 2); - } - - /** - * This method can be called from within - * {@link #processSpecial processSpecial} in subclasses of - * ComplExpBasic to add a directional mark before an - * operator if needed for correct display, depending on the - * base direction of the expression and on the class of the - * characters in leanText preceding and following - * the operator itself. - * - * @param operLocation offset of the operator in leanText. - * - */ - protected void processOperator(int operLocation) { - boolean doneAN = false; - - if (getCurDirection() == DIRECTION_RTL) { - // the expression base direction is RTL - for (int i = operLocation - 1; i >= 0; i--) { - byte dirProp = getDirProp(i); - if (dirProp == R || dirProp == AL) - return; - - if (dirProp == L) { - for (int j = operLocation; j < len; j++) { - dirProp = getDirProp(j); - if (dirProp == R || dirProp == AL) - return; - if (dirProp == L || dirProp == EN) { - insertMark(operLocation); - return; - } - } - return; - } - } - return; - } - - // the expression base direction is LTR - if (ignoreArabic) { - if (ignoreHebrew) /* process neither Arabic nor Hebrew */ - return; - /* process Hebrew, not Arabic */ - for (int i = operLocation - 1; i >= 0; i--) { - byte dirProp = getDirProp(i); - if (dirProp == L) - return; - if (dirProp == R) { - for (int j = operLocation; j < len; j++) { - dirProp = getDirProp(j); - if (dirProp == L) - return; - if (dirProp == R || dirProp == EN) { - insertMark(operLocation); - return; - } - } - return; - } - } - } else { - if (ignoreHebrew) { /* process Arabic, not Hebrew */ - for (int i = operLocation - 1; i >= 0; i--) { - byte dirProp = getDirProp(i); - if (dirProp == L) - return; - if (dirProp == AL) { - for (int j = operLocation; j < len; j++) { - dirProp = getDirProp(j); - if (dirProp == L) - return; - if (dirProp == EN || dirProp == AL || dirProp == AN) { - insertMark(operLocation); - return; - } - } - return; - } - if (dirProp == AN && !doneAN) { - for (int j = operLocation; j < len; j++) { - dirProp = getDirProp(j); - if (dirProp == L) - return; - if (dirProp == AL || dirProp == AN) { - insertMark(operLocation); - return; - } - } - doneAN = true; - } - } - } else { /* process Arabic and Hebrew */ - for (int i = operLocation - 1; i >= 0; i--) { - byte dirProp = getDirProp(i); - if (dirProp == L) - return; - if (dirProp == R || dirProp == AL) { - for (int j = operLocation; j < len; j++) { - dirProp = getDirProp(j); - if (dirProp == L) - return; - if (dirProp == R || dirProp == EN || dirProp == AL || dirProp == AN) { - insertMark(operLocation); - return; - } - } - return; - } - if (dirProp == AN && !doneAN) { - for (int j = operLocation; j < len; j++) { - dirProp = getDirProp(j); - if (dirProp == L) - return; - if (dirProp == AL || dirProp == AN || dirProp == R) { - insertMark(operLocation); - return; - } - } - doneAN = true; - } - } - } - } - } - - public int getFinalState() { - return state; - } - - public String leanToFullText(String text) { - return leanToFullText(text, STATE_NOTHING_GOING); - } - - public String leanToFullText(String text, int initState) { - if (text.length() == 0) - return text; - leanToFullTextNofix(text, initState); - return addMarks(true); - } - - void leanToFullTextNofix(String text, int initState) { - leanText = text; - len = leanText.length(); - offsets = new int[20]; - count = 0; - countLimit = offsets.length - 1; - dirProps = new byte[len]; - curOrient = -1; - curDirection = -1; - curPos = 0; - // initialize locations - int k = locations.length; - for (int i = 0; i < k; i++) { - locations[i] = -1; - } - state = STATE_NOTHING_GOING; - nextLocation = -1; - if (initState != STATE_NOTHING_GOING) - curPos = processSpecial(initState, leanText, -1); - - while (true) { - computeNextLocation(); - if (nextLocation >= len) - break; - if (idxLocation < operCount) { - processOperator(nextLocation); - curPos = nextLocation + 1; - } else { - curPos = processSpecial(idxLocation - operCount, leanText, nextLocation); - } - } - } - - public int[] leanBidiCharOffsets(String text) { - return leanBidiCharOffsets(text, STATE_NOTHING_GOING); - } - - public int[] leanBidiCharOffsets(String text, int initState) { - leanToFullTextNofix(text, initState); - return leanBidiCharOffsets(); - } - - public int[] leanBidiCharOffsets() { - int[] result = new int[count]; - System.arraycopy(offsets, 0, result, 0, count); - return result; - } - - public int[] fullBidiCharOffsets() { - int lim = count; - if (prefixLength > 0) { - if (prefixLength == 1) - lim++; - else - lim += FIXES_LENGTH; - } - int[] fullOffsets = new int[lim]; - for (int i = 0; i < prefixLength; i++) { - fullOffsets[i] = i; - } - int added = prefixLength; - for (int i = 0; i < count; i++) { - fullOffsets[prefixLength + i] = offsets[i] + added; - added++; - } - if (prefixLength > 1) { - fullOffsets[lim - 2] = len + lim - 2; - fullOffsets[lim - 1] = len + lim - 1; - } - return fullOffsets; - } - - public String fullToLeanText(String text) { - return fullToLeanText(text, STATE_NOTHING_GOING); - } - - public String fullToLeanText(String text, int initState) { - int i; // TBD this variable is used for multiple unrelated tasks - setMarkAndFixes(); - // remove any prefix and leading mark - int lenText = text.length(); - for (i = 0; i < lenText; i++) { - char c = text.charAt(i); - if (c != curEmbed && c != curMark) - break; - } - if (i > 0) { - text = text.substring(i); - lenText = text.length(); - } - // remove any suffix and trailing mark - for (i = lenText - 1; i >= 0; i--) { - char c = text.charAt(i); - if (c != PDF && c != curMark) - break; - } - if (i < 0) { - leanText = EMPTY_STRING; - len = 0; - return leanText; - } - if (i < (lenText - 1)) { - text = text.substring(0, i + 1); - lenText = text.length(); - } - char[] chars = text.toCharArray(); - // remove marks from chars - int cnt = 0; - for (i = 0; i < lenText; i++) { - char c = chars[i]; - if (c == curMark) - cnt++; - else if (cnt > 0) - chars[i - cnt] = c; - } - String lean = new String(chars, 0, lenText - cnt); - leanToFullTextNofix(lean, initState); - String full = addMarks(false); /* only marks, no prefix/suffix */ - if (full.equals(text)) - return lean; - - // There are some marks in full which are not in text and/or vice versa. - // We need to add to lean any mark appearing in text and not in full. - // The completed lean can never be longer than text itself. - char[] newChars = new char[lenText]; - char cFull, cText; - int idxFull, idxText, idxLean, markPos, newCharsPos; - int lenFull = full.length(); - idxFull = idxText = idxLean = newCharsPos = 0; - while (idxText < lenText && idxFull < lenFull) { - cFull = full.charAt(idxFull); - cText = text.charAt(idxText); - if (cFull == cText) { /* chars are equal, proceed */ - idxText++; - idxFull++; - continue; - } - if (cFull == curMark) { /* extra Mark in full text */ - idxFull++; - continue; - } - if (cText == curMark) { /* extra Mark in source full text */ - idxText++; - // idxText-2 always >= 0 since leading Marks were removed from text - if (text.charAt(idxText - 2) == curMark) - continue; // ignore successive Marks in text after the first one - markPos = fullToLeanPos(idxFull); - // copy from chars (== lean) to newChars until here - for (i = idxLean; i < markPos; i++) { - newChars[newCharsPos++] = chars[i]; - } - idxLean = markPos; - newChars[newCharsPos++] = curMark; - continue; - } - // we should never get here (extra char which is not a Mark) - throw new IllegalStateException("Internal error: extra character not a Mark."); //$NON-NLS-1$ - } - if (idxText < lenText) /* full ended before text - this should never happen */ - throw new IllegalStateException("Internal error: unexpected EOL."); //$NON-NLS-1$ - - // copy the last part of chars to newChars - for (i = idxLean; i < lean.length(); i++) { - newChars[newCharsPos++] = chars[i]; - } - lean = new String(newChars, 0, newCharsPos); - leanText = lean; - len = leanText.length(); - return lean; - } - - public int leanToFullPos(int pos) { - int added = prefixLength; - for (int i = 0; i < count; i++) { - if (offsets[i] <= pos) - added++; - else - return pos + added; - } - return pos + added; - } - - public int fullToLeanPos(int pos) { - pos -= prefixLength; - int added = 0; - for (int i = 0; i < count; i++) { - if ((offsets[i] + added) < pos) - added++; - else - break; - } - pos -= added; - if (pos < 0) - pos = 0; - else if (pos > len) - pos = len; - return pos; - } - - /** - * This method can be called from within {@link #indexOfSpecial} or - * {@link #processSpecial} in subclasses of ComplExpBasic - * to specify that a mark character must be added before the character - * at the specified position of the lean text when generating the - * full text. The mark character will be LRM for complex expressions - * with a LTR base direction, and RLM for complex expressions with RTL - * base direction. The mark character is not added physically by this - * method, but its position is noted and will be used when generating - * the full text. - * - * @param offset position of the character in leanText. - * It must be a non-negative number smaller than the length - * of the lean text. - * For the benefit of efficiency, it is better to insert - * multiple marks in ascending order of the offsets. - * - */ - protected void insertMark(int offset) { - int index = count - 1; // index of greatest member <= offset - // look up after which member the new offset should be inserted - while (index >= 0) { - int wrkOffset = offsets[index]; - if (offset > wrkOffset) - break; - if (offset == wrkOffset) - return; // avoid duplicates - index--; - } - index++; // index now points at where to insert - // check if we have an available slot for new member - if (count >= countLimit) { - int[] newOffsets = new int[offsets.length * 2]; - System.arraycopy(offsets, 0, newOffsets, 0, count); - offsets = newOffsets; - countLimit = offsets.length - 1; - } - - int length = count - index; // number of members to move up - if (length > 0) // shift right all members greater than offset - System.arraycopy(offsets, index, offsets, index + 1, length); - - offsets[index] = offset; - count++; - // if the offset is 0, adding a mark does not change anything - if (offset < 1) - return; - - byte dirProp = getDirProp(offset); - // if the current char is a strong one or a digit, we change the - // dirProp of the previous char to account for the inserted mark - if (dirProp == L || dirProp == R || dirProp == AL || dirProp == EN || dirProp == AN) - index = offset - 1; - else - // if the current char is a neutral, we change its own dirProp - index = offset; - setMarkAndFixes(); - setDirProp(index, curStrong); - } - - private String addMarks(boolean addFixes) { - // add prefix/suffix only if addFixes is true - if ((count == 0) && (!addFixes || (getCurOrient() == getCurDirection()) || (curOrient == ORIENT_IGNORE))) { - prefixLength = 0; - return leanText; - } - int newLen = len + count; - if (addFixes && ((getCurOrient() != getCurDirection()) || (curOrient == ORIENT_UNKNOWN))) { - if ((orientation & ORIENT_CONTEXTUAL_LTR) == 0) { - prefixLength = PREFIX_LENGTH; - newLen += FIXES_LENGTH; - } else { /* contextual orientation */ - prefixLength = 1; - newLen++; /* +1 for a mark char */ - } - } else { - prefixLength = 0; - } - char[] fullChars = new char[newLen]; - // add a dummy offset as fence - offsets[count] = len; - int added = prefixLength; - // add marks at offsets - setMarkAndFixes(); - for (int i = 0, j = 0; i < len; i++) { - char c = leanText.charAt(i); - if (i == offsets[j]) { - fullChars[i + added] = curMark; - added++; - j++; - } - fullChars[i + added] = c; - } - if (prefixLength > 0) { /* add prefix/suffix ? */ - if (prefixLength == 1) { /* contextual orientation */ - fullChars[0] = curMark; - } else { - // When the orientation is RTL, we need to add EMBED at the - // start of the text and PDF at its end. - // However, because of a bug in Windows' handling of LRE/PDF, - // we add EMBED_PREFIX at the start and EMBED_SUFFIX at the end. - fullChars[0] = curEmbed; - fullChars[1] = curMark; - fullChars[newLen - 1] = PDF; - fullChars[newLen - 2] = curMark; - } - } - return new String(fullChars); - } - - public void assumeMirrored(boolean shouldBeMirrored) { - mirrored = shouldBeMirrored; - curDirection = -1; - } - - public boolean isMirrored() { - return mirrored; - } - - public void assumeOrientation(int desiredOrientation) { - if (desiredOrientation < ORIENT_LTR || desiredOrientation > ORIENT_IGNORE) - orientation = ORIENT_UNKNOWN; // TBD should throw new IllegalArgumentException()? - orientation = desiredOrientation; - } - - public int recallOrientation() { - return orientation; - } - - public void setArabicDirection(int not_mirrored, int mirrored) { - direction[0][0] = not_mirrored & 1; - direction[0][1] = mirrored & 1; - curDirection = -1; - } - - public void setArabicDirection(int direction) { - setArabicDirection(direction, direction); - } - - public void setHebrewDirection(int not_mirrored, int mirrored) { - direction[1][0] = not_mirrored & 1; - direction[1][1] = mirrored & 1; - curDirection = -1; - } - - public void setHebrewDirection(int direction) { - setHebrewDirection(direction, direction); - } - - public void setDirection(int not_mirrored, int mirrored) { - setArabicDirection(not_mirrored, mirrored); - setHebrewDirection(not_mirrored, mirrored); - } - - public void setDirection(int direction) { - setDirection(direction, direction); - } - - public int[][] getDirection() { - return direction; - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpDelims.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpDelims.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpDelims.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpDelims.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpDelims is a processor for complex expressions - * composed of text segments separated by operators where the text segments - * may include delimited parts within which operators are treated like - * regular characters. - * - * @see IComplExpProcessor - * @see ComplExpBasic - * - * @author Matitiahu Allouche - */ -public class ComplExpDelims extends ComplExpBasic { - char[] delims; - - /** - * Constructor for a complex expressions processor with support for - * operators and delimiters. - * - * @param operators string grouping one-character operators which - * separate the text of the complex expression into segments. - * - * @param delims delimiters implemented in this class instance. - * This parameter is a string which must include an even - * number of characters. The first 2 characters of a string - * constitute a pair, the next 2 characters are a second pair, etc... - * In each pair, the first character is a start delimiter and - * the second character is an end delimiter. In the lean - * text, any part starting with a start delimiter and ending with - * the corresponding end delimiter is a delimited part. Within a - * delimited part, operators are treated like regular characters, - * which means that they do not define new segments. - */ - public ComplExpDelims(String operators, String delims) { - super(operators, delims.length() / 2); - this.delims = delims.toCharArray(); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { - char delim = delims[whichSpecial * 2]; - - return leanText.indexOf(delim, fromIndex); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int processSpecial(int whichSpecial, String leanText, int operLocation) { - processOperator(operLocation); - int loc = operLocation + 1; - char delim = delims[(whichSpecial * 2) + 1]; - loc = leanText.indexOf(delim, loc); - if (loc < 0) - return leanText.length(); - return loc + 1; - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpDelimsEsc.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpDelimsEsc.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpDelimsEsc.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpDelimsEsc.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpDelims is a processor for complex expressions - * composed of text segments separated by operators where the text segments - * may include delimited parts within which operators are treated like - * regular characters and the delimiters may be escaped. - * This is similar to {@link ComplExpDelims} except - * that delimiters can be escaped using the backslash character. - *

- * - * @see IComplExpProcessor - * @see ComplExpBasic - * - * @author Matitiahu Allouche - */ -public class ComplExpDelimsEsc extends ComplExpDelims { - /** - * Constructor for a complex expressions processor with support for - * operators and delimiters which can be escaped. - * - * @param operators string grouping one-character operators which - * separate the text of the complex expression into segments. - * - * @param delims delimiters implemented in this class instance. - * This parameter is a string which must include an even - * number of characters. The first 2 characters of a string - * constitute a pair, the next 2 characters are a second pair, etc... - * In each pair, the first character is a start delimiter and - * the second character is an end delimiter. In the lean - * text, any part starting with a start delimiter and ending with - * the corresponding end delimiter is a delimited part. Within a - * delimited part, operators are treated like regular characters, - * which means that they do not define new segments.
- *  
- * Note however that an ending delimiter preceded by an odd - * number of backslashes is considered as a regular character - * and does not mark the termination of a delimited part. - */ - public ComplExpDelimsEsc(String operators, String delims) { - super(operators, delims); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int processSpecial(int whichSpecial, String leanText, int operLocation) { - processOperator(operLocation); - int loc = operLocation + 1; - char delim = delims[(whichSpecial * 2) + 1]; - while (true) { - loc = leanText.indexOf(delim, loc); - if (loc < 0) - return leanText.length(); - int cnt = 0; - for (int i = loc - 1; leanText.charAt(i) == '\\'; i--) { - cnt++; - } - loc++; - if ((cnt & 1) == 0) - return loc; - } - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpDoNothing.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpDoNothing.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpDoNothing.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpDoNothing.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,246 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * This class is a minimal processor which implements the - * IComplExpProcessor interface but does no real processing. - * Since it is optimized for minimal overhead, it can - * be used as a low-cost default processor when no complex expression is - * involved and no processing is needed, but a general framework of - * handling complex expressions must be preserved. - * - * @author Matitiahu Allouche - */ - -public class ComplExpDoNothing implements IComplExpProcessor { - - private static final int[] EMPTY_INT_ARRAY = new int[0]; - private static final int[][] ALL_LTR = new int[][] { {DIRECTION_LTR, DIRECTION_LTR}, {DIRECTION_LTR, DIRECTION_LTR}}; - - /** - * Allocate a ComplExpDoNothing processor instance. - * Such a processor does not modify text submitted to it, and can be - * used as a place holder when the text to process is not a known - * complex expression. - */ - public ComplExpDoNothing() { - return; - } - - /** - * For class ComplExpDoNothing - * this method does nothing. - */ - public void selectBidiScript(boolean arabic, boolean hebrew) { - // empty - } - - /** - * For class ComplExpDoNothing - * this method always returns false. - */ - public boolean handlesArabicScript() { - return false; - } - - /** - * For class ComplExpDoNothing - * this method always returns false. - */ - public boolean handlesHebrewScript() { - return false; - } - - /** - * For class ComplExpDoNothing this method - * returns a string identical to the text parameter. - */ - public String leanToFullText(String text) { - return text; - } - - /** - * For class ComplExpDoNothing this method - * returns a string identical to the text parameter. - */ - public String leanToFullText(String text, int initState) { - return text; - } - - /** - * For class ComplExpDoNothing this method - * returns a zero length array. - */ - public int[] leanBidiCharOffsets(String text) { - return EMPTY_INT_ARRAY; - } - - /** - * For class ComplExpDoNothing this method - * returns a zero length array. - */ - public int[] leanBidiCharOffsets(String text, int initState) { - return EMPTY_INT_ARRAY; - } - - /** - * For class ComplExpDoNothing this method - * returns a zero length array. - */ - public int[] leanBidiCharOffsets() { - return EMPTY_INT_ARRAY; - } - - /** - * For class ComplExpDoNothing this method - * returns a zero length array. - */ - public int[] fullBidiCharOffsets() { - return EMPTY_INT_ARRAY; - } - - /** - * For class ComplExpDoNothing this method - * returns a string identical to the text parameter. - */ - public String fullToLeanText(String text) { - return text; - } - - /** - * For class ComplExpDoNothing this method - * returns a string identical to the text parameter. - */ - public String fullToLeanText(String text, int initState) { - return text; - } - - /** - * For class ComplExpDoNothing this method - * returns value {@link #STATE_NOTHING_GOING}. - */ - public int getFinalState() { - return STATE_NOTHING_GOING; - } - - /** - * For class ComplExpDoNothing this method - * returns an index identical to the pos parameter. - */ - public int leanToFullPos(int pos) { - return pos; - } - - /** - * For class ComplExpDoNothing this method - * returns an index identical to the pos parameter. - */ - public int fullToLeanPos(int pos) { - return pos; - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void assumeMirrored(boolean mirrored) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * always returns false. - */ - public boolean isMirrored() { - return false; - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void assumeOrientation(int orientation) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * always returns ORIENT_LTR. - */ - public int recallOrientation() { - return ORIENT_LTR; - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void setArabicDirection(int not_mirrored, int mirrored) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void setArabicDirection(int direction) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void setHebrewDirection(int not_mirrored, int mirrored) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void setHebrewDirection(int direction) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void setDirection(int not_mirrored, int mirrored) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * does nothing. - */ - public void setDirection(int direction) { - // empty - } - - /** - * For class ComplExpDoNothing this method - * returns all directions as DIRECTION_LTR. - */ - public int[][] getDirection() { - return ALL_LTR; - } - - /** - * For class ComplExpDoNothing this method - * returns DIRECTION_LTR. - */ - public int getCurDirection() { - return DIRECTION_LTR; - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpFactory.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpFactory.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/complexp/ComplExpFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.complexp; + +import org.eclipse.equinox.bidi.internal.complexp.BiDiTypesCollector; + +/** + * @noinstantiate This class is not intended to be instantiated by clients. + */ +// TBD do we really want to provide individual instances of the text processors? +final public class ComplExpFactory implements IBiDiProcessor { + + /** + * Factory method to create a new instance of the bi-directional text + * processor for the specified text type. This method may return null + * if it is unable to locate processor for the specified text type. + * + * @see #PROPERTY + * @see #UNDERSCORE + * @see #COMMA_DELIMITED + * @see #SYSTEM_USER + * @see #FILE + * @see #EMAIL + * @see #URL + * @see #REGEXP + * @see #XPATH + * @see #JAVA + * @see #SQL + * @see #RTL_ARITHMETIC + * + * @param type specifies the type of complex expression to process. + * @return a IComplExpProcessor instance capable of handling + * the type of complex expression specified. May return null + * if the processor not found. + */ + public static IComplExpProcessor create(String type) { + return BiDiTypesCollector.getInstance().makeProcessor(type); + } + +} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpJava.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpJava.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpJava.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpJava.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,116 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpJava is a processor for complex expressions - * composed of Java statements. Such a complex expression may span - * multiple lines. - *

- * In applications like an editor where parts of the text might be modified - * while other parts are not, the user may want to call - * {@link IComplExpProcessor#leanToFullText leanToFullText} - * separately on each line and save the initial state of each line (this is - * the final state of the previous line which can be retrieved using - * {@link IComplExpProcessor#getFinalState getFinalState}. If both the content - * of a line and its initial state have not changed, the user can be sure that - * the last full text computed for this line has not changed either. - * - * @see IComplExpProcessor - * @see ComplExpBasic#state - * - * @author Matitiahu Allouche - */ -public class ComplExpJava extends ComplExpBasic { - private static final byte WS = Character.DIRECTIONALITY_WHITESPACE; - static final String operators = "[](){}.+-<>=~!&*/%^|?:,;\t"; - static String lineSep; - - /** - * Constructor for a complex expressions processor with support for - * Java statements. - */ - public ComplExpJava() { - super(operators, 4); - // TBD use bundle properties - if (lineSep == null) - lineSep = System.getProperty("line.separator", "\n"); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { - switch (whichSpecial) { - case 0 : /* space */ - return leanText.indexOf(' ', fromIndex); - case 1 : /* literal */ - return leanText.indexOf('"', fromIndex); - case 2 : /* slash-aster comment */ - return leanText.indexOf("/*", fromIndex); - case 3 : /* slash-slash comment */ - return leanText.indexOf("//", fromIndex); - } - // we should never get here - return -1; - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int processSpecial(int whichSpecial, String leanText, int operLocation) { - int loc, cnt, i; - - processOperator(operLocation); - switch (whichSpecial) { - case 0 : /* space */ - operLocation++; - while (operLocation < leanText.length() && leanText.charAt(operLocation) == ' ') { - setDirProp(operLocation, WS); - operLocation++; - } - return operLocation; - case 1 : /* literal */ - loc = operLocation + 1; - while (true) { - loc = leanText.indexOf('"', loc); - if (loc < 0) - return leanText.length(); - for (cnt = 0, i = loc - 1; leanText.charAt(i) == '\\'; i--) { - cnt++; - } - loc++; - if ((cnt & 1) == 0) - return loc; - } - case 2 : /* slash-aster comment */ - if (operLocation < 0) - loc = 0; // initial state from previous line - else - loc = operLocation + 2; // skip the opening slash-aster - loc = leanText.indexOf("*/", loc); - if (loc < 0) { - state = 2; - return leanText.length(); - } - return loc + 2; - case 3 : /* slash-slash comment */ - loc = leanText.indexOf(lineSep, operLocation + 2); - if (loc < 0) - return leanText.length(); - return loc + lineSep.length(); - } - // we should never get here - return operLocation + 1; - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpRegex.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpRegex.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpRegex.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpRegex.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,200 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpRegex is a processor for regular expressions. - * Such expressions may span multiple lines. - *

- * In applications like an editor where parts of the text might be modified - * while other parts are not, the user may want to call - * {@link IComplExpProcessor#leanToFullText leanToFullText} - * separately on each line and save the initial state of each line (this is - * the final state of the previous line which can be retrieved using - * {@link IComplExpProcessor#getFinalState getFinalState}. If both the content - * of a line and its initial state have not changed, the user can be sure that - * the last full text computed for this line has not changed either. - * - * @see IComplExpProcessor - * @see ComplExpBasic#state - * - * @author Matitiahu Allouche - */ -public class ComplExpRegex extends ComplExpBasic { - static final String operators = ""; - static final String[] startStrings = {"(?#", /* 0 *//* comment (?#...) */ - "(?<", /* 1 *//* named group (? */ - "(?'", /* 2 *//* named group (?'name' */ - "(?(<", /* 3 *//* conditional named back reference (?() */ - "(?('", /* 4 *//* conditional named back reference (?('name') */ - "(?(", /* 5 *//* conditional named back reference (?(name) */ - "(?&", /* 6 *//* named parentheses reference (?&name) */ - "(?P<", /* 7 *//* named group (?P */ - "\\k<", /* 8 *//* named back reference \k */ - "\\k'", /* 9 *//* named back reference \k'name' */ - "\\k{", /* 10 *//* named back reference \k{name} */ - "(?P=", /* 11 *//* named back reference (?P=name) */ - "\\g{", /* 12 *//* named back reference \g{name} */ - "\\g<", /* 13 *//* subroutine call \g */ - "\\g'", /* 14 *//* subroutine call \g'name' */ - "(?(R&", /* 15 *//* named back reference recursion (?(R&name) */ - "\\Q" /* 16 *//* quoted sequence \Q...\E */ - }; - static final char[] endChars = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - ')', '>', '\'', ')', ')', ')', ')', '>', '>', '\'', '}', ')', '}', '>', '\'', ')'}; - static final int numberOfStrings = startStrings.length; - static final int maxSpecial = numberOfStrings + 1; - - /** - * Constructor for a complex expressions processor with support for - * regular expressions. - */ - public ComplExpRegex() { - super(operators, maxSpecial); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { - byte dirProp; - - if (whichSpecial < numberOfStrings) { - /* 0 *//* comment (?#...) */ - /* 1 *//* named group (? */ - /* 2 *//* named group (?'name' */ - /* 3 *//* conditional named back reference (?(name) */ - /* 4 *//* conditional named back reference (?() */ - /* 5 *//* conditional named back reference (?('name') */ - /* 6 *//* named parentheses reference (?&name) */ - /* 7 *//* named group (?P */ - /* 8 *//* named back reference \k */ - /* 9 *//* named back reference \k'name' */ - /* 10 *//* named back reference \k{name} */ - /* 11 *//* named back reference (?P=name) */ - /* 12 *//* named back reference \g{name} */ - /* 13 *//* subroutine call \g */ - /* 14 *//* subroutine call \g'name' */ - /* 15 *//* named back reference recursion (?(R&name) */ - /* 16 *//* quoted sequence \Q...\E */ - return leanText.indexOf(startStrings[whichSpecial], fromIndex); - } - // look for R, AL, AN, EN which are potentially needing a mark - for (; fromIndex < leanText.length(); fromIndex++) { - // there never is a need for a mark before the first char - if (fromIndex <= 0) - continue; - - dirProp = getDirProp(fromIndex); - // R and AL will always be examined using processOperator() - if (dirProp == R || dirProp == AL) - return fromIndex; - - if (dirProp == EN || dirProp == AN) { - // no need for a mark after the first digit in a number - if (getDirProp(fromIndex - 1) == dirProp) - continue; - - for (int i = fromIndex - 1; i >= 0; i--) { - dirProp = getDirProp(i); - // after a L char, no need for a mark - if (dirProp == L) - continue; - - // digit after R or AL or AN need a mark, except for EN - // following AN, but this is a contrived case, so we - // don't check for it (and calling processOperator() - // for it will do no harm) - if (dirProp == R || dirProp == AL || dirProp == AN) - return fromIndex; - } - continue; - } - } - return -1; - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int processSpecial(int whichSpecial, String leanText, int operLocation) { - int loc; - - switch (whichSpecial) { - case 0 : /* comment (?#...) */ - if (operLocation < 0) { - // initial state from previous line - loc = 0; - } else { - processOperator(operLocation); - // skip the opening "(?#" - loc = operLocation + 3; - } - loc = leanText.indexOf(')', loc); - if (loc < 0) { - state = whichSpecial; - return leanText.length(); - } - return loc + 1; - case 1 : /* named group (? */ - case 2 : /* named group (?'name' */ - case 3 : /* conditional named back reference (?(name) */ - case 4 : /* conditional named back reference (?() */ - case 5 : /* conditional named back reference (?('name') */ - case 6 : /* named parentheses reference (?&name) */ - processOperator(operLocation); - // no need for calling processOperator() for the following cases - // since the starting string contains a L char - case 7 : /* named group (?P */ - case 8 : /* named back reference \k */ - case 9 : /* named back reference \k'name' */ - case 10 : /* named back reference \k{name} */ - case 11 : /* named back reference (?P=name) */ - case 12 : /* named back reference \g{name} */ - case 13 : /* subroutine call \g */ - case 14 : /* subroutine call \g'name' */ - case 15 : /* named back reference recursion (?(R&name) */ - // skip the opening string - loc = operLocation + startStrings[whichSpecial].length(); - // look for ending character - loc = leanText.indexOf(endChars[whichSpecial], loc); - if (loc < 0) - return leanText.length(); - return loc + 1; - case 16 : /* quoted sequence \Q...\E */ - if (operLocation < 0) { - // initial state from previous line - loc = 0; - } else { - processOperator(operLocation); - // skip the opening "\Q" - loc = operLocation + 2; - } - loc = leanText.indexOf("\\E", loc); - if (loc < 0) { - state = whichSpecial; - return leanText.length(); - } - // set the dirProp for the "E" - setDirProp(loc + 1, L); - return loc + 2; - case 17 : /* R, AL, AN, EN */ - processOperator(operLocation); - return operLocation + 1; - - } - // we should never get here - return leanText.length(); - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpSingle.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpSingle.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpSingle.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpSingle.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpSingle is a processor for complex expressions - * composed of two parts separated by an operator. - * The first occurrence of the operator delimits the end of the first part - * and the start of the second part. Further occurrences of the operator, - * if any, are treated like regular characters of the second text part. - * The processor makes sure that the expression be presented in the form - * (assuming that the equal sign is the operator): - *

- *  part1=part2
- *  
- * - * @see IComplExpProcessor - * @see ComplExpBasic - * - * @author Matitiahu Allouche - */ -public class ComplExpSingle extends ComplExpBasic { - char separator; - - /** - * Constructor for a complex expressions processor with support for one - * operator. - * - * @param operators string including at least one character. The - * first character of the string is the operator which divides - * the expression into 2 parts. - * - */ - public ComplExpSingle(String operators) { - super(operators, 1); - separator = operators.charAt(0); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { - return leanText.indexOf(separator, fromIndex); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int processSpecial(int whichSpecial, String leanText, int operLocation) { - processOperator(operLocation); - return leanText.length(); - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpSql.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/ComplExpSql.java diff -N src/org/eclipse/equinox/bidi/complexp/ComplExpSql.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpSql.java 2 Feb 2010 21:55:25 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,135 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 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.equinox.bidi.complexp; - -/** - * ComplExpSql is a processor for complex expressions - * composed of SQL statements. Such a complex expression may span - * multiple lines. - *

- * In applications like an editor where parts of the text might be modified - * while other parts are not, the user may want to call - * {@link IComplExpProcessor#leanToFullText leanToFullText} - * separately on each line and save the initial state of each line (this is - * the final state of the previous line which can be retrieved using - * {@link IComplExpProcessor#getFinalState getFinalState}. If both the content - * of a line and its initial state have not changed, the user can be sure that - * the last full text computed for this line has not changed either. - * - * @see IComplExpProcessor - * @see ComplExpBasic#state - * - * @author Matitiahu Allouche - */ -public class ComplExpSql extends ComplExpBasic { - private static final byte WS = Character.DIRECTIONALITY_WHITESPACE; - static final String operators = "\t!#%&()*+,-./:;<=>?|[]{}"; - static String lineSep; - - /** - * Constructor for a complex expressions processor with support for - * SQL statements. - */ - public ComplExpSql() { - super(operators, 5); - // TBD use bundle properties - if (lineSep == null) - lineSep = System.getProperty("line.separator", "\n"); - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { - switch (whichSpecial) { - case 0 : /* space */ - return leanText.indexOf(" ", fromIndex); - case 1 : /* literal */ - return leanText.indexOf('\'', fromIndex); - case 2 : /* delimited identifier */ - return leanText.indexOf('"', fromIndex); - case 3 : /* slash-aster comment */ - return leanText.indexOf("/*", fromIndex); - case 4 : /* hyphen-hyphen comment */ - return leanText.indexOf("--", fromIndex); - } - // we should never get here - return -1; - } - - /** - * This method is not supposed to be invoked directly by users of this - * class. It may be overridden by subclasses of this class. - */ - protected int processSpecial(int whichSpecial, String leanText, int operLocation) { - int loc; - - processOperator(operLocation); - switch (whichSpecial) { - case 0 : /* space */ - operLocation++; - while (operLocation < leanText.length() && leanText.charAt(operLocation) == ' ') { - setDirProp(operLocation, WS); - operLocation++; - } - return operLocation; - case 1 : /* literal */ - loc = operLocation + 1; - while (true) { - loc = leanText.indexOf('\'', loc); - if (loc < 0) { - state = whichSpecial; - return leanText.length(); - } - if ((loc + 1) < leanText.length() && leanText.charAt(loc + 1) == '\'') { - loc += 2; - continue; - } - return loc + 1; - } - case 2 : /* delimited identifier */ - loc = operLocation + 1; - while (true) { - loc = leanText.indexOf('"', loc); - if (loc < 0) - return leanText.length(); - - if ((loc + 1) < leanText.length() && leanText.charAt(loc + 1) == '"') { - loc += 2; - continue; - } - return loc + 1; - } - case 3 : /* slash-aster comment */ - if (operLocation < 0) - loc = 0; // initial state from previous line - else - loc = operLocation + 2; // skip the opening slash-aster - loc = leanText.indexOf("*/", loc); - if (loc < 0) { - state = whichSpecial; - return leanText.length(); - } - // we need to call processOperator since text may follow the - // end of comment immediately without even a space - processOperator(loc); - return loc + 2; - case 4 : /* hyphen-hyphen comment */ - loc = leanText.indexOf(lineSep, operLocation + 2); - if (loc < 0) - return leanText.length(); - return loc + lineSep.length(); - } - // we should never get here - return leanText.length(); - } -} Index: src/org/eclipse/equinox/bidi/complexp/ComplExpUtil.java =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/components/bundles/org.eclipse.equinox.bidi/src/org/eclipse/equinox/bidi/complexp/ComplExpUtil.java,v retrieving revision 1.1 diff -u -r1.1 ComplExpUtil.java --- src/org/eclipse/equinox/bidi/complexp/ComplExpUtil.java 2 Feb 2010 21:55:25 -0000 1.1 +++ src/org/eclipse/equinox/bidi/complexp/ComplExpUtil.java 3 Feb 2010 19:53:44 -0000 @@ -11,6 +11,7 @@ package org.eclipse.equinox.bidi.complexp; import java.util.Locale; +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; /** * This class provides a number of convenience functions facilitating the @@ -40,225 +41,6 @@ * @author Matitiahu Allouche */ final public class ComplExpUtil { - /** - * Constant indicating a default type of complex expression processor. - * This type does not add any directional formatting character, it is - * a "transparent" processor. - * - * @see #create - */ - public static final int DEFAULT = 0; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing property file statements. - * This type covers expression of the form
- *      name=value - * - * @see #create - */ - public static final int PROPERTY = 1; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing compound names. - * This type covers names made of one or more parts, each one connected - * to the previous one by one underscore, as below:
- *      part1_part2_part3 - * - * @see #create - */ - public static final int COMPOUND_NAME = 2; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing comma-delimited lists. - * This types covers expressions made of one or more parts, each one - * separated from the previous one by a comma, as below:
- *      part1,part2,part3 - * - * @see #create - */ - public static final int COMMA_DELIMITED = 3; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing system(user) constructs. - * This type covers expression of the form
- *      system(user)
- * with a system name immediately followed by a user name within - * parentheses. - * - * @see #create - */ - public static final int SYSTEM_USER = 4; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing directory and file paths. - * - * @see #create - */ - public static final int PATH = 5; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing e-mail addresses. - * - * @see #create - */ - public static final int EMAIL = 6; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing URLs. - * - * @see #create - */ - public static final int URL = 7; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing regular expressions, possibly spanning more than one - * line. - * - * @see #create - */ - public static final int REGEXP = 8; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing Xpath expressions. - * - * @see #create - */ - public static final int XPATH = 9; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing Java code, possibly spanning more than one line. - * - * @see #create - */ - public static final int JAVA = 10; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing SQL statements, possibly spanning more than one line. - * - * @see #create - */ - public static final int SQL = 11; - - /** - * Constant indicating a type of complex expression processor adapted - * to processing arithmetic expressions with a RTL base direction. - * - * @see #create - */ - public static final int RTL_ARITHMETIC = 12; - - /** Constant indicating the highest value used in this package for - * types of complex expressions. - * @see #create - */ - public static final int HIGHEST = 12; - - /** Constant indicating the base direction of a string representing - * a left-to-right complex expression. - * @see #insertMarks - */ - public static final int DIRECTION_LTR = IComplExpProcessor.DIRECTION_LTR; - - /** Constant indicating the base direction of a string representing - * a right-to-left complex expression. - * @see #insertMarks - */ - public static final int DIRECTION_RTL = IComplExpProcessor.DIRECTION_RTL; - - /** - * prevent instantiation - */ - private ComplExpUtil() { - // empty - } - - /** - * Factory method to create specialized implementations - * of IComplExpProcessor adapted to specific types of - * complex expressions. - * - * @param type specifies the type of complex expression to process. - * This must be one of the values - * {@link #DEFAULT}, - * {@link #PROPERTY}, - * {@link #COMPOUND_NAME}, - * {@link #COMMA_DELIMITED}, - * {@link #SYSTEM_USER}, - * {@link #PATH}, - * {@link #EMAIL}, - * {@link #URL}, - * {@link #REGEXP}, - * {@link #XPATH}, - * {@link #JAVA}, - * {@link #SQL}, - * {@link #RTL_ARITHMETIC} - * - * @return a IComplExpProcessor instance capable of - * handling the type of complex expression specified. - * If the type is not a valid value, - * null is returned. - * - */ - public static IComplExpProcessor create(int type) { - IComplExpProcessor complexp; - if (type == DEFAULT) { - return new ComplExpDoNothing(); - } - switch (type) { - case PROPERTY : - complexp = new ComplExpSingle("="); - break; - case COMPOUND_NAME : - complexp = new ComplExpBasic("_"); - break; - case COMMA_DELIMITED : - complexp = new ComplExpBasic(","); - break; - case SYSTEM_USER : - complexp = new ComplExpSingle("("); - break; - case PATH : - complexp = new ComplExpBasic(":/\\."); - break; - case EMAIL : - complexp = new ComplExpDelimsEsc("<>.:,;@", "()\"\""); - break; - case URL : - complexp = new ComplExpBasic(":?#/@.[]"); - break; - case REGEXP : - complexp = new ComplExpRegex(); - break; - case XPATH : - complexp = new ComplExpDelims(" /[]<>=!:@.|()+-*", "''\"\""); - break; - case JAVA : - complexp = new ComplExpJava(); - break; - case SQL : - complexp = new ComplExpSql(); - break; - case RTL_ARITHMETIC : - complexp = new ComplExpBasic("+-/*()="); - complexp.setDirection(IComplExpProcessor.DIRECTION_RTL); - break; - default : - return null; - } - ((ComplExpBasic) complexp).type = type; - return complexp; - } /** * Flag specifying that all complex expressions should by default assume @@ -271,6 +53,13 @@ */ static boolean mirroredDefault; + /** + * prevents instantiation + */ + private ComplExpUtil() { + // empty + } + /** Specify whether the GUI where the complex expression will be displayed * is mirrored (is laid out from right to left). The value specified in * this method sets a default for all complex expressions to be created @@ -320,8 +109,8 @@ * This argument may be null if there are no marks to add. * * @param direction specifies the base direction of the complex expression. - * It must be one of the values {@link #DIRECTION_LTR} or - * {@link #DIRECTION_RTL}. + * It must be one of the values {@link IComplExpProcessor#DIRECTION_LTR} or + * {@link IComplExpProcessor#DIRECTION_RTL}. * * @param affix specifies if a prefix and a suffix should be added to * the result to make sure that the direction @@ -342,7 +131,7 @@ String curPrefix, curSuffix, full; char curMark, c; char[] fullChars; - if (direction == DIRECTION_LTR) { + if (direction == IComplExpProcessor.DIRECTION_LTR) { curMark = LRM; curPrefix = "\u202a\u200e"; curSuffix = "\u200e\u202c"; @@ -526,7 +315,7 @@ * * @return the processed string */ - public static String process(String str, int type) { + public static String processTyped(String str, String type) { if ((str == null) || (str.length() <= 1) || (getProcessingNeededScore() != 3)) return str; @@ -535,7 +324,7 @@ if (((c == LRE) || (c == RLE)) && str.charAt(str.length() - 1) == PDF) return str; - IComplExpProcessor processor = create(type); + IComplExpProcessor processor = ComplExpFactory.create(type); if (processor == null) // invalid type return str; @@ -588,11 +377,11 @@ * @return string with no directional formatting characters * */ - public static String deprocess(String str, int type) { + public static String deprocess(String str, String type) { if ((str == null) || (str.length() <= 1) || (getProcessingNeededScore() != 3)) return str; - IComplExpProcessor processor = create(type); + IComplExpProcessor processor = ComplExpFactory.create(type); if (processor == null) // invalid type return str; Index: src/org/eclipse/equinox/bidi/complexp/IBiDiProcessor.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/IBiDiProcessor.java diff -N src/org/eclipse/equinox/bidi/complexp/IBiDiProcessor.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/complexp/IBiDiProcessor.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.complexp; + +/** + * Bi-directional processors supplied in this bundle. + * + * @noextend This interface is not intended to be extended by clients. + */ +public interface IBiDiProcessor { + + /** + * Constant indicating a type of complex expression processor adapted + * to processing property file statements. It expects the following + * string format: + *

+	 *  name=value
+	 * 
+ */ + public String PROPERTY = "property"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing compound names. + * This type covers names made of one or more parts separated by underscores: + *
+	 *  part1_part2_part3
+	 * 
+ */ + public String UNDERSCORE = "underscore"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing comma-delimited lists, such as: + *
+	 *  part1,part2,part3
+	 * 
+ */ + public String COMMA_DELIMITED = "comma"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing expressions with the following string format: + *
+	 *  system(user)
+	 * 
+ */ + public String SYSTEM_USER = "system"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing directory and file paths. + */ + public String FILE = "file"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing e-mail addresses. + */ + public String EMAIL = "email"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing URLs. + */ + public String URL = "url"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing regular expressions, possibly spanning more than one + * line. + */ + public String REGEXP = "regex"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing XPath expressions. + */ + public String XPATH = "xpath"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing Java code, possibly spanning more than one line. + */ + public String JAVA = "java"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing SQL statements, possibly spanning more than one line. + */ + public String SQL = "sql"; //$NON-NLS-1$ + + /** + * Constant indicating a type of complex expression processor adapted + * to processing arithmetic expressions with a RTL base direction. + */ + public String RTL_ARITHMETIC = "math"; //$NON-NLS-1$ +} Index: src/org/eclipse/equinox/bidi/complexp/IComplExpProcessor.java =================================================================== RCS file: /cvsroot/rt/org.eclipse.equinox/components/bundles/org.eclipse.equinox.bidi/src/org/eclipse/equinox/bidi/complexp/IComplExpProcessor.java,v retrieving revision 1.1 diff -u -r1.1 IComplExpProcessor.java --- src/org/eclipse/equinox/bidi/complexp/IComplExpProcessor.java 2 Feb 2010 21:55:25 -0000 1.1 +++ src/org/eclipse/equinox/bidi/complexp/IComplExpProcessor.java 3 Feb 2010 19:53:44 -0000 @@ -10,6 +10,8 @@ ******************************************************************************/ package org.eclipse.equinox.bidi.complexp; +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + /** * This interface provides a generic mechanism to handle * complex expressions, with as main purpose to ensure that they are Index: src/org/eclipse/equinox/bidi/complexp/StringProcessor.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/complexp/StringProcessor.java diff -N src/org/eclipse/equinox/bidi/complexp/StringProcessor.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/complexp/StringProcessor.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.complexp; + +import org.eclipse.equinox.bidi.internal.complexp.BiDiTypesCollector; + +/** + * The API part for the TextProcessor replacement. + */ +// TBD processors currently are not thread-safe (ComplExpBasic has class variables containing +// parsing state). This means that either: +// a) a new instance of the processor needs to be created for every call; +// b) processors have to be made thread-safe. +public class StringProcessor { + + static public String[] getKnownTypes() { + return BiDiTypesCollector.getInstance().getTypes(); + } + + static public IComplExpProcessor getProcessor(String type) { + return BiDiTypesCollector.getInstance().getProcessor(type); + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/BiDiActivator.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/BiDiActivator.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/BiDiActivator.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/BiDiActivator.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import org.eclipse.osgi.framework.log.FrameworkLog; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +public class BiDiActivator implements BundleActivator { + + private ServiceTracker logTracker = null; + private BundleContext bundleContext; + + private static BiDiActivator instance; + + public BiDiActivator() { + instance = this; // there is only one bundle activator + } + + public void start(BundleContext context) throws Exception { + bundleContext = context; + instance = this; + } + + public void stop(BundleContext context) throws Exception { + if (logTracker != null) { + logTracker.close(); + logTracker = null; + } + bundleContext = null; + } + + private FrameworkLog getFrameworkLog() { + if (logTracker == null) { + logTracker = new ServiceTracker(bundleContext, FrameworkLog.class.getName(), null); + logTracker.open(); + } + return (FrameworkLog) logTracker.getService(); + } + + static public void logError(String message, Exception e) { + FrameworkLog frameworkLog = instance.getFrameworkLog(); + if (frameworkLog != null) { + frameworkLog.log(new FrameworkLogEntry("org.eclipse.equinox.bidi", FrameworkLogEntry.ERROR, 1, message, 0, e, null)); //$NON-NLS-1$ + return; + } + System.err.println(message); + if (e != null) + e.printStackTrace(); + } + +} Index: src/org/eclipse/equinox/bidi/internal/complexp/BiDiTypesCollector.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/BiDiTypesCollector.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/BiDiTypesCollector.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/BiDiTypesCollector.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import java.util.HashMap; +import java.util.Map; +import org.eclipse.core.runtime.*; +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +public class BiDiTypesCollector implements IRegistryEventListener { + + private static final String EXT_POINT = "org.eclipse.equinox.bidi.bidiTypes"; //$NON-NLS-1$ + + private static final String CE_NAME = "typeDescription"; //$NON-NLS-1$ + private static final String ATTR_TYPE = "type"; //$NON-NLS-1$ + private static final String ATTR_PROCESSOR = "class"; //$NON-NLS-1$ + + private Map types; + private Map factories; + + static private BiDiTypesCollector instance = new BiDiTypesCollector(); + + private BiDiTypesCollector() { + IExtensionRegistry registry = RegistryFactory.getRegistry(); + registry.addListener(this, EXT_POINT); + } + + static public BiDiTypesCollector getInstance() { + return instance; + } + + public String[] getTypes() { + if (types == null) + read(); + int size = types.size(); + String[] result = new String[size]; + types.keySet().toArray(result); + return result; + } + + public IComplExpProcessor getProcessor(String type) { + if (types == null) + read(); + Object processor = types.get(type); + if (processor instanceof IComplExpProcessor) + return (IComplExpProcessor) processor; + return null; + } + + public IComplExpProcessor makeProcessor(String type) { + if (factories == null) + read(); + IConfigurationElement ce = (IConfigurationElement) factories.get(type); + if (ce == null) + return null; + Object processor; + try { + processor = ce.createExecutableExtension(ATTR_PROCESSOR); + } catch (CoreException e) { + BiDiActivator.logError("BiDi types: unable to create processor for " + type, e); //$NON-NLS-1$ + return null; + } + if (processor instanceof IComplExpProcessor) + return (IComplExpProcessor) processor; + return null; + } + + private void read() { + if (types == null) + types = new HashMap(); + else + types.clear(); + + if (factories == null) + factories = new HashMap(); + else + factories.clear(); + + IExtensionRegistry registry = RegistryFactory.getRegistry(); + IExtensionPoint extPoint = registry.getExtensionPoint(EXT_POINT); + IExtension[] extensions = extPoint.getExtensions(); + + for (int i = 0; i < extensions.length; i++) { + IConfigurationElement[] confElements = extensions[i].getConfigurationElements(); + for (int j = 0; j < confElements.length; j++) { + if (CE_NAME != confElements[j].getName()) + BiDiActivator.logError("BiDi types: unexpected element name " + confElements[j].getName(), new IllegalArgumentException()); //$NON-NLS-1$ + String type = confElements[j].getAttribute(ATTR_TYPE); + Object processor; + try { + processor = confElements[j].createExecutableExtension(ATTR_PROCESSOR); + } catch (CoreException e) { + BiDiActivator.logError("BiDi types: unable to create processor for " + type, e); //$NON-NLS-1$ + continue; + } + types.put(type, processor); + factories.put(type, confElements[j]); + } + } + } + + public void added(IExtension[] extensions) { + types = null; + factories = null; + } + + public void removed(IExtension[] extensions) { + types = null; + factories = null; + } + + public void added(IExtensionPoint[] extensionPoints) { + types = null; + factories = null; + } + + public void removed(IExtensionPoint[] extensionPoints) { + types = null; + factories = null; + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpBasic.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpBasic.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/ComplExpBasic.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/ComplExpBasic.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,976 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import org.eclipse.equinox.bidi.complexp.ComplExpUtil; +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpBasic is a + * complex expression processor for simple types of complex expressions. + * Normally, a group of operators is specified when creating a new + * instance. + * Lean text which is submitted to this processor is divided into + * segments by the operators. The processor adds directional formatting + * characters into the lean text to generate a full text where + * operators and text segments will be presented in left-to-right sequence. + * + * @see IComplExpProcessor + * + * @author Matitiahu Allouche + */ +public class ComplExpBasic implements IComplExpProcessor { + + final private static String EMPTY_STRING = ""; //$NON-NLS-1$ + + /** + * Flag specifying that a specific instance of complex expression should + * assume that the GUI is mirrored (globally going from right to left). + * This flag overrides the default flag mirroredDefault + * for the parent complex expression instance. + * @see #assumeMirrored + * @see #isMirrored + * @see ComplExpUtil#mirroredDefault + */ + protected boolean mirrored = ComplExpUtil.isMirroredDefault(); + + /** + * Orientation that should be assumed for the text component where the + * complex expression will be displayed. It can be specified using + * {@link #assumeOrientation}. + * It must be one of the values + * {@link IComplExpProcessor#ORIENT_LTR ORIENT_LTR}, + * {@link IComplExpProcessor#ORIENT_LTR ORIENT_RTL}, + * {@link IComplExpProcessor#ORIENT_CONTEXTUAL_LTR ORIENT_CONTEXTUAL_LTR} or + * {@link IComplExpProcessor#ORIENT_CONTEXTUAL_RTL ORIENT_CONTEXTUAL_RTL}. + * {@link IComplExpProcessor#ORIENT_UNKNOWN ORIENT_UNKNOWN}. + * {@link IComplExpProcessor#ORIENT_IGNORE ORIENT_IGNORE}. + * The default is ORIENT_LTR. + *

+ * The orientation affects the addition of directional formatting + * characters as prefix and/or suffix when generating the full + * text of the complex expression. + * + * @see #assumeOrientation + * @see #recallOrientation + * @see #leanToFullText + */ + protected int orientation; + + /** + * Type of the complex expression processor specified when calling + * {@link ComplExpUtil#create} + */ + protected int type; + + /** + * Base direction of the complex expression. This is an array such that + *

+ * Each of the elements in the array must be one of the values + * {@link IComplExpProcessor#DIRECTION_LTR DIRECTION_LTR}, + * {@link IComplExpProcessor#DIRECTION_LTR DIRECTION_RTL}. + * The default is DIRECTION_LTR. + * + * @see #setDirection(int) setDirection + * @see #getDirection getDirection + */ + protected int[][] direction = new int[2][2]; + + /** + * This field represents the final state achieved in a previous call to + * {@link IComplExpProcessor#leanToFullText leanToFullText} or + * {@link IComplExpProcessor#fullToLeanText fullToLeanText}, + * {@link IComplExpProcessor#leanBidiCharOffsets(java.lang.String text)} or + * {@link IComplExpProcessor#leanBidiCharOffsets(java.lang.String text, int initState)}. + * The state is an opaque value which makes sense only + * within calls to a same complex expression processor. + * The only externalized value is + * {@link IComplExpProcessor#STATE_NOTHING_GOING} which means that + * there is nothing to remember from the last call. + *

+ * state should be used only for complex expressions + * which span more than one line, when the user makes a separate call to + * leanToFullText, fullToLeanText or + * leanBidiCharOffsets for each + * line in the expression. The final state value retrieved after the + * call for one line should be used as the initial state in the call + * which processes the next line. + *

+ * If a line within a complex expression has already been processed by + * leanToFullText and the lean version of that line has + * not changed, and its initial state has not changed either, the user + * can be sure that the full version of that line is also + * identical to the result of the previous processing. + * + * @see IComplExpProcessor#getFinalState + * @see IComplExpProcessor#leanToFullText(String text, int initState) + * @see IComplExpProcessor#fullToLeanText(String text, int initState) + * @see IComplExpProcessor#leanBidiCharOffsets(String text, int initState) + */ + protected int state = STATE_NOTHING_GOING; + + private boolean ignoreArabic, ignoreHebrew; + + public static final byte B = Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR; + public static final byte L = Character.DIRECTIONALITY_LEFT_TO_RIGHT; + public static final byte R = Character.DIRECTIONALITY_RIGHT_TO_LEFT; + public static final byte AL = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC; + public static final byte AN = Character.DIRECTIONALITY_ARABIC_NUMBER; + public static final byte EN = Character.DIRECTIONALITY_EUROPEAN_NUMBER; + public static final char LRM = 0x200E; + public static final char RLM = 0x200F; + public static final char LRE = 0x202A; + public static final char RLE = 0x202B; + public static final char PDF = 0x202C; + public static final char[] MARKS = {LRM, RLM}; + public static final char[] EMBEDS = {LRE, RLE}; + public static final byte[] STRONGS = {L, R}; + public static final int PREFIX_LENGTH = 2; + public static final int SUFFIX_LENGTH = 2; + public static final int FIXES_LENGTH = PREFIX_LENGTH + SUFFIX_LENGTH; + + private byte curStrong = -1; + private char curMark; + private char curEmbed; + private int prefixLength; + char[] operators; + int operCount; + int[] locations; + int specialsCount; + int nextLocation; + int len; + private String leanText; + private int idxLocation; + private int[] offsets; + private int count, countLimit; + private int curPos; + // For positions where it has been looked up, the entry will receive + // the Character directionality + 2 (so that 0 indicates that the + // the directionality has not been looked up yet. + private byte[] dirProps; + // current UI orientation (after resolution if contextual) + private int curOrient = -1; + // Current expression base direction (after resolution if depending on + // script and/or on GUI mirroring (0=LTR, 1=RTL)) + private int curDirection = -1; + + /** + * Constructor specifying operators. The processor will add directional + * formatting characters to lean text to generate a full + * text so that the operators and the segments of text between operators + * are displayed from left to right, while each segment is displayed + * according to the UBA. + * + * @param operators string grouping one-character operators which + * separate the text of the complex expression into segments. + */ + public ComplExpBasic(String operators) { + this.operators = operators.toCharArray(); + operCount = this.operators.length; + locations = new int[operCount]; + } + + public void setType(int expressionType) { + type = expressionType; + } + + /** + * Constructor specifying operators and a number of special cases. + * In ComplExpBasic the special cases are implemented as + * doing nothing. Subclasses of ComplExpBasic may override + * methods indexOfSpecial and processSpecial + * to provide specific handling for the special cases. + * Examples of special cases are comments, literals, or anything which + * is not identified by a one-character operator. + *

+ * Independently of the special cases, the processor will add directional + * formatting characters to lean text to generate a full + * text so that the operators and the segments of text between operators + * are displayed from left to right, while each segment is displayed + * according to the UBA. + * + * @param operators string grouping one-character operators which + * separate the text of the complex expression into segments. + * + * @param specialsCount number of special cases supported by this + * class. Handling of the special cases is implemented with + * methods indexOfSpecial and + * processSpecial. + * + * @see #indexOfSpecial indexOfSpecial + * @see #processSpecial processSpecial + */ + public ComplExpBasic(String operators, int specialsCount) { + this.operators = operators.toCharArray(); + operCount = this.operators.length; + this.specialsCount = specialsCount; + locations = new int[operCount + specialsCount]; + } + + public void selectBidiScript(boolean arabic, boolean hebrew) { + ignoreArabic = !arabic; + ignoreHebrew = !hebrew; + } + + public boolean handlesArabicScript() { + return !ignoreArabic; + } + + public boolean handlesHebrewScript() { + return !ignoreHebrew; + } + + void computeNextLocation() { + nextLocation = len; + // Start with special sequences to give them precedence over simple + // operators. This may apply to cases like slash+asterisk versus slash. + for (int i = 0; i < specialsCount; i++) { + int loc = locations[operCount + i]; + if (loc < curPos) { + loc = indexOfSpecial(i, leanText, curPos); + if (loc < 0) + loc = len; + locations[operCount + i] = loc; + } + if (loc < nextLocation) { + nextLocation = loc; + idxLocation = operCount + i; + } + } + for (int i = 0; i < operCount; i++) { + int loc = locations[i]; + if (loc < curPos) { + loc = leanText.indexOf(operators[i], curPos); + if (loc < 0) + loc = len; + locations[i] = loc; + } + if (loc < nextLocation) { + nextLocation = loc; + idxLocation = i; + } + } + } + + /** + * This method is called repeatedly by leanToFullText to + * locate all special cases specified in the constructor + * (see {@link #ComplExpBasic(String operators, int specialsCount)}), + * varying whichSpecial from zero to + * specialsCount - 1. It is meant to be overridden in + * subclasses of ComplExpBasic. + * Those subclasses may use methods + * {@link #getDirProp getDirProp}, + * {@link #setDirProp setDirProp} and + * {@link #insertMark insertMark} within indexOfSpecial. + * + * @param whichSpecial number of the special case to locate. The meaning + * of this number is internal to the class implementing + * indexOfSpecial. + * + * @param text text of the complex expression. + * + * @param fromIndex the index within leanText to start + * the search from. + * + * @return the position where the start of the special case was located. + * The method must return the first occurrence of whatever + * identifies the start of the special case after + * fromIndex. The method does not have to check if + * this occurrence appears within the scope of another special + * case (e.g. a comment starting delimiter within the scope of + * a literal or vice-versa). + * If no occurrence is found, the method must return -1. + *

+ * In ComplExpBasic this method always returns -1. + * + */ + protected int indexOfSpecial(int whichSpecial, String text, int fromIndex) { + // This method must be overridden by all subclasses with special cases. + return -1; + } + + /** + * This method is called by leanToFullText + * when a special case occurrence is located by + * {@link #indexOfSpecial indexOfSpecial}. + * It is meant to be overridden in subclasses of ComplExpBasic. + * Those subclasses may use methods + * {@link #getDirProp getDirProp}, + * {@link #setDirProp setDirProp} and + * {@link #insertMark insertMark} within processSpecial. + *

+ * If a special processing cannot be completed within a current call to + * processSpecial (for instance, a comment has been started + * in the current line but its end appears in a following line), + * processSpecial should put in the {@link #state} + * member of the class instance a number which characterizes this + * situation. On a later call to + * {@link IComplExpProcessor#leanToFullText(String text, int initState)} + * specifying that state value, processSpecial will be + * called with that value for parameter whichSpecial and + * -1 for parameter operLocation and should + * perform whatever initializations are required depending on the state. + * + * @param whichSpecial number of the special case to handle. + * + * @param text text of the complex expression. + * + * @param operLocation the position returned by indexOfSpecial. + * In calls to leanToFullText or + * fullToLeanText specifying an initState + * parameter, processSpecial is called when initializing + * the processing with the value of whichSpecial + * equal to initState and the value of + * operLocation equal to -1. + * + * @return the position after the scope of the special case ends. + * For instance, the position after the end of a comment, + * the position after the end of a literal. + *

+ * In ComplExpBasic this method always returns + * operLocation + 1 (but it should never be called). + * + */ + protected int processSpecial(int whichSpecial, String text, int operLocation) { + // This method must be overridden by all subclasses with any special case. + return operLocation + 1; + } + + private int getCurOrient() { + if (curOrient >= 0) + return curOrient; + + if ((orientation & ORIENT_CONTEXTUAL_LTR) == 0) { + // absolute orientation + curOrient = orientation; + return curOrient; + } + // contextual orientation + byte dirProp; + for (int i = 0; i < len; i++) { + dirProp = dirProps[i]; + if (dirProp == 0) { + dirProp = Character.getDirectionality(leanText.charAt(i)); + if (dirProp == B) // B char resolves to L or R depending on orientation + continue; + dirProps[i] = (byte) (dirProp + 2); + } else { + dirProp -= 2; + } + if (dirProp == L) { + curOrient = ORIENT_LTR; + return curOrient; + } + if (dirProp == R || dirProp == AL) { + curOrient = ORIENT_RTL; + return curOrient; + } + } + curOrient = orientation & 1; + return curOrient; + } + + public int getCurDirection() { + if (curDirection >= 0) + return curDirection; + + curStrong = -1; + int idx2 = mirrored ? 1 : 0; + // same direction for Arabic and Hebrew? + if (direction[0][idx2] == direction[1][idx2]) { + curDirection = direction[0][idx2]; + return curDirection; + } + // check if Arabic or Hebrew letter comes first + byte dirProp; + for (int i = 0; i < len; i++) { + dirProp = getDirProp(i); + if (dirProp == AL) { + curDirection = direction[0][idx2]; + return curDirection; + } + if (dirProp == R) { + curDirection = direction[1][idx2]; + return curDirection; + } + } + // found no Arabic or Hebrew character + curDirection = DIRECTION_LTR; + return curDirection; + } + + private void setMarkAndFixes() { + int dir = getCurDirection(); + if (curStrong == STRONGS[dir]) + return; + curStrong = STRONGS[dir]; + curMark = MARKS[dir]; + curEmbed = EMBEDS[dir]; + } + + /** + * This method can be called from within {@link #indexOfSpecial indexOfSpecial} + * or {@link #processSpecial processSpecial} in subclasses of + * ComplExpBasic to retrieve the bidirectional class of + * characters in leanText. + * + * @param index position of the character in leanText. + * + * @return the bidirectional class of the character. It is one of the + * values which can be returned by + * java.lang.Character#getDirectionality. + * However, it is recommended to use getDirProp + * rather than java.lang.Character.getDirectionality + * since getDirProp manages a cache of character + * properties and so can be more efficient than calling the + * java.lang.Character method. + * + */ + protected byte getDirProp(int index) { + byte dirProp = dirProps[index]; + if (dirProp == 0) { + dirProp = Character.getDirectionality(leanText.charAt(index)); + if (dirProp == B) + dirProp = getCurOrient() == ORIENT_RTL ? R : L; + dirProps[index] = (byte) (dirProp + 2); + return dirProp; + } + return (byte) (dirProp - 2); + } + + /** + * This method can be called from within {@link #indexOfSpecial indexOfSpecial} + * or {@link #processSpecial processSpecial} in subclasses of + * ComplExpBasic to set or override the bidirectional + * class of characters in leanText. + * + * @param index position of the character in leanText. + * + * @param dirProp bidirectional class of the character. It is one of the + * values which can be returned by + * java.lang.Character.getDirectionality. + * + */ + protected void setDirProp(int index, byte dirProp) { + dirProps[index] = (byte) (dirProp + 2); + } + + /** + * This method can be called from within + * {@link #processSpecial processSpecial} in subclasses of + * ComplExpBasic to add a directional mark before an + * operator if needed for correct display, depending on the + * base direction of the expression and on the class of the + * characters in leanText preceding and following + * the operator itself. + * + * @param operLocation offset of the operator in leanText. + * + */ + protected void processOperator(int operLocation) { + boolean doneAN = false; + + if (getCurDirection() == DIRECTION_RTL) { + // the expression base direction is RTL + for (int i = operLocation - 1; i >= 0; i--) { + byte dirProp = getDirProp(i); + if (dirProp == R || dirProp == AL) + return; + + if (dirProp == L) { + for (int j = operLocation; j < len; j++) { + dirProp = getDirProp(j); + if (dirProp == R || dirProp == AL) + return; + if (dirProp == L || dirProp == EN) { + insertMark(operLocation); + return; + } + } + return; + } + } + return; + } + + // the expression base direction is LTR + if (ignoreArabic) { + if (ignoreHebrew) /* process neither Arabic nor Hebrew */ + return; + /* process Hebrew, not Arabic */ + for (int i = operLocation - 1; i >= 0; i--) { + byte dirProp = getDirProp(i); + if (dirProp == L) + return; + if (dirProp == R) { + for (int j = operLocation; j < len; j++) { + dirProp = getDirProp(j); + if (dirProp == L) + return; + if (dirProp == R || dirProp == EN) { + insertMark(operLocation); + return; + } + } + return; + } + } + } else { + if (ignoreHebrew) { /* process Arabic, not Hebrew */ + for (int i = operLocation - 1; i >= 0; i--) { + byte dirProp = getDirProp(i); + if (dirProp == L) + return; + if (dirProp == AL) { + for (int j = operLocation; j < len; j++) { + dirProp = getDirProp(j); + if (dirProp == L) + return; + if (dirProp == EN || dirProp == AL || dirProp == AN) { + insertMark(operLocation); + return; + } + } + return; + } + if (dirProp == AN && !doneAN) { + for (int j = operLocation; j < len; j++) { + dirProp = getDirProp(j); + if (dirProp == L) + return; + if (dirProp == AL || dirProp == AN) { + insertMark(operLocation); + return; + } + } + doneAN = true; + } + } + } else { /* process Arabic and Hebrew */ + for (int i = operLocation - 1; i >= 0; i--) { + byte dirProp = getDirProp(i); + if (dirProp == L) + return; + if (dirProp == R || dirProp == AL) { + for (int j = operLocation; j < len; j++) { + dirProp = getDirProp(j); + if (dirProp == L) + return; + if (dirProp == R || dirProp == EN || dirProp == AL || dirProp == AN) { + insertMark(operLocation); + return; + } + } + return; + } + if (dirProp == AN && !doneAN) { + for (int j = operLocation; j < len; j++) { + dirProp = getDirProp(j); + if (dirProp == L) + return; + if (dirProp == AL || dirProp == AN || dirProp == R) { + insertMark(operLocation); + return; + } + } + doneAN = true; + } + } + } + } + } + + public int getFinalState() { + return state; + } + + public String leanToFullText(String text) { + return leanToFullText(text, STATE_NOTHING_GOING); + } + + public String leanToFullText(String text, int initState) { + if (text.length() == 0) + return text; + leanToFullTextNofix(text, initState); + return addMarks(true); + } + + void leanToFullTextNofix(String text, int initState) { + leanText = text; + len = leanText.length(); + offsets = new int[20]; + count = 0; + countLimit = offsets.length - 1; + dirProps = new byte[len]; + curOrient = -1; + curDirection = -1; + curPos = 0; + // initialize locations + int k = locations.length; + for (int i = 0; i < k; i++) { + locations[i] = -1; + } + state = STATE_NOTHING_GOING; + nextLocation = -1; + if (initState != STATE_NOTHING_GOING) + curPos = processSpecial(initState, leanText, -1); + + while (true) { + computeNextLocation(); + if (nextLocation >= len) + break; + if (idxLocation < operCount) { + processOperator(nextLocation); + curPos = nextLocation + 1; + } else { + curPos = processSpecial(idxLocation - operCount, leanText, nextLocation); + } + } + } + + public int[] leanBidiCharOffsets(String text) { + return leanBidiCharOffsets(text, STATE_NOTHING_GOING); + } + + public int[] leanBidiCharOffsets(String text, int initState) { + leanToFullTextNofix(text, initState); + return leanBidiCharOffsets(); + } + + public int[] leanBidiCharOffsets() { + int[] result = new int[count]; + System.arraycopy(offsets, 0, result, 0, count); + return result; + } + + public int[] fullBidiCharOffsets() { + int lim = count; + if (prefixLength > 0) { + if (prefixLength == 1) + lim++; + else + lim += FIXES_LENGTH; + } + int[] fullOffsets = new int[lim]; + for (int i = 0; i < prefixLength; i++) { + fullOffsets[i] = i; + } + int added = prefixLength; + for (int i = 0; i < count; i++) { + fullOffsets[prefixLength + i] = offsets[i] + added; + added++; + } + if (prefixLength > 1) { + fullOffsets[lim - 2] = len + lim - 2; + fullOffsets[lim - 1] = len + lim - 1; + } + return fullOffsets; + } + + public String fullToLeanText(String text) { + return fullToLeanText(text, STATE_NOTHING_GOING); + } + + public String fullToLeanText(String text, int initState) { + int i; // TBD this variable is used for multiple unrelated tasks + setMarkAndFixes(); + // remove any prefix and leading mark + int lenText = text.length(); + for (i = 0; i < lenText; i++) { + char c = text.charAt(i); + if (c != curEmbed && c != curMark) + break; + } + if (i > 0) { + text = text.substring(i); + lenText = text.length(); + } + // remove any suffix and trailing mark + for (i = lenText - 1; i >= 0; i--) { + char c = text.charAt(i); + if (c != PDF && c != curMark) + break; + } + if (i < 0) { + leanText = EMPTY_STRING; + len = 0; + return leanText; + } + if (i < (lenText - 1)) { + text = text.substring(0, i + 1); + lenText = text.length(); + } + char[] chars = text.toCharArray(); + // remove marks from chars + int cnt = 0; + for (i = 0; i < lenText; i++) { + char c = chars[i]; + if (c == curMark) + cnt++; + else if (cnt > 0) + chars[i - cnt] = c; + } + String lean = new String(chars, 0, lenText - cnt); + leanToFullTextNofix(lean, initState); + String full = addMarks(false); /* only marks, no prefix/suffix */ + if (full.equals(text)) + return lean; + + // There are some marks in full which are not in text and/or vice versa. + // We need to add to lean any mark appearing in text and not in full. + // The completed lean can never be longer than text itself. + char[] newChars = new char[lenText]; + char cFull, cText; + int idxFull, idxText, idxLean, markPos, newCharsPos; + int lenFull = full.length(); + idxFull = idxText = idxLean = newCharsPos = 0; + while (idxText < lenText && idxFull < lenFull) { + cFull = full.charAt(idxFull); + cText = text.charAt(idxText); + if (cFull == cText) { /* chars are equal, proceed */ + idxText++; + idxFull++; + continue; + } + if (cFull == curMark) { /* extra Mark in full text */ + idxFull++; + continue; + } + if (cText == curMark) { /* extra Mark in source full text */ + idxText++; + // idxText-2 always >= 0 since leading Marks were removed from text + if (text.charAt(idxText - 2) == curMark) + continue; // ignore successive Marks in text after the first one + markPos = fullToLeanPos(idxFull); + // copy from chars (== lean) to newChars until here + for (i = idxLean; i < markPos; i++) { + newChars[newCharsPos++] = chars[i]; + } + idxLean = markPos; + newChars[newCharsPos++] = curMark; + continue; + } + // we should never get here (extra char which is not a Mark) + throw new IllegalStateException("Internal error: extra character not a Mark."); //$NON-NLS-1$ + } + if (idxText < lenText) /* full ended before text - this should never happen */ + throw new IllegalStateException("Internal error: unexpected EOL."); //$NON-NLS-1$ + + // copy the last part of chars to newChars + for (i = idxLean; i < lean.length(); i++) { + newChars[newCharsPos++] = chars[i]; + } + lean = new String(newChars, 0, newCharsPos); + leanText = lean; + len = leanText.length(); + return lean; + } + + public int leanToFullPos(int pos) { + int added = prefixLength; + for (int i = 0; i < count; i++) { + if (offsets[i] <= pos) + added++; + else + return pos + added; + } + return pos + added; + } + + public int fullToLeanPos(int pos) { + pos -= prefixLength; + int added = 0; + for (int i = 0; i < count; i++) { + if ((offsets[i] + added) < pos) + added++; + else + break; + } + pos -= added; + if (pos < 0) + pos = 0; + else if (pos > len) + pos = len; + return pos; + } + + /** + * This method can be called from within {@link #indexOfSpecial} or + * {@link #processSpecial} in subclasses of ComplExpBasic + * to specify that a mark character must be added before the character + * at the specified position of the lean text when generating the + * full text. The mark character will be LRM for complex expressions + * with a LTR base direction, and RLM for complex expressions with RTL + * base direction. The mark character is not added physically by this + * method, but its position is noted and will be used when generating + * the full text. + * + * @param offset position of the character in leanText. + * It must be a non-negative number smaller than the length + * of the lean text. + * For the benefit of efficiency, it is better to insert + * multiple marks in ascending order of the offsets. + * + */ + protected void insertMark(int offset) { + int index = count - 1; // index of greatest member <= offset + // look up after which member the new offset should be inserted + while (index >= 0) { + int wrkOffset = offsets[index]; + if (offset > wrkOffset) + break; + if (offset == wrkOffset) + return; // avoid duplicates + index--; + } + index++; // index now points at where to insert + // check if we have an available slot for new member + if (count >= countLimit) { + int[] newOffsets = new int[offsets.length * 2]; + System.arraycopy(offsets, 0, newOffsets, 0, count); + offsets = newOffsets; + countLimit = offsets.length - 1; + } + + int length = count - index; // number of members to move up + if (length > 0) // shift right all members greater than offset + System.arraycopy(offsets, index, offsets, index + 1, length); + + offsets[index] = offset; + count++; + // if the offset is 0, adding a mark does not change anything + if (offset < 1) + return; + + byte dirProp = getDirProp(offset); + // if the current char is a strong one or a digit, we change the + // dirProp of the previous char to account for the inserted mark + if (dirProp == L || dirProp == R || dirProp == AL || dirProp == EN || dirProp == AN) + index = offset - 1; + else + // if the current char is a neutral, we change its own dirProp + index = offset; + setMarkAndFixes(); + setDirProp(index, curStrong); + } + + private String addMarks(boolean addFixes) { + // add prefix/suffix only if addFixes is true + if ((count == 0) && (!addFixes || (getCurOrient() == getCurDirection()) || (curOrient == ORIENT_IGNORE))) { + prefixLength = 0; + return leanText; + } + int newLen = len + count; + if (addFixes && ((getCurOrient() != getCurDirection()) || (curOrient == ORIENT_UNKNOWN))) { + if ((orientation & ORIENT_CONTEXTUAL_LTR) == 0) { + prefixLength = PREFIX_LENGTH; + newLen += FIXES_LENGTH; + } else { /* contextual orientation */ + prefixLength = 1; + newLen++; /* +1 for a mark char */ + } + } else { + prefixLength = 0; + } + char[] fullChars = new char[newLen]; + // add a dummy offset as fence + offsets[count] = len; + int added = prefixLength; + // add marks at offsets + setMarkAndFixes(); + for (int i = 0, j = 0; i < len; i++) { + char c = leanText.charAt(i); + if (i == offsets[j]) { + fullChars[i + added] = curMark; + added++; + j++; + } + fullChars[i + added] = c; + } + if (prefixLength > 0) { /* add prefix/suffix ? */ + if (prefixLength == 1) { /* contextual orientation */ + fullChars[0] = curMark; + } else { + // When the orientation is RTL, we need to add EMBED at the + // start of the text and PDF at its end. + // However, because of a bug in Windows' handling of LRE/PDF, + // we add EMBED_PREFIX at the start and EMBED_SUFFIX at the end. + fullChars[0] = curEmbed; + fullChars[1] = curMark; + fullChars[newLen - 1] = PDF; + fullChars[newLen - 2] = curMark; + } + } + return new String(fullChars); + } + + public void assumeMirrored(boolean shouldBeMirrored) { + mirrored = shouldBeMirrored; + curDirection = -1; + } + + public boolean isMirrored() { + return mirrored; + } + + public void assumeOrientation(int desiredOrientation) { + if (desiredOrientation < ORIENT_LTR || desiredOrientation > ORIENT_IGNORE) + orientation = ORIENT_UNKNOWN; // TBD should throw new IllegalArgumentException()? + orientation = desiredOrientation; + } + + public int recallOrientation() { + return orientation; + } + + public void setArabicDirection(int not_mirrored, int mirrored) { + direction[0][0] = not_mirrored & 1; + direction[0][1] = mirrored & 1; + curDirection = -1; + } + + public void setArabicDirection(int direction) { + setArabicDirection(direction, direction); + } + + public void setHebrewDirection(int not_mirrored, int mirrored) { + direction[1][0] = not_mirrored & 1; + direction[1][1] = mirrored & 1; + curDirection = -1; + } + + public void setHebrewDirection(int direction) { + setHebrewDirection(direction, direction); + } + + public void setDirection(int not_mirrored, int mirrored) { + setArabicDirection(not_mirrored, mirrored); + setHebrewDirection(not_mirrored, mirrored); + } + + public void setDirection(int direction) { + setDirection(direction, direction); + } + + public int[][] getDirection() { + return direction; + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelims.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelims.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelims.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelims.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpDelims is a processor for complex expressions + * composed of text segments separated by operators where the text segments + * may include delimited parts within which operators are treated like + * regular characters. + * + * @see IComplExpProcessor + * @see ComplExpBasic + * + * @author Matitiahu Allouche + */ +public class ComplExpDelims extends ComplExpBasic { + char[] delims; + + /** + * Constructor for a complex expressions processor with support for + * operators and delimiters. + * + * @param operators string grouping one-character operators which + * separate the text of the complex expression into segments. + * + * @param delims delimiters implemented in this class instance. + * This parameter is a string which must include an even + * number of characters. The first 2 characters of a string + * constitute a pair, the next 2 characters are a second pair, etc... + * In each pair, the first character is a start delimiter and + * the second character is an end delimiter. In the lean + * text, any part starting with a start delimiter and ending with + * the corresponding end delimiter is a delimited part. Within a + * delimited part, operators are treated like regular characters, + * which means that they do not define new segments. + */ + public ComplExpDelims(String operators, String delims) { + super(operators, delims.length() / 2); + this.delims = delims.toCharArray(); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { + char delim = delims[whichSpecial * 2]; + + return leanText.indexOf(delim, fromIndex); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int processSpecial(int whichSpecial, String leanText, int operLocation) { + processOperator(operLocation); + int loc = operLocation + 1; + char delim = delims[(whichSpecial * 2) + 1]; + loc = leanText.indexOf(delim, loc); + if (loc < 0) + return leanText.length(); + return loc + 1; + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelimsEsc.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelimsEsc.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelimsEsc.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDelimsEsc.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpDelims is a processor for complex expressions + * composed of text segments separated by operators where the text segments + * may include delimited parts within which operators are treated like + * regular characters and the delimiters may be escaped. + * This is similar to {@link ComplExpDelims} except + * that delimiters can be escaped using the backslash character. + *

+ * + * @see IComplExpProcessor + * @see ComplExpBasic + * + * @author Matitiahu Allouche + */ +public class ComplExpDelimsEsc extends ComplExpDelims { + /** + * Constructor for a complex expressions processor with support for + * operators and delimiters which can be escaped. + * + * @param operators string grouping one-character operators which + * separate the text of the complex expression into segments. + * + * @param delims delimiters implemented in this class instance. + * This parameter is a string which must include an even + * number of characters. The first 2 characters of a string + * constitute a pair, the next 2 characters are a second pair, etc... + * In each pair, the first character is a start delimiter and + * the second character is an end delimiter. In the lean + * text, any part starting with a start delimiter and ending with + * the corresponding end delimiter is a delimited part. Within a + * delimited part, operators are treated like regular characters, + * which means that they do not define new segments.
+ *  
+ * Note however that an ending delimiter preceded by an odd + * number of backslashes is considered as a regular character + * and does not mark the termination of a delimited part. + */ + public ComplExpDelimsEsc(String operators, String delims) { + super(operators, delims); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int processSpecial(int whichSpecial, String leanText, int operLocation) { + processOperator(operLocation); + int loc = operLocation + 1; + char delim = delims[(whichSpecial * 2) + 1]; + while (true) { + loc = leanText.indexOf(delim, loc); + if (loc < 0) + return leanText.length(); + int cnt = 0; + for (int i = loc - 1; leanText.charAt(i) == '\\'; i--) { + cnt++; + } + loc++; + if ((cnt & 1) == 0) + return loc; + } + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDoNothing.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDoNothing.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDoNothing.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/ComplExpDoNothing.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,248 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * This class is a minimal processor which implements the + * IComplExpProcessor interface but does no real processing. + * Since it is optimized for minimal overhead, it can + * be used as a low-cost default processor when no complex expression is + * involved and no processing is needed, but a general framework of + * handling complex expressions must be preserved. + * + * @author Matitiahu Allouche + */ +// TBD is this needed? +public class ComplExpDoNothing implements IComplExpProcessor { + + private static final int[] EMPTY_INT_ARRAY = new int[0]; + private static final int[][] ALL_LTR = new int[][] { {DIRECTION_LTR, DIRECTION_LTR}, {DIRECTION_LTR, DIRECTION_LTR}}; + + /** + * Allocate a ComplExpDoNothing processor instance. + * Such a processor does not modify text submitted to it, and can be + * used as a place holder when the text to process is not a known + * complex expression. + */ + public ComplExpDoNothing() { + return; + } + + /** + * For class ComplExpDoNothing + * this method does nothing. + */ + public void selectBidiScript(boolean arabic, boolean hebrew) { + // empty + } + + /** + * For class ComplExpDoNothing + * this method always returns false. + */ + public boolean handlesArabicScript() { + return false; + } + + /** + * For class ComplExpDoNothing + * this method always returns false. + */ + public boolean handlesHebrewScript() { + return false; + } + + /** + * For class ComplExpDoNothing this method + * returns a string identical to the text parameter. + */ + public String leanToFullText(String text) { + return text; + } + + /** + * For class ComplExpDoNothing this method + * returns a string identical to the text parameter. + */ + public String leanToFullText(String text, int initState) { + return text; + } + + /** + * For class ComplExpDoNothing this method + * returns a zero length array. + */ + public int[] leanBidiCharOffsets(String text) { + return EMPTY_INT_ARRAY; + } + + /** + * For class ComplExpDoNothing this method + * returns a zero length array. + */ + public int[] leanBidiCharOffsets(String text, int initState) { + return EMPTY_INT_ARRAY; + } + + /** + * For class ComplExpDoNothing this method + * returns a zero length array. + */ + public int[] leanBidiCharOffsets() { + return EMPTY_INT_ARRAY; + } + + /** + * For class ComplExpDoNothing this method + * returns a zero length array. + */ + public int[] fullBidiCharOffsets() { + return EMPTY_INT_ARRAY; + } + + /** + * For class ComplExpDoNothing this method + * returns a string identical to the text parameter. + */ + public String fullToLeanText(String text) { + return text; + } + + /** + * For class ComplExpDoNothing this method + * returns a string identical to the text parameter. + */ + public String fullToLeanText(String text, int initState) { + return text; + } + + /** + * For class ComplExpDoNothing this method + * returns value {@link #STATE_NOTHING_GOING}. + */ + public int getFinalState() { + return STATE_NOTHING_GOING; + } + + /** + * For class ComplExpDoNothing this method + * returns an index identical to the pos parameter. + */ + public int leanToFullPos(int pos) { + return pos; + } + + /** + * For class ComplExpDoNothing this method + * returns an index identical to the pos parameter. + */ + public int fullToLeanPos(int pos) { + return pos; + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void assumeMirrored(boolean mirrored) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * always returns false. + */ + public boolean isMirrored() { + return false; + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void assumeOrientation(int orientation) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * always returns ORIENT_LTR. + */ + public int recallOrientation() { + return ORIENT_LTR; + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void setArabicDirection(int not_mirrored, int mirrored) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void setArabicDirection(int direction) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void setHebrewDirection(int not_mirrored, int mirrored) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void setHebrewDirection(int direction) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void setDirection(int not_mirrored, int mirrored) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * does nothing. + */ + public void setDirection(int direction) { + // empty + } + + /** + * For class ComplExpDoNothing this method + * returns all directions as DIRECTION_LTR. + */ + public int[][] getDirection() { + return ALL_LTR; + } + + /** + * For class ComplExpDoNothing this method + * returns DIRECTION_LTR. + */ + public int getCurDirection() { + return DIRECTION_LTR; + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpSingle.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/ComplExpSingle.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/ComplExpSingle.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/ComplExpSingle.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpSingle is a processor for complex expressions + * composed of two parts separated by an operator. + * The first occurrence of the operator delimits the end of the first part + * and the start of the second part. Further occurrences of the operator, + * if any, are treated like regular characters of the second text part. + * The processor makes sure that the expression be presented in the form + * (assuming that the equal sign is the operator): + *
+ *  part1=part2
+ *  
+ * + * @see IComplExpProcessor + * @see ComplExpBasic + * + * @author Matitiahu Allouche + */ +public class ComplExpSingle extends ComplExpBasic { + char separator; + + /** + * Constructor for a complex expressions processor with support for one + * operator. + * + * @param operators string including at least one character. The + * first character of the string is the operator which divides + * the expression into 2 parts. + * + */ + public ComplExpSingle(String operators) { + super(operators, 1); + separator = operators.charAt(0); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { + return leanText.indexOf(separator, fromIndex); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int processSpecial(int whichSpecial, String leanText, int operLocation) { + processOperator(operLocation); + return leanText.length(); + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpComma.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpComma.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpComma.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpComma.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +/** + * Processor adapted to processing comma-delimited lists, such as: + *
+ *  part1,part2,part3
+ * 
+ */ +public class ComplExpComma extends ComplExpBasic { + public ComplExpComma() { + super(","); //$NON-NLS-1$ + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpEmail.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpEmail.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpEmail.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpEmail.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpDelimsEsc; + +/** + * Processor adapted to processing e-mail addresses. + */ +public class ComplExpEmail extends ComplExpDelimsEsc { + public ComplExpEmail() { + super("<>.:,;@", "()\"\""); //$NON-NLS-1$ //$NON-NLS-2$ + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpFile.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpFile.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpFile.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpFile.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +/** + * Processor adapted to processing directory and file paths. + */ +public class ComplExpFile extends ComplExpBasic { + public ComplExpFile() { + super(":/\\."); //$NON-NLS-1$ + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpJava.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpJava.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpJava.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpJava.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpJava is a processor for complex expressions + * composed of Java statements. Such a complex expression may span + * multiple lines. + *

+ * In applications like an editor where parts of the text might be modified + * while other parts are not, the user may want to call + * {@link IComplExpProcessor#leanToFullText leanToFullText} + * separately on each line and save the initial state of each line (this is + * the final state of the previous line which can be retrieved using + * {@link IComplExpProcessor#getFinalState getFinalState}. If both the content + * of a line and its initial state have not changed, the user can be sure that + * the last full text computed for this line has not changed either. + * + * @see IComplExpProcessor + * @see ComplExpBasic#state + * + * @author Matitiahu Allouche + */ +public class ComplExpJava extends ComplExpBasic { + private static final byte WS = Character.DIRECTIONALITY_WHITESPACE; + static final String operators = "[](){}.+-<>=~!&*/%^|?:,;\t"; + static String lineSep; + + /** + * Constructor for a complex expressions processor with support for + * Java statements. + */ + public ComplExpJava() { + super(operators, 4); + // TBD use bundle properties + if (lineSep == null) + lineSep = System.getProperty("line.separator", "\n"); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { + switch (whichSpecial) { + case 0 : /* space */ + return leanText.indexOf(' ', fromIndex); + case 1 : /* literal */ + return leanText.indexOf('"', fromIndex); + case 2 : /* slash-aster comment */ + return leanText.indexOf("/*", fromIndex); + case 3 : /* slash-slash comment */ + return leanText.indexOf("//", fromIndex); + } + // we should never get here + return -1; + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int processSpecial(int whichSpecial, String leanText, int operLocation) { + int loc, cnt, i; + + processOperator(operLocation); + switch (whichSpecial) { + case 0 : /* space */ + operLocation++; + while (operLocation < leanText.length() && leanText.charAt(operLocation) == ' ') { + setDirProp(operLocation, WS); + operLocation++; + } + return operLocation; + case 1 : /* literal */ + loc = operLocation + 1; + while (true) { + loc = leanText.indexOf('"', loc); + if (loc < 0) + return leanText.length(); + for (cnt = 0, i = loc - 1; leanText.charAt(i) == '\\'; i--) { + cnt++; + } + loc++; + if ((cnt & 1) == 0) + return loc; + } + case 2 : /* slash-aster comment */ + if (operLocation < 0) + loc = 0; // initial state from previous line + else + loc = operLocation + 2; // skip the opening slash-aster + loc = leanText.indexOf("*/", loc); + if (loc < 0) { + state = 2; + return leanText.length(); + } + return loc + 2; + case 3 : /* slash-slash comment */ + loc = leanText.indexOf(lineSep, operLocation + 2); + if (loc < 0) + return leanText.length(); + return loc + lineSep.length(); + } + // we should never get here + return operLocation + 1; + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpMath.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpMath.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpMath.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpMath.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +/** + * Processor adapted to processing arithmetic expressions with right-to-left + * base direction. + */ +public class ComplExpMath extends ComplExpBasic { + public ComplExpMath() { + super("+-/*()="); //$NON-NLS-1$ + setDirection(DIRECTION_RTL); + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpProperty.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpProperty.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpProperty.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpProperty.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpSingle; + +/** + * Processor adapted to processing property file statements. + * It expects the following string format: + *

+ *  name=value
+ * 
+ */ +public class ComplExpProperty extends ComplExpSingle { + + public ComplExpProperty() { + super("="); //$NON-NLS-1$ + } + +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpRegex.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpRegex.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpRegex.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpRegex.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpRegex is a processor for regular expressions. + * Such expressions may span multiple lines. + *

+ * In applications like an editor where parts of the text might be modified + * while other parts are not, the user may want to call + * {@link IComplExpProcessor#leanToFullText leanToFullText} + * separately on each line and save the initial state of each line (this is + * the final state of the previous line which can be retrieved using + * {@link IComplExpProcessor#getFinalState getFinalState}. If both the content + * of a line and its initial state have not changed, the user can be sure that + * the last full text computed for this line has not changed either. + * + * @see IComplExpProcessor + * @see ComplExpBasic#state + * + * @author Matitiahu Allouche + */ +public class ComplExpRegex extends ComplExpBasic { + static final String operators = ""; + static final String[] startStrings = {"(?#", /* 0 *//* comment (?#...) */ + "(?<", /* 1 *//* named group (? */ + "(?'", /* 2 *//* named group (?'name' */ + "(?(<", /* 3 *//* conditional named back reference (?() */ + "(?('", /* 4 *//* conditional named back reference (?('name') */ + "(?(", /* 5 *//* conditional named back reference (?(name) */ + "(?&", /* 6 *//* named parentheses reference (?&name) */ + "(?P<", /* 7 *//* named group (?P */ + "\\k<", /* 8 *//* named back reference \k */ + "\\k'", /* 9 *//* named back reference \k'name' */ + "\\k{", /* 10 *//* named back reference \k{name} */ + "(?P=", /* 11 *//* named back reference (?P=name) */ + "\\g{", /* 12 *//* named back reference \g{name} */ + "\\g<", /* 13 *//* subroutine call \g */ + "\\g'", /* 14 *//* subroutine call \g'name' */ + "(?(R&", /* 15 *//* named back reference recursion (?(R&name) */ + "\\Q" /* 16 *//* quoted sequence \Q...\E */ + }; + static final char[] endChars = { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + ')', '>', '\'', ')', ')', ')', ')', '>', '>', '\'', '}', ')', '}', '>', '\'', ')'}; + static final int numberOfStrings = startStrings.length; + static final int maxSpecial = numberOfStrings + 1; + + /** + * Constructor for a complex expressions processor with support for + * regular expressions. + */ + public ComplExpRegex() { + super(operators, maxSpecial); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { + byte dirProp; + + if (whichSpecial < numberOfStrings) { + /* 0 *//* comment (?#...) */ + /* 1 *//* named group (? */ + /* 2 *//* named group (?'name' */ + /* 3 *//* conditional named back reference (?(name) */ + /* 4 *//* conditional named back reference (?() */ + /* 5 *//* conditional named back reference (?('name') */ + /* 6 *//* named parentheses reference (?&name) */ + /* 7 *//* named group (?P */ + /* 8 *//* named back reference \k */ + /* 9 *//* named back reference \k'name' */ + /* 10 *//* named back reference \k{name} */ + /* 11 *//* named back reference (?P=name) */ + /* 12 *//* named back reference \g{name} */ + /* 13 *//* subroutine call \g */ + /* 14 *//* subroutine call \g'name' */ + /* 15 *//* named back reference recursion (?(R&name) */ + /* 16 *//* quoted sequence \Q...\E */ + return leanText.indexOf(startStrings[whichSpecial], fromIndex); + } + // look for R, AL, AN, EN which are potentially needing a mark + for (; fromIndex < leanText.length(); fromIndex++) { + // there never is a need for a mark before the first char + if (fromIndex <= 0) + continue; + + dirProp = getDirProp(fromIndex); + // R and AL will always be examined using processOperator() + if (dirProp == R || dirProp == AL) + return fromIndex; + + if (dirProp == EN || dirProp == AN) { + // no need for a mark after the first digit in a number + if (getDirProp(fromIndex - 1) == dirProp) + continue; + + for (int i = fromIndex - 1; i >= 0; i--) { + dirProp = getDirProp(i); + // after a L char, no need for a mark + if (dirProp == L) + continue; + + // digit after R or AL or AN need a mark, except for EN + // following AN, but this is a contrived case, so we + // don't check for it (and calling processOperator() + // for it will do no harm) + if (dirProp == R || dirProp == AL || dirProp == AN) + return fromIndex; + } + continue; + } + } + return -1; + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int processSpecial(int whichSpecial, String leanText, int operLocation) { + int loc; + + switch (whichSpecial) { + case 0 : /* comment (?#...) */ + if (operLocation < 0) { + // initial state from previous line + loc = 0; + } else { + processOperator(operLocation); + // skip the opening "(?#" + loc = operLocation + 3; + } + loc = leanText.indexOf(')', loc); + if (loc < 0) { + state = whichSpecial; + return leanText.length(); + } + return loc + 1; + case 1 : /* named group (? */ + case 2 : /* named group (?'name' */ + case 3 : /* conditional named back reference (?(name) */ + case 4 : /* conditional named back reference (?() */ + case 5 : /* conditional named back reference (?('name') */ + case 6 : /* named parentheses reference (?&name) */ + processOperator(operLocation); + // no need for calling processOperator() for the following cases + // since the starting string contains a L char + case 7 : /* named group (?P */ + case 8 : /* named back reference \k */ + case 9 : /* named back reference \k'name' */ + case 10 : /* named back reference \k{name} */ + case 11 : /* named back reference (?P=name) */ + case 12 : /* named back reference \g{name} */ + case 13 : /* subroutine call \g */ + case 14 : /* subroutine call \g'name' */ + case 15 : /* named back reference recursion (?(R&name) */ + // skip the opening string + loc = operLocation + startStrings[whichSpecial].length(); + // look for ending character + loc = leanText.indexOf(endChars[whichSpecial], loc); + if (loc < 0) + return leanText.length(); + return loc + 1; + case 16 : /* quoted sequence \Q...\E */ + if (operLocation < 0) { + // initial state from previous line + loc = 0; + } else { + processOperator(operLocation); + // skip the opening "\Q" + loc = operLocation + 2; + } + loc = leanText.indexOf("\\E", loc); + if (loc < 0) { + state = whichSpecial; + return leanText.length(); + } + // set the dirProp for the "E" + setDirProp(loc + 1, L); + return loc + 2; + case 17 : /* R, AL, AN, EN */ + processOperator(operLocation); + return operLocation + 1; + + } + // we should never get here + return leanText.length(); + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSql.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSql.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSql.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSql.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +import org.eclipse.equinox.bidi.complexp.IComplExpProcessor; + +/** + * ComplExpSql is a processor for complex expressions + * composed of SQL statements. Such a complex expression may span + * multiple lines. + *

+ * In applications like an editor where parts of the text might be modified + * while other parts are not, the user may want to call + * {@link IComplExpProcessor#leanToFullText leanToFullText} + * separately on each line and save the initial state of each line (this is + * the final state of the previous line which can be retrieved using + * {@link IComplExpProcessor#getFinalState getFinalState}. If both the content + * of a line and its initial state have not changed, the user can be sure that + * the last full text computed for this line has not changed either. + * + * @see IComplExpProcessor + * @see ComplExpBasic#state + * + * @author Matitiahu Allouche + */ +public class ComplExpSql extends ComplExpBasic { + private static final byte WS = Character.DIRECTIONALITY_WHITESPACE; + static final String operators = "\t!#%&()*+,-./:;<=>?|[]{}"; + static String lineSep; + + /** + * Constructor for a complex expressions processor with support for + * SQL statements. + */ + public ComplExpSql() { + super(operators, 5); + // TBD use bundle properties + if (lineSep == null) + lineSep = System.getProperty("line.separator", "\n"); + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int indexOfSpecial(int whichSpecial, String leanText, int fromIndex) { + switch (whichSpecial) { + case 0 : /* space */ + return leanText.indexOf(" ", fromIndex); + case 1 : /* literal */ + return leanText.indexOf('\'', fromIndex); + case 2 : /* delimited identifier */ + return leanText.indexOf('"', fromIndex); + case 3 : /* slash-aster comment */ + return leanText.indexOf("/*", fromIndex); + case 4 : /* hyphen-hyphen comment */ + return leanText.indexOf("--", fromIndex); + } + // we should never get here + return -1; + } + + /** + * This method is not supposed to be invoked directly by users of this + * class. It may be overridden by subclasses of this class. + */ + protected int processSpecial(int whichSpecial, String leanText, int operLocation) { + int loc; + + processOperator(operLocation); + switch (whichSpecial) { + case 0 : /* space */ + operLocation++; + while (operLocation < leanText.length() && leanText.charAt(operLocation) == ' ') { + setDirProp(operLocation, WS); + operLocation++; + } + return operLocation; + case 1 : /* literal */ + loc = operLocation + 1; + while (true) { + loc = leanText.indexOf('\'', loc); + if (loc < 0) { + state = whichSpecial; + return leanText.length(); + } + if ((loc + 1) < leanText.length() && leanText.charAt(loc + 1) == '\'') { + loc += 2; + continue; + } + return loc + 1; + } + case 2 : /* delimited identifier */ + loc = operLocation + 1; + while (true) { + loc = leanText.indexOf('"', loc); + if (loc < 0) + return leanText.length(); + + if ((loc + 1) < leanText.length() && leanText.charAt(loc + 1) == '"') { + loc += 2; + continue; + } + return loc + 1; + } + case 3 : /* slash-aster comment */ + if (operLocation < 0) + loc = 0; // initial state from previous line + else + loc = operLocation + 2; // skip the opening slash-aster + loc = leanText.indexOf("*/", loc); + if (loc < 0) { + state = whichSpecial; + return leanText.length(); + } + // we need to call processOperator since text may follow the + // end of comment immediately without even a space + processOperator(loc); + return loc + 2; + case 4 : /* hyphen-hyphen comment */ + loc = leanText.indexOf(lineSep, operLocation + 2); + if (loc < 0) + return leanText.length(); + return loc + lineSep.length(); + } + // we should never get here + return leanText.length(); + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSystem.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSystem.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSystem.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpSystem.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpSingle; + +/** + * Processor adapted to processing expressions with the following string format: + *

+ *  system(user)
+ * 
+ */ +public class ComplExpSystem extends ComplExpSingle { + + public ComplExpSystem() { + super("("); //$NON-NLS-1$ + } + +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpURL.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpURL.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpURL.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpURL.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +/** + * Processor adapted to processing URLs. + */ +public class ComplExpURL extends ComplExpBasic { + public ComplExpURL() { + super(":?#/@.[]"); //$NON-NLS-1$ + } +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpUnderscore.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpUnderscore.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpUnderscore.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpUnderscore.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpBasic; + +/** + * Processor adapted to processing compound names. + * This type covers names made of one or more parts, separated by underscores: + *
+ *  part1_part2_part3
+ * 
+ */ +public class ComplExpUnderscore extends ComplExpBasic { + public ComplExpUnderscore() { + super("_"); //$NON-NLS-1$ + } + +} Index: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpXPath.java =================================================================== RCS file: src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpXPath.java diff -N src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpXPath.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/equinox/bidi/internal/complexp/consumable/ComplExpXPath.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2010 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.equinox.bidi.internal.complexp.consumable; + +import org.eclipse.equinox.bidi.internal.complexp.ComplExpDelims; + +/** + * Processor adapted to processing XPath expressions. + */ +public class ComplExpXPath extends ComplExpDelims { + public ComplExpXPath() { + super(" /[]<>=!:@.|()+-*", "''\"\""); //$NON-NLS-1$ //$NON-NLS-2$ + } +}