/******************************************************************************* * Copyright (c) 2011 Sebastian Benz. * 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: * Sebastian Benz - initial API and implementation ******************************************************************************/ package de.sebastianbenz.xgherkin.ui.highlighting; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightedPositionAcceptor; import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator; import de.sebastianbenz.xgherkin.gherkin.Example; import de.sebastianbenz.xgherkin.gherkin.ExampleRow; import de.sebastianbenz.xgherkin.gherkin.GherkinPackage; import de.sebastianbenz.xgherkin.gherkin.Step; import de.sebastianbenz.xgherkin.gherkin.util.GherkinSwitch; public class SemanticHighlightingCalculator implements ISemanticHighlightingCalculator { private static final Pattern PLACEHOLDER = Pattern.compile("<[^<\\r\\n]*>"); private class Implementation extends GherkinSwitch<Boolean> { private final IHighlightedPositionAcceptor acceptor; public Implementation(IHighlightedPositionAcceptor acceptor) { this.acceptor = acceptor; } @Override public Boolean caseExample(Example example) { ExampleRow heading = example.getHeading(); if (heading == null) { return Boolean.TRUE; } ICompositeNode node = NodeModelUtils.getNode(heading); acceptor.addPosition(node.getOffset(), node.getLength(), HighlightingConfiguration.CODE_BOLD_ID); return Boolean.TRUE; } @Override public Boolean caseStep(Step object) { String desc = object.getDesc().get(0); highlightFirstWord(object, desc); hightlightPlaceHolders(object, desc); return Boolean.TRUE; } private void hightlightPlaceHolders(Step object, String desc) { Matcher matcher = PLACEHOLDER.matcher(desc); while (matcher.find()) { int offset = matcher.start() + offset(object); int length = matcher.end() - matcher.start(); acceptor.addPosition(offset, length, HighlightingConfiguration.CODE_BOLD_ID); } } // @Override // public Boolean caseAsA(AsA object) { // highlight("As a", object); // return Boolean.TRUE; // } // // @Override // public Boolean caseInOrderTo(InOrderTo object) { // highlight("In order to", object); // return Boolean.TRUE; // } // // @Override // public Boolean caseIWantTo(IWantTo object) { // highlight("I want to", object); // return Boolean.TRUE; // } private void highlightFirstWord(Step object, String desc) { int begin = 0; for (; isWhiteSpace(desc, begin); begin++) { } int end = desc.indexOf(' ', begin); if (end > 0) { highlight(desc.substring(begin, end), object); } } private boolean isWhiteSpace(String desc, int begin) { return desc.charAt(begin) == ' ' || desc.charAt(begin) == '\t'; } // @Override // public Boolean caseAndStep(AndStep object) { // highlight("And", object); // return Boolean.TRUE; // } // // @Override // public Boolean caseGivenStep(GivenStep object) { // highlight("Given", object); // return Boolean.TRUE; // } // // @Override // public Boolean caseThenStep(ThenStep object) { // highlight("Then", object); // return Boolean.TRUE; // } // // @Override // public Boolean caseWhenStep(WhenStep object) { // highlight("When", object); // return Boolean.TRUE; // } // private void highlight(String string, Step object) { acceptor.addPosition(offset(object), string.length(), HighlightingConfiguration.KEYWORD_ID); } private int offset(Step content) { List<INode> nodes = NodeModelUtils.findNodesForFeature(content, GherkinPackage.Literals.STEP__DESC); return nodes.iterator().next().getOffset(); } } public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor) { if (noNodeModel(resource)) { return; } Implementation highlighter = new Implementation(acceptor); Iterator<EObject> contents = resource.getAllContents(); while (contents.hasNext()) { highlighter.doSwitch((EObject) contents.next()); } } protected EObject root(XtextResource resource) { return resource.getParseResult().getRootASTElement(); } protected boolean noNodeModel(XtextResource resource) { return resource == null || resource.getParseResult() == null || root(resource) == null; } }