Package com.puppetlabs.xtext.dommodel.formatter

Source Code of com.puppetlabs.xtext.dommodel.formatter.FlowLayout

/**
* 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.xtext.dommodel.formatter;

import com.puppetlabs.xtext.dommodel.IDomNode;
import com.puppetlabs.xtext.dommodel.IDomNode.NodeClassifier;
import com.puppetlabs.xtext.dommodel.RegionMatch;
import com.puppetlabs.xtext.dommodel.formatter.css.Alignment;
import com.puppetlabs.xtext.dommodel.formatter.css.IFunctionFactory;
import com.puppetlabs.xtext.dommodel.formatter.css.LineBreaks;
import com.puppetlabs.xtext.dommodel.formatter.css.Spacing;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.AlignedSeparatorIndex;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.AlignmentStyle;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.LineBreakStyle;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.SpacingStyle;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.TokenTextStyle;
import com.puppetlabs.xtext.dommodel.formatter.css.StyleFactory.VerbatimStyle;
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.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.name.Named;

/**
* <p>
* A Dom Model Formatter driven by rules in a {@link DomCSS}.
* </p>
* <p>
* If there are no rules for spacing and line breaks in the style sheet produced by the given domProvider, default rules
* for "one space" and "no line break" will be used. This makes this formatter function as a "one space formatter" in
* the default case.
* </p>
* <p>
* Comment formatting is performed by delegating to an instance of {@link ILayout} that is bound to the name
* {@value #COMMENT_LAYOUT_NAME}.
* </p>
*/
public class FlowLayout extends AbstractLayoutManager implements ILayoutManager {

  /**
   * The name of the wanted ILayoutManager to handle comment formatting.
   */
  public static final String COMMENT_LAYOUT_NAME = "CommentsLayout";

  private static final Spacing defaultSpacing = new Spacing(1);

  private static final LineBreaks defaultLineBreaks = new LineBreaks(0);

  @Inject
  private IFunctionFactory functions;

  @Inject
  @Named(COMMENT_LAYOUT_NAME)
  protected ILayout commentLayout;

  @Override
  protected void formatComment(StyleSet styleSet, IDomNode node, ITextFlow output, ILayoutContext context) {
    RegionMatch match = intersect(node, context);
    if(match.isInside()) {
      if(match.isContained() && !context.isWhitespacePreservation()) {
        Preconditions.checkState(
          commentLayout != null, "setCommentLayout(ILayout) must have been called first.");
        commentLayout.format(styleSet, node, output, context);
      }
      else
        // output the part of the text that is inside the region as verbatim text
        output.appendText(match.apply().getFirst(), true);
    }
  }

  @Override
  protected void formatToken(StyleSet styleSet, IDomNode node, ITextFlow output, ILayoutContext context) {
    RegionMatch match = intersect(node, context);
    if(match.isInside()) {
      if(match.isContained() && !context.isWhitespacePreservation())
        formatTokenInternal(styleSet, node, output, context);
      else
        // output the part of the text that is inside the region as verbatim text
        output.appendText(match.apply().getFirst(), true);
    }

  }

  /**
   * Formats the node without any checks for whitespace preservation or matching the contexts formatting region.
   *
   * @param styleSet
   * @param node
   * @param output
   * @param context
   */
  private void formatTokenInternal(StyleSet styleSet, IDomNode node, ITextFlow output, ILayoutContext context) {
    String text = styleSet.getStyleValue(TokenTextStyle.class, node, functions.textOfNode());

    Alignment alignment = styleSet.getStyleValue(AlignmentStyle.class, node);
    boolean verbatim = styleSet.getStyleValue(VerbatimStyle.class, node, Boolean.FALSE);
    final boolean defaultAlignment = alignment == null;
    if(defaultAlignment)
      alignment = Alignment.left;
    final int textLength = text.length();
    final Integer widthObject = styleSet.getStyleValue(WidthStyle.class, node);
    final int width = widthObject == null
        ? textLength
        : widthObject.intValue();
    final int diff = width - textLength;

    switch(alignment) {
      case left:
        output.appendText(text, verbatim);
        // need to output padding separately as a 0 space gives the text flow permission to wrap which is a surprise
        // just because everything is left aligned by default.
        //
        if(diff > 0 || !defaultAlignment)
          output.appendSpaces(diff); // ok if 0 or negative = no spaces
        break;
      case right:
        // ok to output 0 space that potentially triggers wrapping
        output.appendSpaces(diff).appendText(text);
        break;
      case center:
        int leftpad = (diff) / 2;
        output.appendSpaces(leftpad).appendText(text).appendSpaces(diff - leftpad);
        break;
      case separator:
        // width must have been set as it is otherwise meaningless to try to align on
        // separator.
        if(widthObject == null) {
          output.appendText(text);
        }
        else {
          // use first non word char as default
          // right align in the given width
          int separatorIndex = styleSet.getStyleValue(
            AlignedSeparatorIndex.class, node, functions.firstNonWordChar());
          if(separatorIndex > -1)
            output.appendSpaces(width - separatorIndex).appendText(text);
          else
            output.appendSpaces(diff).appendText(text);
        }
        break;
    }
  }

  @Override
  protected void formatWhitespace(StyleSet styleSet, IDomNode node, ITextFlow output, ILayoutContext context) {
    RegionMatch match = intersect(node, context);
    boolean wsp = context.isWhitespacePreservation();
    boolean implied = node.getStyleClassifiers().contains(NodeClassifier.IMPLIED);

    // TODO: the combination of whitespacePreservation, implied-space AND regional formatting is not
    // tested - it implies a priori knowledge of the textual representation of a serialized model without
    // any source text nodes; and will probably in practice never be requested. (A serialization pass would
    // needed to get the text to figure out where nodes are...)
    //
    if(match.isInside()) {
      if(match.isContained() && (!wsp || implied)) {
        // format if contained and formatting is wanted, or the space is implied
        Spacing spacing = styleSet.getStyleValue(SpacingStyle.class, node, defaultSpacing);
        LineBreaks lineBreaks = styleSet.getStyleValue(LineBreakStyle.class, node, defaultLineBreaks);
        String text = styleSet.getStyleValue(TokenTextStyle.class, node);
        applySpacingAndLinebreaks(context, node, text, spacing, lineBreaks, output);
      }
      else {
        output.appendText(match.apply().getFirst());
      }
    }
  }

}
TOP

Related Classes of com.puppetlabs.xtext.dommodel.formatter.FlowLayout

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.