intellij-elixir

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

OTHER License

Stars
1.8K
Committers
55

Bot releases are visible (Hide)

intellij-elixir - v10.0.0

Published by KronicDeth almost 6 years ago

Thanks

  • For reporting the new for a runWriteAction when adding new JDKs in Small IDES
  • For reporting that a modular element could become invalid during completion and not have a valid containing file.
  • For reporting that :crypto wasn't in the default module filters even though its NIFs can't be interpreted.
  • For reporting that the redefinition of defmodule in distillery broke the GoTo Symbol contributor.
  • For reporting "Test framework quit unexpectedly" being reported instead of showing the compilation errors during tests, which turned out to be a deprecation in OpenAPI and a change in ExUnit output in Elixir 1.7 I missed.
  • For reporting that Elixir was bigger than Erlang, or at least the icons in IntelliJ 2018.3 EAP :trollface:.
  • For reporting poor error message when removing module filters
  • For reporting that I can't make the fact that there is no use call a cache dependency
  • For reporting that completion with nested modules was broken
  • For reporting that alias __MODULE__, as: Mod did not work for resolving references through Mod.

Changelog

v10.0.0

Enhancements

  • #1272 - @KronicDeth
    • Go To Symbol and completion will only resolve in project source unless non-project sources are turned on.
      • deps are properly marked as Libraries and no longer count as being in the project scope for the Go To tools.
      • In umbrella projects, when in_umbrella is used, the Project Module for each apps/#{APP_NAME} will be marked a dependency,
      • Library and Modules are properly connected as dependencies, so that only declared dependencies will resolve, lessening false completions and declarations when different OTP app share common Module or function names.
    • deps and the _build/#{MIX_ENV}/lib/#{DEP_NAME} will be marked as Excluded, so that Libraries appear in External Libraries at the bottom of the Project Pane.
  • #1275 - @KronicDeth
    • Go To Class action (Cmd+O) to go to modules separately from all functions as would happen with Go To Symbols (Alt+Cmd+O).
      • New ModuleName index keeps track of only the names of modulars:

        • defmodule
        • defimpl
        • defprotocol

        It is used to power gotoClassContributor for Go To Class action.

  • #1280 - Handle commit and override for Mix.Dep. - @KronicDeth
  • #1283 - Add .eex to .ex and .exs for accepted file extensions used to hyperlink files in stacktraces. - @KronicDeth
  • #1285 - @KronicDeth
    • Resolve unaliased name when using alias __MODULE__, as: Mod
    • Resolve usage of Mod in alias __MODULE__, as Mod
      1. Mod
      2. __MODULE__ in alias __MODULE__
      3. defmodule MyModule that is enclosing __MODULE__.
    • Disable ProcessCanceledException for runIde gradle task, to allow for easier manual testing of completion and Go To actions during development.
    • Completion of functions in current module when using Mod. after alias __MODULE__, as: Mod.
    • Show more context for alias calls in presentations, like "Choose Declaration" pop up for Go To Declaration.
      • Show resolved __MODULE__ name (alias MyModule) when using alias __MODULE__.
      • Show full alias MyModule, as: Mod when listing Mod in alias __MODULE__, as Mod.
  • #1293 - @KronicDeth
    • Exclude common directories when importing projects
      • cover for test coverage
      • doc for ex_doc
      • logs for log files
      • assets/node_modules/phoenix for phoenix
      • assets/node_modules/phoenix_html for phoenix_html
    • Setup Libraries and Module dependencies when importing projects from Mix.
  • #1299 - Regression test for #1270. - @KronicDeth
  • #1313 - @KronicDeth
    • Update gradle wrapper to 3.5 to allow for environment variable overrides
    • Setup datetime based pre-release versioning to ensure that correct version of pre-release plugin is used when testing Install Plugin From Disk.
  • #1318 - @KronicDeth

