/* * #%~ * org.overture.ide.ui * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ide.ui.editor.syntax; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.IWordDetector; import org.eclipse.jface.text.rules.Token; import org.eclipse.jface.text.rules.WordRule; /** * Rule scanner for multiword words like "is subclass responsibility". * * @author kel */ public class MultipleWordsWordRule extends WordRule { /** * Used as result for {@link MultipleWordsWordRule#checkMatch(String)} to hold the token and unmatched length * * @author kel */ private static class WordMatch { public final IToken token; public final Integer unMatchedLength; public WordMatch(IToken token, Integer unMatchedLength) { this.token = token; this.unMatchedLength = unMatchedLength; } } public MultipleWordsWordRule(IWordDetector detector, IToken defaultToken, boolean ignoreCase) { super(detector, defaultToken, ignoreCase); } private StringBuffer fBuffer = new StringBuffer(); private boolean fIgnoreCase = false; @SuppressWarnings("unchecked") public void addWord(String word, IToken token) { Assert.isNotNull(word); Assert.isNotNull(token); // If case-insensitive, convert to lower case before adding to the map if (fIgnoreCase) { word = word.toLowerCase(); } fWords.put(word, token); } /** * Calculates the maximum number of parts in the largest word in the rule scanner * * @return the largest number of parts. (number of spaces spaced words" */ private int getMaxPartCount() { int max = 0; for (Object k : super.fWords.keySet()) { String key = k.toString(); int count = key.split("\\s+?").length; if (count > max) { max = count; } } return max; } int offset = 0; private int read(ICharacterScanner scanner){ offset++; return scanner.read(); } private void unread(ICharacterScanner scanner){ offset--; scanner.unread(); } private IToken returnEmpty(IToken token) { if(offset!=0) { System.out.println("Something is wrong: "+offset); } return token; } /* * @see IRule#evaluate(ICharacterScanner) */ public IToken evaluate(ICharacterScanner scanner) { offset = 0; int c = read(scanner); if (c != ICharacterScanner.EOF && fDetector.isWordStart((char) c)) { if (fColumn == UNDEFINED || fColumn == scanner.getColumn() - 1) { fBuffer.setLength(0); fBuffer.append((char) c); for (int i = 0; i < getMaxPartCount(); i++) { // read a word for each part do { c = read(scanner); fBuffer.append((char) c); // System.out.println("Read: '"+c + "' - '"+(char)c+"'"); } while (c != ICharacterScanner.EOF && c != ' ' && fDetector.isWordStart((char) c)); } // we may have read EOF so unread it popEof(scanner); final char lastChar = fBuffer.charAt(fBuffer.length()-1); if (lastChar==' ' || lastChar=='\t' || lastChar=='\n' || lastChar=='\r') { unread(scanner);// last space fBuffer.delete(fBuffer.length() - 1, fBuffer.length()); } String text = fBuffer.toString().toString().replace('\n', ' ').replace('\r', ' ').replace('\t', ' '); String key = text;// text.substring(0, text.length() - 1); WordMatch match = checkMatch(key); if (match != null) { if (match.unMatchedLength > 0) { // unread unmatched parts for (int i = 0; i < match.unMatchedLength; i++) { unread(scanner); } } return match.token; } if (fDefaultToken.isUndefined()) { unreadBuffer(scanner); } return returnEmpty(fDefaultToken); } } unread(scanner); return returnEmpty(Token.UNDEFINED); } private void popEof(ICharacterScanner scanner) { while (fBuffer.length() > 0 && fBuffer.charAt(fBuffer.length() - 1) == (char) -1) { unread(scanner); fBuffer.delete(fBuffer.length() - 1, fBuffer.length()); } } /** * Checks if the scanned multipart word exists in the {@code fWords} maps keys collection os if the prefix exists. * * @param key * @return */ private WordMatch checkMatch(String key) { String matchString = key; while (matchString.indexOf(' ') > -1) { if (fWords.containsKey(matchString)) { // System.out.println("key '"+key+"' not matched: "+(key.length() // - matchString.length())); return new WordMatch((IToken) fWords.get(matchString), key.length() - matchString.length()); } matchString = matchString.substring(0, matchString.lastIndexOf(' ')); } return null; } protected void unreadBuffer(ICharacterScanner scanner) { // System.out.println("Did not match '"+fBuffer+"' " + fBuffer.length()); for (int i = fBuffer.length() - 1; i >= 0; i--) { unread(scanner); // System.out.println("Unread"); } } }