/**
* 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.comments;
import org.cloudsmith.xtext.dommodel.IDomNode;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import com.google.inject.ImplementedBy;
/**
* <p>
* An ICommentConfiguration describes the configuration of comment (container-) extraction, parsing, and formatting.
* </p>
* <p>
* It is responsible for <i>comment classification</i> - associating a more specific comment type for an IDomNode representing a comment. The class
* used to describe the comment type is configurable via the generic type {@code T}. The default implementation uses {@link CommentType} as {@code T}.
* This type is expected by the default configuration of comment formatting, but a custom implementation may use a different type (throughout) if
* needed).
* </p>
* <p>
* The comment type classification can be used in a CSS selector, thus allowing a layout manager to be selected per comment type. The default layout
* manager is capable of providing reasonable formatting as described by an {@code ICommentConfiguration}, but can naturally be customized.
* </p>
* <p>
* Since the style classifiers of an IDomNode is a Set of Objects, a concrete implementation may choose any suitable instances to describe the various
* types of comments in the DSL language being laid out. This interface contains an enumerator for the three most common comments types (
* {@code Singleline}, {@code Multiline}, and {@code Documentation}), but this enumerator says nothing about the interior syntax and semantics of the
* respective comments.
* </p>
*
* <p>
* Note that the default {@code ICommentConfiguration} implementation assumes that the three default comment types use Java conventions. Simply bind a
* specialization of the {@link ICommentConfiguration.Default} class, or a different/more advanced implementation when so required:
* <ul>
* <li>If comment grammar rules are not "ML_COMMENT" and "SL_COMMENT". (This also requires customization of the {@code IHiddenTokenHelper} class which
* is used to determine if a token is a comment (of any type).</li>
* <li>If comments do not follow Java comment syntax (e.g. using '#' instead of '//' for single line comments.</li>
* <li>A different comment type scheme is wanted than {@link CommentType}.</li>
* <li>If different types of comments should be formatted with different {@link ICommentFormatterAdvice}.</li>
* </ul>
* </p>
* <p>
* To summarize: The {@code ICommentConfiguration} classifies a comment. The resulting classifier is used to select styling (i.e. a selection of an
* {@code ILayoutManager} and and other style information as determined by a CSS driven formatter). The selected ILayoutManager is responsible for the
* formatting of the comment(s). By default an ILayoutManager is configured for comments that use an {@code ICommentConfiguration} to map the
* {@code CommentType} to a description of the comment's syntax and semantics ({@link #getContainerInformation(Object)}), and a description of wanted
* formatting ({@link #getFormatterAdvice(Object)}). It is the responsibility of the selected {@code ILayoutManager} to apply the container
* information and formatting advice to the comment using an implementation specific comment processor.
* </p>
*
*/
@ImplementedBy(ICommentConfiguration.Default.class)
public interface ICommentConfiguration<T> {
public static enum CommentType {
/**
* Returned when a comment classifier is asked to classify something that
* is not one of the known comment types (or not a comment at all).
*/
Unknown, SingleLine, Multiline, Documentation;
}
/**
* <p>
* An implementation of {@link ICommentConfiguration} that classifies comments based on the grammar rule name of the comment terminals;
* "ML_COMMENT", and "SL_COMMENT". This implementation returns {@link CommentType#Unknown} for all other nodes.
* </p>
* <p>
* When asked to classify an IDomNode, this node must either have an INode attached, or an attached grammar rule that describes the comment type.
* </p>
*/
public static class Default implements ICommentConfiguration<CommentType> {
private static final ICommentFormatterAdvice defaultAdvice = new ICommentFormatterAdvice.DefaultCommentAdvice();
@Override
public CommentType classify(EObject grammarElement) {
if(grammarElement != null && grammarElement instanceof AbstractRule) {
AbstractRule rule = (AbstractRule) grammarElement;
if("ML_COMMENT".equals(rule.getName()))
return CommentType.Multiline;
if("SL_COMMENT".equals(rule.getName()))
return CommentType.SingleLine;
}
return CommentType.Unknown;
}
/**
* Returns the comment type based on the node's attached {@code INode} if available, otherwise
* the node's attached <i>grammar element</i>. The node must be a leaf node.
*/
@Override
public CommentType classify(IDomNode node) {
INode inode = node.getNode();
if(inode != null)
return classify(inode);
if(node.isLeaf())
return classify(node.getGrammarElement());
return CommentType.Unknown;
}
@Override
public CommentType classify(INode node) {
EObject ge = node.getGrammarElement();
if(node instanceof ILeafNode)
return classify(ge);
return CommentType.Unknown;
}
@Override
public ICommentContainerInformation getContainerInformation(CommentType commentType) {
// Preconditions.checkArgument(genericCommentType instanceof CommentType, "must be instance of CommentType");
// CommentType commentType = (CommentType) genericCommentType;
switch(commentType) {
case SingleLine:
return new ICommentContainerInformation.JavaSLCommentContainer();
case Multiline:
return new ICommentContainerInformation.JavaLikeMLCommentContainer();
case Documentation:
return new ICommentContainerInformation.JavaDocLikeCommentContainer();
}
// Unknown type
return new ICommentContainerInformation.UnknownCommentContainer();
}
/**
* @return {@link DefaultCommentFormattingAdvice} irrespective of {@code commentType}.
*/
@Override
public ICommentFormatterAdvice getFormatterAdvice(CommentType commentType) {
return defaultAdvice;
}
}
public T classify(EObject abstractRule);
public T classify(IDomNode node);
public T classify(INode node);
/**
* Returns an {@link ICommentContainerInformation} for the given commentType (a classifier produced
* by one of the {@code classify} methods, typically an instance of {@link CommentType}), describing
* the expected container for this type of comment.
*
* @param commentType
* describes the comment type
* @return information about the comment container of the given {@code commentType}
*/
public ICommentContainerInformation getContainerInformation(T commentType);
/**
* Returns an {@link ICommentFormatterAdvice} describing how a comment of the given commentType (a classifier produced
* by one of the {@code classify} methods, typically an instance of {@link CommentType}) should be formatted
* with respect to its textual content and in relationship to its container.
*
* @param commentType
* describes the comment type
* @return formatting advice for a comment of the given {@code commentType}
*/
public ICommentFormatterAdvice getFormatterAdvice(T commentType);
}