/*******************************************************************************
* Copyright (c) 2005, 2012 eBay Inc.
* 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
*
*******************************************************************************/
package org.eclipse.vjet.eclipse.codeassist.keywords;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.dltk.mod.compiler.env.ISourceModule;
public class SimpleKeywordCompletionEngine implements KeywordCompletionEngine {
private static final char TRIGGER_SPACE = ' ';
private static final char TRIGGER_TAB = '\t';
private static final char TRIGGER_DOT = '.';
private static final char TRIGGER_SEMICOLON = ';';
private static final char TRIGGER_COLON = ':';
private static final char TRIGGER_LPARENTHESIS = '(';
private static final char TRIGGER_RPARENTHESIS = ')';
private static final char TRIGGER_LBRACE = '{';
private static final char TRIGGER_RBRACE = '}';
private static final char TRIGGER_NEWLINE_1 = '\r';
private static final char TRIGGER_NEWLINE_2 = '\n';
private static final String TRIGGER_LINE = " \t.;:{}()\r\n";
private static final String EMPTY = "";
private int cursor;
private char[] cntx;
private int initPos;
private int startPosToComplete;
private static VjoKeywordCompletionResult prevResult = null;
private List<IVjoCompletionData> keywords = new ArrayList<IVjoCompletionData>();
public SimpleKeywordCompletionEngine(ISourceModule module, int initPos) {
this.cntx = module.getSourceContents().toCharArray();
this.initPos = initPos - 1;
}
private char[] getInvertedBackwardBlock(int size) {
int amount = cursor < size ? cursor + 1 : size;
int limit = cursor - amount;
char[] block = new char[amount];
for (int iter = cursor; iter > limit; iter--) {
block[cursor - iter] = cntx[iter];
}
return block;
}
private void processingContext() {
boolean stopSearching = false;
cursor = initPos;
int bCounter = 0; // braces counter {
int pCounter = 0; // parenthesis counter (
int unclosedBFlags = 0; // right braces counter
int unclosedPFlags = 0; // right braces counter
while (cursor != -1 && !stopSearching) {
switch (cntx[cursor]) {
case TRIGGER_RPARENTHESIS: // )
// maybe this is end of top-level keywords such as protos,
// props, ect.
// this can be also end of function parameter declaration
if (pCounter == 0) {
IVjoCompletionData nearestKeyword = new VjoKeywordPatternHelper(
getInvertedBackwardBlock(100)).lookupNearestKeyword();
if (nearestKeyword != null) { // if null still searching
if (nearestKeyword.isTopLevelKeyword()
&& !nearestKeyword.isComposableKeyword()) {
keywords.addAll(((ITopLevel) nearestKeyword).getPeerKeywords());
stopSearching = true;
} else if (nearestKeyword.isComposableKeyword()) {
keywords.addAll(((IComposable) nearestKeyword).getAllowedCompositeKeywords());
stopSearching = true;
}
}
}
unclosedPFlags++;
pCounter++; // increase parenthesis counter
break;
case TRIGGER_LPARENTHESIS: // (
// maybe this is start of top-level keywords such as protos,
// props, ect.
// this can be also start of function parameter declaration
pCounter--; // decrease parenthesis counter
break;
case TRIGGER_RBRACE: // }
unclosedBFlags++;
bCounter++; // increase braces counter
break;
case TRIGGER_LBRACE: // {
if (bCounter == 0) {
// we are inside some block
// lookup for the nearest keyword
IVjoCompletionData nearestKeyword = new VjoKeywordPatternHelper(
getInvertedBackwardBlock(100)).lookupNearestKeyword();
stopSearching = true;
if(nearestKeyword != null){
keywords.addAll( ((IEnclosable) nearestKeyword).getAllowedEnclosedKeywords());
}
// else specified keyword isn't implemented yet
}
else if (bCounter == 1) {
if (pCounter == 1) {
// we are outside of top-level keyword such as
// protos, props, ect...
IVjoCompletionData nearestKeyword = new VjoKeywordPatternHelper(
getInvertedBackwardBlock(100)).lookupNearestKeyword();
keywords.addAll(((IComposable) nearestKeyword).getAllowedCompositeKeywords());
stopSearching = true;
} else if (unclosedBFlags == 1 && unclosedPFlags == 0) {
// maybe we are after unclosed keyword like 'do'
// we need to get complemented parts for it
IVjoCompletionData nearestKeyword = new VjoKeywordPatternHelper(
getInvertedBackwardBlock(100)).lookupNearestKeyword();
if (nearestKeyword != null && nearestKeyword.isUnclosed()) {
keywords = ((IUnclosed) nearestKeyword).getComplementedKeywords();
// store last position
int cur = cursor;
// filter obtained complemented keywords
filter();
stopSearching = !((IUnclosed)nearestKeyword).isSelfSufficient();
// reset cursor to the last saved position
cursor = cur;
}
// else still searching...
}
}// end bCounter == 1
bCounter--; // decrease breaces counter
// ---- end case TRIGGER_LBRACE
}// end switch
cursor--;
}// end while
if (cursor == -1 && !stopSearching) {
// we are at the start of editor page
// get all top-level keywords
keywords.addAll(VjoKeywordFactory.getTopLevelKeywords());
}
}
private void filter() {
List<IVjoCompletionData> filteredKeywords = new ArrayList<IVjoCompletionData>();
// return to the initial position
cursor = initPos;
char[] invertedBlock = getInvertedBackwardBlock(100);
Iterator<IVjoCompletionData> iterator = keywords.iterator();
while (iterator.hasNext()) {
IVjoCompletionData keyword = iterator.next();
if (new VjoKeywordPatternHelper(invertedBlock)
.isSuitableForCompleteion(keyword)) {
cursor = initPos;
StringBuffer buf = new StringBuffer();
// search word to complete
while (cursor > -1 && (TRIGGER_LINE.indexOf(cntx[cursor]) == -1 ||
keyword.isAllowedTrigger(cntx[cursor]))) {
buf.insert(0, cntx[cursor--]);
}
String word = buf.toString();
startPosToComplete = cursor + 1;
if (keyword.canComplete(word)) {
filteredKeywords.add(keyword);
}
}
keywords = filteredKeywords;
}
}
/* (non-Javadoc)
* @see org.eclipse.vjet.eclipse.codeassist.keywords.KeywordCompletionEngine#getCompletionResult()
*/
public VjoKeywordCompletionResult getCompletionResult() {
// parsing context
processingContext();
// filter obtained keywords
filter();
// return filtered keywords
return getCompletionResultForVjoKeyword(keywords, startPosToComplete);
}
private static VjoKeywordCompletionResult getCompletionResultForVjoKeyword(
List<IVjoCompletionData> keywords, int startPosToComplete) {
prevResult = new VjoKeywordCompletionResult(keywords,
startPosToComplete);
return prevResult;
}
public static VjoKeywordCompletionResult getJustObtainedResult() {
return prevResult;
}
}