IntelliJ Elixir - Elixir plugin for JetBrain's IntelliJ Platform

v4.5.0 was a canary release, so it’s release notes are included in this general release in case you didn’t run the canary

Thanks

  • Thanks to Matt Briggs (@mbriggs) and Andrei Dziahel (@develop7) for reporting the NullPointerException from org.elixir_lang.psi.scope.call_definition_clause.Variants.getLookupElementCollection.
  • Thanks to Sergey Zubtsovskiy (@szubtsovskiy) for reporting StackOverflowErrors from certain forms of with and helping me narrow down specific minimal reproduction cases.
  • Thanks to @mdhirsch for finding a parser bug (!) after all this time: newlines weren’t allowed before do for do blocks.
  • Thanks to Scott Bennett (sbennett33) for finding a case that triggered the ElixirNoParenthesesStrict error handling, which revealed that isVariable didn’t handle it correctly.
  • Thanks to Andrei Dziahel (@develop7) for reporting an error that while I couldn’t reproduce did lead to an improved error reporter, so I can figure it out if it happens again.
  • Thanks to Danni Friedland (BlueHotDog) for reporting a bug that led me to find that Prefix.primaryArguments wasn’t using Normalized and still was using basic asserts.
  • Thanks to Aaron Foster (AnimalRepellentGranules) for reporting that the do end matching was too aggressive and incorrectly matched on one liners starting at the do:.

Changelog

v4.6.0

Enhancements

Bug Fixes

  • #454 - Return emptySet when lookupElementByPsiElement is null. - @KronicDeth
  • #455 - @KronicDeth
    • Don’t do a naked assert that there are 2 children because this can fail during error recovery on the operand, instead use the prefix.Normalized.operand() through prefix.operand().

      WARNING: This changes the @NotNull array so that its sole element changes from @NotNull to @Nullable. It may trigger new bugs.

  • #461 - Use shipped GeneratedParserUtilBase.DUMMY_BLOCK because the DUMMY_BLOCK MUST match the GeneratedParserUtilBase to detect dummy blocks inserted for error handling. - @KronicDeth
  • #465 - Skip over ElixirNoParenthesesStrict for isVariable - @KronicDeth
  • #466 - Allow newlines before do in doBlock - @KronicDeth
  • #467 - Don’t match do or fn to end when used as a keyword key. - @KronicDeth
  • #474 - @KronicDeth
    • Check if iterator.atEnd() before calling iterator.getTokenType() to avoid IndexOutOfBounds exception.
    • Don’t add current call definition clause being written to completion
  • #476 - When#leftOperand will return null (because it’s normalized) if there are left-hand error elements, but when stripping guards we want best-effort to match human expectations, so don’t use normalized null, but use left, non-error element if it is unique. - @KronicDeth
  • #477 - Highlight types in QualifiedNoParenthesesCall - @KronicDeth
  • #478 - Still not obvious why name for a CallDefinitionClause lookup renderer can be longer than presentableText, so still log an error, but with Logger.error, so we get name, presentableText, and the original element. - @KronicDeth
  • #479 - @KronicDeth
    • Skip Arguments elements in previousParentExpresion to eliminate an unnecessary level of processing declarations since calls will enter their arguments.
    • Only put new ENTRANCE in ResolveState in variable.MultiResolve.resolveResultList, so that caller can override the default value.
    • Set ENTRANCE to matchAncestor instead of previous expression to eliminate the looping that occurred when a variable was unbound (or a function) because the check for with (and for) was expecting the ENTRANCE to be the previous child expression instead of the with clause as a whole (or the Arguments element as had been the case before 6fcc19b).
  • #483 - @KronicDeth
    • Resolves functions qualified by Aliases that are either direct Module references or one-step aliases.
    • Remove Call#resolvedFunctionName because import can’t rename functions.
  • #484 - Don’t type-highlight BracketOperations as they occur when putting maps or structs in front of lists. - @KronicDeth
  • #485 - Treat Enum.each the same as Enum.map around def - @KronicDeth
  • #486 - Increase resolvedFinalArity by 1 for piping. - @KronicDeth
  • #498 - @KronicDeth
    • Go To Declaration resolves through import
      • for import MyModule
        • the import statement
        • the call definition clause in the imported Module.
      • for import MyModule, only: [name: arity]
        • the import statement
        • the call definition clause in the imported Module.
      • for import MyModule, except: [name: arity] if reference is not name/arity.
        • the import statement
        • the call definition clause in the imported Module.

