Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Autocomplete import example(Little contribution : an example of autocomplete import with namespace)
Autocomplete import example [message #873557] Fri, 18 May 2012 14:24
CRASNIER Stéphane is currently offline CRASNIER StéphaneFriend
Messages: 13
Registered: May 2012
Junior Member
Hi all,

Autcompleting import thanks to a proposal provider and add them automatically to the model was not so easy for me. So if it is the same for you, here is a litlle example.

This code is a first draft so it is neither optimzed nore very beautiful. BTW, I'm quite new to XText so the way I've done thing is certainly not the best one. All comments/suggestion are welcome to improve it.

First, the imports are called "uses" in my context and the root node is a Graphe. Referenced elements are entities. Here is an extract of the grammar :
Graphe:
    uses=Uses
    (entities+=Entity)+	
    [...]

Uses:{Uses}
    (use+=Use)*
;

Use: 'use:' importedNamespace=Fqn';';
Fqn:ID('.'ID)*;


The Use declarations have to be embedded in the Uses in order to make the serializer keep the hidden token (mainly the comments in my context). Otherwise they are deleted.

That's why a custom scope provider has to be written in order to add the imported namespaces of the uses. Given the fact that entities and uses are at the same level, the importedNamespace of the uses are not added to the scope. Here is the code of the provider to bind instead of the "natural" ImportedNamespaceAwareLocalScopeProvider :
public class UsesImportedNamespaceAwareLocalScopeProvider extends
		ImportedNamespaceAwareLocalScopeProvider {
	protected List<ImportNormalizer> getImportedNamespaceResolvers(
			final EObject context, final boolean ignoreCase) {
		List<ImportNormalizer> result = super.getImportedNamespaceResolvers(
				context, ignoreCase);
		if (context != null && context instanceof Graphe) {
			Uses uses = ((Graphe) context).getUses();
			if (uses != null) {
				result.addAll(getImportedNamespaceResolvers(uses, ignoreCase));
			}
		}
		return result;
	}
}


Finally, the example of proposal provider to bind in the UI module. It seems to be quite obvious and all is in the reference documentation but I find it quite difficult to put the things alltogether to make them work so if this extract can help... :
public class MyModelProposalProvider extends
		AbstractMyModelProposalProvider {

	@Inject
	private IContainer.Manager manager;

	@Inject
	private IQualifiedNameConverter converter;

	@Inject
	private IResourceServiceProvider.Registry rspr;

	@Inject
	private ResourceDescriptionsProvider resourceDescriptionsProvider;

	private IResourceDescription.Manager getManager(Resource res) {
		IResourceServiceProvider resourceServiceProvider = rspr
				.getResourceServiceProvider(res.getURI());
		return resourceServiceProvider.getResourceDescriptionManager();
	}

	public void completeUse_ImportedNamespace(Use use, Assignment assignment,
			ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		super.completeUse_ImportedNamespace(use, assignment, context, acceptor);
		Resource resource = use.eResource();
		if (resource != null) {
			String importedNamespace = use.getImportedNamespace();
			IResourceDescription.Manager mngr = getManager(resource);
			IResourceDescriptions index = resourceDescriptionsProvider
					.createResourceDescriptions();

			IResourceDescription descr = mngr.getResourceDescription(resource);

			for (IContainer visibleContainer : manager.getVisibleContainers(
					descr, index)) {
				for (IResourceDescription visibleResourceDesc : visibleContainer
						.getResourceDescriptions()) {
					Iterable<IEObjectDescription> exportedObject = visibleResourceDesc
							.getExportedObjects();
					if (exportedObject != null) {
						for (IEObjectDescription ieObjectDescription : exportedObject) {
							if (ieObjectDescription != null) {
								QualifiedName qualifiedName = ieObjectDescription
										.getQualifiedName();
								if (qualifiedName != null) {
									String[] imports = new String[] {};
									boolean addSegment = false;
									if (importedNamespace != null) {
										importedNamespace = importedNamespace.trim();
										imports = importedNamespace.split("\\.");
										addSegment = importedNamespace
												.endsWith(".")
												|| importedNamespace.equals("");
									} else {
										addSegment = true;
									}
									int segmentsCount = imports.length;
									if (addSegment) {
										segmentsCount++;
									}
									if (qualifiedName.getSegmentCount() == segmentsCount) {
										boolean ok = true;
										if (importedNamespace != null
												&& !importedNamespace.equals("")) {
											ok = startsWith(
													qualifiedName,
													converter
															.toQualifiedName(importedNamespace),
													true);
										}
										if (ok) {
											ICompletionProposal proposal = createCompletionProposal(
													qualifiedName.toString(),
													context);
											acceptor.accept(proposal);
										}

									}
								}

							}
						}
					}

				}
			}
		}
	}

	private static boolean startsWith(QualifiedName name, QualifiedName prefix,
			boolean ignoreCase) {
		if (prefix.getSegmentCount() > name.getSegmentCount())
			return false;
		int endIndex = prefix.getSegmentCount();
		for (int i = 0; i < endIndex; ++i) {
			String comparedName = name.getSegment(i);
			if (i == (endIndex - 1)) {
				comparedName = name.getSegment(i).substring(0,
						prefix.getSegment(i).length());
			}
			if ((ignoreCase && !comparedName.equalsIgnoreCase(prefix.getSegment(i)))
					|| (!ignoreCase && !comparedName.equals(prefix.getSegment(i))))
				return false;
		}
		return true;
	}

	private void handleReferenceProposal(EObject model, Assignment assignment,
			ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		Resource resource = model.eResource();
		// From the super class : cross reference retrieving.
		CrossReference crossReference = ((CrossReference) assignment
				.getTerminal());
		EReference ref = GrammarUtil.getReference(crossReference);
		if (ref != null && resource != null) {
			IResourceDescription.Manager mngr = getManager(resource);
			IResourceDescriptions index = resourceDescriptionsProvider
					.createResourceDescriptions();

			IResourceDescription descr = mngr.getResourceDescription(resource);

			for (IContainer visibleContainer : manager.getVisibleContainers(
					descr, index)) {
				for (IResourceDescription visibleResourceDesc : visibleContainer
						.getResourceDescriptions()) {
					Iterable<IEObjectDescription> objExportes = visibleResourceDesc
							.getExportedObjectsByType(ref.getEReferenceType());
					if (objExportes != null) {
						for (IEObjectDescription ieObjectDescription : objExportes) {
							if (ieObjectDescription != null) {
								QualifiedName qualifiedName = ieObjectDescription
										.getQualifiedName();
								String proposalStr = qualifiedName
										.getLastSegment();
								String useStr = qualifiedName.toString();

								ConfigurableCompletionProposal proposal = (ConfigurableCompletionProposal) createCompletionProposal(
										proposalStr, new StyledString(
												proposalStr + " - " + useStr),
										null, context);
								proposal.setAdditionalProposalInfo(qualifiedName);
								proposal.setTextApplier(new UseReplacementTextApplier());
								acceptor.accept(proposal);
							}
						}
					}

				}
			}
		}
	}

	private class UseReplacementTextApplier extends ReplacementTextApplier {

		@Override
		public void apply(IDocument document,
				ConfigurableCompletionProposal proposal)
				throws BadLocationException {
			final ConfigurableCompletionProposal proposalAux = proposal;
			super.apply(document, proposal);
			((IXtextDocument) document)
					.modify(new IUnitOfWork.Void<XtextResource>() {
						public void process(XtextResource resource) {
							String qName = proposalAux
									.getAdditionalProposalInfo();
							if (qName != null && !"".equals(qName)) {
								Graphe graphe = (Graphe) resource.getContents()
										.get(0);
								Uses uses= graphe.getUses();
								EList<Use> liste = uses.getUse();
								if (liste != null) {
									int index = 0;
									for (Iterator<Use> iterator = liste
											.iterator(); iterator.hasNext();) {
										Use use = iterator.next();
										String ns = use.getImportedNamespace();
										if (ns != null) {
											int comp = ns.compareTo(qName);
											if (comp == 0) {
												// The use is already here.
												index = -1;
											} else {
												// The use has to be inserted
												// here.
												break;
											}
											index++;
										}
									}
									if (index >= 0) {
										Use newUse = MyModelFactory.eINSTANCE
												.createUse();
										newUse.setImportedNamespace(qName);
										liste.add(index, newUse);
									}
								}
							}
						}
					});
		}

		@Override
		public String getActualReplacementString(
				ConfigurableCompletionProposal proposal) {
			String ret = null;
			if (proposal != null) {
				ret = proposal.getReplacementString();
			}
			return ret;
		}

	}
	
		@Override
	public void completeEnregistrementRef_Reference(EObject model,
			Assignment assignment, ContentAssistContext context,
			ICompletionProposalAcceptor acceptor) {
		handleReferenceProposal(model, assignment, context, acceptor);
	}
	
	[... bind all needed complete methods to the handleReferenceProposal method]
}
Previous Topic:(Xtext) 15 Minute Tutorial needs to be updated for version 2.2
Next Topic:Lookahead value of xtext grammar
Goto Forum:
  


Current Time: Tue Dec 01 19:04:15 GMT 2020

Powered by FUDForum. Page generated in 0.01628 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top