KronicDeth

KronicDeth

Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine)

This is a plugin that adds support for Elixir to JetBrains IntelliJ IDEA platform IDEs (DataGrip, AppCode, IntelliJ IDEA, PHPStorm, PyCharm, Rubymine, WebStorm).

It works with the free, open source Community edition of IntelliJ IDEA in addition to the paid JetBrains IDEs like Ultimate edition of IntelliJ. No feature is locked to a the paid version of the IDEs, but the plugin works best in IntelliJ because only IntelliJ supports projects with different languages than the default (Java for IntelliJ, Ruby for Rubymine, etc).

The plugin itself is free. Once you have your IDE of choice installed, you can install this plugin.

https://github.com/KronicDeth/intellij-elixir

Showing Posts 41 to 50

KronicDeth

KronicDeth OP

v6.7.0

Donate

Thanks

  • For reporting performance issues with nesting anonymous functions
  • For helping with parser change ideas
  • For reporting general performance issues

Changelog

v6.7.0

Enhancements

  • #943 - @KronicDeth
    • Regression test for #580
    • {EOL}|.{ANY} in Elixir.flex
    • Convert (some) unimportant newlines from EOL to WHITE_SPACE token, as GrammarKit is smarter about reparsing when only WHITE_SPACE changes in size.
      • After
        • fn
        • do
        • ->
        • block identifier (after, catch, else, and rescue)
        • keyword pair colon
        • (
      • Before
        • Comments

Bug Fixes

  • #943 - @KronicDeth
    • Remove !stabOperationPrefix before expression, since stabOperationPrefix itself starts with expression and instead put a negative look-ahead, !(infixComma | stabInfixOperator) after expression. This now works when it previously didn’t because COMMA was added to expressionRecoverUntil, which means both COMMA and STAB_OPERATOR are now in both not eaten by expression’s error recovery.

      This drops Fn1 through Fn8 to ~176ms instead of the previous time of the last optimization of 13 seconds for Fn8. It started at 26 seconds and now it appears that the time no longer grows with the number of fn. It also eliminates the pause when hitting entering inside the fn nesting.

      Data and Chart

Installation Instructions

KronicDeth

KronicDeth OP

Version 7.0.0

Donate

Thanks

  • For reporting that mix credo spiking the CPU can make IntelliJ appear sluggish while its using mix credo for annotations.
  • For explaining how to properly switch invalidate the parsed files when the Elixir level changes when the SDK changes

Changelog

v7.0.0

Enhancements

  • #944 - @KronicDeth
    • Eliminate the majority of the eolStar parser rules around operators where they do not matter leaving only the eolStar after COMMA and the the ones that help differentiate unary and binary +/-. This simplifies the parser and under certain conditions should prevent reparsing when only WHITE_SPACE changes in size.
      • Look-ahead in the lexer, where it’s cheaper than the parser to see if the next token does not care if there’s an EOL or normal WHITE_SPACE.
      • After operators that don’t care if they are followed by EOL, try to match all following WHITE_SPACE, ESCAPED_EOL and EOL.
  • #950 - @KronicDeth
    • If you want to limit the performance impact of the credo annotator because mix credo spikes your CPU, you can limit the number of mix credo runs to 1 per open file by disabling the Explanation tooltip

      1. Preferences > Editor > Inspections > Credo
      2. Uncheck “Include Explanation”

      If you don’t want the annotator to run at all on open editors, then you can disable the paired
      inspection

      1. Preferences > Editor > Inspections
      2. Uncheck Elixir > Credo

      If you’ve unchecked the inspection, it disables both the annotation and the pair inspection when Analyze > Inspect Code… is run. You can still run the Credo inspection by name.

      1. Analyze > Run Inspection By Name… (⌥⇧⌘I)
      2. Type “Credo”
      3. Select “Credo” from the shortened list
      4. Hit Enter.

      You’ll be presented with a “Run ‘Credo’” dialog

      1. Change the “Inspection scope” from “Whole project”, which would include the deps to “Custom scope”
      2. Select “Project Production Files” from the “Custom scope” dropdown
      3. Click “OK”
  • #951 - @KronicDeth
    • Setup VirtualFilePointerManager during ParsingTestCase
    • Put LineMarkerInfo on leaf elements for Method (Call Definition) Separators for a performance improvement.
    • Add IntelliJ IDEA 2017.3 to the build matrix

Bug Fixes

  • #947 - When the SDK changes, record what Release of Elixir is used indirectly, using a Level enum that only cares about the major and minor version. Changing the Level, will mark the open files and .beam files as invalidated, so that if the SDK is changed, the stubs and code Level will agree, so there isn’t a stub incompatibility with the PSI. - @KronicDeth
  • #950 - Allow credo section to be empty when processing credo explanations - @KronicDeth
  • #951 - @KronicDeth
    • Prevent negative indent, not supported in 2017.3
    • Cleanup SDKs from MixProjectImportBuilderTest

Incompatible Changes

README Updates

Credo

Annotator

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

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

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

Inspection

Batch Mode

If you’d like to run the mix credo external annotator when it is disabled, you can run it using the inspection name.

  1. Analyze > Run Inspection By Name… (⌥⇧⌘I)
  2. Type “Credo”
  3. Select “Credo” from the shortened list
  4. Hit Enter.

You’ll be presented with a “Run ‘Credo’” dialog

  1. Change the “Inspection scope” from “Whole project”, which would include the deps to “Custom scope”
  2. Select “Project Production Files” from the “Custom scope” dropdown
  3. Click “OK”

The Inspections Result Tool Pane will open and show results as each file is processed.

  1. Click the :play_button: to expand the Credo section to show all warnings

    Individual Entry

  2. Click an entry for the details of an individual warning with a code highlighting.

    Code Highlighting

    The view will show the parts of the file that aren’t annotated as collapsed with the discontinuous line number indicating the jumps.

    If you click on + collapse markers, you can expand the collapsed sections to see the full context

    Expansion

    Or you can hover over the collapsed section to see a tooltip preview of the expansion

Configuration

Preferences > Editor > Inspections Preferences > Editor > Inspections > Credo Editor Inspections
Elixir > Credo Include Explanation Highlight Message Explanation in tooltip mix credo Runs Highlight Message mix credo Runs Action
Per File Per Issue Working Directory Inspect Code Run Inspection By Name
Yes Yes Yes 1 1 Yes Yes 1 Yes Yes
Yes Yes No 1 0 Yes Yes 1 Yes Yes
ⁿ/ₐ No No No 0 0 Yes Yes 1 No Yes

If you want to limit the performance impact of the credo annotator because mix credo spikes your CPU, you can limit the number of mix credo runs to 1 per open file by disabling the Explanation tooltip

  1. Preferences > Editor > Inspections > Credo
  2. Uncheck “Include Explanation”

If you don’t want the annotator to run at all on open editors, then you can disable the paired inspection

  1. Preferences > Editor > Inspections
  2. Uncheck Elixir > Credo

Once the annotator is disabled, you can still run the inspection in batch mode

Installation Instructions

KronicDeth

KronicDeth OP

Version 7.1.0

Donate

Changelog

v7.1.0

Enhancements

  • #955 - @KronicDeth
    • Start using Kotlin for new development.
    • Elixir Facet in Small IDEs
      • Preferences > Languages & Frameworks > Elixir can set the Elixir Facet SDK for the Project Module used in Small IDEs as a per-project settings.
      • Preferences > Languages & Frameworks > Elixir> SDKs can add, delete, and configure Elixir SDKs as per-application settings.
      • Preferences > Languages * Frameworks > Elixir > Internal SDKs can add, delete, and configure Erlang SDK for Elixir SDKs as per-application settings.
    • Configure SDK before running mix when importing mix projects, so that the mix path does not need to be configured separately from the SDK path.
      • The mix path no longer needs to be setup independently from the Elixir SDK.
  • #957 - Add Local shared credo inspection, so the the credo inspection works for Code > Code Cleanup. - @KronicDeth
  • #958 - @KronicDeth
    • Show Mix ExUnit in context menu in Elixir Facets, so that

      • Run ‘Mix ExUnit …’
      • Debug ‘Mix ExUnit …’
      • "Create “Mix ExUnit …'”

      appear in Rubymine when you right-click the test directory and it is Marked as a Test Sources Root. It will appear green in Rubymine if already marked. To mark it, do the following:

      1. Right-Click test directory
      2. Select “Mark Directory as > Test Sources Root”

Bug Fixes

  • #955 - @KronicDeth
    • Protect access to JavadocOrderRootType.getInstance() so that it doesn’t cause an error in Small IDEs where its Extension Point is not defined.
    • If the explanation tooltip is empty, fallback to the message for the credo annotator instead.
  • #956 - Check if SdkAdditionalData is null before getting ErlangSDK as it can be null in certain scenarios in Rubymine. - @KronicDeth
  • #958 - @KronicDeth
    Fix isConfigurationFromContext, so that it works on Mix ExUnit Run Configurations generated from directories. Check if the programParameters and workingDirectory match by just
    generating another configuration from the context as this ensures the logic matches and includes support for PsiDirectory.

README Updates

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. Select a Project SDK directory by clicking Configure.
  7. 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.
    )
  8. 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.)
  9. Click Finish after you select SDK name from the Project SDK list.
  10. The “Mix project root” will be filled in with the selected directory.
  11. (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 local.hex --force and mix deps.get will be run.
  1. Click Next
  2. 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.
  3. Check the box next to the project root to use only its mix.exs. (It will likely be the first checkbox at the top.)
  4. Click Finish

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).

