Package com.puppetlabs.geppetto.pp.dsl.formatting

Source Code of com.puppetlabs.geppetto.pp.dsl.formatting.AssignmentLayout$FirstLeafWithTextAndTheRest

/**
* 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.formatting;

import java.util.Iterator;
import java.util.List;

import com.puppetlabs.geppetto.common.stats.IntegerCluster;
import com.puppetlabs.geppetto.pp.AppendExpression;
import com.puppetlabs.geppetto.pp.AssignmentExpression;
import com.puppetlabs.geppetto.pp.dsl.services.PPGrammarAccess;
import com.puppetlabs.xtext.dommodel.DomModelUtils;
import com.puppetlabs.xtext.dommodel.IDomNode;
import com.puppetlabs.xtext.dommodel.formatter.DelegatingLayoutContext;
import com.puppetlabs.xtext.dommodel.formatter.DomNodeLayoutFeeder;
import com.puppetlabs.xtext.dommodel.formatter.ILayoutManager.ILayoutContext;
import com.puppetlabs.xtext.dommodel.formatter.css.Alignment;
import com.puppetlabs.xtext.dommodel.formatter.css.IStyleFactory;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.WidthStyle;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleSet;
import com.puppetlabs.xtext.textflow.ITextFlow;
import com.puppetlabs.xtext.textflow.TextFlow;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Action;
import org.eclipse.xtext.Keyword;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Provider;

/**
* A sub layout handler for AssignmentExpression that optionally cluster-aligns a sequence of assignments.
*
*/
public class AssignmentLayout {

  private static class FirstLeafWithTextAndTheRest implements Predicate<IDomNode> {
    private boolean firstLeafSeen = false;

    @Override
    public boolean apply(IDomNode input) {
      if(!DomModelUtils.isHidden(input))
        firstLeafSeen = true;
      return firstLeafSeen;
    }
  }

  @Inject
  private IStyleFactory styles;

  @Inject
  private DomNodeLayoutFeeder feeder;

  @Inject
  private Provider<IBreakAndAlignAdvice> adviceProvider;

  private Action theAssignmentExpression;

  private Keyword theEqualSign;

  private Keyword thePlusEqualSign;

  private Action theAppendExpression;

  private static Predicate<IDomNode> untilTheEnd = Predicates.alwaysFalse();

  @Inject
  public AssignmentLayout(PPGrammarAccess grammarAccess) {
    // selectorEntryRule = grammarAccess.getSelectorEntryRule();
    theAssignmentExpression = grammarAccess.getAssignmentExpressionAccess().getAssignmentExpressionLeftExprAction_1_0();
    theEqualSign = grammarAccess.getAssignmentExpressionAccess().getEqualsSignKeyword_1_1();
    theAppendExpression = grammarAccess.getAppendExpressionAccess().getAppendExpressionLeftExprAction_1_0();
    thePlusEqualSign = grammarAccess.getAppendExpressionAccess().getPlusSignEqualsSignKeyword_1_1();
  }

  protected boolean _format(AppendExpression o, StyleSet styleSet, IDomNode node, ITextFlow flow,
      ILayoutContext context) {
    return commonFormat(styleSet, node, flow, context);
  }

  protected boolean _format(AssignmentExpression o, StyleSet styleSet, IDomNode node, ITextFlow flow,
      ILayoutContext context) {
    return commonFormat(styleSet, node, flow, context);
  }

  protected boolean commonFormat(StyleSet styleSet, IDomNode node, ITextFlow flow, ILayoutContext context) {

    // unify the width of assignment expression LHS by scanning forward...

    int availableWidth = 132; // irrelevant, but a value needed for width

    IBreakAndAlignAdvice advice = adviceProvider.get();
    final boolean doAlignment = advice.isAlignAssignments();
    if(!doAlignment)
      return false;

    // used to collect the widths of each LHS width (typically just a variable name, but can be complex).
    List<Integer> widths = Lists.newArrayList();

    List<IDomNode> equalSignNodes = Lists.newArrayList();
    IntegerCluster clusters = new IntegerCluster(advice.clusterSize());

    boolean containsAppend = false;

    // while siblings are assignments, starting with the current one
    for(IDomNode aeNode = node; aeNode != null && includeInSequence(aeNode); aeNode = aeNode.getNextSibling()) {
      DelegatingLayoutContext innerContext = new DelegatingLayoutContext(context, availableWidth);
      TextFlow measuredFlow = new TextFlow(innerContext);

      // iterate to format the LHS expression and measure, and find the = sign (which gets padded)
      Iterator<IDomNode> itor = aeNode.treeIterator();
      while(itor.hasNext()) {
        IDomNode n = itor.next();
        // forward until assignment expression =, or +=
        if(!(n.getGrammarElement() == theAssignmentExpression || n.getGrammarElement() == theAppendExpression))
          continue;

        // Measure assignment expression
        feeder.sequence(n, measuredFlow, innerContext, new FirstLeafWithTextAndTheRest(), untilTheEnd);

        // forward to = or += sign
        while(itor.hasNext()) {
          n = itor.next();
          if(n.getGrammarElement() == theEqualSign || n.getGrammarElement() == thePlusEqualSign)
            break;
        }
        if(n.getGrammarElement() == thePlusEqualSign)
          containsAppend = true;

        if(!itor.hasNext())
          break; // WAT, nothing after the '=', give up on this assignment, try to align the others

        // If assignment node already has a width, it was processed by a preceding assignment
        // and we were done a long time ago...
        //
        WidthStyle widthStyle = n.getStyles().getStyle(WidthStyle.class, n);
        if(widthStyle != null)
          return false;

        equalSignNodes.add(n);

        // collect the width of the last selector entry's values
        int lastLineWidth = measuredFlow.getWidthOfLastLine();
        clusters.add(lastLineWidth);
        widths.add(lastLineWidth);
        break;
      }
    }
    markupWidths(equalSignNodes, widths, availableWidth, clusters, doAlignment, containsAppend);

    return false;
  }

  protected boolean includeInSequence(IDomNode node) {
    EObject semantic = node.getSemanticObject();
    return semantic instanceof AssignmentExpression || semantic instanceof AppendExpression;

  }

  /**
   * assign widths and alignment to the equal sign nodes
   *
   * @param equalSignNodes
   * @param widths
   * @param availableWidth
   * @param clusters
   * @param doCompaction
   * @return
   */
  private void markupWidths(List<IDomNode> equalSignNodes, List<Integer> widths, int availableWidth,
      IntegerCluster clusters, boolean doAlignment, boolean containsAppend) {
    // assign widths and alignment to the fat comma nodes
    int opW = containsAppend
        ? 2
        : 1;
    for(int i = 0; i < equalSignNodes.size(); i++) {
      IDomNode c = equalSignNodes.get(i);
      int w = widths.get(i);
      int mw = doAlignment
          ? clusters.clusterMax(w)
          : w;
      if(doAlignment)
        c.getStyles().add(StyleSet.withStyles(styles.align(Alignment.right), //
          styles.width(opW + mw - w)));
    }
  }
}
TOP

Related Classes of com.puppetlabs.geppetto.pp.dsl.formatting.AssignmentLayout$FirstLeafWithTextAndTheRest

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.