/******************************************************************************* * Copyright (c) 2011, 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: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.lang.ide.core_text; import java.util.function.Function; import melnorme.utilbox.misc.ArrayUtil; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IRule; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.IWordDetector; import org.eclipse.jface.text.rules.Token; /** * A rule that matches exact sequences in the scanner. * A word detector is used to specify word parts that if present after a matched possible sequence, * will cause this rule *not* to match. * It is recommended that there are not too many possibleSequence's as performance will not be ideal otherwise. */ public class FullPatternRule implements IRule { protected IToken token; protected final IWordDetector ruleCancelWordDetector; protected char[][] possibleSequences; public FullPatternRule(IToken token, String[] possibleSequences, IWordDetector ruleCancelWordDetector) { this.token = token; this.ruleCancelWordDetector = ruleCancelWordDetector; this.possibleSequences = ArrayUtil.map(possibleSequences, STRING_to_CHAR_ARRAY, char[].class); } @Override public IToken evaluate(ICharacterScanner scanner) { int ch = scanner.read(); for (int i = 0; i < possibleSequences.length; i++) { char[] sequence = possibleSequences[i]; if(matchesSequence(scanner, ch, sequence)) { int endCh = scanner.read(); scanner.unread(); // rewind end character if(endCh == ICharacterScanner.EOF || !ruleCancelWordDetector.isWordPart((char) endCh)) { return token; } // need to rewind scanner until first character scannerUnread(scanner, sequence.length-1); } } scanner.unread(); return Token.UNDEFINED; } /** Returns true or false according to whether scanner matches given sequence, with given firstChar already read * from the scanner. */ protected static boolean matchesSequence(ICharacterScanner scanner, int firstChar, char[] sequence) { int ch = firstChar; if(ch == sequence[0]) { for(int i = 1; i < sequence.length; ++i) { ch = scanner.read(); // The if will also trigger if ch is EOF if(ch != sequence[i]) { // need to rewind scanner until first character scannerUnread(scanner, i); return false; } } return true; } return false; } protected static void scannerUnread(ICharacterScanner scanner, int count) { while(--count >= 0) { scanner.unread(); } } public static final Function<String, char[]> STRING_to_CHAR_ARRAY = new Function<String, char[]>() { @Override public char[] apply(String obj) { return obj.toCharArray(); } }; }