Rich IDEs

Rich IDEs can use the Project Structure system to configure Elixir and Erlang SDKs and select the Project/Module SDK.

Small IDEs

Because Small IDEs like Rubymine do not have Project Structure, the Elixir SDK, Erlang SDK, and selected SDK must be configured in Preferences.

Elixir Facet SDK

Facets are a feature of JetBrains OpenAPI that allow additional languages and frameworks to be added to a Module. In Small IDEs, each Project has only one Module and its SDK MUST match the Small IDE’s language, such as a Ruby SDK in Rubymine, so to allow an Elixir SDK to be selected, an Elixir Facet is added to the Module in Small IDEs.

To configure the Elixir Facet SDK

  1. Open Preferences > Languages & Frameworks > Elixir
  2. Select a previously created Elixir SDK from the SDK combo box.
  • If there is no Elixir SDK, you can create one first.
  1. Click Apply to save the Preferences changes or OK to save and close.
Elixir SDKs

In Small IDEs, Elixir SDKs are tracked as Application Preferences, so any Elixir SDK you create in one project will be usable in another and you won’t have to create the SDK in each project, just select it.

  1. Open Preferences > Languages & Frameworks > Elixir > SDKs

  2. Click + to add a new Elixir SDK

  3. If you don’t already have an Erlang SDK for Elixir SDK setup, you’ll need to create one first.

  4. You’ll be prompted with the default path for the most recent version of Erlang installed.

    You can change directory to a select a different version. The home directory for “Erlang SDK for Elixir SDK” for Homebrew is NOT /usr/local/Cellar/erlang/VERSION, but /usr/local/Cellar/erlang/VERSION/lib/erlang due to where the OTP app ebin directories are located.

  5. Click OK to create the Erlang SDK for Elixir SDK.

  6. With at least one Erlang SDK for Elixir SDK setup, you’ll be prompted with the default path for the most recent version of Elixir installed.

  7. Click OK to create the Elixir SDK.

  8. Click Apply to save the Preferences changes or OK to save and close.

