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

Source Code of com.puppetlabs.geppetto.pp.dsl.ppformatting.FormattingCommentAssociator$CommentAssociations

/**
* 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.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.parsetree.reconstr.impl.NodeIterator;
import org.eclipse.xtext.parsetree.reconstr.impl.TokenUtil;
import org.eclipse.xtext.util.Pair;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;

/**
* Provides a mapping from semantic objects to comments before and after the object.
*
*/
public class FormattingCommentAssociator {
  public static class CommentAssociations {
    Multimap<EObject, INode> beforeMap;

    Multimap<EObject, INode> afterMap;

    public CommentAssociations() {
      beforeMap = ArrayListMultimap.create();
      afterMap = ArrayListMultimap.create();
    }

    protected void acceptAfter(EObject obj, Collection<? extends INode> commentNodes) {
      for(INode n : commentNodes)
        afterMap.put(obj, n);
      commentNodes.clear();
    }

    protected void acceptAfter(EObject obj, INode node) {
      afterMap.put(obj, node);
    }

    protected void acceptBefore(EObject obj, Collection<? extends INode> commentNodes) {
      for(INode n : commentNodes)
        beforeMap.put(obj, n);
      commentNodes.clear();
    }

    protected void acceptBefore(EObject obj, INode node) {
      beforeMap.put(obj, node);
    }

    public Iterator<INode> after(EObject obj) {
      Collection<INode> val = afterMap.get(obj);
      if(val == null)
        return Iterators.emptyIterator();
      return val.iterator();
    }

    public Iterator<INode> before(EObject obj) {
      Collection<INode> val = beforeMap.get(obj);
      if(val == null)
        return Iterators.emptyIterator();
      return val.iterator();
    }
  }

  @Inject
  protected TokenUtil tokenUtil;

  /**
   * This implementation associates each comment with the next following semantic token's EObject, except for the
   * case, where a line of the document end by a semantic element followed by a comment. Then, the the comment is
   * associated with this preceding semantic token.
   */
  protected void associateCommentsWithSemanticEObjects(CommentAssociations mapping, ICompositeNode rootNode) {
    // System.out.println(EmfFormatter.objToStr(rootNode));
    EObject currentEObject = null;
    List<ILeafNode> currentComments = new ArrayList<ILeafNode>();

    NodeIterator nodeIterator = new NodeIterator(rootNode);
    // rewind to previous token with token owner
    while(nodeIterator.hasPrevious() && currentEObject == null) {
      INode node = nodeIterator.previous();
      if(tokenUtil.isToken(node)) {
        currentEObject = tokenUtil.getTokenOwner(node);
      }
    }
    while(nodeIterator.hasNext()) {
      INode node = nodeIterator.next();
      if(tokenUtil.isCommentNode(node)) {
        currentComments.add((ILeafNode) node);
      }
      boolean isToken = tokenUtil.isToken(node);
      if((node instanceof ILeafNode || isToken) && node.getStartLine() != node.getEndLine() &&
          currentEObject != null) {
        // found a newline -> associating existing comments with currentEObject
        mapping.acceptAfter(currentEObject, currentComments);
        // addMapping(mapping, currentComments, currentEObject);
        currentEObject = null;
      }
      if(isToken) {
        Pair<List<ILeafNode>, List<ILeafNode>> leadingAndTrailingHiddenTokens = tokenUtil.getLeadingAndTrailingHiddenTokens(node);
        for(ILeafNode leadingHiddenNode : leadingAndTrailingHiddenTokens.getFirst()) {
          if(tokenUtil.isCommentNode(leadingHiddenNode)) {
            currentComments.add(leadingHiddenNode);
          }
        }
        nodeIterator.prune();
        currentEObject = tokenUtil.getTokenOwner(node);
        if(currentEObject != null) {
          mapping.acceptBefore(currentEObject, currentComments);
          // addMapping(mapping, currentComments, currentEObject);
          if(node.getOffset() > rootNode.getOffset() + rootNode.getLength()) {
            // found next EObject outside rootNode
            break;
          }
        }
      }
    }
    if(!currentComments.isEmpty()) {
      if(currentEObject != null) {
        mapping.acceptBefore(currentEObject, currentComments);
        // addMapping(mapping, currentComments, currentEObject);
      }
      else {
        EObject objectForRemainingComments = getEObjectForRemainingComments(rootNode);
        if(objectForRemainingComments != null) {
          mapping.acceptBefore(currentEObject, currentComments);
          // addMapping(mapping, currentComments, objectForRemainingComments);
        }
      }
    }
  }

  public CommentAssociations associateCommentsWithSemanticEObjects(EObject model, Set<ICompositeNode> roots) {
    CommentAssociations mapping = new CommentAssociations();
    for(ICompositeNode rootNode : roots)
      associateCommentsWithSemanticEObjects(mapping, rootNode);
    return mapping;
  }

  protected EObject getEObjectForRemainingComments(ICompositeNode rootNode) {
    TreeIterator<INode> i = rootNode.getAsTreeIterable().iterator();
    while(i.hasNext()) {
      INode o = i.next();
      if(o.hasDirectSemanticElement())
        return o.getSemanticElement();
    }
    return null;
  }

}
TOP

Related Classes of com.puppetlabs.geppetto.pp.dsl.ppformatting.FormattingCommentAssociator$CommentAssociations

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.