Bug Fixes

  • #1277 - Don't include null useCall as __MODULE__ dependency. - @KronicDeth
  • #1279 - @KronicDeth
    • Wrap LibraryTable#removeLibrary in write action.
    • Wrap Library#modifiableModule#commit in write action.
  • #1282 - Check if Mix.Dep has already been seen to prevent recursive loops. - @KronicDeth
  • #1287 - @KronicDeth
    • More closely match ExUnit.CliFormatter output in Test Runner.
      • Don't inspect ExUnit failure reason as ##teamcity message.
      • Add captured logs to failure
      • Colorize test failures - including diff colorization
    • .formatter.exs input globs would not match file paths because it was default that needed lib on top and not version-dependent paths used in resources/exunit.
  • #1291 - @KronicDeth
    • Ignore branch and hex options when finding path of Mix.Dep
    • Map Elixir 1.7 :excluded and :skipped (added in elixir-lang/elixir#7245) to testIgnored teamcity message, thereby restoring ignored test counts and markers from Elixir 1.6.
  • #1293 - @KronicDeth
    • When the entire deps directory has updated sync the children deps directories and then sync all modules instead of syncing them after each dep.
    • For an unknown reason, when sync occurs at initComponent time in DepsWatcher or mix.Watcher, the child directories of the project basedDir aren't shown in the Project Pane until a change is applied in Project Structure.
    • Use invokeAndWait instead of invokeLater to ensure order of syncs.
  • #1299 - When finding a defmodule, check that it is an ancestor of the entrance of the ResolveState, so that nested sibling modules are not scanned for potential call definition clauses, but only the outer module of the entrance. - @KronicDeth
  • #1300 - Improve error message for org.elixir_lang.debugger.settings.stepping.module_filter.editor.table.Model.getValueAt, so we can detect if there is an off-by-1 error. - @KronicDeth
  • #1304 - Remove @2x and @3x SVG icons that render wrong size in 2018.3 EAP. - @KronicDeth
  • #1305 - @KronicDeth
    • Fix unused variables in TeamCityExUnitFormatting
      • reason was completely unused.
      • details should have been used.
  • #1306 - @KronicDeth
    • flushBufferBeforeTerminating was deprecated and in newer IntelliJ the call to processStatuses does not occur unless flushBufferOnProcessTermination is also overridden.
    • Treat == Compilation error in STDOUT as ERROR for ExUnit reporter
    • Convert (CompileError) of a test file to test failure. The "Test framework quit unexpectedly" is converted to a failed run with a single test with the compilation error as the failure message.
  • #1308 - @KronicDeth
    • Don't treat redefinition of defmodule macro as module definition (as occurs in @bitwalker's distillery's Mix.Tasks.Release.Init.MixMock
      • Bump AllName VERSION to re-index and drop bad call definition head from #1301.
  • #1310 - Don't log compilation errors as test failures unless a test has started. Test name being called mix test does not work, so log those compilation errors as normal build messages instead. - @KronicDeth
  • #1311 - Don't interpret :crypto by default: :crypto includes NIFs that can't be reloaded and so kills the debugger. - @KronicDeth
  • #1312 - Protect from null containingFile for modular names during completion. - @KronicDeth
  • #1313 - Wrap syncPublisher(JDK_TABLE_TOPIC) in invokeLater runWriteAction. - @KronicDeth

Incompatible Changes

  • #1272 - @KronicDeth
    • Dependencies are now counted as external to the project, so the Go To tools, like Go To Symbol will no longer include matches for both project sources and dependencies sources together, instead they will follow the more JetBrains native behavior
      • Project sources will be shown by default
      • If there are no project matches, dependencies will be shown instead.
      • If you want to include dependency (non-project) matches, you can check the box or hit Cmd+O.
  • #1293 - Modules and Libraries won't be automatically setup when a project or module is opened, but instead only when apps or deps directories or subdirectories change. - @KronicDeth

README Updates

Installation

Canary releases

Builds on master will produce pre-release builds of format NEXT_VERSION-pre+YYYYMMDDHHMMSS.

Inside IDE using JetBrains repository

You will need to add the canary repository once to your IDE:

  1. Preferences
  2. Plugins
  3. Browse Repositories
  4. Manage Repositories
  5. Click +
  6. Enter the IntelliJ Elixir canary URL: https://plugins.jetbrains.com/plugins/list?channel=canary&pluginId=7522
  7. Click OK
  8. Click OK to close the Custom Plugin Repositories dialog.

With the canary repository setup:

  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 latest pre-release zip.
In IDE
  1. Preferences
  2. Plugins
  3. Install plugin from disk...
  4. Select the downloaded zip.
  5. Apply
  6. Restart the IDE.
intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181026005139

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025235555

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025233115

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025230421

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025192802

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025025704

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025024310

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025023243

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025022131

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025020337

Published by KronicDeth almost 6 years ago

intellij-elixir - https://github.com/KronicDeth/intellij-elixir/releases/tag/v10.0.0-pre+20181025005945

Published by KronicDeth almost 6 years ago

intellij-elixir - v9.0.0

Published by KronicDeth about 6 years ago

Thanks

  • For reporting that renaming variables didn't work on bracket operations, which reminded me I still had the feature open to resolve bracket operation identifiers from 2016(!).
  • For reporting that they wanted Go To Source and Go To Decompiled to be separated
  • For let me know that some users were like me and liked being able to jump to decompiled code, which was the impetus for Go To Related support after Go To Declaration switched to preferring source.
    • Kimberly Milner (at ElixirConf 2018)
  • For reporting that I broke completion through imports when I did the Kotlin conversion back in v7.5.0 (released June 5th 2018) 🤦‍♂️

v9.0.0

Enhancements

  • #1255 - @KronicDeth
    • Resolve calls through use AnAlias calls
      1. AnAlias will be resolved to its modular (module, implementation, or protocol)
      2. The __using__ macro in the modular is found
      3. The last call in __using__ is checked
      • If it is a quote block, check for call definitions recursively inside the block

      • If it is an apply/3 call

        1. Resolve the first argument as a modular
        2. Scan for each function in modular
        3. In each function Goto Step 3 above

        This handling is what specifically makes use MyAppWeb, :controller in Phoenix apps now work.

      • If it is a general call

        1. Resolve the call to its definition
        2. Goto Step 3 above
  • #1259 - @KronicDeth
    • Go To Related (Ctrl+Cmd+Up) can be used to Go To the decompiled Module or call definitions when on a source modular (defimpl, defmodule, or defprotocol) or callable (def, defp, defmacro, defmacrop). This somewhat restores the ability to go to both source and decompiled module and calls before 9.0.0, but now the source is preferred for Go To Declaration and the decompiled will only be available if there is no source and if you definitely want decompiled, you'll need to use Go To Related.

Bug Fixes

  • #1245 - Specify that Kotlin Plugin is needed in CONTRIBUTING.md, so IntelliJ plays nice. - @sfat
  • #1246 - @KronicDeth
    • Resolve unqualified bracket operation identifiers (var in var[key]) to variables or 0-arity calls.
      • Fixes renames of variables not renaming usage of variables for Access lookups (i.e. var[key]).
  • #1248 - @KronicDeth
    • Go To Symbol will no longer show redundant entries
      • Call Definitions (name/arity) is no longer shown if the Call Definition Clause is also included. This isn't a large loss because the /arity was not searchable and only part of the presentation.
      • If there is a decompiled and a source version of a symbol, only the source version will be shown.
        • The source Implementation will be shown and not the decompiled Module with the same fully-qualified name (<protocol>.<for>).
      • Items will be deduped if they point to the same element, such as function clauses with default arguments because when presented they look the same even if internally one is representing /1 and /2, for example.
  • #1249 - Ensure that Go To Declaration for qualified calls such as Module.function(...) where Module is an alias does not return the decompiled version of Module when the source is available. - @KronicDeth
  • #1256 - @KronicDeth
    • Fix completion not working for unqualified functions from imports.
      • When I switched to using ?.let I accidentally hid the if from running when there was no ENTRANCE_CALL_DEFINITION_CLAUSE, so the correct form is add if there is no entrance or if there is a non-equivalent entrance.
      • I just straight up forgot an ! on a contains check. I moved to computeIfAbsent, so it is more obvious what the intent is.

Incompatible Changs

  • #1248 Go To Symbol and Go To Declaration will no longer suggest decompiled modules or functions if source modules or functions of the same name or module/name/arity exists. - @KronicDeth

README updates

Features

Go To Related

Go To Related is like Go To Declaration, but more general, for anything that is related to an element, but not its declaration.

In IntelliJ Elixir, Go To Related can be used to go to the decompiled version of a modular (defimpl, defprotocol, or defmodule) or a callable (def, defp, defmacro, defmacrop) definition.

Decompiled Module

  1. Place the cursor on the name of the modular, such as EExTest.Accounts in defmodule EExTest.Accounts do
  2. Go To Related
    • Navigate > Related Symbol
    • Ctrl+Cmd+Up
  3. Select a "Decompiled BEAM" target from the "Choose Target" context menu
    Choose Target.png
  4. You will be taken to the decompiled module
    Decompiled.png

Decompiled Call Definition

  1. Place the cursor on the name of the call, such as get_user! in def get_user!(id)
  2. Go To Related
    • Navigate > Related Symbol
    • Ctrl+Cmd+Up
  3. Select a "Decompiled BEAM" target from the "Choose Target" context menu
    Choose Target.png
  4. You will be taken to the decompiled module
    Decompiled.png
intellij-elixir - v8.1.0

Published by KronicDeth about 6 years ago

Thanks

  • For consulting on the design of the new flat icons to match IntelliJ IDEA 2018.2's design guidelines and showing me how to use Figma.
    • Narek Khachatryan (@nk8)
  • For reporting that Decimal.base10? could not resolve its enclosing modular
  • For reporting that completion of SDK files was broken in Small IDEs, which led to discovering the External Libraries were needed in Small IDEs for SDK indexing to occur. (Indexing of SDKs is automatic in IntelliJ IDEA.)
  • For explaining IntelliJ IDEA 2018.2's design guidlines
    • Alina Mishna
  • For providing the SVG version of the Elixir icon
    • Alina Mishna
  • For providing the Elixir icon made by Alina Mishna

Changelog

v8.1.0

Enhancements

Bug Fixes

  • #1233 - Look above Enum.reduce for enclosing macro call. - @KronicDeth
  • #1234 - @KronicDeth
    • Add Facet SDK as External Library to re-enable indexing. When the External Library was removed in 4297287 in favor of a real SDK, completion for SDK .beam modules was lost because Small IDEs don't index SDKs, but only External Libraries, so add Application-wide External Libraries for SDKs when they are created (and update, remove on edit or delete), which are then added as a Dependency for the facet's module when the SDK is set for the Small IDE project.
      • Convert old modules with Elixir facets to also have External Library, so that users don't need to remove and add the SDKs to get the External Library.
  • #1237 - @KronicDeth
    • Use #AEB9C0 for JetBrains Default/Light Gray. Use #87939A for JetBrains Darcula Gray. Colors based on IntelliJ's color picker picking its own colors.

      Icon matching testing done under both themes in 2018.2.1. Weirdly, the colors are different in the SVGs in my intellij-community@master. Hopefully, this doesn't mean the colors change again in 2018.3.

  • #1244 - @KronicDeth
    • Run createLibrary inside runWriteAction.
    • Remove test that leaks threads and so causes builds to fail.
intellij-elixir - v8.0.0

Published by KronicDeth about 6 years ago

Thanks

  • For reporting NPE in the improved version of the getPresentation
  • For reporting that the safe cast for quote bound variables wasn't so safe
  • For reporting the disassembler did not support all OTP 21 opcodes
  • For requesting spellchecking
  • For reporting that Phoenix's use of quote inside a literal [head | tail] list code not be parsed to find the parent modular.
  • For reporting that the missing Erlang SDK message wasn't clear clicking OK would take you through the setup and cancel would stop Elixir+Erlang SDK confirmation.
  • For reporting that variables use scope could not be calculated in EEx tags.
  • For reporting that @ was allowed in atoms, but not atom keyword keys.
  • For reporting that eachEbinPath did not restrict itself to directories and blow up on files.
  • For reporting that Module.aliasedName still contained assert even though it uses Normalized to protect from PsiErrors.
  • For reporting that Unaliased.down did not have a useful error message

Changelog

v8.0.0

Enhancements

  • #1175 - @KronicDeth
    • New and improved Run/Debug Configurations
      • Distillery Release CLIs for running console, foreground, etc
        Options for configuring each part of the command line
        • Path to Release CLI
        • Release CLI arguments (like a command console)
        • Settings that are normally hidden in environment variables
          • erl arguments (ERL_OPTS)
          • elixir -extra arguments (EXTRA_OPTS)
          • Code Loading Mode (CODE_LOADING_MODE)
          • Log Directory (RUNNER_LOG_DIR)
          • Replace OS Vars (REPLACE_OS_VARS)
          • sys.config file (SYS_CONFIG_PATH)
          • Release Config Directory (RELEASE_CONFIG_DIR)
          • Pipe directory (PIPE_DIR)
        • Use Pseudo-Terminal (PTY) to allow overriding console type when it can't be inferred from the Release CLI arguments, such as using PTY for console because it uses an iex-like shell.
        • Working Directory
        • Environment Variables
      • iex console with proper PTY support (colors, tab completion, history)
        Options for configuring each part of the command line
        • iex arguments
        • erl arguments
        • Working Directory
        • Environment Variables
      • elixir with colors
        Options for configuring each part of the command line
        • elixir arguments
        • erl arguments
        • Working Directory
        • Environment Variables
      • mix tasks getting expanded options to match the new configurations
        • mix arguments, which used to be called "Program Arguments" (I figured out how to customize that name. 😉)
        • elixir arguments
        • erl arguments
        • Working Directory
        • Environment Variables
      • iex -S mix
        Options for configuring each part of the command line
        • mix arguments
        • iex arguments
        • erl arguments
        • Working Directory
        • Environment Variables
      • mix test
        • mix test arguments, which used to be called "Program Arguments"
        • elixir arguments
        • erl arguments
        • Working Directory
        • Environment Variables
    • Debugger enhancements
      • All the above configurations can be debugged using the debugger. It is no longer restricted to only working with mix-based configurations.
      • Filter more common dependency modules from being interpreted by default.
        • credo
        • inch_ex
        • earmark
        • ex_doc
      • More ways to filter interpreted modules
        • Run Configurations now have an Interpreted Modules tab, next to Configuration, which by default imports the Application-wide settings, but allows
          • Disabling inherited filters
          • Adding configuration-specific filters
          • Remove configuration-specific filters
        • Allow interpreted modules to be uninterpreted when the debugger is running, using the "Interpreted Modules" tab.
      • Improved Variables pane by showing the Elixir name of variables instead of Erlang names
      • Evaluate can evaluate an Elixir expression in any stack frame.
  • #1192 - @KronicDeth
    • Add all OTP 21 opcodes to disassembler. Previous opcode set was
      frozen prior to OTP 21 release and missed some later additions.

      number name Added
      160 build_stacktrace Before OTP 21 release
      161 raw_raise Now
      162 get_hd Now
      163 get_tl Now
  • #1196 - @KronicDeth
    • Spell checking for identifiers, aliases, comments, and literals (charlists, strings, and sigils).
      • Dictionaries for common dependencies
        • Elixir
        • Ecto
  • #1203 - @KronicDeth
    • Elixir 1.7 debugger Variables and Evaluate compatibility
      • Elixir 1.7 names Erlang variables like _<elixirVariableName>@<counter> while Elixir 1.6 used V<elixirVariableName>@<counter>
      • Elixir 1.7 changed elixir_erl record and %Macro.Env{}, which changed how :elixir.quoted_to_erl needed to be called.
  • #1208 - Update 2018.2 to 2018.2.1 in build matrix. - @KronicDeth
  • #1210 - Regression test for #1141 - @KronicDeth
  • #1212 - Improve Cannot Create SDK error message (additions in bold): "You need to configure an Erlang SDK for Elixir SDK. Click OK to be take through the Erlang SDK configuration. Click Cancel to stop configuring this SDK AND the Erlang SDK." - @KronicDeth
  • #1223 - Convert mix and mix test run configurations to new format. - @KronicDeth

Bug Fixes

  • #1188 - Show ... for module name when Dbgi has no module name as happens for instrumented modules from IEx.break/4. - @KronicDeth
  • #1189 - Don't assume callDefinitionClause is non-null. - @KronicDeth
  • #1190 - Don't assume parent of list access expression is QuotableKeywordPair- @KronicDeth
  • #1191 - Don't assume parent of keywords is a list. - @KronicDeth
  • #1208 - TerminalExecutionConsole itself echos input in 2018.2 and 2018.2.1, which was introduced in https://github.com/JetBrains/intellij-community/commit/fd7bbd0cb7f3c2a5add8872e0e6c5172be5f074a#diff-5acc2eb2e78fe52d7458d4a48b0eac9f, but it was reverted in JetBrains/intellij-community@5f4465b, so this uses that version to maintain compatibility across supported versions. - @KronicDeth
  • #1210 - In Phoenix.Router.Helpers, a quote block appears as the head of [head | tail] list, so add support for search for enclosing macro call above |. - @KronicDeth
  • #1213 - Treat EEx tag the same as StabBody for use scope. - @KronicDeth
  • #1214 - Use ATOM for keyword keys instead of IDENTIFIER_TOKEN as ATOM allows for @, which is needed for correctness. - @KronicDeth
  • #1215 - In eachEbinPath, the ebin directories were found by iterating <SDK_HOME_PATH>/lib and then iterating grandchild of that, so that all paths matching <SDK_HOME_PATH>/lib/<APP>/ebin would be added, but for some installs from source, like SDK, there are non-OTP-app files in <SDK_HOME_PATH>/lib, so filter <SDK_HOME_PATH>/lib/<APP> to only directories. - @KronicDeth
  • #1216 - org.elixir.lang.psi.scope.Module.aliasedName(QualifiedAlias) was already converted to use org.elixir_lang.psi.operation.Normalized and org.elixir_lang.psi.infix.Normalized, which makes it work with errors in the PSI tree, so there's no need protect with an assert and that assert would be wrong in times of errors handled by Normalized. - @KronicDeth
  • #1217 - org.elixir_lang.reference.module.UnaliasedName.down(PsiElement) only expects ElixirAccessExpression or QualifiableAlias, but for unexpected classes of elements, it was a simple Kotlin TODO(), which didn't log anything useful for enhancements. Replace the TODO() with an org.elixir_lang.errorreport.Logger.error, so that the element's class and content can be reported when this happens again. - @KronicDeth
  • #1164 - Use / in paths passed to Erlang, even on Windows - @notriddle

Incompatible Changes

  • #1175 - Drop support for IntelliJ IDEA before 2017.3 as they lack the TerminalExecutionConsole used to run iex in a PTY. - @KronicDeth

README Updates

Features

Debugger

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, explore frames, and evaluate code when suspended.

Starting the Debugger Session

It takes awhile, once the debugged process is started to configure the debugger in BEAM. To ensure that breakpoints are setup before allow the debugged code to run, the debugger blocks until setup is complete.

  1. The debugged process will wait for the debugger to attach
    Waiting for debugger to attach.png
  2. Breakpoints will be set
  3. The debugger will mark modules to be interpreted
    1. The code paths will be scanned for .beam files
      • Code paths from the Elixir SDK will be skipped
        Skipped.png
      • .beam files will be interpreted unless they match the Module Filter Pattern
        Completed.png
  4. The debugger attaches (so it can receive breakpoint events) and allows the debugged process to continue.
    Attached.png

Examining Suspended Program

Variables

Binary.png

Binaries show each byte at the byte's offset.

Bitstring.png

Bitstrings show each byte with any partial byte annotated with its bitwidth.

Boolean.png

Boolean variables are rendered as their value.

Charlist.png

Charlists show the integer values because they're treated as lists

Functions.png

Functions don't have literal representation, so the inspect form starting with #Fun<...> is shown

Lists.png

Lists render differently based on whether the list is improper or not. Improper lists show the head and tail while proper lists show their element by offset.

Maps.png

Maps render differently based on the key type. If the map uses all atom keys, the key will equal the value in the nested children while non-atom keys are shown as entries at a specific offset with the key and value. This is done, so that complex keys that have subterms can be expanded or collapsed, which is not possible for the simpler atom rendering.

Numbers.png

Floats and integers are rendered as literals.

Pid.png

Pids are broken up into their hidden node, id, and serial`.

String.png

Strings show their literal value and unicode is fully supported.

Tuple.png

Tuples show their elements at their offsets.

Rebound.png

While Elixir allows rebinding variable names, Erlang does not, so when viewed in the Variables pane, rebound variables will have an @VERSION after their name indicating which rebinding of a the variable is.

Evaluate

When stopped at a breakpoint, you can use the Evaluate button (it looks like a simple pocket calculator) to open an editor to type code to be executed in the current stack frame.

Evaluate.png

The evaluator supports the full syntax.

Result.png

The result of evaluating the code with be shown as the value of result below the entered "Expression".

Exception.png

Typo.png

Errors in the code will report back as a result tuple with an :EXIT tag. This reflects that the error has crashed the process that was evaluating the code. Thankfully, due to how how the interpreter is written, this does not lose the current stack frame and stepping or other evaluation can continue.

Run/Debug Configurations

Distillery Release CLI Elixir Mix Icon with tapered neck to make a retort as used in distilleries

Distillery's mix release produces a CLI for running the release.

  1. Build the release: mix release
    ==> Release successfully built!
        You can run it in one of the following ways:
          Interactive: _build/ENV/rel/NAME/bin/NAME console
          Foreground: _build/ENV/rel/NAME/bin/NAME foreground
          Daemon: _build/ENV/rel/NAME/bin/NAME start
    
  2. Run > Edit Configurations...
    Edit Run Configurations
  3. Click +
  4. Select "Distillery Release CLI"
    Add New Distillery Release CLI
  5. Fill in the "Release CLI Path" with the full path to the _build/ENV/rel/NAME/bin/NAME path produed by mix release above.
  6. Fill in the "Release CLI arguments".
    • console runs a shell with the release loaded similar to iex -S mix.
    • foreground to runs the release without a shell, like mix or mix run.
      The available commands are controlled by your release config rel/config.exs that Distillery uses.
  7. (Optionally) fill in "erl arguments" with arguments to erl before it runs elixir.
    This is the same as the ERL_OPTS environment variable supported by Distillery.
  8. (Optionally) fill in "elixir -extra arguments" with arguments to pass to elixir before it run the release.
    This is the same as the EXTRA_OPTS environment variable supported by Distillery.
  9. (Optionally) change the Code Loading Mode
    This is the same as the CODE_LOADING_MODE environment variable supported by Distillery.
    • Use Default - use whatever is configured in rel/config.exs. Don't set CODE_LOADING_MODE environment variable.
    • embedded - load all code immediately on boot. Set CODE_LOADING_MODE=embedded.
    • interactive - load code on-demand as it is needed/referenced. Set CODE_LOADING_MODE=interactive.
  10. (Optionally) set the "Log Directory"
    This is the same as the RUNNER_LOG_DIR environment variable supported by Distillery.
  11. (Optionally) change "Replace OS Vars"
    This is the same as the REPLACE_OS_VARS environment variable supported by Distillery.
    • Use Default - use whatever is configured in rel/config.exs. Don't set REPLACE_OS_VARS environment variable.
    • false - don't replace "${A_VAR_NAME}" in the generated configuration with A_VAR environment variable at runtime. Set REPLACE_OS_VARS=false.
    • true - replace "${A_VAR_NAME}" in the generated configuration with A_VAR environment variable at runtime. Set REPLACE_OS_VARS=true.
  12. (Optionally) set "sys.config File"
    This is the same the SYS_CONFIG_PATH environment variable supported by Distillery.
  13. (Optionally) set "Release Config Directory".
    This is the same as the RELEASE_CONFIG_DIR environment variable supported by Distillery.
  14. (Optionally) set "Pipe directory".
    This is the same as the PIPE_DIR environment variable supported by Distillery.
  15. (Optionally) set "Use Pseudo-terminal (PTY).
    If checked use PTY for interactive shells. Automatically on when "Release CLI Arguments" starts with one of the known interactive commands (attach, console, console_boot, console_clean, or remote_console).
  16. Fill in the "Working directory.
    • Type the absolute path to the directory.
    • Select the path using directory picker by clicking the ... button
  17. (Optionally) click the ... button on the "Environment variables" line to add environment variables.
  18. Click "OK" to save the Run Configuration and close the dialog
Running
  1. Click the Run Arrow in the Toolbar to run the _build/ENV/rel/NAME/bin/NAME
  2. The Run pane will open
    • If the either "Use Pseduo-terminal (PTY)" is checked of the "Release CLI Arguments" are known to need a PTY, an interactive shell will appear in the Run pane where you can enter iex commands.
    • Otherwise, the output of running the command will be shown.
Debugging
  1. (Optionally) before debugging, customize the modules that will be interpreted.
    1. Run > Edit Configurations...
    2. Click the "Interpreted Modules" tab next to default "Configuration" tab.
    3. Enable/Disable "Inherit Application Module Filters". Will change the Module Filters show in the below "Do not interpreter modules matching patterns" list.
    4. Uncheck any inherited module filters that you would rather be interpreted and therefore debuggable
    5. Click + to add module filters that are specific to this configuration. This can be useful if you know interpreting a specific module in your project's dependencies or project leads to too much slowdown when debugging or causes the debugger to hang/crash.
    6. Click - to remove configuration-specific module filters added with +. Inherited module filters cannot be removed with -, they can only be disabled by unchecking.
  2. Add the :debugger application to your release
    1. Open rel/config.exs
    2. In the release NAME block, in the set :applications block add :debugger:
      --- a/rel/config.exs
      +++ b/rel/config.exs
      @@ -41,6 +41,8 @@ end
       release :intellij_elixir do
         set version: current_version(:intellij_elixir)
         set applications: [
      +    # needed for IntelliJ Elixir debugger
      +    :debugger,
           :runtime_tools
         ]
       end
      
  3. For how to use the debugger, including how to set breakpoints see the Debugger section.
  4. Click the Debug bug in the Toolbar to debug the mix tests

Elixir Elixir Drop

Although it is exceedingly rare, as most Elixir projects use mix, it is supported to run/debug elixir directly, such as when doing elixir script.exs.

  1. Run > Edit Configuations...
    Edit Run Configurations
  2. Click +
  3. Select "Elixir"
    Add New Elixir
  4. Fill in the "elixir arguments".
  5. (Optionally) fill in "erl arguments" with arguments to erl before it runs elixir.
  6. Fill in the "Working directory"
  • Type the absolute path to the directory.
  • Select the path using directory picker by clicking the ... button
  1. (Optionally) click the ... button on the "Environment variables" line to add environment variables.
  2. Click "OK" to save the Run Configuration and close the dialog

With the Run Configuration defined, you can either Run or Debug elixir

Running
  1. Click the Run arrow in the Toolbar to run elixir.
    Run
  2. The Run pane will open, showing the results of elixir.
Debugging
  1. (Optionally) before debugging, customize the modules that will be interpreted.
    1. Run > Edit Configurations...
    2. Click the "Interpreted Modules" tab next to default "Configuration" tab.
    3. Enable/Disable "Inherit Application Module Filters". Will change the Module Filters show in the below "Do not interpreter modules matching patterns" list.
    4. Uncheck any inherited module filters that you would rather be interpreted and therefore debuggable
    5. Click + to add module filters that are specific to this configuration. This can be useful if you know interpreting a specific module in your project's dependencies or project leads to too much slowdown when debugging or causes the debugger to hang/crash.
    6. Click - to remove configuration-specific module filters added with +. Inherited module filters cannot be removed with -, they can only be disabled by unchecking.
  2. For how to use the debugger, including how to set breakpoints see the Debugger section.
  3. Click the Debug bug in the Toolbar to debug elixir

IEx (Interactive Elixir)

iex run configurations allow you to run iex with IntelliJ Elixir attached. It is most useful when debugging, but it also allows you save customizations in the configuration when it is more complicated than just iex.

  1. Run > Edit Configurations...
    Edit Run Configurations
  2. Click +
  3. Select "IEx"
    Elixir Drop inside round-bottom flask
  4. (Optionally) fill in "iex arguments" with arguments to iex.
  5. (Optionally) full in "erl arguments" with arguments to erl before it runs iex.
  6. Fill in the "Working directory"
  • Type the absolute path to the directory.
  • Select the path using directory picker by clicking the ... button
  1. (Optionally) click the ... button on the "Environment variables" line to add environment variables.
  2. Click "OK" to save the Run Configuration and close the dialog

With the Run Configuration defined, you can either Run or Debug the iex configuration.

Running
  1. Click the Run arrow in the Toolbar to run iex
    Run
Debugging
  1. (Optionally) before debugging, customize the modules that will be interpreted.
    1. Run > Edit Configurations...
    2. Click the "Interpreted Modules" tab next to default "Configuration" tab.
    3. Enable/Disable "Inherit Application Module Filters". Will change the Module Filters show in the below "Do not interpreter modules matching patterns" list.
    4. Uncheck any inherited module filters that you would rather be interpreted and therefore debuggable
    5. Click + to add module filters that are specific to this configuration. This can be useful if you know interpreting a specific module in your project's dependencies or project leads to too much slowdown when debugging or causes the debugger to hang/crash.
    6. Click - to remove configuration-specific module filters added with +. Inherited module filters cannot be removed with -, they can only be disabled by unchecking.
  2. For how to use the debugger, including how to set breakpoints see the Debugger section.
  3. Click the Debug bug in the Toolbar to debug iex.

Mix Tasks Elixir Drop mixed in a round-bottom flask

Much like rake tasks in Rubymine, this plugin can run mix tasks.

  1. Run > Edit Configurations...
    Edit Run Configurations
  2. Click +
  3. Select "Elixir Mix"
    Add New Elixir Mix
  4. Fill in the "mix arguments" starting with the name of the mix task followed by any arguments to that task.
  5. (Optionally) fill in "elixir arguments" with arguments to elixir before it runs mix.
  6. (Optionally) fill in "erl arguments" with arguments to erl before it runs elixir.
  7. Fill in the "Working directory"
  • Type the absolute path to the directory.
  • Select the path using directory picker by clicking the ... button
  1. (Optionally) click the ... button on the "Environment variables" line to add environment variables.
  2. Click "OK" to save the Run Configuration and close the dialog

With the Run Configuration defined, you can either Run or Debug the Mix Task

Running
  1. Click the Run arrow in the Toolbar to run the mix task
    Run
  2. The Run pane will open, showing the results of the mix task.
    • If there is an error with a FILE:LINE stack stack_frame, it will be a clickable link that will take you to that location
      Error link
Debugging
  1. (Optionally) before debugging, customize the modules that will be interpreted.
    1. Run > Edit Configurations...
    2. Click the "Interpreted Modules" tab next to default "Configuration" tab.
    3. Enable/Disable "Inherit Application Module Filters". Will change the Module Filters show in the below "Do not interpreter modules matching patterns" list.
    4. Uncheck any inherited module filters that you would rather be interpreted and therefore debuggable
    5. Click + to add module filters that are specific to this configuration. This can be useful if you know interpreting a specific module in your project's dependencies or project leads to too much slowdown when debugging or causes the debugger to hang/crash.
    6. Click - to remove configuration-specific module filters added with +. Inherited module filters cannot be removed with -, they can only be disabled by unchecking.
  2. For how to use the debugger, including how to set breakpoints see the Debugger section.
  3. Click the Debug bug in the Toolbar to debug the mix task

IEx Mix

If you want to run iex in the context of the project, you need to run iex -S mix, but if you don't want to have to worry about forgetting whether it's -s or -S or if it is mix -S iex or iex -S mix, you can use an IEx Mix configuration.

  1. Run > Edit Configurations...
    Edit Run Configurations
  2. Click +
  3. Select "IEx Mix"
    The Mix Icon with ">" to indicate the IEX prompt
  4. (Optionally) fill in "mix arguments", such as phx.server if you want to launch Phoenix inside of iex.
  5. (Optionally) fill in "iex arguments" with arguments to iex before -S mix.
  6. (Optionally) full in "erl arguments" with arguments to erl before it runs iex.
  7. Fill in the "Working directory"
  • Type the absolute path to the directory.
  • Select the path using directory picker by clicking the ... button
  1. (Optionally) click the ... button on the "Environment variables" line to add environment variables.
  2. Click "OK" to save the Run Configuration and close the dialog

Wih the Run Configuration defined, you can either Run or Debug iex -S mix

Running
  1. Click the Run Arrow in the Toolbar to run iex -S mix
Debugging
  1. (Optionally) before debugging, customize the modules that will be interpreted.
    1. Run > Edit Configurations...
    2. Click the "Interpreted Modules" tab next to default "Configuration" tab.
    3. Enable/Disable "Inherit Application Module Filters". Will change the Module Filters show in the below "Do not interpreter modules matching patterns" list.
    4. Uncheck any inherited module filters that you would rather be interpreted and therefore debuggable
    5. Click + to add module filters that are specific to this configuration. This can be useful if you know interpreting a specific module in your project's dependencies or project leads to too much slowdown when debugging or causes the debugger to hang/crash.
    6. Click - to remove configuration-specific module filters added with +. Inherited module filters cannot be removed with -, they can only be disabled by unchecking.
  2. For how to use the debugger, including how to set breakpoints see the Debugger section.
  3. Click the Debug bug in the Toolbar to debug iex -S mix.

mix test

The mix test task gets a special type of Run Configuration, Elixir Mix ExUnit. Using this Run Configuration type instead, of the basic Elixir Mix Run Configuration will cause the IDE to attach a special formatter to mix test, so that you get the standard graphical tree of Test Results

The Run pane will show Test Results. If there is a compilation error before or during mix test, it will be shown as a test failure. If the compilation failure is in a _test.exs file can it can be inferred from the stacktrace, the compilation error will show up as a test failure in that specific module.

doctest names are rearranged 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).

Creating mix test Run Configurations Manually
  1. Run > Edit Configurations...
    Edit Run Configurations
  2. Click +
  3. Select "Elixir Mix ExUnit"
    Add New Elixir Mix ExUnit
  4. Fill in the "mix test arguments" with the argument(s) to pass to mix test. Normally, this will be a directory like test, relative to the "Working directory"
  5. (Optionally) fill in "elixir arguments" with the arguments to elixir before it runs mix test.
  6. (Optionally) fill in "erl arguments"with the arguments toerlbefore it runselixir`.
  7. Fill in the "Working directory"
  • Type the absolute path to the directory.
  • Select the path using directory picker by clicking the ... button
  1. (Optionally) click the ... button on the "Environment variables" line to add environment variables.
  2. Click "OK" to save the Run Configuration and close the dialog

With the Run Configuration defined you can either Run or Debug the mix tests

Running
  1. Click the Run arrow in the Toolbar to run the mix test task
  2. The Run pane will open showing the Test Results
    Test Results
Debugging
  1. (Optionally) before debugging, customize the modules that will be interpreted.
    1. Run > Edit Configurations...
    2. Click the "Interpreted Modules" tab next to default "Configuration" tab.
    3. Enable/Disable "Inherit Application Module Filters". Will change the Module Filters show in the below "Do not interpreter modules matching patterns" list.
    4. Uncheck any inherited module filters that you would rather be interpreted and therefore debuggable
    5. Click + to add module filters that are specific to this configuration. This can be useful if you know interpreting a specific module in your project's dependencies or project leads to too much slowdown when debugging or causes the debugger to hang/crash.
    6. Click - to remove configuration-specific module filters added with +. Inherited module filters cannot be removed with -, they can only be disabled by unchecking.
  2. For how to use the debugger, including how to set breakpoints see the Debugger section.
  3. Click the Debug bug in the Toolbar to debug the mix tests

While you can create Elixir Mix ExUnit run configurations manually using the Run > Edit Configurations... menu, it is probably more convenient to use the context menu.

Creating mix test Run Configurations from context

The context menu must know that the the directory, file, or line you are right-clicking is a test. It does this by checking if the current directory or an ancestor is marked as a Test Sources Root.

  1. In the Project pane, ensure your OTP application's test directory is marked as a Test Sources Root
  2. Check if the test directory is green. If it is, it is likely a Test Sources Root. This color may differ in different themes, so to be sure you can check the context menu
  3. Right-click the test directory.
  4. Hover over "Mark Directory As >"
    * If "Unmark as Test Sources Root" is shown, then the directory is already configured correctly, and create from context will work.
    Mark Directory As > Unmark as Test Sources Root
    * If "Test Sources Root" is shown, then the directory need to be configured by clicking that entry
    Mark Directory As > Test Sources Root
Creating/Running mix test Run Configurations from directory
  1. Right-click the directory in the Project pane
  2. Click "Run Mix ExUnit", which will both create the Run Configuration and Run it.
    Run Mix ExUnit
  • If you want to only create the Run Configuration, select "Create Mix ExUnit" instead

Alternatively, you can use keyboard shortcuts

  1. Select the directory in the Project pane.
  2. Ctrl+Shift+R will create the Run Configuration and Run it.
Creating/Running mix test Run Configurations from file
  1. Right-click the file in the Project pane
  2. Click "Run Mix ExUnit", which will both create the Run Configuration and Run it.
  • If you want to only create the Run Configuration, select "Create Mix ExUnit" instead

Alternatively, you can use keyboard shortcuts

  1. Select the directory in the Project pane.
  2. Ctrl+Shift+R will create the Run Configuration and Run it.

Finally, you can use the editor tabs

  1. Right-click the editor tab for the test file you want to run
    Run Mix ExUnit
  2. Click "Run Mix ExUnit", which will both create the Run Configuration and Run it.
  • If you want to only create the Run Configuration, select "Create Mix ExUnit" instead
Creating/Running mix test Run Configurations from line

If you want to be able to run a single test, you can create a Run Configuration for a line in that test

  1. Right-click a line in the test file
    Run Mix ExUnit
  2. Click "Run Mix ExUnit", which will both create the Run Configuration and Run it.
  • If you want to only create the Run Configuration, select "Create Mix ExUnit" instead

Alternatively, you can use keyboard shortcuts

  1. Place the cursor on the line you want to test
  2. Ctrl+Shift+R will create the Run Configuration and Run it.
intellij-elixir - v7.5.0

Published by KronicDeth over 6 years ago

Thanks

  • For reporting that true: and false: did not work as keyword keys
  • For reporting that creating the editor panel for the BEAM Chunks Code editor at boot raised an "Access is allowed from event dispatch thread only." error.
  • For reporting that creating the editor panel for the BEAM Chunks Documentation editor at boot raised an "Access is allowed from event dispatch thread only." error.
  • For requesting that #{ auto-close with }
  • For reporting a potential race-condition that led to pre-maturely decompiling an incomplete .beam file when it is being rebuilt.
  • For reporting that the bad .beam files that are test cases in Erlang's :kernel test code were correctly caught by the bug reporter, but they should be ignored since they're a known failure.
  • For reporting the null argument being passed for startingReference in ElixirPsiImplUtil.aliasToModular.

Changelog

v7.5.0

Enhancements

  • #1055 - Refactor ElixirPsiImplUtil into separate files tied to specific classes or interfaces to shrink its size. - @KronicDeth
  • #1073 - Complete #{ with }. - @KronicDeth
  • #1109 - @KronicDeth
    • Read Write Accessor Detector
      • Variable/Parameter declarations/rebindings are highlighted as writes while other usages are highlighted as reads.
    • Improved Find & Show Usages
      • Added Find & Show Usages for Functions at declaration and usage site
        • Multi-clause functions use all clauses as targets and find usages of all clauses.
      • Improved Find & Show Usages for Modules/Aliases
    • Improved Element Descriptions
      • It is easier to distinguish aliases and the defmodule that is being aliased because element description now include alias or defmodule before the Alias name based on how the Alias is defined in the scope.
      • Call definitions use the same presentation for Structure View and Find Usages, so that Compile/Runtime time icons, and visibility are the same in both.
  • #1111 - Regression test for #1091 - @KronicDeth
  • #1120 - Add regression tests for #1116 that test that parameter and variables can be renamed. - @KronicDeth
  • #1124 - Update IntelliJ versions in build matrix to include 2018.1 and latest patch version of other versions. - @KronicDeth
  • #1126 - @KronicDeth
    • Add Elixir 1.6.X to build matrix
    • Update grammar and quoter to match native 1.6 behavior when SDK is >= 1.6.
    • New default SDK level is 1.7 to handle builds from master.
  • #1127 - Regression test for #1105 - @KronicDeth

Bug Fixes

  • #1056 - Certain .beam files in the OTP source are purposely invalid, so ignore them when trying to parse and don't log the expected error. - @KronicDeth
  • #1060 - Log available bytes and total size when header is not FOR1. - @KronicDeth
  • #1071 - erl_abstract_code format Dbgi chunks can now be navigated similar to how elixir_erl format Dbgi chunks can be navigated. Instead of converting the Erlang Abstract Code back to Erlang, which would not be highlighted if intellij-erlang and requires the user to know Erlang, the Erlang Abstract Code is translated back to Elixir source, so you can use the Dbgi chunk view to translate Erlang to Elixir. - @KronicDeth
  • #1111 - Allow zero or more new lines after the struct name before the opening curly brace ({). - @KronicDeth
  • #1112 - @KronicDeth
    • In order to prevent Access is allowed from event dispatch thread only errors when creating read-only code editor in subtabs of the BEAM Chunks editor, only create those editors when their parent tab is selected.

      Affected tabs:

      • Code (Elixir & Erlang)
      • ExDc
      • Dbgi (Elixir & Erlang)
  • #1114 - Check for suffix instead of full match to detect predefined macros when annotating. Location strings have become more complex, such as including the file path for root level modules, so the old exact matching on the module name no longer works. - @KronicDeth
  • #1120 - Restore parameter and variable rename. It broke because the changes to make Find Usages work and have Go To Declaration default to Find Usage when there is only one target disabled the default selected element code that the VariableInplaceRenameHandler used. - @KronicDeth
  • #1121 - @KronicDeth
    • Allow module attribute declaration to resolve to itself, so that unused module attributes don't say they can't find the declaration.
    • Restore rename module attributes.
  • #1127 - Allow true and false to be keyword keys. - @KronicDeth

README Updates

Features

.beam Files

BEAM Chunks

Dbgi
Tab

The Dbgi tab appearance varies based on whether it was created with Erlang or Elixir, reflecting the fact that the Dbgi format is dependent on the backend that wrote it.

####### Elixir (:elixir_erl backend)

The Dbgi tab 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.

Dbgi Attributes Table

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

Tree

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.

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

####### Erlang (:erlang_abstract_code backend)

The Dbgi tab has Abstract Code and Compile Options tabs.

Dbgi Tabs

######## Abstract Code

The Abstract Code tab is split between a tree of Attributes, Functions, Function/Arity, and clauses.

Tree

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.

Clause
Function
Module

The abstract code stored in the :erlang_abstract_code backend format is the Erlang Abstract Format. Instead of converting the Erlang Abstract Format back to Erlang, which would require IntelliJ Erlang to highlight and annotate and for you to be used to reading Erlang, the Erlang Abstract Format is translated back to Elixir. Using the BEAM Chunk Dbgi viewer can be a way to convert compiled Erlang code to Elixir source automatically.

Find Usages and Show Usages

Find Usages is a feature of JetBrains IDEs. It is the dual of Go To Declaration. While Go To Declaration jumps from a usage to the declaration, Find Usages finds all usages that could jump to a declaration. When used on a usage, Find Usage first finds the declaration(s) and then finds usages of those declaration(s).

Find Usages will open all the found usages in the Find Tool Window (unless you have it configured to not open and jump direct if only one usage is found). If you want to jump to usages quickly, Show Usages, which opens a lookup dialog at the cursor and allows you to select a usage to jump to in the lookup dialog with the arrow keys may be more useful.

Function

  1. Place the cursor over the name of a function, such as hd in the definition def hd([h | t]]) do or hd in a usage hd(list).
  2. Active the Find Usages action with one of the following:
    • Alt+F7
    • Select Edit > Find > Find Usages from the menu.
  3. A Find Usages dialog will appear in the Find Tool Window.