You can further customize the Elixir SDK by selecting its name from the left list.

  • Change Home Path
  • Change Internal Erlang SDK
  • Change ebin directories on the Classpath tab
Internal Erlang SDK

If you want to change the Internal Erlang SDK, you’ll need to create a new Erlang SDK for Elixir SDK.

  1. Open Preferences > Languages & Frameworks > Elixir > Internal SDKs

  2. Follow the same steps as above to create an SDK

Installation Instructions

KronicDeth

KronicDeth OP

Version 7.2.0

Donate

Thanks

  • For reporting that OrderRootType.getOrderRootType now has a @NotNull annotation, which causes newer Small IDE releases to break when trying to access JavaDocRootType.getInstance().
  • For reporting “invokeAndWait from read-action leads to possible deadlock” warning

Changelog

v7.2.0

Enhancements

  • #963 - mix runs will be faster as they will no longer check to see if the SDK is updated. - @KronicDeth

Bug Fixes

  • #963 - Avoid problems with read and write locks when updating Elixir SDK on-demand by instead updating them when any project is open using a project converter. - @KronicDeth
  • #964 - JetBrains/intellij-community@9adbba0 added @NotNull to OrderRootType.getOrderRootType, which JavaDocRootType.getInstance calls, which means any Small IDE using intellij-community since 4 months ago, including the newest CLion cannot have JavadocOrderRootType.getInstance safely called. - @KronicDeth
  • #966 - Path changes were not being written back to disk because the projectSdksModel.apply() was being called before the editor.apply(), which would have copied to the editor's path changes to the projectSdksModel. - @KronicDeth

Installation Instructions

KronicDeth

KronicDeth OP

Version 7.2.1

Donate

Thanks

  • For reporting that .bat was no longer needed on WIndows
  • For reporting that Credo annotator broke on Elixir scratch files
  • For reporting that another read action wrapper was needed in the Mix project importer
  • For reporting ExternalLanguageAnnotators.allForFile was being called with a null PsiFile
  • For reporting the Credo annotator, in certain projects, severely slows down the responsiveness of the editor.
  • For pairing with me to demonstrate the responsiveness problems
  • For reporting that configuring Erlang SDK for Elixir SDK failed when more than CLASSES and SOURCES Root Types are installed

Changelog

v7.2.1

Bug Fixes

  • #980 - Use documentionRootType to indirectly get the documentation OrderRootType in the Erlang SDK Type, so that it works in Small IDEs that have more than CLASSES and SOURCES root types installed. - @KronicDeth
  • #981 - @KronicDeth
    • The credo annotator is disabled by default as numerous users find running mix credo in the background has a negative impact on their system performance. If you like to try enabling the annotation, you can turn it on using the configuration.

      1. Preferences > Editor > Inspections > Elixir
      2. Check “Credo”
      3. Click OK to save and close Preferences

      If you notice a degradation the in the responsiveness of the editor, it is recommended you disable the annotator again.

      1. Preferences > Editor > Inspections > Elixir
      2. Uncheck “Credo”
      3. Click OK to save and close Preferences
  • #982 - Protect from PsiFile being null in Local credo inspector - @KronicDeth
  • #983 - Run Qualified#moduleName getText in Read Action. - @KronicDeth
  • #985 - Scratch Files have a Project, but not a Module, so change flow to use Project when Module is null in credo annotator. - @KronicDeth
  • #986 - Don’t add .bat to mix on Windows. mix is never run as an executable. It is either run as a script to elixir.bat OR as an argument to erl.exe when erl.exe is running elixir. - @KronicDeth

README Updates

Credo

Annotator

When enabled, 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.

Enable

The credo annotator is disabled by default as numerous users find running mix credo in the background has a negative impact on their system performance. If you like to try enabling the annotation, you can turn it on using the configuration.

  1. Preferences > Editor > Inspections > Elixir
  2. Check “Credo”
Disable

If you notice a degradation the in the responsiveness of the editor, it is recommended you disable the annotator again.

  1. Preferences > Editor > Inspections > Elixir
  2. Uncheck “Credo”

Installation Instructions

KronicDeth

KronicDeth OP

