Velocity/Freemarker feedback

Resolving and completion has improved greatly over last month. There are still some issues, however things are good enough in general to discuss some higher-level desired functionality.

Definition of context variables in external metadata

As discussed in JIRA, sometimes you don't want to use the Jetbrains-specific @vtlvariable/@ftlvariable comment annotations (eg. in a multi-IDE team). In addition, some context variables can be present for all (or most) templates in a module, and adding the the same comment annotation over and over is a drag.

So, the most valuable new feature would be the possibility to declare context variables (similar to @vtlvariable/@ftlvariable) outside of the template file.

Provide two "scopes":

  • variables defined for current template

  • variables defined for all templates in module

UI

Add extra file tab (similar to web.xml editor). It allows quick navigation without digging into some detailed UI like facet or settings. This tab contains two tables, both having two columns (variable name and variable type). First table contains page-specific variables, the second table module-specific. Ctrl-B from template navigates to this tab.

Provide a second QuickFix ("Define implicit variable in config"?). This quickfix doesn't navigate to the second tab, but just shows a dialog/popup that accepts a type. Provide "module-wide" checkbox (unchecked by default) that determines in which scope/table the variable definition ends up. Accepting this dialog adds the definition, without ever switching to the second tab. This maintains editor flow. I can always Ctrl-B after accepting the dialog to change things, since editor caret will still be on variable reference (which is now resolved).

When invoking the fix, scan the current template for usages of the variable below caret. Collect (for now unresolved) property and method references, use these to perform a search in module classpath. Dialog suggests type candidates based on this search. Esc key clears suggestions and allows me to enter something myself (Ctrl-Shift-Space should be available). When there's only one match, I should be able to simply accept the dialog using Enter key and be done. :)

Storage

Can this data be stored in .iml file?

Predefined context variable groups

A possible extension to above support. Provide a way to define named sets of (name,type) tuples. In the context tab, allow a way to quickly add such set to either page or module scope.

For example FreemarkerServlet exposes not only JspTaglibs, but 4 other variables as well. Defining a group containing all 5 once, and then adding it to "module" scope for a given module quickly gets one started. I'd imagine such "group definitions" to be IDE-global.

Freemarker JSP taglib support

The JSP taglib support is often used when using Freemarker for HTML views. Things like Ctrl-Q and missing required attribute checking should be available. I'll file issues as I go.

Spring support/integration

Spring MVC makes it trivial to use Velocity or Freemarker. Better IDEA support would be very valuable here. Unsorted list of problems/features:

  • for Velocity, Spring implicitly includes "spring.vm" macros. No need to #include anything. How do I configure this for one or more templates?

  • for Freemarker, an <#import> is needed, however no full path needs to be specified. How do I configure this?

  • for the Spring messageXxx macros, provide resource bundle key resolving

  • for the Spring bindXxx macros, IDEA should know that these define a variable of type BindStatus.


That's it for now. Comments welcome. If needed, I'll provide a quick UI mockup sketch.

12 comments
Comment actions Permalink

As for implicit variables that don't clutter source file or are defined
for the whole module/project, I prefer to be text-editor-centric. What
about having special files in your project and possibly version control
that are of Freemarker/Velocity type and contain only comments with
implicit variables. They will be then implicitly included into actually
used template files. The inclusion scope can be saved in .iml and
configured via intention actions. This would solve also the problem with
names tuple sets.

JSPTagLibs actually can't be defined via any declarative comment (of
course it can, but this would be a very special ad-hoc comment), its
support requires some code. I'm not sure that those 4 remaining
variables from FreemarkerServlet will be easier to support.

0
Comment actions Permalink

Peter,

1) Text based solution would be fine. My reason for suggesting UI described above is that most other .vm/.ftl editors use something like that. Anyway, perhaps you could provide a more detailed example of how things will work in your proposal? For example, let's assume I have 20 .ftl files in my module. I'd like to define (implicit, non-@ftlvariable) context for all of them. Some variables I'd like to be template-local, while others would need to be module-wide. What files will be created, etc?

