/******************************************************************************* * Copyright (c) 2005, 2009 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.internal.xpand2.codeassist; import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.internal.xpand2.XpandTokens; import org.eclipse.internal.xtend.expression.codeassist.ProposalComputer; import org.eclipse.internal.xtend.expression.codeassist.ProposalFactory; import org.eclipse.xtend.expression.ExecutionContext; public class StatementProposalComputer implements ProposalComputer { public List<Object> computeProposals(final String txt, final ExecutionContext ctx, final ProposalFactory factory) { final List<Object> result = new ArrayList<Object>(); final String prefix = ""; final String ws = findTrailingWhitespace(txt); final Stack<StackElement> s = FastAnalyzer.computeStack(txt); if (s.size() > 0) { final StackElement se = s.peek(); result.add(factory.createStatementProposal(XpandTokens.LT + "END" + se.block + XpandTokens.RT, "END" + se.block, prefix)); if (contains(XpandTokens.IF, s)) { result.add(factory.createStatementProposal(XpandTokens.LT + "ELSE" + XpandTokens.RT, "ELSE", prefix)); result.add(factory.createStatementProposal(XpandTokens.LT + "ELSEIF statement" + XpandTokens.RT, "ELSEIF", prefix)); } if (!contains(XpandTokens.FILE, s)) { result.add(fileBlockProposal(ws, factory)); } if (!contains(XpandTokens.PROTECT, s)) { result.add(protectBlockProposal(ws, factory)); } result.add(foreachBlockProposal(ws, factory)); result.add(ifBlockProposal(ws, factory)); result.add(letBlockProposal(ws, factory)); result.add(expandStatementProposal(ws, factory)); result.add(remBlockProposal(ws, factory)); } else { if (txt.indexOf(XpandTokens.LT + XpandTokens.DEFINE) == -1) { if (txt.indexOf(XpandTokens.LT + XpandTokens.EXTENSION) == -1) { result.add(importStatementProposal(factory)); } result.add(extensionStatementProposal(factory)); } result.add(defineBlockProposal(ws, factory)); result.add(aroundBlockProposal(ws, factory)); result.add(remBlockProposal(ws, factory)); } return result; } private Object importStatementProposal(final ProposalFactory factory) { final String insertString = XpandTokens.LT + XpandTokens.IMPORT + " my::imported::namespace" + XpandTokens.RT; return factory.createStatementProposal(insertString, "IMPORT statement", "", insertString .indexOf("my::imported::namespace"), "my::imported::namespace".length()); } private Object extensionStatementProposal(final ProposalFactory factory) { final String insertString = XpandTokens.LT + XpandTokens.EXTENSION + " path::to::AbstractExtension" + XpandTokens.RT; return factory.createStatementProposal(insertString, "EXTENSION statement", "", insertString .indexOf("path::to::AbstractExtension"), "path::to::AbstractExtension".length()); } private final static Pattern WS_PATTERN = Pattern.compile("(\\n?[\\t ]*)\\z"); private String findTrailingWhitespace(final String txt) { final Matcher m = StatementProposalComputer.WS_PATTERN.matcher(txt); m.find(); return m.group(1); } private Object expandStatementProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "EXPAND definition FOR this" + XpandTokens.RT; return factory.createStatementProposal(insertString, "EXPAND statement", "", insertString.indexOf("definition"), "definition".length()); } private Object letBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "LET expression AS e" + XpandTokens.RT + ws + XpandTokens.LT + "ENDLET" + XpandTokens.RT; return factory.createStatementProposal(insertString, "LET block", "", insertString.indexOf("expression"), "expression".length()); } private Object ifBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "IF condition" + XpandTokens.RT + ws + XpandTokens.LT + "ENDIF" + XpandTokens.RT; return factory.createStatementProposal(insertString, "IF block", "", insertString.indexOf("condition"), "condition".length()); } private Object foreachBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "FOREACH elements AS e" + XpandTokens.RT + ws + XpandTokens.LT + "ENDFOREACH" + XpandTokens.RT; return factory.createStatementProposal(insertString, "FOREACH block", "", insertString.indexOf("elements"), "elements".length()); } private Object protectBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "PROTECT CSTART '/*' CEND '*/' ID uniqueId" + XpandTokens.RT + ws + XpandTokens.LT + "ENDPROTECT" + XpandTokens.RT; return factory.createStatementProposal(insertString, "PROTECT region", "", insertString.indexOf("uniqueId"), "uniqueId".length()); } private Object fileBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "FILE fileName" + XpandTokens.RT + ws + XpandTokens.LT + "ENDFILE" + XpandTokens.RT; return factory.createStatementProposal(insertString, "FILE block", "", insertString.indexOf("fileName"), "fileName".length()); } private Object defineBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "DEFINE definionName FOR Type" + XpandTokens.RT + ws + XpandTokens.LT + "ENDDEFINE" + XpandTokens.RT; return factory.createStatementProposal(insertString, "new DEFINE", "", insertString.indexOf("definionName"), "definionName".length()); } private Object aroundBlockProposal(final String ws, final ProposalFactory factory) { final String insertString = XpandTokens.LT + "AROUND fullyQualifiedDefinionName FOR Type" + XpandTokens.RT + ws + XpandTokens.LT + "ENDAROUND" + XpandTokens.RT; return factory.createStatementProposal(insertString, "new AROUND", "", insertString .indexOf("fullyQualifiedDefinionName"), "fullyQualifiedDefinionName".length()); } /** * Creates a proposal for a REM block * * @param ws * @param factory * @return * @since 4.2 */ private Object remBlockProposal(final String ws, final ProposalFactory factory) { final String blockContent = "comment"; final String insertString = XpandTokens.LT + "REM" + XpandTokens.RT + blockContent + XpandTokens.LT + "ENDREM" + XpandTokens.RT; return factory.createStatementProposal(insertString, "REM block", "", insertString.indexOf(blockContent), blockContent.length()); } private boolean contains(final String blockName, final Stack<StackElement> s) { for (StackElement element : s) { if (element.block.equals(blockName)) { return true; } } return false; } protected String findPrefix(final String txt) { final StringBuffer result = new StringBuffer(); int i = txt.length() - 1; char c = txt.charAt(i); while (i > 0 && Character.isJavaIdentifierStart(c)) { result.append(c); c = txt.charAt(--i); } return result.reverse().toString(); } }