Version 7.3.0

Donate

Thanks

Changelog

v7.3.0

Enhancements

  • #1015 - @KronicDeth
    • Add supplemental file editor for .beam files: “BEAM Chunks”. The decompiled binary file will continue to be shown on the default “Text” editor tab.
  • #1021 - @KronicDeth
    • Support for Remove incorrect wording regarding test cases · elixir-lang/elixir@23c7542 · GitHub

      Version Struct Started Event Finished Event %ExUnit.Test{} field
      < 1.6.0 %ExUnit.TestCase{} :case_started :case_finished case
      >= 1.6.0 %ExUnit.TestCase{} :module_started :module_finished module

      Because Elixir 1.6.0 could not introduce a breaking change, the < 1.6.0 events are fired, but resources/exunit/1.6.0/team_city_ex_unit_formatting.ex will ignore them and only convert the >= 1.6.0 events to TeamCity event used in the JetBrains Test Runner UI.

  • #1018 - Expose Declarations > Functions and Declarations > Macros in Color Settings - @dimcha

Bug Fixes

  • #1019 - Don’t use StreamEx because support is inconsistent across IDEs - @KronicDeth

README.md Updates

.beam Files

.beam files are the compiled version of modules on the BEAM virtual machine used by Elixir and Erlang. They are the equivalent of .class files in Java.

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

.beam files have 2 editors registered: decompiled Text and BEAM Chunks

file Editor Tabs

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.

BEAM Chunks

.beam files are composed of binary chunks. Each chunk is formatted

Offset +0 +1 +2 +3
0 Name (ASCII Characters)
4 Length (`unsigned-big-integer`)
8+ Chunk-Specific

This format is generically referred to as Type-Length-Value

The BEAM Chunks editor tab is subdivided into further tabs, one for each chunk in the .beam file.

BEAM Chunks editor chunk tabs

The tabs are listed in the order that the chunks occur in the .beam file.

Atom / AtU8

The Atom chunk holds LATIN-1 encoded atoms while AtU8 chunk holds UTF-8 atoms. There will only be one of these atom-related chunks in any given .beam file. AtU8 is used in newer versions of OTP that support UTF-8 atoms. AtU8 was introduced in OTP 20.

Format
Offset +0 +1 +2 +3
0 atom count (`unsigned-big-integer`)
4 length1 (`unsigned-byte`) bytes (for length1)
4+length1+...+lengthn-1 lengthn (`unsigned-byte`) bytes (for lengthn)
Tab

The Atom/AtU8 tab shows a table with the columns

Column Description Source
Index 1-based to match Erlang convention. In the Code chunk, atom(0) is reserved to always translate to nil Derived
Byte Count The byte count for the atom’s bytes Raw
Characters From encoding the bytes as LATIN-1 for Atom chunk or UTF-8 for AtU8 chunk Derived

Attr

The Attr chunk holds the module attributes, but only those that are persisted. Erlang module attributes are persisted by default, but in Elixir module attributes need to be marked as persisted with Module.register_attribute/3

Format

The Attr chunk uses External Term Format (term_to_binary’s output) to encode a proplist, which is similar to, but not quite the same an Elixir Keyword list

All modules will have a :vsn attribute that is either set explicitly or defaults to the MD5 of the module.

Tab

The Attr tab shows a table with the columns

Column Description Source
Key Attribute name Raw
Value Attribute value. Note: The value always appears as a list as read from the binary format. I don’t know why. Raw

CInf

The CInf chunk is the Compilation Information for the Erlang or Erlang Core compiler. Even Elixir modules have it because Elixir code passes through this part of the Erlang Core compiler

Format

The CInf chunk uses External Term Format (term_to_binary’s output) to encode a proplist, which is similar to, but not quite the same an Elixir Keyword list

Tab

The CInf tab shows a table with the columns

Column Description Source
Key Option name Raw
Value Inspected value Raw

Code

The Code chunk contains the byte code for the module.

Format

It is encoded in BEAM Compact Term Encoding, which differs from the binary format produced by term_to_binary.

Tab

The Code tab shows a read-only editor with one byte code operation on each line. For ease of reading, operations are grouped by function and then label block with indentation indicating scope.

By default as many references to other chunks and references to other parts of Code chunk are inlined to ease understanding. If you want to see the raw byte code operations, you can turn off the various inliners.

####### Controls

