Sunday, June 19, 2011

Customizing Content Assist with Xtext

As basically every part of Eclipse Xtext, the content assist API provides a reasonable default behavior and is greatly customizable by means of dependency injection. This blog post demonstrates, how easy it is to create own completion proposals with this API.

For the sake of simplicity, I'll use a grammar that fits in a single line:

It allows to define exactly one color literal and the syntax is not really strict about the literal's format. Valid input files are considered to look like color "0,0,0" or color "255,255,255".

Now comes the fun part: The proposal list for the rgb string should provide some frequently used values, e.g. literals for black or white.

Therefore I have to customize the proposal provider. Xtext already provides an empty stub implementation that will take the custom code. In order to change the proposals for the rgb-value in the parser rule Color, the method completeColor_Rgb(..) has to be overridden. JDT's content assist or the quick outline in the proposal provider implementation helps to find all suitable entry points.

Two lines of code later, I can already insert literals for black or white:
However, there are far more possibilities than simply creating plain vanilla proposals. The overloaded factory method createCompletionProposal(..) returns an instance of the ConfigurableCompletionProposal which has a quite powerful API. It allows to change the appearance of the display string, I can set additional hover information, enable linked edit modes for the custom proposal or make it auto-insertable to name only a few.

The next example uses an own ReplacementTextApplier to hook into the actual moment, when the proposal is applied:

You'll guess that already from the code: This implementation allows to pick the color by means of a color chooser after the proposal has been selected, but see yourself:

There are plenty of other interesting APIs and services around the code completion in Xtext that are worthy of talking about (e.g. the prefix matcher, which Alex covered in his recent post), but I'll leave them for another post.

6 comments:

Irfan said...

(~cast~) is giving me an error,stating primitive type expected.
I tried to typecast this in the following way:ConfigurableCompletionProposal pickColor =
(ConfigurableCompletionProposal) createCompletionProposal("Pick color...",
context);
But after that it was giving error on the use of "ReplacementTextApplier()"..stating that it was an invalid argument.please provide the solution.
Thanks in advance

Unknown said...

Hi Irfan,

you are right, the code snippet was simplified. You have to replace ~cast~ by ConfigurableCompletionProposal and add imports, e.g. for org.eclipse.xtext.ui.editor.contentassist.ReplacementTextApplier. Organize imports will be helpful.

Karsten Thoms said...

Nice! Used this in the Spray language now.

~Karsten

Sandeep said...

in my view, content assist should be wholistic in the sense that we as developer should be given all kind of options for languages like javascript out of the box. Don't know why Eclipse is still not providing the same out of the box. It does however support syntax highlighting for javascript code.

Unknown said...

Hello Sebastian,

We have form based editor and xtexteditor as Source page.

we used embedded editor to implement the content assist feature in form pages. But it displays all the contents as proposals when 'ctrl + space' keys pressed together. We want to display field specific content assist.

Eg: let say Source page looks:

boardStatus = "test.bst"

loadStatus = "test.lst"

..... and so on


let say XYZ form page:
____________
boardStatus: |____________|
____________
loadStatus: |____________|

we have swt text widget for each of field present in source page.

problem:

I want to display all the "boardStatus" files present in current working directory as proposal in form page.

It would be great help you provide some input.

Thanks

ConsideredTrue said...

Hi Sebastian,

do you know a good way to test a customized proposal provider?

Thanks,

ERIC