Package com.puppetlabs.geppetto.pp.dsl.ppformatting

Source Code of com.puppetlabs.geppetto.pp.dsl.ppformatting.PPFormatter

/**
* Copyright (c) 2013 Puppet Labs, 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:
*   Puppet Labs
*/
package com.puppetlabs.geppetto.pp.dsl.ppformatting;

import java.util.List;

import com.puppetlabs.geppetto.pp.dsl.services.PPGrammarAccess;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;
import org.eclipse.xtext.formatting.impl.FormattingConfig;
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
import org.eclipse.xtext.util.Pair;

/**
* This class contains custom formatting description.
*
* see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#formatting
* on how and when to use it
*
* Also see {@link org.eclipse.xtext.xtext.XtextFormattingTokenSerializer} as an example
*
* TODO: Formatting currently plagued by bugs in Xtext 2.0. See JUnit tests.
*/
public class PPFormatter extends AbstractDeclarativeFormatter {

  protected void assignmentExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    c.setLinewrap().after(ga.getAssignmentExpressionAccess().getGroup_1());
  }

  protected void atExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    // At expression
    // -- no space between EXPR and [
    // -- no space after opening [
    // -- no space before closing ]
    c.setNoSpace().before(ga.getAtExpressionAccess().getLeftSquareBracketKeyword_1_1());
    c.setNoSpace().after(ga.getAtExpressionAccess().getLeftSquareBracketKeyword_1_1());
    c.setNoSpace().before(ga.getAtExpressionAccess().getRightSquareBracketKeyword_1_3());

  }

  protected void caseExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();

    Keyword caseLbr = ga.getCaseAccess().getLeftCurlyBracketKeyword_3();
    Keyword caseRbr = ga.getCaseAccess().getRightCurlyBracketKeyword_5();
    c.setLinewrap().after(caseLbr);
    c.setLinewrap().around(caseRbr);
    c.setIndentation(caseLbr, caseRbr);

    caseLbr = ga.getCaseExpressionAccess().getLeftCurlyBracketKeyword_2();
    caseRbr = ga.getCaseExpressionAccess().getRightCurlyBracketKeyword_4();
    c.setLinewrap().after(caseLbr);
    c.setLinewrap().around(caseRbr);
    c.setIndentation(caseLbr, caseRbr);
  }

  protected void classExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();

    Keyword lbr = ga.getHostClassDefinitionAccess().getLeftCurlyBracketKeyword_4();
    Keyword rbr = ga.getHostClassDefinitionAccess().getRightCurlyBracketKeyword_6();
    c.setLinewrap().after(lbr);
    c.setLinewrap().around(rbr);
    c.setIndentation(lbr, rbr);

    // linewrap statements
    // not a good idea since non-parenthesised function calls are separate expressions,
    // each 'statement' must do its own terminating linewrap
    // c.setLinewrap().after(ga.getHostClassDefinitionAccess().getStatementsAssignment_5());

    // but not between what is a non parenthesized function call
    // TODO: Broken...
    c.setNoLinewrap().between(ga.getLiteralNameOrReferenceRule(), ga.getLiteralNameOrReferenceRule());
    // as per https://bugs.eclipse.org/bugs/show_bug.cgi?id=340166#c5
    // c.setNoLinewrap().between(ga.getLiteralNameOrReferenceRule(), ga.getExpressionListRule());

  }

  protected void collectExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    c.setLinewrap().after(ga.getCollectExpressionAccess().getLeftCurlyBracketKeyword_1_2_0());
    c.setIndentation(
      ga.getCollectExpressionAccess().getLeftCurlyBracketKeyword_1_2_0(),
      ga.getCollectExpressionAccess().getRightCurlyBracketKeyword_1_2_2());
    c.setLinewrap().before(ga.getCollectExpressionAccess().getRightCurlyBracketKeyword_1_2_2());
  }

  @Override
  protected void configureFormatting(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();

    // not a good idea since non-parenthesised function calls are separate expressions,
    // each 'statement' must do its own terminating linewrap
    // c.setLinewrap().after(ga.getPuppetManifestAccess().getStatementsAssignment_2());

    // Add add and preserve newlines around comments
    c.setLinewrap(0, 1, 2).before(ga.getSL_COMMENTRule());

    // NOTE: default set to 0 to allow "inline" comments like /* this one */ without requiring
    // a linewrap.
    c.setLinewrap(0, 0, 2).before(ga.getML_COMMENTRule());
    c.setLinewrap(0, 0, 1).after(ga.getML_COMMENTRule());

    stringExpressionConfiguration(c);
    ifExpressionConfiguration(c);
    caseExpressionConfiguration(c);
    classExpressionConfiguration(c);
    selectorExpressionConfiguration(c);
    definitionExpressionConfiguration(c);
    assignmentExpressionConfiguration(c);
    importExpressionConfiguration(c);
    literalListAndHashConfiguration(c);
    functionCallConfiguration(c);
    nodeExpressionConfiguration(c);
    // commas
    for(Keyword comma : ga.findKeywords(",")) {
      c.setNoSpace().before(comma);
    }

    // TODO: Old formatter needs this fixed since there is no endComma rule - they are just optional commas in
    // various expressions. They may be ok already with a general rule "no space before a comma keyword".
    // c.setNoSpace().before(ga.getEndCommaRule());

    // no space between unary operators (! -) and the following expression
    c.setNoSpace().after(ga.getNotExpressionAccess().getExclamationMarkKeyword_0());
    c.setNoSpace().after(ga.getUnaryMinusExpressionAccess().getHyphenMinusKeyword_0());

    resourceExpressionConfiguration(c);
    collectExpressionConfiguration(c);
    atExpressionConfiguration(c);
    parenthisedExpressionConfguration(c);
    manifestConfiguration(c);

    // DEBUG: uncomment next to get a diagram of the formatter
    // super.saveDebugGraphvizDiagram("debugDiagram.dot");
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter#createFormatterStream(java.lang.String,
   * org.eclipse.xtext.parsetree.reconstr.ITokenStream, boolean)
   */
  @Override
  public ITokenStream createFormatterStream(String indent, ITokenStream out, boolean preserveWhitespaces) {
    // Create opportunity to use the TokenStreamWrapper around out... (used for debugging).
    return super.createFormatterStream(indent, out, preserveWhitespaces);
  }

  protected void definitionExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    Keyword lbr = ga.getDefinitionAccess().getLeftCurlyBracketKeyword_3();
    Keyword rbr = ga.getDefinitionAccess().getRightCurlyBracketKeyword_5();
    c.setLinewrap().after(lbr);
    c.setLinewrap().around(rbr);
    c.setIndentation(lbr, rbr);

    List<Pair<Keyword, Keyword>> pairs = ga.getDefinitionArgumentListAccess().findKeywordPairs("(", ")");
    if(pairs.size() == 1) {
      c.setIndentation(pairs.get(0).getFirst(), pairs.get(0).getSecond());
      c.setNoSpace().after(pairs.get(0).getFirst());
      c.setNoSpace().before(pairs.get(0).getSecond());
    }
    List<Keyword> commas = ga.getDefinitionArgumentListAccess().findKeywords(",");
    for(Keyword comma : commas)
      c.setLinewrap().after(comma);
  }

  protected void functionCallConfiguration(FormattingConfig c) {
    throw new RuntimeException("Configuring formatting using PPFormatter is deprecated");
    // PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();

    // c.setNoSpace().before(ga.getFunctionCallAccess().getLeftParenthesisKeyword_1_1());
    // c.setNoSpace().after(ga.getFunctionCallAccess().getLeftParenthesisKeyword_1_1());
    //
    // c.setNoSpace().after(ga.getFunctionCallAccess().getLeftParenthesisKeyword_1_1());
    // c.setNoSpace().before(ga.getFunctionCallAccess().getRightParenthesisKeyword_1_3());
  }

  protected void ifExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    Keyword lbr = ga.getIfExpressionAccess().getLeftCurlyBracketKeyword_2();
    Keyword rbr = ga.getIfExpressionAccess().getRightCurlyBracketKeyword_4();
    c.setLinewrap().after(lbr);
    c.setIndentation(lbr, rbr);
    c.setLinewrap().around(rbr);

    lbr = ga.getElseExpressionAccess().getLeftCurlyBracketKeyword_1();
    rbr = ga.getElseExpressionAccess().getRightCurlyBracketKeyword_3();
    c.setLinewrap().after(lbr);
    c.setIndentation(lbr, rbr);
    c.setLinewrap().around(rbr);

    lbr = ga.getElseIfExpressionAccess().getLeftCurlyBracketKeyword_2();
    rbr = ga.getElseIfExpressionAccess().getRightCurlyBracketKeyword_4();
    c.setLinewrap().after(lbr);
    c.setIndentation(lbr, rbr);
    c.setLinewrap().around(rbr);
  }

  protected void importExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    // This does not work - no element of Import makes the linewrap take effect
    c.setLinewrap().after(ga.getImportExpressionAccess().getGroup_2());
  }

  protected void literalListAndHashConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    // -- no space after opening [
    // -- no space before closing ]
    c.setNoSpace().after(ga.getLiteralListAccess().getLeftSquareBracketKeyword_1());
    c.setNoSpace().before(ga.getLiteralListAccess().getRightSquareBracketKeyword_3());

    // -- no space after opening {
    // -- no space before closing }
    c.setNoSpace().after(ga.getLiteralHashAccess().getLeftCurlyBracketKeyword_1());
    c.setNoSpace().before(ga.getLiteralHashAccess().getRightCurlyBracketKeyword_4());
  }

  protected void manifestConfiguration(FormattingConfig c) {
    // PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    // does not have intended (positive) effect, does instead screw up other statements
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=340166#c6
    // c.setLinewrap().after(ga.getPuppetManifestAccess().getStatementsAssignment_1());
  }

  protected void nodeExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();

    Keyword lbr = ga.getNodeDefinitionAccess().getLeftCurlyBracketKeyword_4();
    Keyword rbr = ga.getNodeDefinitionAccess().getRightCurlyBracketKeyword_6();
    c.setLinewrap().after(lbr);
    c.setLinewrap().around(rbr);
    c.setIndentation(lbr, rbr);
  }

  protected void parenthisedExpressionConfguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    c.setNoSpace().after(ga.getParenthisedExpressionAccess().getLeftParenthesisKeyword_0());
    c.setNoSpace().before(ga.getParenthisedExpressionAccess().getRightParenthesisKeyword_3());
  }

  /**
   * Adds formatting instructions for ResourceExpression and VirtualResourceExpression.
   * Sample formatting (wanted result) :
   *
   * <pre>
   * type {
   *     "title" :
   *         attr => expr,
   *         attr => expr,
   *         attr => expr ;
   *     "title" :
   *         attr => expr,
   *         attr => expr
   * }
   * Type {
   *     attr => expr,
   *     attr => expr
   * }   
   * &#064; type {
   * ... // as above
   * }
   * &#064;&#064; type {
   * ... // as above
   * }
   *
   * </pre>
   *
   * @param c
   *            - formatter to configure
   */
  protected void resourceExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();

    // + linebreak after «'title' :»
    for(Keyword colon : ga.getResourceBodyAccess().findKeywords(":")) {
      c.setLinewrap().after(colon);
      c.setNoLinewrap().before(colon);
    }
    // + indent the body of the resource expression
    {
      Keyword lbr = ga.getResourceExpressionAccess().getLeftCurlyBracketKeyword_0_1_1();
      Keyword rbr = ga.getResourceExpressionAccess().getRightCurlyBracketKeyword_0_1_3();
      c.setIndentation(lbr, rbr);
      c.setNoLinewrap().before(lbr);
      c.setLinewrap().after(lbr);
      c.setLinewrap().before(rbr);
      c.setLinewrap().after(rbr);
      Keyword endComma = ga.getAttributeOperationsAccess().getCommaKeyword_2();
      c.setLinewrap(1).between(endComma, rbr);
    }
    // repeat for literal class for of the rule
    {
      Keyword lbr = ga.getResourceExpressionAccess().getLeftCurlyBracketKeyword_1_2();
      Keyword rbr = ga.getResourceExpressionAccess().getRightCurlyBracketKeyword_1_4();
      c.setIndentation(lbr, rbr);
      c.setNoLinewrap().before(lbr);
      c.setLinewrap().after(lbr);
      c.setLinewrap().before(rbr);
      c.setLinewrap().after(rbr);
      Keyword endComma = ga.getAttributeOperationsAccess().getCommaKeyword_2();
      c.setLinewrap(1).between(endComma, rbr);
    }

    // + linebreak after «attribute (=>|+>) expr,»
    Keyword comma = ga.getAttributeOperationsAccess().getCommaKeyword_1_0_0();
    c.setNoLinewrap().before(comma);
    c.setLinewrap().after(comma);

    // c.setLinewrap().after(ga.getAttributeOperationsAccess().getCommaKeyword_2());
    // for(Keyword comma : ga.getAttributeOperationsAccess().findKeywords(",")) {
    // if(comma == ga.getAttributeOperationsAccess().get)
    // c.setLinewrap().after(comma);
    // }
    // linebreak after each resource body in a list of resource bodies
    {
      Keyword semi = ga.getResourceExpressionAccess().getSemicolonKeyword_0_1_2_1_0();
      c.setNoLinewrap().before(semi);
      c.setLinewrap(2).after(semi);
      Keyword endSemi = ga.getResourceExpressionAccess().getSemicolonKeyword_0_1_2_2();
      c.setNoLinewrap().before(endSemi);
      c.setLinewrap(1).after(endSemi);
    }
    { // repeat for second group
      Keyword semi = ga.getResourceExpressionAccess().getSemicolonKeyword_1_3_1_0();
      c.setNoLinewrap().before(semi);
      c.setLinewrap(2).after(semi);
      Keyword endSemi = ga.getResourceExpressionAccess().getSemicolonKeyword_1_3_2();
      c.setNoLinewrap().before(endSemi);
      c.setLinewrap(1).after(endSemi);
    }
    // c.setLinewrap(1).between(endSemi, rbr);

    // no wrap when RESOURCE -> RESOURCE is used
    // c.setNoLinewrap().before(ga.getRelationshipExpressionAccess().getOpNameAssignment_1_1());
    c.setNoLinewrap().before(ga.getRelationshipExpressionAccess().getOpNameAssignment_1_1());

    // + indent the list of attribute operations but only when when they have a title
    // TODO: 1.0GA (changing resource expression grammar)
    c.setIndentationIncrement().before(ga.getResourceBodyAccess().getAttributesAssignment_0_2());
    c.setIndentationDecrement().after(ga.getResourceBodyAccess().getAttributesAssignment_0_2());

    // this will always indent even if there is no title
    // c.setIndentationIncrement().before(ga.getAttributeOperationsRule());
    // c.setIndentationDecrement().after(ga.getAttributeOperationsRule());

    // this was workaround for bug in Xtext 1.0
    // for(Assignment theCall : ga.getResourceBodyAccess().findAssignments(ga.getAttributeOperationsRule())) {
    // c.setIndentationIncrement().before(theCall);
    // c.setIndentationDecrement().after(theCall);
    // }

    // No space between the two @@ in a virtual exported resource
    {
      Keyword at1 = ga.getVirtualNameOrReferenceAccess().getCommercialAtKeyword_0();
      RuleCall at2 = ga.getVirtualNameOrReferenceAccess().getExportedATBooleanParserRuleCall_1_0();
      RuleCall value = ga.getVirtualNameOrReferenceAccess().getValueUnionNameOrReferenceParserRuleCall_2_0();

      c.setNoSpace().between(at1, at2);
      c.setNoSpace().between(at1, value);
      c.setNoSpace().between(at2, value);
      // ga.getVirtualNameOrReferenceAccess().getCommercialAtKeyword_0(),
      // ga.getVirtualNameOrReferenceAccess().getValueAssignment_2());
      // c.setNoSpace().between(
      // ga.getVirtualNameOrReferenceAccess().getCommercialAtKeyword_0(),
      // ga.getVirtualNameOrReferenceAccess().getExportedATBooleanParserRuleCall_1_0());
    }
  }

  protected void selectorExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    Keyword lbr = ga.getSelectorExpressionAccess().getLeftCurlyBracketKeyword_1_2_0_0();
    Keyword rbr = ga.getSelectorExpressionAccess().getRightCurlyBracketKeyword_1_2_0_4();
    c.setLinewrap().after(lbr);
    c.setLinewrap().before(rbr);
    c.setIndentation(lbr, rbr);
    Keyword comma = ga.getSelectorExpressionAccess().getCommaKeyword_1_2_0_2_0_0();
    // RuleCall endcomma = ga.getSelectorExpressionAccess().getEndCommaParserRuleCall_1_3_0_4_0();

    c.setLinewrap().after(comma);
    c.setLinewrap(1).between(comma, rbr);
    // c.setLinewrap(1).between(endcomma, rbr);
  }

  protected void stringExpressionConfiguration(FormattingConfig c) {
    PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
    c.setNoSpace().after(ga.getUnquotedStringAccess().getDollarSignLeftCurlyBracketKeyword_1());
    c.setNoSpace().before(ga.getUnquotedStringAccess().getRightCurlyBracketKeyword_3());
  }

  // /**
  // * The "input" formatting stream, used for debugging the input to the declarative formatter.
  // * Use the TokenStreamWrapper to debug the output.
  // */
  // @SuppressWarnings("unused")
  // private class PuppetFormattingStream extends FormattingConfigBasedStream {
  //
  // public PuppetFormattingStream(ITokenStream out, String indentation, FormattingConfig cfg,
  // IElementMatcher<ElementPattern> matcher, IHiddenTokenHelper hiddenTokenHelper, boolean preserveSpaces) {
  // super(out, indentation, cfg, matcher, hiddenTokenHelper, preserveSpaces);
  // }
  //
  // @Override
  // public void writeHidden(EObject grammarElement, String value) throws IOException {
  // // if(grammarElement instanceof AbstractRule && "OWS".equals(((AbstractRule)grammarElement).getName())) {
  // // debugPrintln("writeHidden OWS with value «"+value+"»");
  // // }
  // super.writeHidden(grammarElement, value);
  // }
  //
  // @Override
  // public void writeSemantic(EObject grammarElement, String value) throws IOException {
  // super.writeSemantic(grammarElement, value);
  // }
  // }
  //
  // @SuppressWarnings("unused")
  // private class TokenStreamWrapper implements ITokenStream {
  // final private ITokenStream wrapped;
  //
  // TokenStreamWrapper(ITokenStream out) {
  // this.wrapped = out;
  // }
  //
  // @Override
  // public void flush() throws IOException {
  // System.err.println("flush");
  // wrapped.flush();
  // }
  //
  // @Override
  // public void writeHidden(EObject grammarElement, String value) throws IOException {
  // PPGrammarAccess ga = (PPGrammarAccess) getGrammarAccess();
  // System.err.println("hidden : [" + value + "] element=" + grammarElement.toString());
  // if(grammarElement instanceof RuleCall &&
  // ((RuleCall) grammarElement).getRule().getName().equals("unionNameOrReference")) {
  // RuleCall rc = (RuleCall) grammarElement;
  // if(rc.eContainer() instanceof Assignment) {
  // Assignment a = (Assignment) rc.eContainer();
  // System.err.println("NameOrReference contained in assignment to: " + a.getFeature());
  // }
  // }
  // wrapped.writeHidden(grammarElement, value);
  //
  // }
  //
  // @Override
  // public void writeSemantic(EObject grammarElement, String value) throws IOException {
  // System.err.println("semantic : [" + value + "] element=" + grammarElement.toString());
  // wrapped.writeSemantic(grammarElement, value);
  // }
  // }

}
TOP

Related Classes of com.puppetlabs.geppetto.pp.dsl.ppformatting.PPFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.