Control On Off
Inline Atoms atom(0) is inlined as nil atom(N) if "Inline Integers" is Off
atom(n) looks up index `n` in `Atom`/`AtU8` chunk and inlines its `inspect`ed version N if "Inline Integers" is On and the argument supports "Inline Integers"
Inline Functions literal(n) looks up index n in FunT chunk and inlines the name if the argument supports "Inline Functions" literal(n) if "Inline Integers" is Off
n if "Inline Integers" is On and the argument supports "Inline Integers"
Inline Imports literal(n) looks up index n in ImpT and inlines it as a function reference: &module.name/arity if argument supports "Inline Functions" literal(n) if "Inline Integers" Is Off
n if "Inline Integers" is On and the argument supports "Inline Integers"
Inline Integers atom(n) and literal(n) inline as n if argument supports "Inline Integers" atom(n), integer(n), and literal(n)
integer(n) inlines as n
Inline Labels label(n) inlines as n if argument supports "Inline Labels" label(n)
Inline Lines line(literal(n)) looks up index `n` in the "Line Reference" table in the `Lines` chunk. The Line Reference contains a file name index and line. The file name index is looked up in the "File Name" table in the `Lines` chunk. The line from the Line Reference and the File name from the "File Name" table are inlined as `line(file_name: file_name, line: line)`. line operations are left as is
Inline Literals literal(n) looks up index n in LitT chunk and inlines its `inspect`ed version if the argument supports "Inline Literals" literal(n)
Inline Local Calls label(n) finds label(n) in Code chunk, then searches back for the previous func_info operation, then inlines it as a function reference: &module.name/arity if argument supports "Inline Local Calls" label(n)
Inline Strings Looks up bit_length and byte_offset into `StrT` chunk as their CharList value if supported by operation as value to string argument name bit_length and byte_offsetarguments are left as is
Show Argument Names Adds keyword argument names before each argument value Leaves values as positional arguments

If any of the inliners are incorrect or you have an argument name that makes more sense, please open an issue.

Dbgi

The Dbgi chunk contains Debug Info. It was introduced in OTP 20 as a replacement for the Abst chunk. While the Abst chunk was required to contain the Erlang AST, the Dbgi format can contain the debug info for other languages, such as Elixir quoted form AST.

Format

Because the format is language neutral, the format is a set of nested, versioned formats. The outer most layer is

{:debug_info_v1, backend, metadata | :none}

For :debug_info_v1, Elixir’s backend is :elixir_erl. The metadata for :elixir_erl is further versioned: {:elixir_v1, map, specs}.

map contains the bulk of the data.

Key Value
:attributes Attributes similar to the Attr chunk, but at the Elixir, instead of Core Erlang level. Usually they match with the exception that attributes doesn’t contain vsn when Attr contains the MD5 version
:compile_opts Compilation options similar to CInf chunk’s options key, but at for Elixir, instead of Core Erlang level.
:definitions The Elixir quoted AST for reach function clause.
:file The name of the file the module was generated from.
:line The line in :file where the module was defined, such as the line defmodule occurred.
:module The name of the module as an atom
:unreachable Unreachable functions
Tab

The Dbgi tag show the single value map entries: :file, :line, and :module.

Singletons

For the multi-value keys: :attributes, :compile_opts, and :definitions, there are individual tabs.

Multivalue Tabs

####### Attributes

The Attributes tab has the same format as the Attrs chunk.

####### Compile Options

The Compile Options tab is usually empty, much like the CInf options key for Erlang.

Table

####### Definitions

The Definitions tab is split between a tree of Module, Function/Arity and clauses.

Clicking on a clause will show only that clause, but clicking on a higher level in the tree will show all clauses in the function or the entire Module.



The AST stored in the definitions tab and the process of converting it back to code is not format preserves, so it will not look precisely like the source code as the AST has undergone some macro expansion before its put in the Dbgi chunk. As common idioms are understood, reversals will be add to the renderer.

ExDc

The ExDc chunk stores ExDoc. Not the rendered HTML from the ex_doc package, but the the @doc, @moduledoc, and @typedoc attribute values that work even without ex_doc installed. This chunk is what is consulted when the h helper is used in iex.

Format

The ExDc chunk is the encoded with term_to_binary. The term format is a versioned as {version, versioned_format}. The current version tag is :elixir_docs_v1 and the versioned_format is a Keyword.t with keys matching the Code.get_docs/2 tags :callback_docs, :docs, :moduledoc, and :type_docs keys.

Tab

Like Dbgi, the ExDc tab is split between a tree to navigate and an editor to show the decompiled value.


Click on a node in the tree will show all docs at that level and any descendants.

Node Description
Root All docs
Module @moduledoc
Types All @typedocs
Types child A specific @typedoc
Callbacks All @callback @docs
Callbacks child A specific @callback’s @doc
Functions/Macros All @docs for functions/macros
Functions/Macros child A specific function/macro’s @doc
ExpT

The ExpT chunk is the Export Table. The name “Export” derives from the Erlang module attribute -export, which is used to “export” functions from a module. It is the equivalent of making a function or macro public with def and defmacro as opposed to making it private with defp and defmacrop in Elixir.

Format

The BEAM format and the ExpT chunk, being made for Erlang, has no concept of macros. It only understands functions, so Elixir macros, like __using__/1 called by use are compiled to plain Erlang functions with MACRO- prefixed to their name and an extra argument (the __CALLER__ environment) as the first argument, which increases the arity, yielding a full MFA of MACRO-__using__/2 as seen above.

Tab

The ExpT tab shows a table with the columns

Column Description Source
Atom Index Index into the Atom or AtU8 chunk for the function’s name Raw
Name The atom referenced by “Atom Index” Derived
Arity The arity (argument count) of the function Raw
Label Label index in the Code chunk where the function is defined. This label is usually immediately after the func_info operation and before the first pattern match or guard operation. Raw

ImpT

The ImpT chunk is the Import Table. It DOES NOT encode just the Erlang -import attributes or Elixir import macro calls: it tracks any external function or macro called from another module. call_ext_* operations in the Code chunk don’t store the Module and Function (MF) of the function they will call directly in the bytecode, instead, one of the arguments is an index into the ImpT chunk. This way, all external calls are normalized into the ImpT chunk instead of being denormalized to the call site. The arity still appears at the call site to help with checking the argument count.

