/******************************************************************************* * Copyright (c) 2012 itemis AG (http://www.itemis.eu) 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 *******************************************************************************/ package org.xpect.expectation.impl; import java.util.List; import org.xpect.XpectArgument; import org.xpect.expectation.IExpectationRegion; import org.xpect.expectation.IMultiLineExpectationRegion; import org.xpect.expectation.ISingleLineExpectationRegion; import org.xpect.expectation.impl.TargetSyntaxSupport.TargetLiteralSupport; import org.xpect.text.IReplacement; import org.xpect.text.Replacement; import org.xpect.text.Text; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Strings; /** * @author Moritz Eysholdt - Initial contribution and API */ public class AbstractExpectation { private final XpectArgument argument; private final IExpectationRegion region; private final TargetLiteralSupport targetLiteral; private final TargetSyntaxSupport targetSyntax; public AbstractExpectation(XpectArgument argument, TargetSyntaxSupport targetSyntax) { super(); this.argument = argument; this.region = argument.getStatement().getRelatedRegion(IExpectationRegion.class); Preconditions.checkPositionIndex(region.getOffset(), region.getDocument().length()); Preconditions.checkPositionIndex(region.getOffset() + region.getLength(), region.getDocument().length()); this.targetSyntax = targetSyntax; this.targetLiteral = targetSyntax.getLiteralSupport(region.getOffset()); } protected String findValidSeparator(String value, String suggestedSeparator) { if (suggestedSeparator != null && !value.contains(suggestedSeparator)) return suggestedSeparator; final String chars = "-~=+*%#$&"; for (int i = 3; i < 80; i++) { for (int c = 0; i < chars.length(); c++) { String separator = Strings.repeat(String.valueOf(chars.charAt(c)), i); if (!value.contains(separator)) return separator; } } throw new IllegalStateException(); } public XpectArgument getArgument() { return argument; } public String getExpectation() { if (region.getLength() < 0) return ""; Text substring = new Text(region.getDocument().toString().substring(region.getOffset(), region.getOffset() + region.getLength())); if (region instanceof IMultiLineExpectationRegion) { String indentation = ((IMultiLineExpectationRegion) region).getIndentation(); List<String> lines = substring.splitIntoLines(); String newLines[] = new String[lines.size()]; for (int i = 0; i < lines.size(); i++) if (lines.get(i).startsWith(indentation)) newLines[i] = lines.get(i).substring(indentation.length()); else newLines[i] = lines.get(i); return Joiner.on(substring.getNL()).join(newLines); } else { return substring.getText().toString(); } } public IExpectationRegion getRegion() { return region; } protected IReplacement getReplacement(Text value, boolean enforceMultiLine) { Text document = new Text(region.getDocument()); if (region instanceof IMultiLineExpectationRegion) { IMultiLineExpectationRegion mlRegion = (IMultiLineExpectationRegion) region; String indentation = mlRegion.getIndentation(); String separator = findValidSeparator(value.toString(), mlRegion.getSeparator()); int sepOpening = mlRegion.getOpeningSeparatorOffset(); int sepClosing = mlRegion.getClosingSeparatorOffset(); String betweenSeparatorAndExpectation = document.substring(sepOpening + mlRegion.getSeparator().length(), mlRegion.getOffset()); String betweenExpectationAndSeparator = document.substring(mlRegion.getOffset() + mlRegion.getLength(), sepClosing); String indented = indentation + value.indentWith(indentation); StringBuilder builder = new StringBuilder(); builder.append(separator); builder.append(betweenSeparatorAndExpectation); builder.append(indented); builder.append(betweenExpectationAndSeparator); builder.append(separator); return new Replacement(document.getText(), sepOpening, (sepClosing + mlRegion.getSeparator().length()) - sepOpening, builder.toString()); } else if (region instanceof ISingleLineExpectationRegion) { ISingleLineExpectationRegion slRegion = (ISingleLineExpectationRegion) region; if (enforceMultiLine) { String separator = findValidSeparator(value.toString(), null); String indentation = document.findIndentation(slRegion.getOpeningSeparatorOffset()); String insideIndentation = indentation; if (insideIndentation.length() > 0) { char first = insideIndentation.charAt(0); if (first == '\t') insideIndentation += first; else insideIndentation += "" + first + first + first + first; } String indented = insideIndentation + value.indentWith(insideIndentation); StringBuilder builder = new StringBuilder(); builder.append(separator); builder.append(document.getNL()); builder.append(indented); builder.append(document.getNL()); builder.append(indentation); builder.append(separator); int length = (slRegion.getOffset() - slRegion.getOpeningSeparatorOffset()) + slRegion.getLength(); return new Replacement(document.getText(), slRegion.getOpeningSeparatorOffset(), length, builder.toString()); } else { return new Replacement(document.getText(), region.getOffset(), region.getLength(), value.toString()); } } throw new IllegalStateException(); } public TargetSyntaxSupport getTargetSyntax() { return targetSyntax; } public TargetLiteralSupport getTargetSyntaxLiteral() { return targetLiteral; } protected String replaceInDocument(String newValue) { Text document = new Text(region.getDocument()); Text value = new Text(newValue); boolean multiline = targetSyntax.supportsMultiLineLiteral() && value.isMultiline(); IReplacement replacement = getReplacement(value, multiline); IReplacement targetReplacement = targetLiteral.adoptToTargetSyntax(replacement, multiline); return document.with(targetReplacement); } }