What's New in IntelliJ Elixir 10.2.0

Tags

Pedestrians holding umbrellas in crosswalk

IntelliJ Elixir, the Elixir plugin for JetBrains IDEs (IntelliJ IDEA, RubyMine, WebStorm, etc), version 10.2.0 has been released. Let’s see what’s new.

Umbrella Project Support for Small IDEs

JetBrains separates its IDEs into two categories:

  1. Small IDEs
  2. Rich IDEs

Small IDEs are “small” because they are targeted at a single language.

  • RubyMine - Ruby
  • WebStorm - JavaScript
  • PHPStorm - PHP
  • PyCharm - Python

Small IDE projects are restricted to a single module using the native language for that IDE. When a Small IDE supports other languages, that single module for the native language is still there. The other language has to be tracked as a custom field in the module file or using the Facets system, which JetBrains introduced originally to track webframework configuration, such as Spring in Java.

Because of this single module restriction, I wasn’t able to give RubyMine and the other small IDEs full Elixir umbrella project support like I can in Rich IDEs, such as IntelliJ IDEA Community Edition (CE) and Ultimate Edition (UE). In the Rich IDEs, a Project can contain multiple modules and each one can be in a different Language. There is no restriction that there be a Java Module in IntelliJ IDEA even though it is the Java IDE from JetBrains.

However, there is a mechanism in some of the small IDEs like RubyMine that can mimic a mutli-module Project: RubyMine supports opening multiple Projects at the same time in one window. In 10.2.0, by setting up a DirectoryConfigurator extension in IntelliJ Elixir, when a Small IDE opens a directory, the plugin can scan for mix.exs files in the immediate directory and any subdirectories. If they are found, each directory gets its own Project instead of its own Module as would happen in IntelliJ IDEA.

I still recommend using IntelliJ IDEA CE or UE for umbrella projects because unlike Projects in Small IDEs, modules in one Project can depend on each other and I use this to mirror the in_umbrella: true dependencies in mix.exs to only show navigation and completions for other modules that are declared dependencies, as explained in the What’s New in IntelliJ Elixir 10.0.0.

Ignore mix.exs Under Assets

When you have Phoenix web project, phoenix and phoenix_html symlink themselves into your assets/node_module folder so you can get the Phoenix JavaScript libraries. But these are symlinks to deps/phoenix and deps/phoenix_html, which means that symlink can see deps/phoenix/mix.exs and deps/phoenix_html/mix.exs. Prior to 10.2.0, Import From External Model, Quick Import, and DirectoryConfigurator would treat these mix.exs as belonging to your project and either prompt to import them for Import From External Model or auto-import them for Quick Improt and DirectoryConfigurator (as those are non-interactive).

IntelliJ Elixir 10.1.0 follows `apps/*_web/assets/node_modules/*` symlinks and thinks phoenix and phoenix_html are Mix projects to import instead of dependencies.

In 10.2.0, assets was added to the ignore list, which already included /_build, /config, /deps, and /tests, so that those phoenix and phoenix_html mix.exs files under assets are no longer treated as importable mix projects.

The `assets` directory is now ignored, so `phoenix` and `phoenix_html` are not listed as Mix projects to import.

Expanded Support for Deps Options

When I added automatic External Libraries support in 10.0.0, I wasn’t sure how the community was using deps. In cases like this, I purposely leave error logger statements, so that users will report needed features instead of unsupported features being silently ignored:

when (key) {
    "app", "branch", "commit", "compile", "git", "github", "hex", "only", "optional", "override",  "runtime" -> acc
    "in_umbrella" -> acc.copy(path =  "apps/$name", type = Type.MODULE)
    else -> {
        Logger.error(logger, "Don't know if Mix.Dep option `$key` is important for determining location of dependency", depsListElement)
        acc
    }
}

The Logger.error will appear in the error reporter in JetBrains IDEs, which will appear as a notification in the bottom left of the IDE window and then as a blink red dot that you can click to file a bug report.

IDE Error Occurred notification

Open an issue against https://github.com/KronicDeth/intellij-elixir

Because of error reports like this from the community I was able to find out that :path, :ref, and :tag keys needed support and those have been added in 10.2.0:

:ref and :tag are simple ignores, but when adding support :path, I wanted to include the directory outside of the project root in the library, which required adding extra steps to the auotmatic External Library management, but it does mean that the IDE is now aware of both the ebin and lib directories for :path deps.

— [org.elixir_lang.mix.Dep.from(ElixirTuple)]’]

(https://github.com/KronicDeth/intellij-elixir/blob/124633eeb954130ef8b440295bee2dce41ac6254/src/org/elixir_lang/mix/Dep.kt#L36-L42)

2018.3 Terminal Compatibility

Over the course of the 2018.X release series, the capabilities of TerminalExecutionConsole packaged with JetBrain’s OpenAPI have kept changing. For a few point releases, it echoed characters to the screen, which broke iex support in IntelliJ Elixir, so I was forced to ship a forked version. But that forked version is incompatible with the other libraries shipped in 2018.3, so IntelliJ Elixir 10.2.0 reverts to using the OpenAPI TerminalExecutionConsole. This fixes the weird Error running ‘run_in_iex’: com.intellij.terminal.JBTerminalWidget.createTerminalSession(Lcom/jediterm/terminal/TtyConnector;)Lcom/jediterm/terminal/ui/TerminalSession; errors when using the IEx and Mix IEx run configurations.

The hint that the single line was related to dependency incompatibilities is that the weird (L and ;)L symbols are used in the class loaders for the JVM, so it indicated I was depending on code that could no longer be loaded.

I try to support the widest range of version of JetBrain IDEs, in case users aren’t upgrading because their IT department pushes a managed version to all the dev environments. But sometimes, such as with this bug, I’m forced to support the latest version because Java Reflection won’t let me fake compatibility with older and newer versions at runtime.

Debugger Warnings

With all the work I did to support the debugger in 8.0.0, including compatibility with both Elixir 1.7 and maintaining Elixir 1.6 compatibility, I left some unused variables, so everyone was getting warnings when the debugger launched:

warning: variable "arg" is unused
  /tmp/intellij_elixir/debugger/lib/intellij_elixir/debugger/server.ex:404

warning: variable "counter" is unused
  /tmp/intellij_elixir/debugger/lib/intellij_elixir/debugger/server.ex:505

When debugging, it’s never good to get warnings from your tools when you’re trying to find out why the code you wrote has a bug, so these warnings have now been fixed.

Installation

You can install IntelliJ Elixir v10.2.0 from inside any of the support JetBrains IDEs. I recommend using IntelliJ IDEA (Community or Ultimate) edition if you’re using umbrella projects.

DockYard is a digital product agency offering exceptional user experience, design, full stack engineering, web app development, custom software, Ember, Elixir, and Phoenix services, consulting, and training.