Format

You may notice that erlang.byte_size/1 is included in the table. This is because even BIFs are referenced by MFA and not a pre-assigned number as would be the case for system calls in operating systems like Linux. BEAM is like an Operation System, but not in all ways.

Tab

The ImpT tab shows a table with the columns

Column Description Source
Index 0-based index used by references in the Code chunk. Derived
Module Atom Index Index into the Atom or AtU8 chunk for the Module’s name Raw
Module Atom The atom referenced by “Module Atom Index”. Derived
Function Atom Index Index into the Atom or AtU8 chunk for the functon’s name Raw
Function Atom The atom referened by “Function Atom Index”. Derived

LitT

The LitT chunk contains literals loaded as arguments in Code chunk.

Format

Confusingly, in the Code chunk sometimes the literal(N) term is used to encode integer N, an index into another chunk, or an actual index into the LitT. How literal terms are handled is completely dependent on the specific operation, so without having outside knowledge about the bytecode operation arguments for BEAM, the best way to figure out if literal terms are an integer or an index is to toggle the various controls in the Code tab to see if literal with no inlining turns into a LitT literal, FunT function reference, ImpT function reference, or integer.

Tab

The LitT tab shows a table with the columns

Column Description Source
# 0-based index used by references in the Code chunk. Derived
Term The equivalent of `raw > binary_to_term()

Line

The Line chunk encodes both the file name and line number for each line(literal(n)) operation in the Code chunk. The n in line(literal(n)) is an index in to the Line References table in the Line chunk. This is used in Phoenix view modules to show where code from templates comes from.

Format

The Line chunk is composed of 2 subsections: (1) Line References and (2) File Names. First there is a header setting up the number of each entry to expect.

Offset +0 +1 +2 +3
0 emulator version (`unsigned-big-integer`)
4 flags (`unsigned-big-integer`)
8 Line Instruction Count (`unsigned-big-integer`)
12 Line Reference Count (`unsigned-big-integer`)
16 File Name Count (`unsigned-big-integer`)

####### Line References

This uses the Compact Term Format used for the Code chunk. The format ends up producing {file_name_index, line} pairs using the following algorithm:

Term Interpretation
atom(n) Change file_name_index to n
integer(n) Add {file_name_index, n} to end of Line References

####### File Names

Offset +0 +1 +2 +3
0 Byte Count (`unsigned-big-integer`) Bytes
Tab

The Line tab has one subtab for each subsection in the tab. Each subsection has its own table.


LocT

The LocT chunk is the dual to the ExpT chunk: it contains all private functions and macros.

Format

You’ll notice entries like -__struct__/1-fun-0-, starts with - and have a / suffix with fun in it. This naming scheme is used for anonymous functions such as those defined with fn or the capture operator (&) in Elixir. Much like how macros don’t really exist and use a MACRO- suffix, anonymous functions/lambdas don’t exist, and instead use a distinct naming scheme -<PARENT_FUNCTION>/*fun*. Unlike MACRO-, which is an Elixir invention, anonymous functions/lambdas really being local named functions with derived names is also done in pure Erlang modules. Erlang’s anonymous functions are defined with fun, which is where the fun part of the naming scheme comes from.

Tab

The LocT tab shows a table with the columns

Column Description Source
Atom Index Index into the Atom or AtU8 chunk for the function’s name Raw
Name The atom referenced by “Atom Index” Derived
Arity The arity (argument count) of the function Raw
Label Label index in the Code chunk where the function is defined. This label is usually immediately after the func_info operation and before the first pattern match or guard operation. Raw

StrT

The StrT chunk contains all Erlang strings (that is, Elixir charlists) used in the Code chunk.

Format

The StrT chunk contains a single contiguous pool. These strings are used for byte code operations like bs_put_string. Not all strings appear in StrT. Some strings, including most Elixir strings (Erlang binaries) appear in the LitT chunk that holds literals. I’m not sure how the compiler determines whether to use StrT or LitT. I think it all depends on the byte code operation.

Instead of encoding the start and length of each string in the chunk itself, the start and length for any given string is passed as arguments to the byte code operations in the Code chunk. By doing this, shared substrings can be efficiently encoded in StrT.

Tab

StrT Pool

Installation Instructions

OvermindDL1

OvermindDL1

Wow, that’s an amazing post and a fantastic update!!

I really need to see if I can get intellij running well so as to use it, the java-built IDE is just sooooo laggy at times (nothing to do with the plugin at all, it just does that anywhere/everywhere). :slight_smile:

KronicDeth

KronicDeth OP

The default install of IntelliJ launches the JVM with a max of 750 MB. (Slack and Chrome normally use gigs of memory, so this isn’t a lot really for an IDE) It won’t ask you to increase this memory limit until its been stuck garbage collecting for tens of minutes, so usually, it ends up appearing laggy where it’s stuck GCing a lot when close to the limit.

You can turn on a memory usage display in the bottom right status bar:

  1. Open Preferences > Appearance & Behavior > Appearance.
  2. Scroll down to Window Options
  3. Check Show memory indicator

The docs for IntelliJ explain the status bar in more detail.

You can increase the max allowed memory for the JVM with

  1. Click Help > Edit Custom VM Options
  2. Change the -Xmx argument to change the max memory. m means megabytes, g means gigabytes, so a max memory of 1 gigabyte would be -Xmx1g.
  3. Save the file
  4. Click File > Invalidate Cache / Restart …
  5. Click Just Restart in the dialog

The status bar indicator should show the new max memory in the “C of DM” for C of D megabytes used.

OvermindDL1

OvermindDL1

I changed the default allocated memory long ago to 2Gigs just because of those issues in the past. ^.^

A lot of the lag just seems to be in the GUI itself though, like it can take a second to change tabs for one example of many, it’s just lots and lots and lots of little things that combine to make the overall experience feel ‘slow’. Eclipse has the same problems. And it’s the same experience on Windows 10 and multiple linux machines thus far.

KronicDeth

KronicDeth OP

Version 7.4.0

Donate

Thanks

Changelog

v7.4.0

Enhancements

  • #1036 - @KronicDeth
    • Clean up debugger
      • mix format debugger
      • Restructure debugger.
      • Convert IDE-side to Kotlin
    • Allow files to skip interpreting in the debugger to be configured in Preferences > Build, Execution, Deployment > Debugger > Stepping. It is recommended to customize these settings instead of using INTELLIJ_ELIXIR_DEBUG_BLACKLIST environment variable. INTELLIJ_ELIXIR_DEBUG_BLACKLIST should be reserved to additional modules that need to not be interpreted only for specific runs.
      • Ship a set of patterns that excludes Elixir standard library by default and most mix phx.new dependencies, so that debugger boots faster for most users.
    • Support debugging .eex templates
      • Detect MFAs that refer to template functions in Phoenix view modules derived from .eex template files, to allow stepping through Elixir tags in those templates.
      • Allow setting breakpoints in .eex files when a .beam file using the template’s relative can be found. This means that the Phoenix view module .beam file must exist in _build prior to setting a breakpoint. Run the Run Configuration once, before debugging to complete the build if setting a breakpoint does not work.
        • .beam files are now indexed by their Line chunk filenames subsection to power this feature.
    • Cache .beam Beam Cache on VirtualFile. Cache is invalidated and refreshed on modification of the VirtualFile. Cache is used for both BEAM Chunks read-only editors and Line chunk file name index.
  • #1037 - Each package manager uses a different root path and which directory to pick above the ebins varies by package manager, so document package manager install paths. - @KronicDeth
  • #1041 - @KronicDeth
    • Restructure JPS code to remove prefixes and suffixes in class names that redundant with package names.
    • Show warnings-as-errors checkbox as original blocker has been fixed for awhile and ProcessAdapter turns warning text into errors that IDE understands.
  • #1045 - @KronicDeth
    • When importing Mix projects, don’t exclude compiler output from indexing because it is needed to resolve Elixir Line Breakpoints in EEx files.
      • For pre-existing Elixir modules, they will be converted to not exclude compiler output.
  • #1047 - @KronicDeth
    • Exclude known uninterpretable modules
      • Bcrypt.Base
      • :erocksdb
      • :lz4
      • :re2

Bug Fixes

  • #1036 - @KronicDeth
    • Turn off dbeug flag when starting IntelliJElixir.DebugServer, which removes the *DBG* statements that kept printing in the ExUnit output when using the debugger.
    • Fix conversion of Elixir module names to Erlang module names for INTELLIJ_ELIXIR_DEBUG_BLACKLIST environment variable.
    • Cache null SDK Release, so that when Elixir is configured, but the Erlang path is broken (such as after a brew unlink erlang, the Release calculating using elixir
    • Implement Macro.atomToString
    • Properly render improper lists
      • Show improper list with explicit | for presenation
      • Children of improper lists show head and tail instead of index.
    • Show Elixir indices (0-based) instead of Erlang indices (1-based`) for lists and tuples.
  • #1037 - Loosen check on the path suffix by looking for only lib and not lib/erlang/lib, so that it works for both Homebrew’s ebin paths and ASDF’s ebin paths. - @KronicDeth
  • #1041 - @KronicDeth
    • Remove unused MixBuilder because building with mix is just an option in ElixirBuilder.
    • Harmonize JPS compile server’s invoking of mix to pattern used in Run Configuration runners.
      • Use mix path from SDK
    • No longer say the build succeeded when there are obvious mix errors
      • Parse mix compile output for compilation errors and warnings
        • When “warnings-as-errors” is enabled in “Elixir compiler” settings, IDE also shows warnings as errors.
        • IDE will know build failed if there are errors (or warnings treated as errors) and properly allow rebuild.
  • #1045 - @KronicDeth
    • Group alternatives in erlang_module_name_patterns_to_regex before pinning: I always forget that the | swallows the ^ and $ in regexes.
    • Reject vs filter accumulation got flipped when switching to Enum.reduce to track rejections.
  • #1047 - @KronicDeth
    • Some modules, like NIF modules, can’t be loaded into the debugger. Individual modules not being debuggable shouldn’t kill the debugger task, so rescue the known error and record it for later debugging of the debugger.
    • Add : to start of Erlang module names for included debugger excludes

