Cross References are a often used concept in Xtext. They ususally work like this
Model:
definitions+=Definition*
usages+=Usage*
;
Definition:
"define" name=ID
;
Usage:
"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
Definition:
"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]
Usage:
"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) {
super(delegate)
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)
}
}
}
super.accept(proposal)
}
}
}
what we basically do is detecting the situation and remove the extra "