v4.5.0

Enhancements

  • #452 - @KronicDeth
    • Go To Declaration for functions and macros (only those defined in parseable-Elixir source. References to Erlang functions or only those available in .beam file, such as the standard library will not resolve.)
    • Completion for functions and macros (only those defined in parseable-Elixir source. Erlang functions and Elixir function only in compiled .beam file, such as the standard library will not complete.)
      • Completion uses the same presentation as Structure View, so the you can tell whether the name is a function/macro, whether it is public/private, and the Module where it is defined.
      • Completed functions/macro insert () after the name in preparation for Elixir 1.4 where it is an error to have bare function calls. It also makes it more obvious that you inserted a function and not a variable.
      • Completion works for all functions when a bare identifier is used. For a qualified identifier, only functions/macros under than Module are shown.

README Changes

Completion

Function and Macro Calls

Completion uses the same presentation as Structure, so you can tell whether the name is function/macro (Time), whether it is public/private (Visibility) and the Module where it is defined. Between the icons and the Modules is the name itself, which is highlighted in bold, the parameters for the call definition follow, so that you can preview the patterns required for the different clauses.

Qualified

Qualified functions and macro calls will complete using those functions and macros defined in the qualifying Module (defmodule), Implementation (defimpl) or Protocol (defprotocol). Completion starts as shown as . is typed after a qualifying Alias.

Unqualified

Function and macro calls that are unqualified are completed from the index of all function and macro definitions, both public and private. (The index contains only those Elixir functions and macro defined in parsable source, such as those in the project or its dependencies. Erlang functions and Elixir functions only in compiled .beam files, such as the standard library will not complete.) Private function and macros are shown, so you can choose them and then make the chosen function or macro public if it is a remote call.

Go To Declaration

Function or Macro

You’ll know if function or macro usage is resolved and Go To Declaration will work if the call is annotated, which in the default themes will show up as italics.

Imported Functions or Macros
  1. Place the cursor over name of the function or macro call.
  2. Activate the Go to Declaration action with one of the following:
    1. Cmd+B
    2. Select Navigate > Declaration from the menu.
    3. Cmd+Click
  3. A Go To Declaration lookup menu will appear, allowing you to jump to either the import that imported the function or macro or jumping directly to the function or macro definition clause. Select which declaration you want.
    1. Use arrow keys to select and hit Enter
    2. Click
Local Functions or Macros
  1. Place the cursor over name of the function or macro call.
  2. Activate the Go to Declaration action with one of the following:
    1. Cmd+B
    2. Select Navigate > Declaration from the menu.
    3. Cmd+Click
  3. Whether a lookup a Go To Declaration lookup menu appears depends on the number of clauses in the function or macro definition:
    1. If there is only one clause in the function or macro definition, you’ll jump immediately to that clause
    2. If there is more than one clause in the function or macro definition, a Go To Declaration lookup menu will appear, allowing you to jump to either the import that imported the function or macro or jumping directly to the function or macro definition clause. Select which declaration you want.
      1. Use arrow keys to select and hit Enter
      2. Click
Remote Functions or Macros
  1. Place the cursor over name of the function or macro call that is qualified by an Alias.
  2. Activate the Go to Declaration action with one of the following:
    1. Cmd+B
    2. Select Navigate > Declaration from the menu.
    3. Cmd+Click
    1. If there is only one clause in the function or macro definition, you’ll jump immediately to that clause
    2. If there is more than one clause in the function or macro definition, a Go To Declaration lookup menu will appear, allowing you to jump to either the import that imported the function or macro or jumping directly to the function or macro definition clause. Select which declaration you want.
      1. Use arrow keys to select and hit Enter
      2. Click

Installation

Inside IDE using JetBrains repository

  1. Preferences
  2. Plugins
  3. Browse Repositories
  4. Select Elixir
  5. Install plugin
  6. Apply
  7. Restart the IDE

Inside IDE using Github releases

In browser

  1. Go to releases.
  2. Download the lastest zip.

In IDE

  1. Preferences
  2. Plugins
  3. Install plugin from disk…
  4. Select the downloaded zip.
  5. Apply
  6. Restart the IDE.
14 Likes