| /******************************************************************************* |
| * Copyright (c) 2010, 2011 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.consumable; |
| |
| import org.eclipse.equinox.bidi.advanced.IStructuredTextExpert; |
| import org.eclipse.equinox.bidi.custom.*; |
| import org.eclipse.equinox.bidi.internal.StructuredTextActivator; |
| |
| /** |
| * Handler for structured text composed of SQL statements. |
| * Such a structured text may span multiple lines. |
| * <p> |
| * 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 IStructuredTextExpert#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 by calling |
| * {@link IStructuredTextExpert#getState()}. |
| * If both the content |
| * of a line and its initial state have not changed, the user can be sure that |
| * the last <i>full</i> text computed for this line has not changed either. |
| * |
| * @see IStructuredTextExpert explanation of state |
| */ |
| public class StructuredTextSql extends StructuredTextTypeHandler { |
| private static final byte WS = Character.DIRECTIONALITY_WHITESPACE; |
| static final String lineSep = StructuredTextActivator.getProperty("line.separator"); //$NON-NLS-1$ |
| private static final Integer STATE_LITERAL = new Integer(2); |
| private static final Integer STATE_SLASH_ASTER_COMMENT = new Integer(4); |
| |
| public StructuredTextSql() { |
| super("\t!#%&()*+,-./:;<=>?|[]{}"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * @return 5 as the number of special cases handled by this handler. |
| */ |
| public int getSpecialsCount(IStructuredTextExpert expert) { |
| return 5; |
| } |
| |
| /** |
| * Locates occurrences of 5 special strings: |
| * <ol> |
| * <li>spaces</li> |
| * <li>literals starting with apostrophe</li> |
| * <li>identifiers starting with quotation mark</li> |
| * <li>comments starting with slash-asterisk</li> |
| * <li>comments starting with hyphen-hyphen</li> |
| * </ol> |
| */ |
| public int indexOfSpecial(IStructuredTextExpert expert, String text, StructuredTextCharTypes charTypes, StructuredTextOffsets offsets, int caseNumber, int fromIndex) { |
| switch (caseNumber) { |
| case 1 : /* space */ |
| return text.indexOf(" ", fromIndex); //$NON-NLS-1$ |
| case 2 : /* literal */ |
| return text.indexOf('\'', fromIndex); |
| case 3 : /* delimited identifier */ |
| return text.indexOf('"', fromIndex); |
| case 4 : /* slash-aster comment */ |
| return text.indexOf("/*", fromIndex); //$NON-NLS-1$ |
| case 5 : /* hyphen-hyphen comment */ |
| return text.indexOf("--", fromIndex); //$NON-NLS-1$ |
| } |
| // we should never get here |
| return -1; |
| } |
| |
| /** |
| * Processes the 5 special cases as follows. |
| * <ol> |
| * <li>skip the run of spaces</li> |
| * <li>look for a matching apostrophe and skip until after it</li> |
| * <li>look for a matching quotation mark and skip until after it</li> |
| * <li>skip until after the closing asterisk-slash</li> |
| * <li>skip until after a line separator</li> |
| * </ol> |
| */ |
| public int processSpecial(IStructuredTextExpert expert, String text, StructuredTextCharTypes charTypes, StructuredTextOffsets offsets, int caseNumber, int separLocation) { |
| int location; |
| |
| StructuredTextTypeHandler.processSeparator(text, charTypes, offsets, separLocation); |
| if (separLocation < 0) { |
| caseNumber = ((Integer) expert.getState()).intValue(); // TBD guard against "undefined" |
| expert.clearState(); |
| } |
| switch (caseNumber) { |
| case 1 : /* space */ |
| separLocation++; |
| while (separLocation < text.length() && text.charAt(separLocation) == ' ') { |
| charTypes.setBidiTypeAt(separLocation, WS); |
| separLocation++; |
| } |
| return separLocation; |
| case 2 : /* literal */ |
| location = separLocation + 1; |
| while (true) { |
| location = text.indexOf('\'', location); |
| if (location < 0) { |
| expert.setState(STATE_LITERAL); |
| return text.length(); |
| } |
| if ((location + 1) < text.length() && text.charAt(location + 1) == '\'') { |
| location += 2; |
| continue; |
| } |
| return location + 1; |
| } |
| case 3 : /* delimited identifier */ |
| location = separLocation + 1; |
| while (true) { |
| location = text.indexOf('"', location); |
| if (location < 0) |
| return text.length(); |
| |
| if ((location + 1) < text.length() && text.charAt(location + 1) == '"') { |
| location += 2; |
| continue; |
| } |
| return location + 1; |
| } |
| case 4 : /* slash-aster comment */ |
| if (separLocation < 0) // continuation line |
| location = 0; |
| else |
| location = separLocation + 2; // skip the opening slash-aster |
| location = text.indexOf("*/", location); //$NON-NLS-1$ |
| if (location < 0) { |
| expert.setState(STATE_SLASH_ASTER_COMMENT); |
| return text.length(); |
| } |
| // we need to call processSeparator since text may follow the |
| // end of comment immediately without even a space |
| StructuredTextTypeHandler.processSeparator(text, charTypes, offsets, location); |
| return location + 2; |
| case 5 : /* hyphen-hyphen comment */ |
| location = text.indexOf(lineSep, separLocation + 2); |
| if (location < 0) |
| return text.length(); |
| return location + lineSep.length(); |
| } |
| // we should never get here |
| return text.length(); |
| } |
| |
| } |