title: Xtext content/template proposal
body: <p>Another Xtext question! My goal would be to create a template/content proposal for an annotation-like structure, which looks like this:</p>
  
  <pre><code>Model:
      elements+=Element*;
  
  Element:
      AnnotationDecl | ClassDecl;
  
  AnnotationDecl:
      'annotation' name=ID '{' fields+=AnnotationDeclField* '}';
  
  AnnotationDeclField:
      name=ID;
  
  Annotation:
      '@' declaration=[AnnotationDecl] '(' members+=AnnotationField* ')';
  
  AnnotationField:
      declaration=[AnnotationDeclField] '=' value=STRING;
  
  ClassDecl:
      annotations+=Annotation* 'class' name=ID '{' /* ... */ '}';
  </code></pre>
  
  <p>And a sample usage of this language would be something like this:</p>
  
  <pre><code>annotation Foo { 
      foo 
      bar
  } 
  
  @Foo(foo = 'foo' bar = 'bar')
  class A { 
  }
  </code></pre>
  
  <h2>The problem</h2>
  
  <p>Now in the current state, if i write the necessary scope provider, Xtext provides a pretty good base for the user for completing this structure, but if he/she is not familiar with the structure of the language, it might be confusing to type the following:</p>
  
  <p><code>@</code> <kbd>ctrl</kbd> + <kbd>space</kbd> Select <code>Foo</code> <kbd>ctrl</kbd> + <kbd>space</kbd> select <code>(</code> <kbd>ctrl</kbd> + <kbd>space</kbd> ...</p>
  
  <p>So my idea would be to provide a pre-filled base, which is syntactically correct, and he/she only has to fill the important parts using the navigation with <kbd>tab</kbd> in a template:</p>
  
  <pre><code>@Foo(foo = '${foo}' bar = '${bar}')
  </code></pre>
  
  <h2>Attempts to solve this:</h2>
  
  <p>I have made 2 attempts to do this, none of them was quite what i'm looking for.</p>
  
  <h2>1. Content proposal</h2>
  
  <p>The first is solving this with content proposals like this:</p>
  
  <pre><code>class MyDslProposalProvider extends AbstractMyDslProposalProvider {
  
      override complete_Annotation(EObject model, RuleCall rc, ContentAssistContext ctx, ICompletionProposalAcceptor acceptor) {
          super.complete_Annotation(model, rc, ctx, acceptor)
          if (model == null || model.eContainer == null) {
              return
          }
          val rootModel = model.eContainer as Model
          val annotationDecls = rootModel.elements.filter(AnnotationDecl)
          annotationDecls.forEach [ annDecl |
              val fieldsProposals = annDecl.fields.map[name].map[field|'''«field» = ${«field»}''']
              val fullProposalText = '''@«annDecl.name»(«fieldsProposals.join(' ')»)'''
              val proposal = createCompletionProposal(fullProposalText, annDecl.name, null, ctx)
              acceptor.accept(proposal)
          ]
      }
  }
  </code></pre>
  
  <p>Which gets the context right, because it shows the proposal right after I type the <code>@</code> character, but because its not a template, it will be used as-is and display the original String what was created:</p>
  
  <pre><code>@Foo(foo = '${foo}' bar = '${bar}')
  </code></pre>
  
  <h2>2. Template proposal</h2>
  
  <p>My second attempt was to create a template proposal provider, which looked like this:</p>
  
  <pre><code>class MyDslTemplateProposalProvider extends DefaultTemplateProposalProvider {
  
      @Inject
      new(TemplateStore templateStore, ContextTypeRegistry registry, ContextTypeIdHelper helper) {
          super(templateStore, registry, helper)
      }
  
      override protected createTemplates(TemplateContext tplCtx, ContentAssistContext ctx, ITemplateAcceptor acceptor) {
          super.createTemplates(tplCtx, ctx, acceptor)
          val rootModel = ctx.rootModel as Model
          if (rootModel == null) {
              return
          }
          val annotationDecls = rootModel.elements.filter(AnnotationDecl)
          annotationDecls.forEach [ annDecl |
              val fieldsProposals = annDecl.fields.map[name].map[field|'''«field» = '${«field»}' '''.toString.trim]
              val fullProposalText = '''@«annDecl.name»(«fieldsProposals.join(' ')»)'''
              val template = new Template(annDecl.name, '', annDecl.name, fullProposalText, true)
              val proposal = createProposal(template, tplCtx, ctx, null, getRelevance(template))
              acceptor.accept(proposal)
          ]
      }
  }
  </code></pre>
  
  <p>Which created exactly what i wanted in terms of content, but I couldn't fine-tune it, so it only shows after I type the <code>'@'</code> character and press <kbd>ctrl</kbd> + <kbd>space</kbd> (like the content proposal), because it looks like it won't show if I'm in the middle of an unfinished rule.</p>
  
  <h2>So my question:</h2>
  
  <p><strong>Which would be the right solution?</strong></p>
  
  <ul>
  <li>Is the regular content proposal configurable somehow, so it's
  interpreted as a template? </li>
  <li>Or can I somehow fine tune the template
  proposal to only show in the context I want it to show (<code>@</code> pressed)?</li>
  </ul>
  
  <p>Thanks in advance, and sorry for the lots of code, I really tried to narrow it down to the relevant parts!</p>