/**
* 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.ui.contentassist;
import static com.puppetlabs.geppetto.pp.adapters.ClassifierAdapter.RESOURCE_IS_CLASSPARAMS;
import static com.puppetlabs.geppetto.pp.adapters.ClassifierAdapter.RESOURCE_IS_OVERRIDE;
import java.util.List;
import java.util.ListIterator;
import com.puppetlabs.geppetto.pp.AssignmentExpression;
import com.puppetlabs.geppetto.pp.AttributeOperation;
import com.puppetlabs.geppetto.pp.PPPackage;
import com.puppetlabs.geppetto.pp.ResourceBody;
import com.puppetlabs.geppetto.pp.ResourceExpression;
import com.puppetlabs.geppetto.pp.StringExpression;
import com.puppetlabs.geppetto.pp.adapters.ClassifierAdapter;
import com.puppetlabs.geppetto.pp.adapters.ClassifierAdapterFactory;
import com.puppetlabs.geppetto.pp.dsl.eval.PPStringConstantEvaluator;
import com.puppetlabs.geppetto.pp.dsl.linking.PPFinder;
import com.puppetlabs.geppetto.pp.dsl.linking.PPFinder.SearchResult;
import com.puppetlabs.geppetto.pp.dsl.ui.labeling.IIconNames;
import com.puppetlabs.geppetto.pp.dsl.ui.labeling.PPDescriptionLabelProvider;
import com.puppetlabs.geppetto.pp.pptp.PPTPPackage;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.swt.graphics.Image;
import org.eclipse.xtext.Assignment;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.ui.IImageHelper;
import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal;
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext;
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor;
import com.google.inject.Inject;
/**
* see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#contentAssist on how to customize content assistant
*/
public class PPProposalProvider extends AbstractPPProposalProvider {
@Inject
private PPStringConstantEvaluator stringConstantEvaluator;
@Inject
protected PPDescriptionLabelProvider descriptionLabelProvider;
@Inject
private PPFinder ppFinder;
// @Inject
// private IGrammarAccess grammarAccess;
@Inject
private IImageHelper imageHelper;
/**
* PP FQN to/from Xtext QualifiedName converter.
*/
@Inject
IQualifiedNameConverter converter;
@Override
public void complete_AttributeOperation(EObject model, RuleCall ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// TODO Auto-generated method stub
// System.err.println("complete_AttributeOperation");
super.complete_AttributeOperation(model, ruleCall, context, acceptor);
}
@Override
public void complete_AttributeOperations(EObject model, RuleCall ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// TODO Auto-generated method stub
// System.err.println("complete_AttributeOperations");
super.complete_AttributeOperations(model, ruleCall, context, acceptor);
}
@Override
public void complete_ResourceBody(EObject model, RuleCall ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// TODO Auto-generated method stub
// System.err.println("complete_ResourceBody");
super.complete_ResourceBody(model, ruleCall, context, acceptor);
}
@Override
public void complete_ResourceExpression(EObject model, RuleCall ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// System.err.println("complete_ResourceExpression");
super.complete_ResourceExpression(model, ruleCall, context, acceptor);
}
@Override
public void complete_unionNameOrReference(EObject model, RuleCall ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
super.complete_unionNameOrReference(model, ruleCall, context, acceptor);
// System.err.println("complete_unionNameOrReference assignment to feature: " + " model: " +
// model.eClass().getName() + " Text: " + context.getCurrentNode().getText());
}
@Override
public void complete_VariableExpression(EObject model, RuleCall ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// check if prefix or just completed node starts with $, if so, do not offer a "$" as a starting point
// to get variable names. (Rationale, showing every possible variable wherever a variable can occur is not a good idea,
// instead, the user must at least enter a $ prefix. Once entered, it is not meaningful to see it as a suggestion).
// (The list of variables is obtained by suggesting varName for a VariableExpression.)
//
String prefix = context.getPrefix();
if("".equals(prefix) && context.getLastCompleteNode() != null &&
context.getLastCompleteNode().getText().startsWith("$"))
prefix = "$";
if(!prefix.startsWith("$")) {
StyledString description = new StyledString("$");
description.append(" - $variable", StyledString.DECORATIONS_STYLER);
acceptor.accept(createCompletionProposal("$", description, getImage(IIconNames.BLUE_CIRCLE), context));
}
super.complete_VariableExpression(model, ruleCall, context, acceptor);
}
@Override
public void completeAssignment(Assignment assignment, ContentAssistContext contentAssistContext,
ICompletionProposalAcceptor acceptor) {
// // DEBUG PRINTOUT
// ParserRule parserRule = GrammarUtil.containingParserRule(assignment);
// String methodName = "complete" + Strings.toFirstUpper(parserRule.getName()) + "_" +
// Strings.toFirstUpper(assignment.getFeature());
// System.err.println("completeAssigment('" + methodName + "')");
// // DEBUG END
super.completeAssignment(assignment, contentAssistContext, acceptor);
}
@Override
public void completeAttributeOperation_Key(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// System.err.println("completeAttributeOperation_Key assignment to feature: " + assignment.getFeature() +
// " model: " + model.eClass().getName() + " Text: " + context.getCurrentNode().getText());
// super.completeAttributeOperation_Key(model, assignment, context, acceptor);
// Proposal for AttributeOperation depends on context (the resource body)
ResourceBody resourceBody = null;
if(model.eClass() == PPPackage.Literals.RESOURCE_BODY) {
// The model is a resource body if an AttributeOperation has not yet been detected by the grammar
resourceBody = (ResourceBody) model;
}
else if(model.eClass() == PPPackage.Literals.ATTRIBUTE_OPERATION) {
// The grammar is lenient with (=> value) being optional (or it is impossible to
// get a ResourceBody context). Special handling is required to avoid producing a
// new list o suggestions for the op position (as the grammar thinks a property name OR and op can
// follow).
resourceBody = (ResourceBody) model.eContainer().eContainer();
// If the current caret position is after the end of the key (+1), do not offer any values
String key = ((AttributeOperation) model).getKey();
if(key != null && key.length() > 0 //
&& context.getOffset() > NodeModelUtils.getNode(model).getOffset() + key.length())
return;
}
else
// can not determine a context
return;
// INode lastCompleteNode = context.getLastCompleteNode();
// EObject ge = lastCompleteNode.getGrammarElement();
// if(ge instanceof RuleCall) {
// RuleCall lastCompletedRuleCall = (RuleCall) ge;
// System.err.println(lastCompletedRuleCall.getRule().getName());
// }
// if(context.getCurrentNode() instanceof HiddenLeafNode) {
// PPGrammarAccess ppga = (PPGrammarAccess) grammarAccess;
// if(ppga.getWSRule() == context.getCurrentNode().getGrammarElement())
// return;
// }
try {
// figure out the shape of the resource
ResourceExpression resourceExpr = (ResourceExpression) resourceBody.eContainer();
ClassifierAdapter adapter = ClassifierAdapterFactory.eINSTANCE.adapt(resourceExpr);
int resourceType = adapter.getClassifier();
// If resource is good, and not 'class', then it must have a known reference type.
// the resource type - also requires getting the type name from the override's expression).
if(resourceType == RESOURCE_IS_CLASSPARAMS) {
// resource is pp: class { classname : parameter => value }
// Find parameters for the class
// Find the class
final String className = stringConstantEvaluator.doToString(resourceBody.getNameExpr());
if(className == null)
return; // not a static expression
// Need the class to get its full name
ppFinder.configure(model.eResource());
List<IEObjectDescription> descs = ppFinder.findHostClasses(resourceBody, className, null).getAdjusted();
if(descs.size() < 1)
return; // can't find class, no proposals
IEObjectDescription desc = descs.get(0); // pick first if ambiguous
// which attribute(s) are we trying to find.
String prefix = context.getPrefix();
QualifiedName fqn = desc.getQualifiedName().append(prefix);
for(IEObjectDescription d : ppFinder.findAttributesWithPrefix(resourceBody, fqn).getAdjusted())
acceptor.accept(createCompletionProposal(d.getName().getLastSegment(), context));
}
else if(resourceType == RESOURCE_IS_OVERRIDE) {
// do nothing (too complicated due to the query being able to match all sorts of things)
}
else {
// Normal Resource
ppFinder.configure(model.eResource());
// Either a default setting Type { } or instance type { }, in both cases propose all properties and parameters
// including meta
IEObjectDescription desc = (IEObjectDescription) adapter.getTargetObjectDescription();
if(desc != null) {
// the type is known
// which attribute(s) are we trying to find.
String prefix = context.getPrefix();
QualifiedName fqn = desc.getQualifiedName().append(prefix);
for(IEObjectDescription d : ppFinder.findAttributesWithPrefix(resourceBody, fqn).getAdjusted())
acceptor.accept(createCompletionProposal(d.getName().getLastSegment(), context));
}
}
}
catch(ClassCastException e) {
// ignore, something is in a weird state, simply ignore proposals
}
}
/*
* (non-Javadoc)
*
* @see com.puppetlabs.geppetto.pp.dsl.ui.contentassist.AbstractPPProposalProvider#completeAttributeOperation_Op(org.eclipse.emf.ecore.EObject,
* org.eclipse.xtext.Assignment, org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext,
* org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor)
*/
@Override
public void completeAttributeOperation_Op(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// Proposal for AttributeOperation depends on context (the resource body)
ResourceBody resourceBody = null;
if(model.eClass() == PPPackage.Literals.RESOURCE_BODY) {
// The model is a resource body if an AttributeOperation has not yet been detected by the grammar
resourceBody = (ResourceBody) model;
}
else if(model.eClass() == PPPackage.Literals.ATTRIBUTE_OPERATION) {
// The grammar is lenient with (=> value) being optional (or it is imposible to
// get a ResourceBody context). Special handling is required to avoid producing a
// new list o suggestions for the op position (as the grammar thinks a property name OR and op can
// follow).
resourceBody = (ResourceBody) model.eContainer().eContainer();
}
else {
// can not determine a context
super.completeAttributeOperation_Op(model, assignment, context, acceptor);
return;
}
try {
// figure out the shape of the resource
ResourceExpression resourceExpr = (ResourceExpression) resourceBody.eContainer();
ClassifierAdapter adapter = ClassifierAdapterFactory.eINSTANCE.adapt(resourceExpr);
int resourceType = adapter.getClassifier();
acceptor.accept(createCompletionProposal("=>", context));
if(resourceType == RESOURCE_IS_OVERRIDE)
acceptor.accept(createCompletionProposal("+>", context));
}
catch(ClassCastException e) {
// squelsh
}
}
@Override
public void completeAttributeOperation_Value(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// TODO Auto-generated method stub
// super.completeAttributeOperation_Value(model, assignment, context, acceptor);
}
@Override
public void completeAttributeOperations_Attributes(EObject model, Assignment assignment,
ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
// TODO Auto-generated method stub
// System.err.println("completeAttributeOperations_Attributes");
super.completeAttributeOperations_Attributes(model, assignment, context, acceptor);
}
@Override
public void completeKeyword(Keyword keyword, ContentAssistContext contentAssistContext,
ICompletionProposalAcceptor acceptor) {
// System.err.println("completeKeyword('" + keyword.getValue() + "')");
// if(keyword.getValue().equals("+>"))
// System.err.println("Oy !!!");
super.completeKeyword(keyword, contentAssistContext, acceptor);
}
@Override
public void completePuppetManifest_Statements(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
super.completePuppetManifest_Statements(model, assignment, context, acceptor);
ppFinder.configure(model.eResource());
for(IEObjectDescription d : ppFinder.findDefinitions(model, null).getAdjusted()) {
String name = converter.toString(d.getQualifiedName());
StyledString styledDescription = new StyledString(name);
styledDescription.append(typeSuffix(d));
acceptor.accept(createCompletionProposal(
name, styledDescription, descriptionLabelProvider.getImage(d), context));
}
// acceptor.accept(createCompletionProposal(converter.toString(d.getQualifiedName()), context));
}
@Override
public void completeRuleCall(RuleCall ruleCall, ContentAssistContext contentAssistContext,
ICompletionProposalAcceptor acceptor) {
// // DEBUG OUTPUT
// AbstractRule calledRule = ruleCall.getRule();
// String methodName = "complete_" + calledRule.getName();
// System.err.println("completeRuleCall('" + methodName + "')");
// // DEBUG END
super.completeRuleCall(ruleCall, contentAssistContext, acceptor);
}
@Override
public void completeTextExpression_Expression(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
completeVarNameCommon(model, assignment, context, acceptor, false, true);
}
@Override
public void completeTextExpression_VarName(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
completeVarNameCommon(model, assignment, context, acceptor, false, false);
}
@Override
public void completeUnquotedString_Expression(EObject model, Assignment assignment, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
// TODO Auto-generated method stub
completeVarNameCommon(model, assignment, context, acceptor, false, true);
}
@Override
public void completeVariableExpression_VarName(EObject model, Assignment ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor) {
completeVarNameCommon(model, ruleCall, context, acceptor, false, false);
}
private void completeVarNameCommon(EObject model, Assignment ruleCall, ContentAssistContext context,
ICompletionProposalAcceptor acceptor, boolean bracedProposal, boolean bracedInput) {
final INode currentNode = context.getCurrentNode();
EObject semantic = null;
EStructuralFeature feature = null;
boolean disqualified = true;
if(currentNode != null) {
semantic = currentNode.getSemanticElement();
if(semantic != null) {
if(semantic instanceof StringExpression == false) {
feature = semantic.eContainingFeature();
// if(feature == null) {
// System.err.println("Null feature");
// }
// disqualify proposals for variable in assignment lhs. (this is what creates a variable, suggestions
// are meaningless). Note that feature may be null here (it is at least not a known lhs in assignment).
if(feature == PPPackage.Literals.BINARY_EXPRESSION__LEFT_EXPR)
disqualified = true;
/* TODO: add more disqualified cases here (if there are any...) */
else
disqualified = false;
}
}
}
if(!disqualified) {
// pick up the default offset and length to replace by the suggestion
// these may be modified later if there are syntax errors / ambiguities and a larger selection is to be replaced
int replacementOffset = context.getReplaceRegion().getOffset();
int replacementLength = context.getReplaceRegion().getLength();
// check conditions when replaced region is not the default, and adjust so the subsequent logic only
// uses prefix and replacement-offset/length
//
String prefix = context.getPrefix();
if(bracedInput) {
if("${".equals(prefix)) {
prefix = "";
replacementOffset += 2;
replacementLength -= 2;
}
}
else if("".equals(prefix) && context.getLastCompleteNode().getText().startsWith("$")) {
prefix = context.getLastCompleteNode().getText();
replacementOffset = context.getLastCompleteNode().getOffset();
replacementLength = context.getLastCompleteNode().getLength();
}
else if(":".equals(prefix) && context.getLastCompleteNode().getText().startsWith("$")) {
prefix = context.getLastCompleteNode().getText() + "::";
replacementOffset = context.getLastCompleteNode().getOffset();
replacementLength = context.getLastCompleteNode().getLength() + 1; // +1 for the prefix ':'
}
else if(prefix.endsWith("$")) {
// this happens in a string when at '"aaa$|..."'
replacementOffset += prefix.length() - 1;
replacementLength = 1;
prefix = "$";
}
if((prefix.startsWith("$") && !prefix.startsWith("${")) || bracedInput) {
// messy
// when after a $ a variable is not recognized until a valid sequence follows i.e (::)?<varchar>. When (::)?<varchar> has been seen
// it is recognized as a VariableExpression
// if inside ${ }, literal names should be proposed, but not if there is a $expr inside - e.g. ${$|, ${...$|, etc.
// create indexed finder from the perspective of the current resource
ppFinder.configure(model.eResource());
// get the fqn (skip the '$') of the name to complete
QualifiedName fqn = converter.toQualifiedName(prefix.substring(bracedInput
? 0
: 1));
// turn global references '::x' into non global
if(fqn.getSegmentCount() > 1 && fqn.getSegment(0).length() == 0)
fqn = fqn.skipFirst(1);
// normal converter does not add trailing empty segment, do so here to enable search in xxx::* namespace
if(prefix.endsWith("::") && fqn.getSegmentCount() > 0)
fqn = fqn.append("");
// find variables using prefixed variant of find
SearchResult r = ppFinder.findVariablesPrefixed(model, fqn, null);
// get the name of the scope we are in to enable reduction of proposal to use locally scoped name
QualifiedName scopeFQN = ppFinder.getNameOfScope(model);
// Remove disqualified entries (known to be uninitialized) ( $x = $x, and define foo ($x, $y = $x) ) (surgical operation)
removeDisqualifiedVariables(r.getAdjusted(), model);
// Create proposals
for(IEObjectDescription d : r.getAdjusted()) {
// Filter out bad name(s)
// https://github.com/puppetlabs/geppetto/issues/263
if("*".equals(d.getQualifiedName().getLastSegment()))
continue;
fqn = d.getQualifiedName();
StringBuilder b = new StringBuilder();
// String description = null;
Image image = null;
// All proposals are variables, so start with $
if(!bracedInput)
b.append("$");
if(bracedProposal)
b.append("{");
// All proposals consisting of one segment are global
if(fqn.getSegmentCount() == 1)
b.append("::");
// TODO: As a consequence of fixing issue #305, this will never happen.
// Investigate if meta parameters should be included at all as variables
//
// If a Parameter, and is Type::name - use only name, display "meta-parameter" (i.e. parameters "inherited" by all types).
if(fqn.getSegmentCount() > 1 && d.getEClass() == PPTPPackage.Literals.PARAMETER &&
"Type".equals(fqn.getFirstSegment())) {
b.append(fqn.getSegment(1));
// TODO: description "meta-parameter" should be provided by description label provider
// description = "meta-parameter";
}
else {
// if name is in same scope as reference, make it a local reference
if(fqn.getSegmentCount() > 1 && fqn.skipLast(1).equals(scopeFQN))
b.append(fqn.getLastSegment());
else
b.append(converter.toString(fqn));
// description = descriptionLabelProvider.typeText(d);
image = descriptionLabelProvider.getImage(d);
}
if(bracedProposal)
b.append("}");
// since $ is in icon, not needed in description (just makes it more difficult to read).
StyledString styledDescription = new StyledString(b.substring(bracedInput
? 0
: 1));
styledDescription.append(typeSuffix(d));
ConfigurableCompletionProposal proposal = doCreateProposal(
b.toString(), styledDescription, image, getPriorityHelper().getDefaultPriority(), context);
proposal.setReplacementOffset(replacementOffset);
proposal.setReplacementLength(replacementLength);
acceptor.accept(proposal);
}
}
}
}
protected Image getImage(String imageName) {
return imageHelper.getImage(imageName);
}
/**
* Remove variables/entries that are not yet initialized. These are the values
* defined in the same name and type if the variable is contained in a definition argument
*
* <p>
* e.g. in define selfref($selfa = $selfref::selfa, $selfb=$selfa::x) { $x=10 } none of the references to selfa, or x are disqualified.
*
* @param descs
* @param o
* @return the number of disqualified variables removed from the list
*/
private int removeDisqualifiedAssignmentVariables(List<IEObjectDescription> descs, EObject o) {
if(descs == null || descs.size() == 0)
return 0;
EObject p = o;
while(p != null && p.eClass().getClassifierID() != PPPackage.ASSIGNMENT_EXPRESSION)
p = p.eContainer();
if(p == null)
return 0; // not in an assignment
// p is an AssignmentExpression at this point
AssignmentExpression d = (AssignmentExpression) p;
final String definitionFragment = d.eResource().getURIFragment(d);
final String definitionURI = d.eResource().getURI().toString();
int removedCount = 0;
ListIterator<IEObjectDescription> litor = descs.listIterator();
while(litor.hasNext()) {
IEObjectDescription x = litor.next();
URI xURI = x.getEObjectURI();
// if in the same resource, and contain by the same EObject
if(xURI.toString().startsWith(definitionURI) && xURI.fragment().startsWith(definitionFragment)) {
litor.remove();
removedCount++;
}
}
return removedCount;
}
/**
* Remove variables/entries that are not yet initialized. These are the values
* defined in the same name and type if the variable is contained in a definition argument
*
* <p>
* e.g. in define selfref($selfa = $selfref::selfa, $selfb=$selfa::x) { $x=10 } none of the references to selfa, or x are disqualified.
*
* @param descs
* @param o
* @return the number of disqualified variables removed from the list
*/
private int removeDisqualifiedDefinitionVariables(List<IEObjectDescription> descs, EObject o) {
if(descs == null || descs.size() == 0)
return 0;
EObject p = o;
while(p != null && p.eClass().getClassifierID() != PPPackage.DEFINITION_ARGUMENT)
p = p.eContainer();
if(p == null)
return 0; // not in a definition argument value tree
// p is a DefinitionArgument at this point, we want it's parent being an abstract Definition
EObject d = p.eContainer();
if(d == null)
return 0; // broken model
d = d.eContainer();
final String definitionFragment = d.eResource().getURIFragment(d);
final String definitionURI = d.eResource().getURI().toString();
int removedCount = 0;
ListIterator<IEObjectDescription> litor = descs.listIterator();
while(litor.hasNext()) {
IEObjectDescription x = litor.next();
URI xURI = x.getEObjectURI();
// if in the same resource, and contain by the same EObject
if(xURI.toString().startsWith(definitionURI) && xURI.fragment().startsWith(definitionFragment)) {
litor.remove();
removedCount++;
}
}
return removedCount;
}
private int removeDisqualifiedVariables(List<IEObjectDescription> descs, EObject o) {
int count = removeDisqualifiedDefinitionVariables(descs, o);
count += removeDisqualifiedAssignmentVariables(descs, o);
return count;
}
public StyledString typeSuffix(IEObjectDescription element) {
EPackage epkg = element.getEClass().getEPackage();
StyledString bld = new StyledString();
if(epkg == PPTPPackage.eINSTANCE || epkg == PPPackage.eINSTANCE) {
bld.append(
" : " + descriptionLabelProvider.getClassLabel(element.getEClass()), StyledString.DECORATIONS_STYLER);
bld.append(" - " + element.getEObjectURI().lastSegment(), StyledString.QUALIFIER_STYLER);
return bld;
}
bld.append(" : ", StyledString.DECORATIONS_STYLER);
return descriptionLabelProvider.getStyledText(element);
}
}