README updates

Debugger

Basics

Excluding Modules

By default, the debugger will scan all the load paths and build path for .beam files and the corresponding modules will be interpreted which causes the Module’s Erlang abstract code chunk to be interpreted in Erlang instead of the bytecode chunk being executed in the C parts of the BEAM. This interpretation is much slower than execution, so by default all of the Elixir standard library and the common modules installed in Phoenix projects are excluded from being interpreted when the debugger starts. The modules can be still be stepped into or have breakpoints explicitly set.

  1. Preferences > Build, Execution, Deployment > Debugger > Stepping
  2. Scroll to Elixir

You can customize these module patterns as an application setting.

Disabling Existing Module Patterns
  1. Preferences > Build, Execution, Deployment > Debugger > Stepping
  2. Scroll to Elixir
  3. Click the Checkbox next to the pattern you want to disable
  4. Click Apply to save or OK to save and close Preferences

Editing Existing Module Patterns
  1. Preferences > Build, Execution, Deployment > Debugger > Stepping
  2. Scroll to Elixir
  3. Click the pattern text box
  4. Click Apply to save or OK to save and close Preferences

Edit

Removing Existing Module Patterns
  1. Preferences > Build, Execution, Deployment > Debugger > Stepping
  2. Scroll to Elixir
  3. Click the row of the pattern you want to remove
  4. Click the “-” Remove button.
  5. Click Apply to save or OK to save and close Preferences