2) I think inference of implicit variables (based on method/property usage) will make a big usability difference. One thing I'm not sure about is the following...Quite often a template recieves a list/array of Foo objects. It would be very valuable if IDEA could both:

  • infer (by noticing foreach/list constructs) that the variable is a List/array

  • infer the element type by looking at accesses inside the loop


Quite often you open a large existing template, and having good inference would get you on your way quickly.
http://www.jetbrains.net/jira/browse/IDEADEV-26979

3) Do you have any ideas how to better support Spring integration? I mean the resolving of "spring.vm" / "spring.ftl" macros.

0
Comment actions Permalink

Taras Tielkes wrote:

1) Text based solution would be fine. My reason for suggesting UI
described above is that most other .vm/.ftl editors use something
like that. Anyway, perhaps you could provide a more detailed example
of how things will work in your proposal? For example, let's assume I
have 20 .ftl files in my module. I'd like to define (implicit,
non-@ftlvariable) context for all of them. Some variables I'd like to
be template-local, while others would need to be module-wide. What
files will be created, etc?

Usage is yellow-highlighted. Alt+Enter, there are 3 quickfixes: define
variable in comment / another file. The first one works as now, the
second lists available files and an option to create new file anywhere
user wants. When a new .ftl file is created, a dialog is shown where
user can define the file scope (module-wide, for that particular source
file, or choose from all .ftl files in module). After dialog is closed,
an @ftlvariable comment is added to the newly created file. I don't yet
understand completely when should I ask for the variable type (and
suggest the inferred ones).

2) I think inference of implicit variables (based on method/property
usage) will make a big usability difference. One thing I'm not sure
about is the following...Quite often a template recieves a
list/array of Foo objects. It would be very valuable if IDEA could
both: * infer (by noticing foreach/list constructs) that the variable
is a List/array * infer the element type by looking at accesses
inside the loop

Quite often you open a large existing template, and having good
inference would get you on your way quickly.
http://www.jetbrains.net/jira/browse/IDEADEV-26979

Agreed.

3) Do you have any ideas how to better support Spring integration? I
mean the resolving of "spring.vm" / "spring.ftl" macros.


As for the fact that their full path need not be entered, I'll hardcode
it somewhere, I think.

0
Comment actions Permalink


> Usage is yellow-highlighted. Alt+Enter, there are 3 quickfixes: define
> variable in comment / another file. The first one works as now, the
> second lists available files and an option to create new file anywhere
> user wants. When a new .ftl file is created, a dialog is shown where
> user can define the file scope (module-wide, for that particular source
> file, or choose from all .ftl files in module). After dialog is closed,
> an @ftlvariable comment is added to the newly created file. I don't yet
> understand completely when should I ask for the variable type (and
> suggest the inferred ones).


How about a single .ftl/.vm file per module, storing both page-specific as well as module-global implicit context variables? Of course you'd have some attribute that specified page/module scope.
The name of the file could be fixed - something like "freemarker-variable-context.ftl" in module root?.

I would prefer that to having a lot of files scattered over my module (that I'd probably have to exclude each time from VCS).

The UI flow would be simple:

  • unresolved variable reference

  • 2 QuickFixes available:

    • define implicit variable in comment

    • define implicit variable in external file

  • both of these would show a dialog with a focused ClassName field, and presenting inferred suggestions

  • checkbox "module-wide" is disabled for first QuickFix, and enabled (but unchecked) for second QuickFix


> > 3) Do you have any ideas how to better support Spring integration? I
> > mean the resolving of "spring.vm" / "spring.ftl" macros.
>
> As for the fact that their full path need not be entered, I'll hardcode
> it somewhere, I think.


