This one may not count as a big new feature, but still – I consider it a nice usability improvement, and our users have told us many times that they like usability improvements. In Demetra, we have merged three tabs of the module configuration UI, “Libraries (Classpath)”, “Order/Export” and “Dependencies”, into a single “Classpath” tab.
The “Add” button shows a popup allowing to choose whether a library or a module dependency should be added.
The lists of global and project libraries can be edited when “Add / Project Library…” or “Add / Global Library…” is clicked, or when “Edit…” is clicked on a project or global library node.
One of the recently implemented features which I’m personally quite happy to see in the product is the possibility to automatically verify @NotNull annotations at runtime.
To give some background, IntelliJ IDEA 5.0 introduced annotations @Nullable and @NotNull which can be used to mark variables, fields, method parameters and return values which may be null (@Nullable) or may never be null (@NotNull). The annotations are clearly useful as documentation (which is quite significant by itself), but the more important thing is that IntelliJ IDEA 5.0 uses them to highlight places where a null pointer exception could occur. If the “Constant conditions and exceptions” inspection is enabled, places where a possibly null value is dereferenced are highlighted as warnings.
Now, this is good but not great. IntelliJ IDEA has a lot of inspections and usually highlights many warnings, and not all of them are promptly resolved. We always wanted to augment the design-time analysis with run-time checks, so that a violation of the @NotNull contract would be clearly reported as soon as it is detected, and not manifest as an NPE several layers deeper in the code. And Demetra provides just that.
If the option “Add @NotNull assertions” is enabled, IDEA instruments the bytecode of compiled classes and adds assertions checking that null values are not passed to @NotNull method parameters, and not returned from methods annotated as @NotNull.
The following screenshot shows a real example of a bug in the InspectionGadgets plugin that we discovered through the @NotNull assertions. (Note that IntelliJ IDEA highlights a possible NPE because the PsiForStatement.getBody() method is annotated as @Nullable.)
The runtime assertions will be of most immediate use to our plugin developers. A significant part of our OpenAPI is annotated with @Nullable and @NotNull, and many plugin programming errors should now be reported much more clearly than before.
(Speaking of plugin developers, today we launched a new plugins page on the IDEA Web site. Hopefully the plugin development information will now be much easier to find.)
Last week we have started the EAP program for IntelliJ IDEA 5.1 (sometimes also called 5.0.3). The main new feature of the version 5.1 is the support for localization (possibility to translate the IntelliJ IDEA user interface into different languages). The EAP builds already contain a mostly complete Japanese localization.
Besides the localization support, it includes a number of new features as well; since most of the team was working on internatialization (i18n) during the development of version 5.1, it shouldn't come as a surprise that most of the new features are also related to i18n. (In fact, working on these features was quite a lot of fun: mostly everyone came up with ideas on improving the i18n support, and took part in implementing them. As a result, we got a much closer collaboration of developers on a small area of code. Some of the new features are literally a patchwork of changes made by different people on the team.)
When you are doing i18n work on a product of IDEA's size, your first goal becomes reducing the number of strings you need to look at from the i18n point of view, as much as possible. The traditional approach of marking every single line containing a string that does not need to be localized with a comment (//non-nls, //noi18n or something like that) was far too inefficient for our project size. Because of this, we came up with the @NonNls annotation for smarter marking of non-localizable items, and greatly extended its applicability in version 5.1. (The complete rules of using @NonNls could probably fill an entire blog post by themselves...)
And the second goal is, of course, reducing the amount of work which needs to be done on every string which does need to be localized. Ideally, all that is needed is a simple Alt-Enter / Enter combination, but IDEA usually can't guess the most meaningful name for a property, so some typing is still required.
I'd like to highlight specifically two of the smarter features that we developed during our i18n work. The first is the "Annotate as @NonNls" quickfix.
The quickfix automatically looks at all the places where a @NonNls annotation can be added to remove the error, and allows to insert it with one click. In this example, you can annotate the parameter of the findFileByRelativePath method (if the string passed to this parameter is never something which needs to be translated), or annotate the homeDirectory variable (if the methods called on it can never accept something which needs to be translated). In this case, it's best to annotate the method parameter because the annotation will cover all other cases when a hard-coded string is passed to the method.
The second is the "I18nize concatenation" quickfix. Here's an example of the code before the quickfix:
And here's the same code after the quickfix, showing also the property created by the quickfix:
Notice how the constant part of the string got moved to a property, placeholders were automatically inserted for the variable parts, and even the apostrophes were correctly escaped according to the format string syntax.
Of course, the code template used by the quickfix is configurable, so if you use non-standard methods to load property strings or perform the formatting (as we do), you can configure it for your needs as well.
Smart, isn't it?
I'll start my description of IntelliJ IDEA 6.0 features with a small UI feature added to facilitate project navigation: the Navigation Bar.
The Navigation Bar is a breadcrumb-like bar which can optionally be displayed above the editor window, and which shows the module and packages in which the currently edited file is contained. For every item in the bar, you can invoke the context menu, or you can show a drop-down list containing all classes and packages in the same level as the selected item. Double-clicking an item in the Navigation Bar selects it in the Project View. The Navigation Bar fully supports keyboard navigation: Left/Right keys move between levels, and Up/Down move between items on the same level.
The main motivation for this feature was to reduce the necessity of using Project View, which takes quite a lot of screen space. We have found out that in most cases we access the project view not to browse, but rather to invoke some action (Find in Path, Inspect Code and so on) on one of the packages containing the currently open file. The Navigation Bar provides a much quicker access to such actions, and allows the left sidebar to be occupied by a different tool window (for example, Favorites or Structure View).
A lot has changed since the last time I updated this blog. I am no longer the project lead for Omea. This summer I joined the IntelliJ IDEA team as a developer. Initially one of my main areas of responsibility was the OpenAPI documentation and support for plugin developers; most of my documentation work has been included in the IntelliJ IDEA 5.0.2 release. Recently I've started working on a new big task: updating and improving the IDEA UI designer.
The main push for me to resume blogging was the publication of the roadmap for IntelliJ IDEA 6.0, codenamed "Demetra". The work on Demetra started not so long ago, but a number of features announced in the roadmap (and some others not mentioned there) have already been implemented. In this blog, I'll describe and show the new cool features of Demetra right as they are being implemented.
(Of course, as Demetra is still far from release, so the details of the user interface and implementation of the features described here may change a lot before the final release, and some features may even get dropped. So please don't treat this blog as final product documentation. :-) )