Remove

Adding New Module Patterns
  1. Preferences > Build, Execution, Deployment > Debugger > Stepping
  2. Scroll to Elixir
  3. Click the “+” Add button
  4. Click the default “*” pattern to edit it
  5. Click Apply to save or OK to save and close Preferences

Add

Environment Variables

If you want to customize the modules to ignore on a per-Run-Configuration basis, you can set an environment variable in the Run Configuration.

Variable Example Description
INTELLIJ_ELIXIR_DEBUG_BLACKLIST iconv,some Excluding modules from debugger

Notice: If you want non Elixir. module in blacklist, write it with: :. This rule applies only to module atoms.

Breakpoints

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. Line break points can be set in .ex and .eex files.

.eex line breaks will only work on Elixir code that is used in Phoenix view modules.

.eex breakpoints only work if a .beam file using the template’s relative can be found. This means that the Phoenix view module .beam file must exist in _build prior to setting a breakpoint. Run the Run Configuration once, before debugging to complete the build if setting a breakpoint does not work.

  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

Building/Compiling

Settings

  • Compile project with mix (use mix compile instead of elixirc directly)
  • Attach docs (don’t use --no-docs elixirc flag)
  • Attach debug info (don’t use --no-debug-info elixirc flag)
  • Warnings as errors (use --warnings-as-errors elixirc flag)
  • Ignore module conflict (use --ignore-module-conflict elixirc flag)

Build Messages

If a file has errors and warnings, they are group together in Build Messages under that file.

Jump To Source

You can jump to errors and warnings in the Build Messages

  1. Highlight the error or warning you want to jump to source

  2. Do one of the following

    1. Right-Click the error or warning

    2. Select Jump to Source from the context menu

      Jump to Source

    OR

    1. Click the error or warning
    2. Press Cmd+Down

You can also turn on Autoscroll to Source, which will Jump To Source whenever you Click or select an error or warning.

Warnings as Errors

Setting

If you enable Warnings as Errors in the settings, then the Warnings will be treated as Errors by elixirc and mix and the Build Messages will show the Warnings as Errors.

Messages

If only warnings remain in the source.

With Warnings as Errors On, all the Warnings will appear as Errors and still fail the build

With Warnings as Errors Off, the Warnings will appear as Warnings and the build will succeed

SDK

Package Manager Install Locations

When configuring an SDK, if you don’t want to use the suggested SDK home path, you’ll need to know where each package manager puts Elixir and Erlang.

Package Manager SDK Type Directory
ASDF Elixir SDK ~/.asdf/installs/elixir/VERSION
Erlang SDK ~/.asdf/installs/erlang/VERSION
Erlang for Elixir SDK
Homebrew Elixir SDK /usr/local/Cellar/elixir/VERSION
Erlang SDK /usr/local/Cellar/erlang/VERSION/lib/erlang
Erlang for Elixir SDK
Nix Elixir SDK /nix/store/SHA256-elixir-VERSION/lib/elixir
Erlang SDK /nix/store/SHA256-erlang-VERSION/lib/erlang
Erlang for Elixir SDK

If you can can’t see hidden files, such as .asdf in your home directory (~), or system directories, such as /usr, you will need to enable Show Hidden Files in the Home Path dialog.

If your dialog looks like this, click the Show Hidden Files button

IntelliJ

If you’re using the macOS native File Picker, use the keyboard shortcut ⌘⇧. (Command+Shift+Period).

Installation Instructions

Where Next? Top

Trending in Announcing Top

woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
anuaralfetahe
Hello Published a new library - ProcessHub! ProcessHub is a library designed to manage process distribution within the Elixir cluster. ...
New
rodloboz
I’ve started working on a new library to run SQL queries and do basic business intelligence. Think “Blazer for Elixir.” Currently it fe...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
sergio
It’s not that it’s vocabulary is too advanced. It’s something worse. I get lost trying to follow even a paragraph written by Claude. It’...
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews