Skip to content

Development Template Proposals

Fernando Dodino edited this page Aug 10, 2019 · 9 revisions

Intro

Templates proposals are code assist elements like the following screenshots

screen shot 2016-07-12 at 22 55 43

XText has a way to add new proposals for your language described in this link (also check xtext doc in depth)

But we have built our own small internal DSL to make it easier to add new templates for a given language element (semantic model).

Adding a new Template

You need to modify the class WollokTemplateProposalProvider

Add a new entry like the following

<< WNamedObject >>
'''object ${objectName} {
	
}
'''

Internally they are all messages and it is a tricky way to model a DSL in xtend with operator overloading. But that's internal details. Overall you need to understand that it has 2 parts:

  • The class of the language element (semantic model). Which is usually the same name as the grammar rule
  • A template with the form of a string

For example if you want to add a new template for an if expression

<< WIfExpression >>
'''if() {
   }
   else {
   }
'''

In the template you can include variables with the form

${name}

For example

'''if(${condicion}) {
       ${then}
   }
   else {
   }
'''

Names are arbitrary. They won't do much, just that it tells de IDE that the user will need to fill something there. So the cursor will be positioned automatically in the first variable and he will be able to navigate to the next one with TAB.

Example screenshot

screen shot 2016-07-12 at 23 09 59

i18n (internationalization)

There's an extra element you need to define, which is the name and the description of the template proposal. Otherwise it will look like the last item in the above image.

As this depends on the language, we have it internationalized (i18n). And our DSL provides a convention over configuration way to define this.

You just need to include two new entries in the messages.properties for:

  • name
  • description

The file is located in

org.uqbar.project.wollok.ui/src/org/uqbar/project/wollok/ui/messages.properties
org.uqbar.project.wollok.ui/src/org/uqbar/project/wollok/ui/messages_es.properties

The entry convention there is:

WollokTemplateProposalProvider_SEMANTICMODELCLASSNAME_name = THE NAME HERE
WollokTemplateProposalProvider_SEMANTICMODELCLASSNAME_description = THE DESCRIPTION HERE

Where you need to change SEMANTICMODELCLASSNAME with your language element class and the value, of course The other parts are "fixed".

Sample for the if example:

WollokTemplateProposalProvider_WIfExpression_name = If expression
WollokTemplateProposalProvider_WIfExpression_description = Add if expression

Mail de Javi Fernándes explicando cómo autocompletar

Sí señor y no señor.

Hay que entender que eclipse tiene 2 tipos de elementos que se muestran en el autocomplete: Proposals: xtext ya provee en base a la gramática (parser). Pero bueno, podrían ser cualquier tipo de proposals. Abajo es la API genérica de eclipse Template proposals: estos son los templates más elaborados como el que te arma ya un if else, o un try catch y te mete variables con el cursor ya puesto para que escribas el contenido Template Proposals

Para los templates proposals tenemos documentación

https://github.com/uqbar-project/wollok/wiki/Development%20-%20Template%20Proposals

Igual lo que más explico ahí es un pequeño DSL interno que hice arriba de la API para generar estos templates más "directos" o simples. Por ejemplo si agregás una nueva regla

WIfComprehension: 'for '(' e=Exp 'in' generator=Gen conditions+=cond ')' '{' body=Body '}'

Es muy probable que quieras un template (porque sino te va proponiendo keyword por keyword. Querés algo así:

for ( e in list if blah) { body }

Entonces eso lo podemos hacer fácil con nuestro DSL

<< WIfComprehension >> ''' for ( ${e} in ${list} if ${cond}) { ${body} } '''

Recién agregué una sección acá de cómo testear los proposals usando XPect y una extensión que le hicimos

https://github.com/uqbar-project/wollok/wiki/Development---Testing#autocomplete-codeassists--templateproposals

Este tipo de tests sirven para las dos cosas, porque testean todas las opciones que aparecen: proposals y template proposals.

(Regular) Proposals

Acá no tenemos nada nuestro hecho arriba de xtext. Y tampoco tenemos documentación (este mail podría ser la gestación). La doc de xtext justo acá http://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#content-assist

Pero trato de aplicarlo a wollok.

Hay que tocar en la clase WollokDslProposalProvider Como varias otras cosas de XText se hace agregando métodos que sigan una convención. Ejemplo, si querés proponer imports, primero tenés que entender cómo es la regla de la gramática

Import: 'import' importedNamespace=QualifiedNameWithWildcard;

Ahí vemos que un Import tiene como una propiedad llamada "importedNamespace". A esa parte es a la que vamos a proponer cosas.

Entonces sobrescribimos el método:

override completeImport_ImportedNamespace(EObject model, Assignment assignment, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {

}

Los nombres fijate que tienen la convención

complete${regla}_${atributo}(ObjetoRegla, ...blah, aceptor)

Después adentro es pelearse con la API para crear los proposals y agregarlos al aceptor

Nosotros ya tenemos un par de métodos útiles para crear los objetos proposals (porque tiene una clase específica, no es sólo texto, con un ícono, descripción, etc).

Por ejemplo para imports estamos haciendo esto

val content = model.file.resourceSet.allContents.filter(WLibraryElement)

// add other files content here

content.forEach[

if (it instanceof WMethodContainer)

    acceptor.accept(createCompletionProposal(fqn, fqn, image, context))

]

La primera linea busca todos los elementos (clase, mixin, objeto, package) en todos los archivos del "classpath" digamos. y después (de un pequeño filtro extra -me pregunto si no habría que refactorizar esto y filtrar directo una sóla vez por WMethodContainer) ... creamos un proposal para cada uno (con createCompletionProposal(), método útil nuestro) y se lo pasamos al acceptor.

O sea.. fijate que básicamente es de bastante alto nivel. Buscás los objetos que querés proponer (métodos, variables, lo que sea) Creas un proposal con cada uno y lo agregás al acceptor. Esos "objetos" están directamente relacionados con la gramática Entonces es crucial entender la gramática de Wollok (ej WMethodContainer, WLibraryElement). Esa es "la dificultad". Y obvio la dificultad propia de lo que quieras hacer en el automcomplete. Por ejemplo si querés proponer sólo mensajes válidos, capaz necesitás un sistema de tipos atrás :P

Clone this wiki locally