Posts Tagged ‘ProposalProvider’

Xtext and Strings as Cross-References

Cross References are a often used concept in Xtext. They ususally work like this


    "define" name=ID

   "use" definition=[Definition]

They can be used in the model like this

define Thing
use Thing

but what if i want to write something like

define "This is a Thing"
use "This is a Thing"

well the definition part is easily changed

    "define" name=STRING

But what about the usage part?
well it is quite easy as well. refName=[Type] is short for refName=[Type|ID] which means ‘Refererence a Type and parse an ID. So to use another Terminal or Data Type Rule we change it to refName=[Type|RULENAME]

   "use" definition=[Definition|STRING]

Now the cross refs are working fine. but if we try the editor we find out what autoedit and content assist disturb each other. We type " and auto edit gets us to "|". If we now type Crtl+Space for content assist we finally get "This is a Thing"" with an extra " at the end.
To avoid this we have to tweak the proposal provider a bit.

package org.xtext.example.mydsl.ui.contentassist

import org.xtext.example.mydsl.ui.contentassist.AbstractMyDslProposalProvider
import org.eclipse.emf.ecore.EObject
import org.eclipse.xtext.Assignment
import org.eclipse.xtext.ui.editor.contentassist.ContentAssistContext
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor
import org.eclipse.xtext.ui.editor.contentassist.ICompletionProposalAcceptor.Delegate
import org.eclipse.jface.text.contentassist.ICompletionProposal
import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal

class MyDslProposalProvider extends AbstractMyDslProposalProvider {

	override completeUsage_Definition(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
		super.completeUsage_Definition(model, assignment, context, new  StringProposalDelegate(acceptor, context))

	static class StringProposalDelegate extends Delegate {

		ContentAssistContext ctx

		new(ICompletionProposalAcceptor delegate, ContentAssistContext ctx) {
			this.ctx = ctx

		override accept(ICompletionProposal proposal) {
			if (proposal instanceof ConfigurableCompletionProposal) {
				val endPos = proposal.replacementOffset + proposal.replacementLength 
				if (ctx.document != null && ctx.document.length > endPos) {
					// We are not at the end of the file
					if ("\"" == ctx.document.get(endPos, 1)) {
						proposal.replacementLength = proposal.replacementLength-1
						proposal.replacementString = proposal.replacementString.substring(0,proposal.replacementString.length-1)



what we basically do is detecting the situation and remove the extra "