/** * Copyright (c) 2012 Cloudsmith Inc. and other contributors, as listed below. * 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: * Cloudsmith * */ package org.cloudsmith.xtext.dommodel.formatter; import org.cloudsmith.xtext.dommodel.DomModelUtils; import org.cloudsmith.xtext.dommodel.IDomNode; import org.cloudsmith.xtext.dommodel.formatter.context.IFormattingContext; import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic; import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic.Acceptor; import org.eclipse.xtext.util.ITextRegion; import org.eclipse.xtext.util.ReplaceRegion; import org.eclipse.xtext.util.TextRegion; /** * A Dom Model Formatter that ensures a single whitespace between tokens. * */ public class OneWhitespaceDomFormatter implements IDomModelFormatter { boolean hasStarted; boolean wsWritten; @Override public ReplaceRegion format(IDomNode dom, ITextRegion regionToFormat, IFormattingContext formattingContext) { return format(dom, regionToFormat, formattingContext, ISerializationDiagnostic.EXCEPTION_THROWING_ACCEPTOR); } @Override public ReplaceRegion format(IDomNode dom, ITextRegion regionToFormat, IFormattingContext formattingContext, Acceptor errors) { hasStarted = false; wsWritten = false; final StringBuilder builder = new StringBuilder(); internalFormat(dom, regionToFormat, formattingContext, builder); final String text = builder.toString(); if(regionToFormat == null) regionToFormat = new TextRegion(0, text.length()); return new ReplaceRegion(regionToFormat, text); } protected void formatComposite(IDomNode node, ITextRegion regionToFormat, IFormattingContext formattingContext, StringBuilder builder) { for(IDomNode n : node.getChildren()) internalFormat(n, regionToFormat, formattingContext, builder); } protected void formatLeaf(IDomNode node, ITextRegion regionToFormat, IFormattingContext formattingContext, StringBuilder builder) { if(DomModelUtils.isWhitespace(node)) { if(formattingContext.isWhitespacePreservation()) { String text = node.getText(); if(isFormattingWanted(node, regionToFormat)) builder.append(text); if(text.length() > 0) wsWritten = true; } return; } if(isFormattingWanted(node, regionToFormat)) { writeSpaceIfNecessary(node, builder); String text = node.getText(); if(text.length() == 0) return; builder.append(node.getText()); } hasStarted = true; wsWritten = false; } protected void internalFormat(IDomNode node, ITextRegion regionToFormat, IFormattingContext formattingContext, StringBuilder builder) { if(node.isLeaf()) formatLeaf(node, regionToFormat, formattingContext, builder); else formatComposite(node, regionToFormat, formattingContext, builder); } protected boolean isFormattingWanted(IDomNode node, ITextRegion regionToFormat) { if(regionToFormat == null) return true; return regionToFormat.contains(node.getOffset()); } protected void writeSpaceIfNecessary(IDomNode node, StringBuilder builder) { if(hasStarted && !wsWritten) { builder.append(" "); wsWritten = true; } } }