Ok, but there's a difference between the two:

  • For velocity, VelocityConfigurer#postProcessVelocityEngine() calls:

    
    

    So contents of "spring.vm" is implicitly included, without need for #include/#parse directive.

  • For freemarker FreeMarkerConfigurer#postProcessTemplateLoaders() calls:

    
    

    The effect is that a template can use <#import "spring.ftl" as spring/> to access the spring-provided macros.


How will IDEA decide to apply such implicit template library file logic? Presence of Spring facet on module seems a reasonable criterium.

0
Comment actions Permalink


>> Usage is yellow-highlighted. Alt+Enter, there are 3 quickfixes:
>> define variable in comment / another file. The first one works as
>> now, the second lists available files and an option to create new
>> file anywhere user wants. When a new .ftl file is created, a dialog
>> is shown where user can define the file scope (module-wide, for
>> that particular source file, or choose from all .ftl files in
>> module). After dialog is closed, an @ftlvariable comment is added
>> to the newly created file. I don't yet understand completely when
>> should I ask for the variable type (and suggest the inferred ones).
>>
>


How about a single .ftl/.vm file per module, storing both
page-specific as well as module-global implicit context variables? Of
course you'd have some attribute that specified page/module scope.
The name of the file could be fixed - something like
"freemarker-variable-context.ftl" in module root?.

Will all users like fixed file in their module root? Though maybe if
it's non-source content root and this is the only file next to the .iml
one, it will be not so annoying. And it has a strong advantage that it
hasn't to be configured in UI.

As for scope attribute, this is a good idea. I was thinking about some
marked sections in this one file.

The UI flow would be simple: * unresolved variable reference * 2
QuickFixes available: ** define implicit variable in comment **
define implicit variable in external file * both of these would show
a dialog with a focused ClassName field, and presenting inferred
suggestions * checkbox "module-wide" is disabled for first QuickFix,
and enabled (but unchecked) for second QuickFix

Great, I like it.

How will IDEA decide to apply such implicit template library file
logic? Presence of Spring facet on module seems a reasonable
criterium.

Certainly. I'm not sure whether Spring or Freemarker (Velocity) plugin
should do this, but some of them will. Now JSPTagLibs are hard-coded
similarly when Web facet is present.

0
Comment actions Permalink

Peter/Maxim,

I think it would be very useful to have this feature for JSP/JSPX as well.

Taras

0
Comment actions Permalink

Any chance of StringTemplate support?

It's a very simple templating engine (as in, should be much easier to implement that Velocity or Freemarker), quite popular, and works well with ANTLR. Terence Parr (the author) even commented on the IDEA 8 roadmap that he'd happily help you.

Thanks,
Christopher

0
Comment actions Permalink

Hello Christopher,

Any chance of StringTemplate support?

It's a very simple templating engine (as in, should be much easier to
implement that Velocity or Freemarker), quite popular, and works well
with ANTLR. Terence Parr (the author) even commented on the IDEA 8
roadmap that he'd happily help you.


We don't have any plans to work on it internally. The Velocity plugin is
open-source so it can be used as a sample for implementing plugins supporting
other template languages.

--
Dmitry Jemerov
Development Lead
JetBrains, Inc.
http://www.jetbrains.com/
"Develop with Pleasure!"


0
Comment actions Permalink


> > The UI flow would be simple: * unresolved variable reference * 2
> > QuickFixes available: ** define implicit variable in comment **
> > define implicit variable in external file * both of these would show
> > a dialog with a focused ClassName field, and presenting inferred
> > suggestions * checkbox "module-wide" is disabled for first QuickFix,
> > and enabled (but unchecked) for second QuickFix
> Great, I like it.


After some thinking the UI could be streamlined even more:

  • provide single QuickFix "Define implicit variable"

  • dialog has radio buttons for two exclusive choices "as @ftlvariable" and "as external annotation"

  • the choice for above radio button is remembered

  • when "as external annotation" is chosen, checkbox "module-wide" is enabled (but unchecked by default)

  • dialog focuses on ClassName field, presenting inferred suggestions, and offers option to his Esc and use manual ClassName completion