If a function has multiple clauses, all clauses for the function will be resolved and used as targets.

Multiple Clauses.png

You can be sure that all clauses were correctly identified as targets because of the multiple entries in the top "Functions" target grouping.

Multiple Functions.png

If instead of bringing up the Find Tool Window, you'd like a lookup dialog above the cursor, you can use Show Usages.

  1. Place the cursor over the name of a function, such as hd in def hd([h | t]]) do
  2. Active the Show Usages action with one of the following:
    • Alt+Cmd+F7
    • Select Edit > Find > Show Usages from the menu.
  3. A Usages lookup will appear above the cursor.
  4. Select an element from the lookup to jump to that usage
intellij-elixir - v7.4.0

Published by KronicDeth over 6 years ago

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

Do Not Step Into The Modules

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

Disable

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

Removed

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

Added

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.

ex

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

eex

.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

Build, Execution, Deployment > Compiler > Elixir Compiler

  • 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

Source

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

Errors and Warnings

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.

Autoscroll to Source

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.

Source

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

Errors

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

Warnings

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.

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

intellij-elixir - v7.3.0

Published by KronicDeth over 6 years ago

Thanks

Changelog

v7.3.0

Enhancements

  • #988 - @KronicDeth
    • Update build matrix
      • Update IntelliJ IDEA version 2017.3 to 2017.3.2
      • Update Elixir version 1.5.2 to 1.5.3
  • #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.
      screen shot 2018-02-01 at 6 38 07 pm
      The BEAM Chunks editor is subdivided into further tabs, one for each chunk in the .beam file.
      screen shot 2018-02-01 at 6 45 23 pm
      The tabs are listed in the order that the chunks occur in the .beam file.
      • The Atom chunk holds LATIN-1 atoms while AtU8 holds UTF8 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 UTF8 atoms.

        The Atom/AtU8 tab shows a table with the columns

        Column Description Source
        Index Which is 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

        screen shot 2018-02-01 at 7 01 43 pm

        Index 1 is always the module name for the .beam file. Since .beam is originally an Erlang format, for Elixir modules, you'll see the full atom name of with the Elixir. prefix instead of the Alias name used in Elixir source.

      • The Attr chunk holds the module attributes, but only those that are persisted.

        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

        screen shot 2018-02-02 at 2 34 22 pm

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

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

        The CInf tab shows a table with the columns

        Column Description Source
        Key Option name Raw
        Value Inspected value Raw

        screen shot 2018-02-02 at 3 19 50 pm

      • The Code chunk contains the byte code for the module. It is encoded in BEAM Compact Term Encoding, which differs from the binary format produced by term_to_binary.

        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.

        screen shot 2018-02-02 at 9 35 59 pm

        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.

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

        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

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

        screen shot 2018-02-02 at 5 26 04 pm

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

        screen shot 2018-02-02 at 5 27 29 pm

        The Attributes tab has the same format as the Attrs chunk

        screen shot 2018-02-02 at 6 47 49 pm

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

        screen shot 2018-02-02 at 6 48 34 pm

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

        screen shot 2018-02-02 at 6 50 14 pm

        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.

        screen shot 2018-02-02 at 6 53 17 pm

        screen shot 2018-02-02 at 8 47 05 pm

        screen shot 2018-02-02 at 8 47 20 pm

        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.

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

        The ExDc binary format is from term_to_binary, so it can be reversed with binary_to_term. 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 :callback_docs, :docs, :moduledoc, and :type_docs keys.

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

        screen shot 2018-02-02 at 8 58 38 pm

        screen shot 2018-02-02 at 9 07 03 pm

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

        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

        screen shot 2018-02-01 at 8 21 13 pm

        You'll notice the first entry starts with MACRO-. This is because the BEAM, 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.

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

        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

        screen shot 2018-02-01 at 8 07 15 pm

        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.

      • The LitT chunk contains literals loaded as arguments in Code chunk. 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.

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

        screen shot 2018-02-01 at 9 25 07 pm

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

        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

        screen shot 2018-02-01 at 9 27 49 pm

        You'll notice the first entry -__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.

      • The StrT chunk contains a single contiguous pool of all Erlang strings (that is, Elixir charlists) used in the Code chunk. 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.

        screen shot 2018-02-01 at 7 56 15 pm

        The StrT is contiguous with no separation of strings. 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.

  • #1021 - @KronicDeth
    • Support for https://github.com/elixir-lang/elixir/commit/23c7542d95683a497a7b93071b9ccbbeb9e45d2f

      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
  • #999 - @ronanboiteau
    • Jetbrains' Gogland is now named GoLand, updated README accordingly
    • In donors list, Garrett Hart had his GitHub URL (@https://github.com/thirdshift) shown instead of his GitHub username (@thirdshift)

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

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

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

AtU8 Table

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

Attr Table

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

CInf Table

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.

Code Chunk Read-Only Editor

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

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.

Dbgi Attributes Table

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

Tree

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.

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

ExDc Tree
Function selected in ExDc tree

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

ExpT Table

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

ImpT Table

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

LitT Table

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.

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

Tab

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

Line References Table
File Names TableTable

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

LocT Table

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

intellij-elixir - v7.2.1

Published by KronicDeth almost 7 years ago

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"
intellij-elixir - v7.2.0

Published by KronicDeth almost 7 years ago

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