IntelliJ Elixir - Elixir plugin for JetBrain's IntelliJ Platform

With both the contribution of ExUnit Mix Tasks in 4.7.0 and the conversion of the build to Gradle for 5.0.0, I’ve added Jake Becker (@JakeBecker) as a Collaborator to the repo.

Thanks

  • Reporting the AssertionError in org.elixir_lang.code_insight.lookup.element_renderer.CallDefinitionClause.renderElement
  • Reporting examples where ElixirVariable could not be determined if it was a variable.
  • Reporting examples where ElixirMultipleAliases could not resolve variable in match.
  • Reporting examples of the annotator highlighting in the wrong file due to the call definition offset always being assumed to be in the same file.
  • Reporting Parameter variable style being incorrectly applied
  • Working with me to figure out that the template tags in the color preview were messed up
  • Reporting mismatch between inspection resource and class due to a copy-and-paste error
    • Markus Fischer (@mfn)
  • Reporting incorrect highlighting of functions with guards
  • Requesting configurable code-folding for module attributes
  • Pointing out it makes no sense for context menus for ExUnit to appear in non-Elixir projects
  • Reporting an example where MatchedUnqualifiedParenthesesCall could not be type highlighted
  • Reporting that function complete didn’t take into account the already typed prefix
  • Requesting completion of Aliases to .beam-only Module, which is what inspired me to attempt decompilation

Changelog

v5.0.0

Enhancements

  • #574 - @KronicDeth
    • Decompile .beam files
      • Structure view for decompiled .beam files
      • Index modules, functions, and macros exported by .beam files
      • Go To Symbol for Modules defined in .beam files (both SDK and deps)
        • Erlang using atoms (like :idna)
        • Elixir using Alias (like Enum)
      • Completion for Modules defined in .beam files (both SDK and deps)
        • Elixir using Alias (like Enum)
      • Completion for functions and macros exported by .beam files
      • Syntax highlighting
  • #579 - Regression test for #575 - @KronicDeth
  • #583 - @KronicDeth
    • Macros appear before functions in decompiled .beam files
      • Header for macro and function sections
  • #585 - @KronicDeth
    • Update ELIXIR_VERSION for 1.2.* from 1.2.3 to 1.2.6
    • Add ELIXIR_VERSION 1.3.4
    • Add ELIXIR_VERSION 1.4.0
    • Update IDEA for 2016.* to 2016.3.1
    • Show OtpErlangBitStr (and therefore OtpErlangBinary contents when tests fail
    • Quote binaries as to_charlist instead of to_char_list for Elixir >= 1.3. Depends on Elixir version of project SDK.
    • Use elixir instead of java VM, so now Erlang and Elixir don’t need to be built on travis-ci, but ant and the jdk need to be installed, but unlike Erlang and Elixir, there are tarballs for that, so this way is faster than the old method without depending on travis-ci cache.
  • #609 - @KronicDeth
    • If multiResolve causes a StackOverflow for org.elixir_lang.annotator.Callable.visitCall, then catch it and use errorreport logger to log the element.
    • Include file path in errorreport excerpt
    • Log element for StackOverflow related to imports
    • Regression test for #605.
    • Log LookupElement#getObject when LookupElement#getPsiElement is null to track down how it was null in #563.
  • #614 - Regression test for #559 - @KronicDeth
  • #504 - @JakeBecker
    • Switch to Gradle for builds.
      • ./gradlew runIde (or the runIde (VERSION) Run Configurations) will run IDEA in a sandbox with the development version of the plugin.
      • ./gradlew test (or the test (VERSION) Run Configurations) will run the main plugin and jps-builder tests.
      • The plugin can now be published with ./gradlew publishPlugin, BUT you’ll need to fill in publish* properties in gradle.properties. This will eventually allow for automated “nightlies” from successful Travis-CI builds on master.
  • #638 - The Callable annotator is meant for variables, parameters, and macro and function calls and declarations. The ModuleAttribute annotator handles module attribute declaration and usage, so we can save reference resolution time by skipping module attributes in Callable. - @KronicDeth
  • #640 - Allow module attribute folding to be configured. - @KronicDeth
  • #662 - @KronicDeth
    • Allow call definition heads to resolves to themselves for consistency with Aliases of defmodule.
    • Generalize Callable.callDefinitionClauseDefiner(Call): in addition to the current CallDefinitionClause, make it work for Implementation, Module, and Protocol.

Bug Fixes

  • #574 - Fix copy-paste errors in MatchOperatorInsteadOfTypeOperator - @KronicDeth
  • #579 - @KronicDeth
    • Subtract 1 from arity in .beam file when decompiling to defmacro calls because the Erlang function for Elixir macros has one addition argument: the first argument is the Caller of the macro.
    • If the name of the decompiled macro/function is an infix operator, then decompile the head as a binary operation instead of a normal prefix name as infix operators aren’t valid prefix names and led to parsing errors, which was the root cause of #575.
    • Fix IntelliJ warnings in BeamFileImpl
    • Remove unused VirtualFile argument to BeamFileImpl#buildFileStub.
  • #583 - @KronicDeth
    • Add ++, =~, and in to INFIX_OPERATOR_SET.
    • Only render infix operators if arity is 2.
    • Prefix operator decompilation: + and - are both binary and unary operators. When a unary operator they need to be wrapped in parentheses, so that the call definition clause is parsed correctly.
  • #585 - @KronicDeth
    • Ignore JFLex jar
    • Don’t check for elixir-lang/elixr files remove in 1.3
    • Allow nil as a keyword key. nil was being lexed as a potential keyword key, but NIL was missing from the token list in the keywordKey grammar rule.
  • #599 - Some SpecialForms don’t work as literals as they would be interpreted as metaprogramming, so their name needs to be wrapped as an atom to unquote. - @KronicDeth
  • #600 - @KronicDeth
    • Check children of MultipleAliases for variable declarations.
    • Treat any variable declared in a MultipleAliases as invalid.
  • #609 - @KronicDeth
    • Skip import Kernel in kernel.ex to prevent stack overflow due to recursive import
    • Strip all outer parentheses for left type operand, so that (+value) can be see as + operator type spec.
    • Use advice from IndexNotReadyException documentation and check DumbService.isDumb(Project) before calling StubIndex.getElements in Module and module.MultiResolve.indexNameElements.
    • Don’t assert that LookupElement#getPsiElement is not null in CallDefinitionCluase.renderElement
    • Update to ant 1.10.1 because 1.10.0 is no longer hosted.
  • #612 - Yeah, it sounds weird, but an ElixirVariable isn’t necessarily a variable if it doesn’t occur in a declaration context. It could just be a no-parentheses function call in the wrong spot, so check the parent PsiElement to determine if ElixirVariable is a variable. - @KronicDeth
  • #614 - Highlight parameterized type head (maybe(t) in @type maybe(t)) the same as a full type definition (maybe(t) in @type maybe(t) :: t | nil) - @KronicDeth
  • #616 - Only show Mix ExUnit Run in context when the module, or when the module is not a available, the project SDK is Elixir. If there is no SDK configured, show “Mix ExUnit Run” in the menu. - @KronicDeth
  • #617 - Mark do: as atom in demo text - @KronicDeth
  • #627 - Annotations can only be applied to the single, active file, which belongs to the referrer Callable. The resolved may be outside the file if it is a cross-file function or macro usage, in which case it’s TextRange should not be highlighted because it is referring to offsets in a different file. - @KronicDeth
  • #634 - @KronicDeth
    • Variable scope for QualifiedMultipleAliases, which occurs when qualified call occurs over a line with assignment to a tuple, such as Qualifier.\n{:ok, value} = call()
    • Remove call definition clauses (function or macro) completion for bare words as it had a detrimental impact on typing feedback (the editor still took input, but it wasn’t rendered until the completion returned OR ESC was hit to cancel the completion, which became excessive once the index of call definition clauses was expanded by the decompilation of the Elixir standard library .beams, so disable it. If bare-words completion is restored. It will either (1) need to not use the Reference#getVariants() API because it generates too many objects that need to be thrown away or (2) need to only complete call definition clauses that are provably in-scope from imports or other macros.
  • #636 - @KronicDeth
    • Both intellij-erlang and intellij-community are Apache 2.0 licensed and its the default license for Elixir projects, so seems like a good choice for LICENSE.md
    • Add CODE_OF_CONDUCT.md
  • #638 - @KronicDeth
    • The run configurations I put together in #504 didn’t allow for the debugger to work properly: neither pause nor breakpoints had any effect, so regenerate them from the Gradle pane.
    • Check parent of when operation in case it’s a guarded function head in org.elixir_lang.annonator.Parameter.putParameterized(Parameter, PsiElement)
    • Instead of highlighting call definition clauses when they are referred to, which only works if it is in the same file, highlight all function and macro declarations when the def* call is encountered.
    • Only increment arity for right pipe operand instead of all operands, so that left operands resolve to correct arity or as variable/parameter.
  • #662 - @KronicDeth
    • Override ModuleImpl#getProject() to prevent StackOverflowError. Without overriding #getProject(), IdentifierHighlighterPass gets stuck in a loop between getManager and getProject on the target (the ModuleImpl) when clicking on the space between defs or defmacros in the decompiled .beam files.
    • Fix source formatting
    • Skip looking for variables unless 0-arity AND no arguments
    • Highlight unresolved macros as macro calls. Anything with a do keyword or a do block will be treated like a macro call even if it can’t be resolved. No resolved is either no resolve results or an empty list
    • Implicit imports at top of file in addition to top of Module.
  • #663 - @KronicDeth
    • CallDefinitionClause completion provider is unexpectedly invoked both when . is typed, but continues to be invoked after a letter is typed after the .; however, once the letter is typed, the letter becomes the default prefix instead, so the prefix should only be reset to "" when it ends in ..
    • Disable Callable#getVariants unless Unqualified to prevents local functions and macros being shown as completions for qualified names.
  • #651 - @StabbyMcDuck
    • Among many other tweaks, the String color is now green, so that Atom and String are no longer close to one another, which was the original issue in #569
      • Alias now has underscored effect
      • Brackets are now greenish instead of brownish
      • Callbacks are now a lighter blue and has underscored effect
      • CharList is little lighter
      • CharToken is dark yellow now instead of dark purple
      • Dot is now purple instead of dark red
      • Expression Substitution Mark is a little lighter
      • Interpolation is now lime green
      • Kernel Macros are a burnt orange
      • Map is now a dark blue instead of a dark yellow
      • Operation Sign is a little lighter
      • Parameters are a little darker
      • Parentheses are redder
      • Predefined is orange instead of blue
      • Specification is now red instead of purple
      • Struct is now purple instead of yellow
      • Type is now green instead of dark purple
      • Variable is more tealish
  • #650 - @StabbyMcDuck
    • Fix indentation to fix sub-lists in CONTRIBUTING.md
    • Fix pluralization in CONTRIBUTING.md
  • #664 - @KronicDeth
    • Check if resolve results are null for For.resolveResultList
    • Check if Protocol.resolveResultList is null
  • #665 - Check match Call is an UnqualifiedNoArgumentCall, in addition to being 0 resolved final arity, before checking if the name matches. - @KronicDeth

Incompatible Changes

  • #585 - Move ^^^ to its own three-operator precedence level to match 1.2. This does mean the parsing will be wrong for Elixir 1.1, but is simpler than maintaining two grammars for those that are still using Elixir 1.1 - @KronicDeth
  • #504 - The ant build files have been removed. To build the build plugin (for Install From Disk), use the ./gradlew buildPlugin. - @JakeBecker
  • #640 - Change to module attribute folding to off by default. - @KronicDeth

README Updates

Decompilation

.beam files, such as those in the Elixir SDK and in your project’s build directory will be decompiled to equivalent def and defmacro calls. The bodies will not be decompiled, only the call definition head and placeholder parameters. These decompiled call definition heads are enough to allow Go To Declaration, the Structure pane, and Completion to work with the decompiled .beam files.

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.
12 Likes

Oh that is cool, I usually just do that manually by using the raw erlang calls, I may have to take a look at this now, though eclipse uses up so much memory that it is hard to run here… ^.^;

Thank you and all of the contributors for their hard work! I had switched to VS Code, but I like WebStorm more for JS. I’m hoping this update brings me back to WS.

Thanks

  • For reporting when scope.isEquivalentTo(lastParent.getParent()) is false in processDeclarationsInPreviousSibling

Changelog

v5.1.0

Enhancements

Bug Fixes

  • #669 - Replace assert scope.isEquivalentTo(lastParent.getParent()) with an if and log what lastParent was when condition is false, so root cause can be traced. - @KronicDeth

README Updates

Debugger

IntelliJ Elixir allows for graphical debugging of *.ex files using line breakpoints.

Line breakpoints for debugger can be set in gutter of editor tab.
Line breakpoints can added by clicking in the left-hand gutter of an editor tab. A red dot will appear marking the breakpoint. When a Run Configuration is Run with the Debug (bug) instead of Run (arrow) button, execution will stop at the breakpoint and you can view the local variables (with Erlang names) and the stackframes.

Steps

  1. Define a run/debug configuration
  2. Create breakpoints in the *.ex files
  3. Launch a debugging session
  4. During the debugger session, step through the breakpoints, examine suspended program, and explore frames.

Basics

After you have configured a run configuration for your project, you can launch it in debug mode by pressing Ctrl+D.

Keyboard Shortcuts
Action Keyword Shortcut
Toggle Breakpoint Cmd+F8
Resume Program Alt+Cmd+R
Step Over F8
Step Into F7
View breakpoint details/all breakpoints Shift+Cmd+F8

Breakpoints

When a breakpoint is set, the editor displays a breakpoint icon in the gutter area to the left of the affected source code. A breakpoint icon denotes status of a breakpoint, and provides useful information about its type, location, and action.

The icons serve as convenient shortcuts for managing breakpoints. Clicking an icon removes the breakpoint. Successive use of Alt - click on an icon toggles its state between enabled and disabled. The settings of a breakpoint are shown in a tooltip when a mouse pointer hovers over a breakpoint icon in the gutter area of the editor.

Status Icon Description
Enabled Red dot Indicates the debugger will stop at this line when the breakpoint is hit.
Disabled Red dot with green dot in center Indicates that nothing happens when the breakpoint is hit.
Conditionally Disabled Red dot with green dot in top-left corner This state is assigned to breakpoints when they depend on another breakpoint to be activated.

When the button Red dot surrounded by crossed-out circle is pressed in the toolbar of the Debug tool window, all the breakpoints in a project are muted, and their icons become grey: Grey dot.

Accessing Breakpoint Properties
Viewing all breakpoints

To view the list of all breakpoints and their properties, do one of the following:

  • Run > View Breakpoints
  • Shift+Cmd+F8
  • Click the Two red dots layered vertically on top of each other with smaller grey rings to right of the red dots
  • Breakpoints are visible in the Favorites tool window.
Viewing a single breakpoint

To view properties of a single breakpoint

Configuring Breakpoints

To configure actions, suspend policy and dependencies of a breakpoint

  1. Open the Breakpoint Properties
    • Right-click a breakpoint in the left gutter, then click the More link or press Shift+Cmd+F8
    • Open the Breakpoints dialog box and select the breakpoint from the list
    • In the Favorites tool window, select the desired breakpoint, and click the pencil icon.
  2. Define the actions to be performed by IntelliJ IDEA on hitting breakpoint:
    • To notify about the reaching of a breakpoint with a text message in the debugging console, check the “Log message to console” check box. A message of the format *DBG* 'Elixir.IntellijElixir.DebugServer' got cast {breakpoint_reached, PID} will appear in the console.
    • To set a breakpoint the current one depends on, select it from the “Disabled until selected breakpoint hit” drop-down list. Once dependency has been set, the current breakpoint is disabled until selected one is hit.
      • Choose the “Disable again” radio button to disable the current breakpoint after selected breakpoint was hit.
      • Choose the “Leave enabled” radio button to keep the current breakpoint enabled after selected breakpoint was hit.
    • Enable suspending an application upon reaching a breakpoint by checking the “Suspend” check box.
Creating Line Breakpoints

A line breakpoint is a breakpoint assigned to a specific line in the source code.

Line breakpoints can be set on executable lines. Comments, declarations and empty lines are not valid locations for the line breakpoints.

  1. Place the caret on the desired line of the source code.
  2. Do one of the following:
    • Click the left gutter area at a line where you want to toggle a breakpoint
    • Run > Toggle Line Breakpoint
    • Cmd+F8
Describing Line Breakpoints
  1. Open the Breakpoints dialog
  2. Right-click the breakpoint you want to describe
  3. Select “Edit description” from the context menu
  4. In the “Edit Description” dialog box, type the desired description.
Searching for Line Breakpoints
  1. Open the Breakpoints dialog
  2. Start typing the description of the desired breakpoint
Jump to Breakpoint Source
  • To view the selected breakpoint without closing the dialog box, use the preview pane.
  • To open the file with the selected breakpoint for editing, double-click the desired breakpoint.
  • To close Breakpoints dialog, press Cmd+Down. The caret will be placed at the line marked with the breakpoint in question.
Disabling Line Breakpoints

When you temporarily disable or enable a breakpoint, its icon changes from to and vice versa.

  1. Place the caret at the desired line with a breakpoint.
  2. Do one of the following:
    • Run > Toggle Breakpoint Enable
    • Right-click the desired breakpoint icon, select or deselect the enabled check box, and then click Done.
    • Alt-click the breakpoint icon
Deleting Line Breakpoints

Do one of he following:

  • In the Breakpoints dialog box, select the desired line breakpoint, and click the red minus sign.
  • In the editor, locate the line with the line breakpoint to be deleted, and click its icon in the left gutter.
  • Place caret on the desired line and press Cmd+F8.

Starting the Debugger Session

  1. Select the run/debug configuration to execute
  2. Do one of the following
    • Click Bug on the toolbar
    • Run > Debug
    • Ctrl+D

OR

Debug quick menu

  1. Ctrl+Alt+D
  2. Select the configuration from the pop-up menu
  3. Hit Enter

Examining Suspended Program

Processes

The "Thread" drop-down lists the current processes in the local node. Only the current process is suspended. The rest of the processes are still running.
Frames

The Frames for the current process can be navigated up and down using the arrow keys or clicking on the frame.
  • Press Up or Down to change frames
  • Click the frame from the list
Jump to Current Execution Point

When changing frames or jumping to definitions, you can lose track of where the debugger is paused. To get back to the current execution point, do one of the following:

  1. Run > Show Execution Point.
  2. Alt+F10
  3. Click on the stepping toolbar of the Debug tool window.
Variables

While Elixir allows rebinding variable names, Erlang does not, so when viewed in the Variables pane, variables will have an @VERSION after their name indicating which rebinding of a the variable is. Even if there is no variable reuse, the first variable will still have @1 in its name.

Stepping

Action Icon Shortcut Description
Show Execution Point Alt+F10 Click this button to highlight the current execution point in the editor and show the corresponding stack frame in the Frames pane.
Step Over F8 Click this button to execute the program until the next line in the current function or file, skipping the function referenced at the current execution point (if any). If the current line is the last one in the function, execution steps to the line executed right after this function.
Step Into F7 Click this button to have the debugger step into the function called at the current execution point.
Step Out Shift+F8 Click this button to have the debugger step out of the current function, to the line executed right after it.

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.

Donations

If you would like to make a donation you can use Paypal:

Donate

If you’d like to use a different donation mechanism (such as Patreon), please open an issue.

11 Likes

Great stuff! Almost feels like I need to try IntelliJ soon… :sunglasses:

1 Like

Likewise, this is shaping up and developing fast!

great enhancements!

this makes it really easier to develop in elixir.

Thanks

  • For reporting SmartHashSet null errors
  • For building their own test versions of 6.0.0 and reporting pre-release bugs
  • For reporting Kernel.SpecialForms colors were wrong after merging the Kernel and Callable annotator
  • For reporting wrong indentation inside of stab (do block body)
  • Decompilation not working for OTP 20 beams using AtU8 instead of Atom chunk
  • Indexing problems with 6.0.0
  • For needling me into testing NixOS
  • Reporting me bundling intellij-erlang’s templates because it was a hard-dependency instead of optional
  • For explaining how to make intellij-erlang a soft-dependency correctly
  • For reporting error inserting completion at end of file
  • For reporting UnmatchedAtUnqualifiedBracketOperation could not be checked to be a parameter
  • For both reporting the debugger crashes and designing how to blacklist bad modules
  • For reporting trailing spaces not being stripped before the formatter was implemented
  • For reporting the dependency on JUnit code in non-test code
  • For reporting "" being sent when ExUnit run configuration had no parameters
  • Chad Woolley (@thewoolleyman)
  • For reporting Absinthe parsing error
  • For reporting ElixirMatchedUnqualifiedNoParenthesesCallImpl parameter name set could not be determined
  • For reporting ModuleAttribute.typeTypeParameterNameSet should assume Aliases are incorrectly capitalized parameter names
  • For reporting the poor choice of background color for sigil in the Default Theme
  • For reporting incorrect highlighting of defmodule
  • For reporting problems decompiling CORBA modules from Erlang
  • For reporting debugger errors
  • For reporting that "'" was being parsed as a heredoc promoter instead of a single quote inside double quotes
  • Decompilation errors with rebar3_hex_config.beam
  • For reporting unhelpful decompilation error messages
  • For a full example to produce an ElixirVariable to trigger isVariable bug
  • For reporting the mix deps.get can hang prompting for if the user wants to mix local.hex --force
  • For reporting mix path quoting problems on Windows
  • For reporting the poor feedback when the bin is selected as the SDK home instead of the parent of bin and lib
  • For reporting double quote balancing issues
  • For reporting that link to file goes to wrong file when multiple files share same filenames
  • For reporting compilations errors do not mark entire test run as failed
  • For reporting inconsistent coloring of defs
  • For asking for Nix/NixOS support

Changelog

v6.0.0

Enhancements

  • #724 - @KronicDeth
    • Code Formatter
      • do block lines are indented
      • do blocks end as the last argument of a no parentheses call unindents to the start of the call
      • If one clause of a multi-clause anonymous function wraps, all clauses wrap.
      • Indent after else
      • Indent map and struct keys
      • All keys wrap if any key wraps
      • No spaces around…
        • .
      • Spaces around…
        • and
        • in
        • or
        • when
      • Configure spaces around…
        • =
        • <- and \\
        • !=, ==, =~, !==, and ===
        • <, <=, >=, and >
        • + and -
        • * and /
        • Unary +, -, !, ^, and ~~~
        • ->
        • ::
        • |
        • || and |||
        • && and &&&
        • <~, |>, ~>, <<<, <<~, <|>, <~>, >>>, and ~>>
        • ..
        • ^^^
        • ++, --, .., <>
        • =>
      • Configure spaces before…
        • ,
      • No space after…
        • @
      • Spaces after…
        • not
        • fn
        • after
        • catch
        • rescue
        • key:
      • Configure space after…
        • &
        • ,
      • Configure spaces within…
        • { }
        • << >>
        • [ ]
        • ( )
      • No space around / in &NAME/ARITY and &QUALIFIER.NAME/ARITY
      • when wraps when its right operand wraps, so that guards start with when on a newline when they are too long.
      • Align |> at start of indented line for pipelines
      • Align end with start of call instead of start of line for do blocks in pipelines
      • Indent list elements when wrapped
      • Indent tuple elements when wrapped
      • Align type definition to right of ::
      • Align guard to right of when when guards span multiple lines
      • Align two operator (++, --, .., <>) operands, so that <> binaries are multiple lines align their starts instead of using continuation indent and being indented relative to first operand.
      • Align pipe | operands, so that alternates in types and specs are aligned instead of continuation indented relative to the first operand.
      • Comments in spec (that is above operands to | align with the operands
      • Remove newlines from pipelines, so that all pipelines start with an initial value or call and each |> is the start of a successive line.
      • Key exclusivity: if an association operation or keyword key is already on a line, the container value automatically has it’s elements wrapped if there is nested associations or keyword pairs, so that two levels of keys are not on the same line.
      • Indent bit string (<< >>) elements when wrapped
  • #732 - @KronicDeth
    • Update IntelliJ IDEA version to latest in each MINOR version:
      • 2017.1.12017.1.5
      • 2016.3.52016.3.7
    • Update Elixir version 1.4.21.4.5
  • #738 - @KronicDeth
    • TeamCityExUnitFormatting.put_event
    • Always match on %__MODULE__{} for state in clauses to prevent state update errors
    • Match on :suite_finished and :suite_started events, so that only events added to the interface will be unknown and IO.warn can be used tell anyone spotting the new event to file an issue.
  • #741 - Instead of pinning position (1 for lines or 3 for heredocs), pin *_PROMOTER token, so it’s more obvious the pattern is that the promoter is pinned. - @KronicDeth
  • #747 - Regression test for #659 - @KronicDeth
  • #629 - Search for Elixir SDKs in /nix/store on Mac if homebrew path does not exist - @KronicDeth
  • #751 - @KronicDeth
    • Regression test for #683
    • Store expected decompilation in files to shrink DecompilerTest length
  • #754 - Update to org.jetbrains.intellij 0.2.15 - @KronicDeth
  • #760 - Use Elixir.LDAPEx.ELDAPv3.beam as regression test for #703 - @KronicDeth
  • #764 - Show quotes in list in macros in Structure View - @KronicDeth
  • #768 - References will be cached until the file containing the PSI element changes, so that results from Callable#multiResolve, CallDefinitionClause#multiResolve, Module#multiResolve, and ModuleAttribute#multiResolve, which are all the extant references, can be cached and invalidated correctly. - @KronicDeth
  • #769 - Use ParameterLists to support Path Variables in program parameters. - @KronicDeth
  • #774 - @KronicDeth
    • Adjust SDK home path when bin, lib, or src to parent directory.
    • Format ElixirSdkType.
  • #775 - Regression test for #354 - @KronicDeth
  • #777 - @KronicDeth
    • Include specific message for each decompilation error reason.

    • Regression test for #772

    • AtU8 UTF8 atoms chunk decompilation to support OTP 20 compiled .beam files.

    • Regression test for Elixir 1.5.0 announcement to ensure that unicode from AtU8 chunk can be read from beam file produced by following Elixir code:
      ```elixir
      defmodule AtU8Test do
      def こんにちは世界 do
      :こんにちは世界

           saudação = "Bom dia!"
      
          saudação
        end
      end
      ```
      
  • #771 - Guard against read/write mismatch in stubs - @KronicDeth
  • #782 - Always install IdeaVIM in the gradle sandbox because it got annoying having to reinstall it when the sandbox reset. - @KronicDeth
  • #786 - @KronicDeth
    • Merge both homebrew and nix store on Mac
    • Merge default and nix store on Linux
  • #789 - Format MixRunningStateUtil and fix warnings. - @KronicDeth

Bug Fixes

  • #726 - @KronicDeth
    • Treat :: the same as : in key: after when in type specifications as it’s a realistic error.
    • Change . to # when referring to constants in javadocs
    • Remove @param without descriptions
    • Remove explicit type from generics when the type can be inferred.
    • Check if atNonNumericOperation reference is non-null before resolving
    • Swap empty branches to inverted conditions for final else.
    • Check if Type leftOperand is null before using it.
    • Remove empty highlightTypesAndTypeParameterUsages(When...)
    • Remove unused highlightTypesAndSpecificationTypeParameterDeclarations
    • Flip equals to eliminate need for null check
    • Remove redundant type arguments (<...>)
    • Change Collections.EMPTY_SET to Collections.emptySet() to prevent uncheck cast warnings.
    • Inline constant argument for errors.
    • Check if when rightOperand is non-null before scanning it for parameter names.
    • Fix typos
  • #732 - @KronicDeth
    • When compilation error is detected during mix test, it will be turned into a test failure.
      • Compilation errors are any stacktraces to stderr that end in (elixir) lib/kernel/parallel_require.ex:.
      • The test failure for the compilation will be attributed to either mix test or the inferred module name of test file.
        • If the first line of the stacktrace contains test/.*_test.exs:\d+: \(module\)
          • The file and line from that line will be used as the location of failure
          • The test/ and .exs will be stripped from the file and it will be camelized to produce the derived test module name of the failure
        • Otherwise, mix test is used
    • Rearrange doc test names to emphasize the function being tested: "test doc at MODULE.FUNCTION/ARITY (COUNT)" becomes "MODULE.FUNCTION/ARITY doc (COUNT)"
      • If MODULE is the same as the test case without the Test suffix, then MODULE. is stripped too and the test name becomes only FUNCTION/ARITY doc (COUNT)
    • Fix parallel test cases nesting under each other due to asynchronous reporting from formatter. ##teamCity testSuiteStarted messages automatically nest, so switched to using nodeId and parentNodeId system, so that nesting is explicit. This will allow multiple parallel tests to show up in GUI too.
    • Elixir. prefix is stripped from test case names.
  • #728 - Handle Elixir versions with non-numeric parts - @pazustep
  • #734 - Use a separate formatter, one GenEvent-based and one GenServer-based, depending on whether the SDK is >= 1.4.0 as that’s when GenEvent was deprecated and GenServer was preferred. - @KronicDeth
  • #736 - @KronicDeth
    • Merge Callable and Kernel annotators
    • Use PsiElementVisitor instead of PsiRecursiveElementVisitor, so that macros in defmodule block don’t get double annotated.
    • Instead of erasing and then applying multiple TextAttributeKey, erase as before, but then merge the TextAttributeKey’s TextAttributes and apply as single setEnforcedTextAttributes. For some reason, this fixes the inconsistency of whether PREDEFINED_CALL or MACRO_CALL is applied first.
    • In case of multiple resolveds, make those that need PREDEFINED_CALL to win.
  • #738 - @KronicDeth
    • TeamCityExUnitFormatting.new should return struct only because none of the formatters expects an :ok tuple.
    • Fix order of TeamCityExUnitFormatting.put_Event catchall parameters.
    • FileReferenceFilter
      • Add .exs to pattern for stacktrace linking.
      • Highlight only stacktrace path and line umber instead of entire line
      • Better path match in stacktraces
        • Only accept VirtualFile if it has a suffix matching the stacktrace’s path instead of accepting the first index file with a matching basename.
        • Allow multiple VirtualFiles to be linked if it turns out there is a true file path collision between two OTP apps in the Project or Libraries.
      • Format and fix warnings
  • #741 - @KronicDeth
    • Pin promoter for all quotes, including the previously missing stringLine and charListLine.
    • Only insert closing quote if previous token was an opening quote.
  • #742 - @KronicDeth
    • On unquote, include argument in name of call definition clause
    • Look outside tuple containing quote for enclosingMacroCall, which allows going to Phoenix.Template.compile’s quote’s defp
    • Treat Module.create as `Modular
    • Or interface to unify Matched and Unmatched Ors.
    • Look at both side of Or operation for nested child calls for Structure view.
    • Make unquote(ARG1) name for getName and indexing
  • #744 - @KronicDeth
    • ElementDescription for ElixirVariable
    • Mark UnqualifiedParenthesesCalls as call instead of variable.
  • #745 - @KronicDeth
    • mix local.hex --force before mix deps.get during project import to prevent prompt for hex update when local hex is earlier than that required by mix.
    • Fix warnings and format MixProjectRootStep
  • #746 - @KronicDeth
    • Mark ElixirDecimalFloat as error in types.
      • If in a Range: “Floats aren’t allowed in Ranges”
      • Otherwise: “Float literals are not allowed in types. Use float() instead”.
  • #747 - @KronicDeth
    • Ignore jps-*/out directories.
    • Look at parent for isParameter for AtUnqualifiedBracketOperation.
    • Treat AtUnqualifiedBracketOperation the same as UnqualifiedBracketOperation for isVariable.
  • #748 - Include path in error messages from buildFileStub - @KronicDeth
  • #749 - Erlang allows do as a function name, but it’s a keyword in Elixir, so wrap it as unquote(:do). The SpecialForm decompiler already did this unquote(...) wrapping, but do is a keyword and not a special form, so rename the decompiler to Unquoted. - @KronicDeth
  • #750 - @KronicDeth
    • Move {3} inside | for SIGIL PROMOTER and TERMINATOR:

      SIGIL_HEREDOC_PROMOTER = ({SIGIL_DOUBLE_QUOTES_PROMOTER}|>
      {SIGIL_SINGLE_QUOTES_PROMOTER}){3}
      SIGIL_HEREDOC_TERMINATOR = ({SIGIL_DOUBLE_QUOTES_TERMINATOR}|>
      {SIGIL_SINGLE_QUOTES_TERMINATOR}){3}
      

      intellij-elixir/src/org/elixir_lang/Elixir.flex at v5.1.0 · KronicDeth/intellij-elixir · GitHub

      The | is inside group that is then {3}'d, so it allows either ' or " in groups of three. This is only applies to the sigils. It’s correct for normal string and charlist heredocs:

      CHAR_LIST_HEREDOC_PROMOTER = {CHAR_LIST_PROMOTER}{3}
      CHAR_LIST_HEREDOC_TERMINATOR = {CHAR_LIST_TERMINATOR}{3}
      
      STRING_HEREDOC_PROMOTER = {STRING_PROMOTER}{3}
      STRING_HEREDOC_TERMINATOR = {STRING_TERMINATOR}{3}
      
      QUOTE_HEREDOC_PROMOTER = {CHAR_LIST_HEREDOC_PROMOTER} | {STRING_HEREDOC_PROMOTER}
      QUOTE_HEREDOC_TERMINATOR = {CHAR_LIST_HEREDOC_TERMINATOR} | {STRING_HEREDOC_TERMINATOR}
      

      intellij-elixir/src/org/elixir_lang/Elixir.flex at v5.1.0 · KronicDeth/intellij-elixir · GitHub

  • #751 - Unquote function names that start with an uppercase codepoint, so that they aren’t parsed as Aliases. These function names occur in the CORBA modules in OTP. - @KronicDeth
  • #754 - @KronicDeth
    • Using intellij.plugins will prevent packaging intellij-erlang as a runtime dependency, which leads to duplicate templates.
    • Don’t use the JPS type for jps-* projects because their deps become incompatible with other projects.
  • #755 - Add missing breaks to case statement in processDeclarations(Match, ...) that caused the logic of whether to check left, right, or both operand based on the whether the treeWalkUp came from always fell through to the RIGHT case, so it was only, always checking the right operand of the match and never the left operand. - @KronicDeth
  • #756 - Skip processDeclarationsInPreviousSibling when lastParent is ElixirFile - @KronicDeth
  • #757 - Remove background color from sigils because it stands out really badly in the Default theme where it’s black on white and while it doesn’t in Darcula, it’s unnecessary there because it’s so close to the editor background color in Darcula. - @KronicDeth
  • #758 - Treat Alias as miscapitalized type parameter. @KronicDeth
  • #759 - Ignore call definition clauses after when in type specifications as it is a common occurrence when typing a specification above a pre-existing call definition clause. - @KronicDeth
  • #761 - Use THashSet instead of the more specific SmartHashSet because THashSet allows null keys, which are expected for the canonicalNameSet. - @KronicDeth
  • #764 - @KronicDeth
    • Look above List for enclosing modular macro.
    • Look above ElixirNoParenthesesManyStrictNoParenthesesExpression for enclosing modular macro.
  • #765 - Remove background color from Sigil Color Scheme Design to match changes in #757. - @KronicDeth
  • #769 - @KronicDeth
    • Check if program parameters is blank before splitting into mix args.
    • Use ParametersList to properly parse quote program parameters.
  • #773 - @KronicDeth
    • Move Quoter into test directory, so it and its dependency on JUnit is only used for test compilation and runtime and not the shipped runtime.
    • Fix Quoter warnings and format.
  • #774 - @KronicDeth
    • Show expected SDK home path structure when invalid. screen shot 2017-08-06 at 2 28 36 pm
    • Suppress invalid warnings in ElixirSdkType.
  • #775 - Always check if resolution result is right operand of match. - @KronicDeth
  • #776 - CallDefinitionClause InsertHandler always assumed there was a character after the insert location, but when inserting at the very end of the file, there isn’t, which caused an IndexOutOfBoundsException. Only check if the following character is not a space, (, or [ when the document is longer than the tail offset to prevent the IndexOutOfBoundsException. If the insertion is at the end of the file, then the () will always be inserted. - @KronicDeth
  • #777 - DecompilatedDecompilation - @KronicDeth
  • #771 - The lower-level Data(Output|IntputStream (write|read)Int don’t work correctly with sizes, so use the JetBrains (write|read)VarInt ones instead. - @KronicDeth
  • #782 - Delegate ChildAttributes to previous child when available: Block.getChildAttributes is used when Enter is pressed to determine the indentation and alignment. Using the default implementation, newlines in stabs look overly indented, but there is a constant, DELEGATE_TO_PREV_CHILD that can be used to just use the last child’s indent as long as there is one, which appears to work well for stabs (do block bodies, etc). - @KronicDeth
  • #783 - @KronicDeth
    • Increase suspect nameSetSize from 4 to 10 because a Poison.Encoder has an impl module for 4 types, and so has 4 canonical names.
    • Only read-ahead if guard length is non-zero; otherwise, only warn the nameSetSize may be suspect and don’t read-ahead as this can mess up OK namesets.
  • #784 - @KronicDeth
    • Override Kernel.SpecialFroms arity intervals
      • alias overridden from 2 to 1-2 to support without :as option.
      • import overridden from 2 to 1-2 to support without :except or :only options.
      • quote overridden from 2 to 1-2 to support block without options.
      • require overridden from 2 to 1-2 to support without :as option.
      • super overridden from 1 to 0- to support calling any super method.
  • #789 - elixir.bat in at least Elixir 1.5.1, will not properly parse a mix path with spaces in it on Windows even when the path has outer quotes (see elixir-lang/elixir#6455). It is not possible to use inner quotes, as you can do in cmd.exe, using the JetBrains and Java libraries hat auto-matically quote, so instead bypass the bad quoting in elixir.bat by doing what elixir.bat does: call erl.exe with all the SDK ebin paths added with -pa, then -noshell -s elixir start_cli to run Elixir and-extra to run requires (-r), mix and its tasks. - @KronicDeth

Incompatible Changes

  • #732 - @KronicDeth
    • Drop 14.1.X support because it does not have support for nodeId test output, so it’s not possible to handle the ExUnit test output in a safe manner while still allowing concurrent output for asynchronous tests.

README Updates

Formatting

IntelliJ Elixir can reformat code to follow a consistent style.

  • do block lines are indented
  • do blocks end as the last argument of a no parentheses call unindents to the start of the call
  • If one clause of a multi-clause anonymous function wraps, all clauses wrap.
  • Indent after else
  • Indent map and struct keys
  • All keys wrap if any key wraps
  • No spaces around…
    • .
  • Spaces around…
    • and
    • in
    • or
    • when
  • Configure spaces around…
    • =
    • <- and \\
    • !=, ==, =~, !==, and ===
    • <, <=, >=, and >
    • + and -
    • * and /
    • Unary +, -, !, ^, and ~~~
    • ->
    • ::
    • |
    • || and |||
    • && and &&&
    • <~, |>, ~>, <<<, <<~, <|>, <~>, >>>, and ~>>
    • ..
    • ^^^
    • ++, --, .., <>
    • =>
  • Configure spaces before…
    • ,
  • No space after…
    • @
  • Spaces after…
    • not
    • fn
    • after
    • catch
    • rescue
    • key:
  • Configure space after…
    • &
    • ,
  • Configure spaces within…
    • { }
    • << >>
    • [ ]
    • ( )
  • No space around / in &NAME/ARITY and &QUALIFIER.NAME/ARITY
  • when wraps when its right operand wraps, so that guards start with when on a newline when they are too long.
  • Align |> at start of indented line for pipelines
  • Align end with start of call instead of start of line for do blocks in pipelines
  • Indent list elements when wrapped
  • Indent tuple elements when wrapped
  • Align type definition to right of ::
  • Align guard to right of when when guards span multiple lines
  • Align two operator (++, --, .., <>) operands, so that <> binaries are multiple lines align their starts instead of using continuation indent and being indented relative to first operand.
  • Align pipe | operands, so that alternates in types and specs are aligned instead of continuation indented relative to the first operand.
  • Comments in spec (that is above operands to | align with the operands
  • Remove newlines from pipelines, so that all pipelines start with an initial value or call and each |> is the start of a successive line.
  • Key exclusivity: if an association operation or keyword key is already on a line, the container value automatically has it’s elements wrapped if there is nested associations or keyword pairs, so that two levels of keys are not on the same line.
  • Indent bit string (<< >>) elements when wrapped

Installation

Installation Instructions

6 Likes

Version 6.1.0

Thanks

  • For reporting the original failure to setup debugger environment
  • For reporting the failure to setup debugger environment persisted in 6.0.0 the same day as a the release

Changelog

v6.1.0

Enhancements

  • #792 - @KronicDeth
    • Since the process of requiring resource files is the same, org.elixir_lang.ElixirModules has static methods for copying resources out to a temporary directory and adding the -r <temporary_path> for one or more resource files to a new or existing ParametersList. These are now shared for the Mix ExUnit and Debugger code paths.
    • Format class
      • ElixirXDebugProcess
      • MixExUnitRunningState
      • MIxRunningState

Bug Fixes

  • #792 - The compiled .beam files were removed in 58e7d4a, which was before v5.1.0, but not all users had problems with using the debugger. #739 persisted (as reported by @erikreedstrom) when 6.0.0 was released; I retried reproducing on a clean VM and I got it. I’m not sure why it worked for some people in prior releases since the .beam don’t exist that were being copied, but now the debugger uses the same system of copying .ex files and requiring them with -r instead of copying .beam and using -pa to add the ebin directory. Fix was verified local under macOS and in Windows VM that reproduced #739. - @KronicDeth

Installation

Installation Instructions

1 Like

Version 6.1.1

Thanks

  • For reporting the need to install intellij-erlang to get icons to resolve
  • For reporting formatter didn’t indent first line of a new do ... end block
  • For reporting still unhelpful errors from beam decoder

Changelog

v6.1.1

Bug Fixes

  • #795 - When #754 made intellij-erlang a soft-dependency, it broke the debugger’s icons that referenced ErlangIcons, but it turns out all the icon constants were aliases to AllIcons.Debugger constants, so by using the AllIcons.Debugger icons directly, the dependency on ErlangIcons can be removed without the need to copy the image files into intellij-elixir. - @KronicDeth
  • #796 - When do ... end template is inserted, it did not have a previous child whose attributes to use, so it used the default, which left the cursor unindented. To get the cursor indented by default, When the ElementType is DO, apply the stabChildrenIndent rules: indent normal and determine whether to indent relative to direct parent using code style setting. - @KronicDeth
  • #797 - Include VirtualFile path in Beam read errors - @KronicDeth

Installation

Installation Instructions

2 Likes

Seeing all the work on the plugin I decided to give it a go.

I managed to set it up and it works just fine. Great job, @KronicDeth. I don’t like how my code looks, though. I find the built-in dark theme a bit too colourful for my liking - I enjoy rather toned-down colours (I’m using zenburn theme in emacs).
I tried some other colour schemes from http://color-themes.com/ but most of them looked hideous (dark purple and almost illegible module names seem to be a common issue). Any suggestions on some good dark, not-too-colourful schemes?

A lot of the pre-existing themes on theme websites don’t work for Elixir because theme bundles for IntelliJ have to know the name of the AttributeKey to set it’s attributes and not all Elixir AttributeKeys fallback to General AttributeKeys, so there’s no mapping in the theme for certain elements OR the fallback is useless whitish color for most of them. You can see the fallbacks in the menus as “use inherited attributes”

It used to be that all Custom Language plugins re-used the Java AttributeKeys, but JetBrains changed their guidance, so that Custom Languages should only use the General AttributeKeys as fallbacks, so themes built for Java or the other JetBrains-supported languages are less likely to look good for Custom Language plugins now.

There is an IntelliJ Zenburn (GitHub - pedropenna/Intellij-Zenburn: ZenBurn color scheme for the Intellij 13 based on Emacs Zenburn colors). If the colors aren’t mapping correctly for Elixir, I can add an

To the plugin and set AttributeKey overrides in the xml file that Elixir needs as I did for the built-in Darcula and Default themes. If you need these overrides, please open an Github issue and I’ll add it as an enhancements. Include lots of screenshots, so I know what I’m aiming for.

3 Likes

You can use this to convert TextMate themes: GitHub - JetBrains/colorSchemeTool

Maybe someone could try converting Elixify :lol:

I think that everyone has full right to use colours he likes most, and nothing wrong with that, but I must say that I really love the default colour theme for Elixir plugin :slight_smile:

Heh, I had the same thought. I use a dark toned down variant of solarized (as seen in my screenshots everywhere) in my terminal, emacs, atom, and more, and I tried to install it in IntelliJ as well when I tested the elixir plugin but noticed that it was not right. ^.^;

I can deal with the color issues though if everything is stable enough, my issue was just Intellij was so so very heavy (at least on windows) and was eating more memory than 4 atom projects. ^.^;

I use IntelliJ for Rust at home though. I prefer IntelliJ for Java as well but I’m forced to use Eclipse for most of my Java work because I’ve yet to find out how to get live code editing work in IntelliJ for an interface I use when it ‘just works’ with Eclipse.

Version 6.2.0

Donate

Thanks

Changelog

v6.2.0

Enhancements

  • #817 - * Add note to README that atom module names should be prefixed with : - @merqlove
  • #827 - @KronicDeth
    • Elixir SDK will now have an Internal Erlang SDK, which can be supplied one of two ways:

      1. If intellij-erlang is installed: its Erlang SDK can be used
      2. Otherwise: the Erlang SDK for Elixir SDK from this plugin can be used

      Either Internal Erlang SDK’s home path is used to locate the erl (or erl.exe on Windows) executable and it is used to run Elixir; bypassing the elixir (or elixir.bat on Windows) script. Instead, as was done in #789, the ebin directories for the Elixir SDK are passed as -pa options to erl.

      The Elixir SDK’s configuration becomes more important: the classpath entries are now the list of ebin directories to pass to erl using -pa instead of scanning for ebins in the homepath, so additional code paths can be added to the Classpaths configuration and they will be used when running mix and mix test. The classpaths will be initialized to the ebin directories under the home path.

      • To support migrating from earlier version of the plugin, an SDK will be updated when it is used for Mix ExUnit Run Configurations
        • The default Internal Erlang SDK will be set, which uses the latest version of Erlang that can be found on the system. When intellij-erlang is installed, intellij-elixir’s Erlang version suggestion is still used because intellij-elixir favors the latest version while intellij-erlang favors the first found, which is usually the oldest version.
        • Update roots (class path, source paths, documentation paths):
          • Class path of HOMEPATH/lib is replaced with HOMEPATH/lib/APP/ebin.
          • Source path of HOMEPATH/lib is replaced with HOMEPATH/lib/APP/lib IF it exists (so only for source SDKs)
          • Documentation of http://elixir-lang.org/docs/stable/elixir/ will be replaced with https://hexdoc.pm/APP/VERSION for every APP in HOMEPATH/lib.
  • #839 - @KronicDeth
    • All ebin paths in the Internal Erlang SDK will be copied to the Elixir SDK, so that they are indexed, which makes the Internal Erlang SDK modules show up in Symbol search.
    • Erlang SDK modules can be completed and then functions in those modules can be completed after typing ..
      • Atoms have References.
        • Indexed atoms (from decompiled Erlang .beams from the Internal Erlang SDK) will be used for completing atoms as soon the atom is parseable: either after the first letter : or inside the quotes when making a quoted atom.
        • Atoms will resolve to modules if the atom is a module name. If the atom is quoted and contains interpolation, it will treat each interpolation as .* and look for regex matches to this derived potential atom name.
    • Completions for functions after . will now work at the end of file. Previously, completions only worked in the middle of a file, where the . could parse the next work an existing call, now if that parse doesn’t work and the only thing after is a new line, it will still complete.
  • #830 - Auto test for mix test case runner will automatically run tests after a change is detected in the project files, which normally happens on save, which happens when losing focus on a changed editor tab by default. - @nivanson
  • #840 - Regression test for #821 - @KronicDeth
  • #841 - Regression test for #803 - @KronicDeth
  • #842 - Regression test for #833 - @KronicDeth
  • #843 - Port elixir-lang/elixir#2774: Allow A-Z as sigil modifiers in addition to a-z to support U ungreedy modifier that replaced r ungreedy modifier for regexes. - @KronicDeth

Bug Fixes

  • #816 - Add notice for debug blacklist that it uses atoms, not Aliases, so you need to qualifier module aliases with Elixir. - @merqlove
  • #817 - Support atoms (prefixed with :) andElixir. and plain Aliases for debugger blacklist. - @merqlove
  • #832 - Add space to import window text - @kentongray
  • #840 - Add END to allowed keywordKey tokens - @KronicDeth
  • #841 - @KronicDeth
    • Only use “Macros” as first header in decompiled .beam files if macro is defmacro. “Macros” header was being printed when there was only functions because the check when there was no lastMacroNameArity didn’t care what the current macroNameArity.macro was.
    • When an .erl file has -compile([compressed]), it will be compiled normally, and then gzipped, so that the .beam will not contain the BEAM magic number FOR1, but instead the gzip magic number 0x1f 0x8b. So, to properly handle normal and compressed, the decompiler needs to look-ahead 2-bytes and check the gzip magic number. If the gzip magic number is detected, the InputStream will be passed through GZIPInputStream before the the normal decoding process.
  • #842 - When decompiling function and macro names from Erlang module, its possible for the name to contain # and they would be interpreted as comments. Accepting those names in Unquoted wouldn’t escape the # from being treated as a comment, so in addition to unquoteing the name, surround it in double quotes. - @KronicDeth
  • #848 - @KronicDeth
    • AdditionalDataConfigurable only copied the the Internal Erlang SDK Code Paths when the selection in the ComboBox was changed, which meant if the there was only one Erlang SDK or the user never changed the selection, the Code Paths were never copied. To get the Code Paths copied when the Elixir SDK is first created and setupSdkPaths interface method is called
      1. All paths are set directly on the Elixir SDK as before
      2. The default Erlang SDK, which should be the one that was last created, is configured in SdkAdditionalaData
      3. The Code paths from the Erlang SDK are copied to the Elixir SDK
        1. If the the Erlang SDK is from intellij-elixir and does not have ebin directories for its Class Paths, then the Class Paths is expanded to Code Paths.
  • #851 - The Code Paths from the Internal Erlang SDK were not being copied from the default Erlang SDK to the Elixir SDK when the default Erlang SDK was set during mix test runs, which meant that the Elixir SDK would not upgrade correctly from 6.1.1 to 6.2.0 without the user deleting the Elixir SDK and recreating it. - @KronicDeth

README Changes

Decompilation

.beam files, such as those in the Elixir SDK, the Elixir SDK’s Internal Erlang SDK, and in your project’s build directory will be decompiled to equivalent def and defmacro calls. The bodies will not be decompiled, only the call definition head and placeholder parameters. These decompiled call definition heads are enough to allow Go To Declaration, the Structure pane, and Completion to work with the decompiled .beam files.

.beam files are not detected purely by their file extension: the BEAM file format starts with a magic number, FOR1, that is checked for before decompiling.

Decompression

If the .beam module was compiled with the compressed compiler directive, which in Erlang looks like

-compile([compressed])

and in Elixir looks like

@compile [:compressed]

then the outer file format is GZip (which is detected by checking for the gzip magic number, 1f 8b, at the start of the file) and the .beam will be (stream) decompressed before the .beam header is checked and the chunks decoded.

Special handling of call definition names

Functions and macros can have names that aren’t valid identifier names, so the decompiler has special handlers to detect these invalid identifiers and escape them to make decompiled code that is parsable as valid Elixir.

Handler Name/Arity Decompiled Reason
Infix Operator !=/2 left != right Infix operators are defined in infix position
!==/2 left !== right
&&/2 left && right
&&&/2 left &&& right
*/2 left * right
=+/2 left + right
=++/2 left ++ right
-/2 left - right
--/2 left -- right
->/2 left -> right
../2 left .. right
//2 left / right
::/2 left :: right
</2 left < right
<-/2 left <- right
<<</2 left <<< right
<<~/2 left <<~ right
<=/2 left <= right
<>/2 left <> right
<|>/2 left <|> right
<~/2 left <~ right
<~>/2 left <~> right
=/2 left = right
==/2 left == right
===/2 left === right
=>/2 left => right
=~/2 left =~ right
>/2 left > right
>=/2 left >= right
>>>/2 left >>> right
\\/2 left \\\\ right
^/2 left ^ right
^^^/2 left ^^^ right
and/2 left and right
in/2 left in right
or/2 left or right
|>/2 left |> right
||/2 left || right
|||/2 left ||| right
~=/2 left ~= right
~>/2 left ~> right
~>>/2 left ~>> right
Prefix Operator +/1 (+value) To prevent precedence errors, unary prefix operators, which also have binary infix operators of the same name need to be defined inside parentheses
-/1 (-value)
Unquoted %/2 unquote(:%)(p0, p1) Special forms need to defined as atom passed to unquote, as special forms are handled before macros defining the calls are applied
%{}/1 unquote(:%{})(p0)
&/1 unquote(:&)(p0)
./2 unquote(:.)(p0, p1)
<<>>/1 unquote(:<<>>)(p0)
do/n unquote(:do)(p0, ...) Keywords need to be escaped
fn/1 unquote(:fn)(p0) Special forms need to defined as atom passed to unquote, as special forms are handled before macros defining the calls are applied
unquote/1 unquote(:unquote)(p0)
unquote_splicing/1 unquote(:unquote_splicing)(p0)
{}/n unquote(:{})(p0, ...)
Capitalized/n unquote(:Capitalized)(p0, ...) Part of the Corba libraries in OTP have functions starting with a capital letter, which would be parsed as an Alias in Elixir if not unquoted.
#text#/1 unquote(:"#text#")(p0)
Part of the XML libraries in OTP have functions that start with or contain `#`, which would parse as a comment in Elixir if not unquoted in a double quoted atom.
Default name/n name(p0, ...) If no specialized handler is required, functions and macros are defined normally with pN for each parameter in the Nth position

SDK

Because Elixir is built on top of Erlang, Elixir command line commands don’t have OS native binaries, instead the OS native binaries from Erlang are used. In order to reliably find the Erlang OS native binaries, like erl and erl.exe, the path to BOTH the Erlang SDK and the Elixir SDK must be configured. This allows you to install Erlang and Elixir with completely different package managers too: you can install Erlang with kerl and Elixir with kiex and you don’t have to worry about IntelliJ not seeing the environment variables set by kerl when launching IntelliJ from an application launchers instead of a terminal.

Since JetBrains’ OpenAPI only supports one SDK per Project or Module, to support Elixir and Erlang SDK at the same time, the Elixir SDK keeps track of an Internal Erlang SDK. When setting up your first Elixir SDK, you will be prompted to create an Erlang SDK (if you have the intellij-erlang plugin installed) or and Erlang for Elixir SDK (if you don’t have intellij-erlang installed and you need to use the minimal Erlang for Elixir SDK supplied by this plugin).

With the Elixir SDK setup with an Internal Erlang SDK, you can see the Elixir SDK name and the home path, but unlike other SDKs, there’s a dropdown for changing the Internal Erlang SDK.

You’ll notice there is a mix of two different parent paths in Class Paths:

  1. Those from the Elixir SDK Home Directory, which are the lib/APP/ebin for the APPs that ships with Elixir: eex, elixir, ex_unit, iex, logger, and mix.

  2. Those from the Internal Erlang SDK Home Directory, which are the lib/APP-VERSION/ebin for the APPs that ship with OTP.

The Class Paths are combined from the two SDKs because OpenAPI doesn’t allow to dynamically delegate to the Internal Erlang SDK when checking for Class Paths to scan for completion and running. If you change the Internal Erlang SDK in the dropdown, the Class Paths will be updated to remove the old Internal Erlang SDK Class Paths and add the new Internal Erlang SDK Class Paths.

These Class Paths are not just for code completion and search anymore, all paths listed as passed with -pa flag to erl or erl.exe when running mix, so that you can mix different versions of OTP applications shipped with different version of OTP, so you can take advantage of the independently updatable OTP apps in the release notes for OTP.

Default SDK

  1. The default SDK for new projects can we set from the Configure menu on Welcome Screen

  2. Hover over “Project Defaults” to see its submenu

  3. Select “Project Structure” from the submenu

  4. IntelliJ will start out with no default SDK. To make the default SDK, an Elixir SDK, Click New

  5. Select “Elixir SDK”

  6. You’ll get “Cannot Create SDK” message because there are no Erlang SDKs for the Elixir SDK to use as an Internal Erlang SDK. Click OK to create the Erlang SDK first.

  7. You’ll be actually prompted to Select Home Directory for the Erlang SDK

    • If you have the intellij-erlang plugin installed, you’ll create an Erlang SDK from it.

      Erlang SDK

      NOTE: Erlang SDK’s default Home Directory favors the oldest version of Erlang installed. You probably want the newest version. To manually select the Home Directory, it is the directory that contains the bin, erts-VERSION, and lib subdirectories. For Homebrew, the path looks like /usr/local/Cellar/erlang/VERSION/lib/erlang. It is important to select the lib/erlang directory and not the VERSION directory for intellij-erlang to accept it as a Home Directory.

    • If you don’t have intellij-erlang installed, then you’ll create and Erlang for Elixir SDK, which is supplied by this plugin.

  8. With an Erlang SDK available to use as the Internal Erlang SDK, you’ll be prompted for the Home Directory for the Elixir SDK.

Installation

Installation Instructions

3 Likes

Version 6.3.0

Donate

Thanks

  • For explaining difficulties with using README Project section in Small IDEs
  • For reporting that the Internal Erlang SDK in Elixir SDK in Rich IDE support in 6.2.0 broke mix test runner for Small IDEs

Changelog

v6.3.0

Enhancements

  • #854 - @KronicDeth
    • credo external annotator
      • Once modifications have settled on a file and all internal annotators have run, mix credo will be run on any modified file.
        • Each check failure reported by mix credo will be turned into a warning annotation (yellow highlight) of the line or line and column credo identified.
        • If you hover over the annotation (either in the source or on right gutter), the mix credo PATH:LINE(:COLUMN) explanation will be shown. Links in the tooltip are clickable and allow you to jump to the specific line or line and column of the failure.
  • #856 - @KronicDeth
    • Explain Rich vs Small IDEs more
    • Add feature support table for Rich vs Small IDEs with links to alternatives for Rich IDEs features not in Small IDEs.
    • Reorder Project subsections based on usage.

Bug Fixes

  • #854 - Rename package with typo org.elixir_lang.annonatororg.elixir_lang.annotator. - @KronicDeth
  • #855 - @KronicDeth
    • Change error to say mix, elixir, or erlang path is not set instead of just mix path.
    • Rewrite of MixRunningStateUtil#setElixir to support calling erl directly in IntelliJ IDEA added a check that sdk type was the Elixir SDK Type, but there was no else clauses to handle that there IS an SDK, but its NOT Elixir, which is the common case on all Small IDEs (like Rubymine). To fill this gap, if the SDK is not Elixir and a Small IDE is detected, then the SDK Home from Preferences > Other Settings > Elixir External Tools > Elixir SDK > Path will be used to get the absolute path to the elixir (or elixir.bat executable and set it in the GeneralCommandLine.
  • #856 - @KronicDeth
    • Add missing ** for bold.
    • Document alternative setup in Small IDEs
    • Put Import from external model first in Project subsections, so that people are more likely to import as a mix project correctly.

README updates

Thanks

  • For explaining difficulties with using README Project section in Small IDEs
  • For reporting that the Internal Erlang SDK in Elixir SDK in Rich IDE support in 6.2.0 broke mix test runner for Small IDEs

Changelog

v6.3.0

Enhancements

  • #854 - @KronicDeth
    • credo external annotator
      • Once modifications have settled on a file and all internal annotators have run, mix credo will be run on any modified file.
        • Each check failure reported by mix credo will be turned into a warning annotation (yellow highlight) of the line or line and column credo identified.
        • If you hover over the annotation (either in the source or on right gutter), the mix credo PATH:LINE(:COLUMN) explanation will be shown. Links in the tooltip are clickable and allow you to jump to the specific line or line and column of the failure.
  • #856 - @KronicDeth
    • Explain Rich vs Small IDEs more
    • Add feature support table for Rich vs Small IDEs with links to alternatives for Rich IDEs features not in Small IDEs.
    • Reorder Project subsections based on usage.

Bug Fixes

  • #854 - Rename package with typo org.elixir_lang.annonatororg.elixir_lang.annotator. - @KronicDeth
  • #855 - @KronicDeth
    • Change error to say mix, elixir, or erlang path is not set instead of just mix path.
    • Rewrite of MixRunningStateUtil#setElixir to support calling erl directly in IntelliJ IDEA added a check that sdk type was the Elixir SDK Type, but there was no else clauses to handle that there IS an SDK, but its NOT Elixir, which is the common case on all Small IDEs (like Rubymine). To fill this gap, if the SDK is not Elixir and a Small IDE is detected, then the SDK Home from Preferences > Other Settings > Elixir External Tools > Elixir SDK > Path will be used to get the absolute path to the elixir (or elixir.bat executable and set it in the GeneralCommandLine.
  • #856 - @KronicDeth
    • Add missing ** for bold.
    • Document alternative setup in Small IDEs
    • Put Import from external model first in Project subsections, so that people are more likely to import as a mix project correctly.

README updates

Elixir plugin

Build Status

This is a plugin that adds support for Elixir to JetBrains IDEs.

The plugin works both in the rich IDEs that allow alternative language SDK selection and small IDEs that are language specific. The rich IDEs work best for IntelliJ Elixir because only in the rich IDEs can have an Elixir SDK set as the Project SDK. In all small IDEs, the native language SDK is always there, which makes anything that uses the SDK, such as running elixir, erl, or mix more complicated both internally and externally in the configuration you have to setup.

IDEs

The plugin is free to use in all JetBrains IDEs. The Cost column in the below table is what JetBrains charges for the IDE itself. IntelliJ Elixir is maintained by @KronicDeth who does not get any of the subscription money. If you want to support the plugin itself, make a donation.

IDE Rich/Small Languages Cost Trial License Source
IntelliJ IDEA Community Edition Rich Java Free N/A Apache 2.0 JetBrains/intellij-community
IntelliJ IDEA Ultimate Edition Rich Java Subscription 30-days Commercial N/A
AppCode Small Objective-C Subscription 30-days Commercial N/A
CLion Small C/C++ Subscription 30-days Commercial N/A
DataGrip Small SQL Subscription 30-days Commercial N/A
Gogland Small Go Free N/A Early Access Preview N/A
PHPStorm Small PHP Subscription 30-days Commercial N/A
PyCharm Community Edition Small Python Free N/A Apache 2.0 JetBrains/intellij-community subdirectory
PyCharm Professional Edition Small Python Subscription N/A Commercial N/A
Rider Small .NET Subcription N/A Commercial N/A
RubyMine Small Ruby Subscription 30-days (90-day for whole team) Commercial N/A
WebStorm Small JavaScript Subscription 30-days Commercial N/A

Once you have your IDE of choice installed, you can install this plugin

Features

Feature Rich Small Alternative
Project Yes No 1. Open directory
2. Elixir SDK Path in External Elixir Tools
Project Structure Automatic Manual
Project Settings Yes No
Module Settings Yes No
New Elixir File Yes Yes
Syntax Highlighting and Semantic Annotation Yes Yes
Grammar Parsing Yes Yes
Inspections Yes Yes
Quick Fixes Yes Yes
Code Folding Yes Yes
Commenter Yes Yes
Debugger Yes Yes
Delimiters Yes Yes
Building/Compiling Yes No Build/compile as part mix run configurations only
Live Templates Yes Yes
Run Configurations Yes Yes
Completion Yes Yes
Decompilation Yes Yes
Go To Declaration Yes Yes
Formatting Yes Yes
Go To Symbol Yes Yes
Go To Test Yes Yes
Go To Test Subject Yes Yes
Find Usage Yes Yes
Refactor Yes Yes
SDK Yes No Elixir SDK Path in External Elixir Tools
Structure Yes Yes

Project

NOTE: This feature only works in Rich IDEs as it depends on an extension point unavailable in Small IDEs. To setup a project in a Small IDE
  1. Open Directory of the project
  2. Setup the Elixir SDK Path in External Elixir Tools

From Existing Sources

Import project from external model

If you’ve already created a mix project, you can load it as an Elixir project into the plugin.

  1. File > New > Project From Existing Sources…
  2. Select the root directory of your project.
  3. Select “Import project from external model”
  4. Select Mix
  5. Click Next
  6. The “Mix project root” will be filled in with the selected directory.
  7. (Optional) Uncheck “Fetch dependencies with mix” if you don’t want to run mix deps.get when importing the project
    • If “Fetch dependencies with mix” is checked both mix hex.local --force and mix deps.get will be run.
  8. Ensure the correct “Mix Path” is detected. On Windows, the mix.bat, such as
    C:\Program Files (x86)\Elixir\bin\mix.bat should be used instead of the mix file without the extension.
  9. Ensure the “Mix Version” is as expected. The number in parentheses should match the Elixir version.
  10. Click Next
  11. All directories with mix.exs files will be selected as “Mix projects to import”. To import just the main project and not its dependencies, click Unselect All.
  12. Check the box next to the project root to use only its mix.exs. (It will likely be the first checkbox at the top.)
  13. Click Next
  14. Select a Project SDK directory by clicking Configure.
  15. The plugin will automatically find the newest version of Elixir installed. (NOTE: SDK detection only works for
    Linux, homebrew installs on OSX, and Windows. Open an issue
    with information about Elixir install locations on your operating system and package manager to have SDK detection
    added for it.
    )
  16. If the automatic detection doesn’t find your Elixir SDK or you want to use an older version, manually select select
    the directory above the bin directory containing elixir, elixirc, iex, and mix. (On Windows it is the
    directory containing elixir.bat, elixirc.bat, iex.bat, and mix.bat.)
  17. Click Finish after you select SDK name from the Project SDK list.
Create project from existing sources

If you’ve already created a (non-mix) project, you can load it as an Elixir project into the plugin.

  1. File > New > Project From Existing Sources…
  2. Select the root directory of your project.
  3. Leave the default selection, “Create project from existing sources”
  4. Click Next
  5. Project name will be filled with the basename of the root directory. Customize it if you like.
  6. Project location will be the root directory.
  7. Click Next.
  8. If you previously opened the directory in IntelliJ or another JetBrains IDE, you’ll be prompted to overwrite the
    .idea directory. Click Yes.
  9. You’ll be prompted with a list of detected Elixir project roots to add to the project. Each root contains a
    mix.exs. Uncheck any project roots that you don’t want added.
  10. Click Next.
  11. Select a Project SDK directory by clicking Configure.
  12. The plugin will automatically find the newest version of Elixir installed. (NOTE: SDK detection only works for
    Linux, homebrew installs on OSX, and Windows. Open an issue
    with information about Elixir install locations on your operating system and package manager to have SDK detection
    added for it.
    )
  13. If the automatic detection doesn’t find your Elixir SDK or you want to use an older version, manually select select
    the directory above the bin directory containing elixir, elixirc, iex, and mix.
  14. Click Next after you select SDK name from the Project SDK list.
  15. Click Finish on the framework page. (No framework detection is implemented yet for Elixir.)
  16. Choose whether to open in a New Window or in This Window.

New

If you want to create a basic (non-mix) Elixir project with a lib directory, perform the following steps.

  1. File > New > Project
  2. Select Elixir from the project type menu on the left
  3. Click Next
  4. Select a Project SDK directory by clicking Configure.
  5. Select a Project SDK directory by clicking Configure.
  6. The plugin will automatically find the newest version of Elixir installed.
    • macOS / OSX
      • Homebrew (/usr/local/Cellar/elixir)
      • Nix (/nix/store)
    • Linux
      • /usr/local/lib/elixir
      • Nix and NixOS (/nix/store)
    • Windows
      • 32-bit (C:\Program Files\Elixir)
      • 64-bit (C:\Program Files (x86)\Elixir)
      • (NOTE: SDK detection only works for Open an issue with information about Elixir install locations on your operating system and package manager to have SDK detection added for it.)
  7. If the automatic detection doesn’t find your Elixir SDK or you want to use an older version, manually select select the directory above the bin directory containing elixir, elixirc, iex, and mix. If the bin, lib, or src directory is incorrectly selected, it will be corrected to the parent directory.
  8. Click Next after you select SDK name from the Project SDK list.
  9. Change the Project name to the name your want for the project
  10. (Optionally) change the Project location if the directory does not match what you want
  11. (Optionally) expand More Settings to change the Module name, Content root, Module file location, and/or Project format. The defaults derived from the Project name and Project location should work for most projects.
  12. Click Finish
  13. Choose whether to open in a New Window or in This Window.

External Annotators

In addition to the built-in syntax highlighting and annotations above, various mix tasks will be run to gather annotations from Elixir status analysis tools.

Credo

If credo is not installed as a project dependency, nothing will happen, but if it is installed, mix credo PATH will be called on any files after updates have quieted. Any credo check failures will show up as warning annotations

Warning Annotations

Individual check failures will show the explanation (from mix credo PATH:LINE(:COLUMN)) if you hover over the annotation

Explanation

You can hover over the explanation and click the embedded links to jump to the line (and column) where the failure occurred.

SDK

NOTE: These instructions only apply to Rich IDEs, for a Small IDE use Elixir SDK Path

Elixir External Tools

Rich IDEs

Elixir External Tools in Rich IDEs

In a Rich IDE, like IntelliJ IDEA, only the path to mix is configured as an external tool. This mix path is only used when creating new projects, so when opening a pre-existing project with Import project from external model, this doesn’t even need to be set.

Small IDEs

Elixir External Tools in Small IDEs

Elixir SDK Path

NOTE: To setup the SDK in a Rich IDE use Import project from external model or SDK

In a Small IDE, like Rubymine, the Project SDK is always a Ruby SDK, so to support a pseudo-Elixir-SDK in a Small IDE, the Elixir SDK Path can be set.

  1. Open Preferences > Other Settings > Elixir External Tools
  2. Set the Elixir SDK Path
  • Paste the path to an Elixir SDK
  • Click the ... to select the directory

The pattern for the Elixir SDK Path varies based on the OS and package manager you used to install Elixir

OS Package Manager Elixir SDK Path
OSX/macOS Homebrew /usr/local/Cellar/elixir/VERSION
OSX/macOS/Linux Nix /nix/store/HASH-elixir-VERSION
Windows 32-bit Erlang Solutions C:\Program Files\Elixir
Windows 64-bit Erlang Solutions C:\Program Files (x86)\Elixir
Linux Default /usr/local/lib/elixir

Installation

Installation Instructions

1 Like

Version 6.4.0

Donate

Thanks

  • For reporting assertion error when explanation content was not indented 5 spaces
  • For reporting assertion error in Credo#stripEdge
  • For reporting that end wasn’t being decompiled with Unquoted in wx-1.8.2/ebin/gl.beam
  • For reporting that $code_change wasn’t being decompiled with Unquoted in tools-2.11/ebin/fprof.beam
  • For reporting that BeamFileImpl needed StubbedSpine getStubbedSpine() in IntelliJ IDEA 2017.3 EAP/Public Preview
  • For showing that StubbedSpine getStubbedSpine() could be copied from ClsFileImpl, but then fixing it, so that getStubbedSpine() had a default implementation on the interface, so I didn’t need to use reflection to support > 2017.3 and earlier versions. :heart:
  • For reporting that Credo annotator violated “Write access is allowed from event dispatch thread only” when Type. putDefaultErlangSdk was triggered for upgraders that didn’t upgrade their SDK manually or with a mix Run Configuration before the Credo annotator started running.
  • For reporting ANSI escape codes were not converted to colors in console output
  • For pointing me towards com.intellij.execution.process.ColoredProcessHandler for ANSI escape code colors. :heart:

Changelog

v6.4.0

Enhancements

Bug Fixes

  • #861 - @KronicDeth.
    • Quote - in addition to # in Unquoted MacroNameArity decompiler.
    • Quote - in decompiled module names.
  • #862 - Wrap call definitions with name nil as unquote(:nil) in the decompiler. - @KronicDeth
  • #884 - Application#runWriteAction MUST be run from EventDispatch thread. This is true when run from a Run Configuration runner, but when the Credo annotator runs runWriteAction, it’s not in an EventDispatch thread, so followed IntelliJ Platform SDK DevGuide - General Threading Rules and wrapped the runWriteAction in Application#invokeAndWait. - @KronicDeth
  • #885 - Wrap sdkModificator::commitChanges in invokeAndWait runWriteAction in MixRunningStateUtil#updateRoots. - @KronicDeth
  • #886 - @KronicDeth
    • Generalize what needs to be double quoted for Unquoted decompiler

      • Aliases and special forms are bare atoms
      • Anything that is NEITHER an identifier NOR a prefix operator is a double quoted atom.

      Normal identifiers and prefix operators then fall through to the Default decompiler.

  • #887 - Add end to Unquoted decompiler bare atoms. - @KronicDeth
  • #888 - Replace asserts in Credo external annotator with extended log messages that record the unexpected line. - @KronicDeth

Installation

Installation Instructions

5 Likes

Version 6.5.0

Donate

Thanks

  • For reporting the grammar did not support not in
  • For reporting the credo edge detection errors were due to UTF-8 charset not being set.
  • For pointed out that GeneralCommandLine#withCharset existed to set the charset to UTF-8 always.

Changelog

v6.5.0

Enhancements

  • #898 - @KronicDeth
    • Update Build Matrix
      • Only include IDEA versions within the last year. Prior versions are supported, but not tested. It is up to users stuck on older versions to report incompatibilities and then I’m specifically fix those bugs.
        • Add 2017.2
        • Drop 2016.1.4
      • Only include Elixir versions within the last year. Prior versions are supported, but not tested. It is up to users stuck on older versions to report incompatibilities and then I’m specifically fix those bugs.
        • Add 1.5.2
        • Drop 1.3.4
      • Only include OTP versions within the last year. Prior versions are supported, but not tested. It is up to users stuck on older versions to report incompatibilities and then I’m specifically fix those bugs.
        • Add 20.1
        • Drop 18.3
    • Support not in grammar added by elixir-lang/elixir#5620 shipped with Elixir 1.5.
    • Don’t treat numeric operands to @ and unary operators as separate operations from non-numeric operands to port elixir-lang/elixir@9747e58db773c716c01c210642ec1d91475e0c83 that shipped with Elixir 1.5.0. This only kicks in if the Elixir SDK is version >= 1.5.0 or not set. With an earlier SDK, you’ll get the earlier behavior.

Bug Fixes

  • #898 - Make binary infix vs unary prefix +/- handling more robust to support one(two, - three) used in Elixir 1.5 enum.ex. - @KronicDeth
  • #901 - Call withCharSet(Charsets.UTF_8) on all GeneralCommandLines to prevent encoding errors on Windows. - @KronicDeth

Installation Instructions

3 Likes

Version 6.5.1

Donate

Thanks

  • For reporting that that Rider does not ship with MockProjectEx and my test checks probably broke the the plugin for all non-IDEA IDEs :man_facepalming: .

Changelog

v6.5.1

Bug Fixes

  • #904 - Don’t do project instanceOf MockProjectEx because not all IDEs, such as Rider, ship with MockProjectEx; instead, do a Class#getCanonicalName() check. - @KronicDeth

Installation Instructions

1 Like