The idea is that one would either

  • add all declarations as @ftlvariable comments

  • or add all declarations as external annotations (for example when working in multi-IDE team)


Above improvement would still allow to use a mix of both, however I think for the "common path" it would make more sense to simply remember the last chosen method of providing external definition.

This way defining variable type would just be a single "Alt-Enter" away in almost all cases.

0
Comment actions Permalink

BTW there is one more choice the user sometimes is forced to make, at
least in FreeMarker support. When she presses Alt+Enter on
${a]]>.b.c.d}, where 'a' is unresolved, a lookup is presented inside
newlyc created comment whether she wants to define 'a', 'a.b', 'a.b.c'
or 'a.b.c.d'. What will you say to this? Another, 'name' field in dialog?

I've implemented type inference, and it works now as another lookup in
comment creation live template, or smart completion in comment type
field later. And, as for me, I'm quite happy when no dialogs are
presented now (if back navigation problem was also fixed, it would be
perfect), and create-from-usage Java fixes also navigate to the place
they change. So I'm not sure whether the complex dialog with 2
text/combo fields, 2 radio buttons and 1 checkbox would be appropriate.
3 fixes (define in file, define externally for this file, externally for
the module) with live templates would do the same. Or one quick fix with
additional 3-alternative popup with preselection. What do you think?

0
Comment actions Permalink


BTW there is one more choice the user sometimes is forced to make, at
least in FreeMarker support. When she presses Alt+Enter on
${a<caret>.b.c.d}, where 'a' is unresolved, a lookup is presented inside
newlyc created comment whether she wants to define 'a', 'a.b', 'a.b.c'
> or 'a.b.c.d'. What will you say to this? Another, 'name' field in dialog?


At least for me, in most cases it will only be necessary to define leftmost part of expression ('a').
Since most often regular JavaBeans object graphs are used, the rest should resolve properly.

Can you give some examples of other 'a.b.c.d' constructs?


> I've implemented type inference, and it works now as another lookup in
> comment creation live template, or smart completion in comment type
> field later. And, as for me, I'm quite happy when no dialogs are


Nice! Does inference also visit foreach/list loops and look at possible types of collection elements?


presented now (if back navigation problem was also fixed, it would be
perfect), and create-from-usage Java fixes also navigate to the place
they change. So I'm not sure whether the complex dialog with 2
text/combo fields, 2 radio buttons and 1 checkbox would be appropriate.
3 fixes (define in file, define externally for this file, externally for
the module) with live templates would do the same. Or one quick fix with
additional 3-alternative popup with preselection. What do you think?


Peter, I suggest to do whatever is less work.
That way you can collect more feedback now about core functionality.
Dialogs can always be added later.

Btw, what back navigation problem? :)

0
Comment actions Permalink

At least for me, in most cases it will only be necessary to define leftmost part of expression ('a').
Since most often regular JavaBeans object graphs are used, the rest should resolve properly.

Can you give some examples of other 'a.b.c.d' constructs?

We have an insider FreeMarker-based project, where there is a global
implicit variable 'model' of hash type, and it's its children that have
to be defined: 'model.object', 'model.session' or something like this.
But it's 'model' that is yellow-highlighted, so users tend to press
Alt+Enter while standing on it.


>> I've implemented type inference, and it works now as another lookup in
>> comment creation live template, or smart completion in comment type
>> field later. And, as for me, I'm quite happy when no dialogs are
>


Nice! Does resolving also visit foreach/list loops and look at possible types of collection elements?

Not yet. I think a separate JIRA issue would be better, not to forget
about it.

Peter, I suggest to do whatever is less work.
That way you can collect more feedback now about core functionality.
Dialogs can always be added later.

Yes!

0

Please sign in to leave a comment.