New: Julia for JetBrains IDEs (Flexible Julia)

Can you try to turn off the “compiled” mode under the debug settings? (there is a checkbox in debugger for it, repl, settings or runtime config.

Breakpoints inside using-loaded packages don’t work because those modules are compiled. It is enabled by default, because it makes things faster, but it will stop you from jumping into modules like that. I keep forgetting about that myself all the time, too.

On a sidenote: i have spent this week working on variable modification & hot-swapping during debug sessions. That will give you the power to modify a compiled module and actually work with the evaluator more in our debugger.

Of course! Sorry, I did not see this option. Without compiled mode Step into and breakpoints work also in our package.

In the tool tip it says"When enabled, stdlib modules run compiled for faster debugging." Maybe this could be made more precise.

Thanks a lot for the very fast help!

1 Like

Absolutely - i should update that description… lol…

Glad that it works! And needless to say: welcome to this awesome community :slight_smile:

Oh and if you can - leave a review on the plugin. It helps a lot!

Big update coming!

Tomorrow I’ll be releasing a major update to the Debugger that allows hot-swapping and in-session variable modification.

I am just adding a few more bugfixes while at it. But phew, that was more complicated than expected :slight_smile:

8 Likes

New Release: Flexible Julia 2026.9.11

New Features:

  • Hot-Swap Debugger: Swap out functions while paused at a breakpoint - changes take effect immediately
  • DAP hot-reload now attempts frame reconstruction so the current paused frame uses the new code right away
  • Tab-iterable variable placeholders in postfix templates .for, .if, .while, .try

Fixes:

  • External package symbols from using fully resolved in undefined variable inspection (#85)
  • Type names in isa and :: expressions no longer flagged as undefined variables (#85)
  • Postfix templates (.for, .if, .while) no longer malformed when expression ends with ) or ] (#88)
  • Quote auto-closing now works for " and ' (#89)

HOT-SWAPPING IS HERE!
This actually took me a lot longer to implement, cause I had to hack my way around frame modification, but now we got hot-swapping support. I got inspired by Julia debugging is extremely slow - #12 by tue, and even though it is not perfect, it is perhaps a step in the right direction.

So here’s what it does: You can now edit a function while paused at a breakpoint and have it take effect immediately - no need to restart your debug session. The DAP layer even tries to reconstruct the current frame so you’re running the new code right away. This means, you can start a debug session (either in REPL or native JetBrains), set a breakpoint and modify the sources. The debugger will update with you. You can see it working in the video in my post above.

This should make the edit-debug cycle a lot faster, especially when you’re tracking down those bugs that only show up after a long warmup.

Apart from that, I also added a few fixes to the validator and some convenience features.


@tue: for sharing your problems with “debugging in julia”
@ufechner7: Thanks for the follow-up on external package symbol recognition!
@SamuelMathieu-code: Appreciate the reports on postfix templates and editor usability - all fixed!


The new release is already available in the beta channel and you can expect JetBrains to approve it today or early tomorrow.

15 Likes

Hi, thank you very much for this amazing plugin ! On my side I’m struggling to activate the license with my JetBrains Educational Pack. I don’t see any way of doing it. Is there any issue on this ?

1 Like

Hey,

you should automatically get the 100% discount if you try to check out the product - just select the annual personal license and select “buy” / “free” / “apply” - the discount should be automatically applied (there should be a dropdown on that page that tells you that you got discounts, listing your student one. I do not have a student account, but i found this picture on the web:


You should see the price dropping to 0 in the purchase overview, it comes a few steps in. There is an additional checkbox you’d need to click before being able to actually checkout anyway, so you can go through the steps until you see the overview.

Just watch out for the one at the bottom that says “I agree to the terms and yada yada yada” and don’t click that until you are sure the price is at 0.

Afterwards on the popup within the IDE (if not already there) refresh the licenses to your account.

Let me know if you bump into any issues with it.


P.S: Welcome to this amazing community - you’ll like it here.

Hey, thank you very much, it works properly. I’ll use it and see if I can contribute by giving some feedbacks :slight_smile:

1 Like

That would be amazing!!! Whatever you spot, open a ticket. Even for feature wishes or so. And if you can, also leave a review on the marketplace, it helps a lot with reaching an audience there!

New Release: Flexible Julia 2026.9.13

New Features:

  • Call Hierarchy Support: Ctrl+Alt+H now works for functions, macros, and types
  • Performance improvements on PSI element validation

Fixes:

  • Parameter types in hover documentation now show actual types (e.g. Int, Settings) instead of always showing Any (#94)
  • Hover documentation now works for functions from non-selective imports (using FLORIDyn) - no more “Documentation not available locally” (#94)
  • Hover documentation at declaration site no longer shows the function signature twice when docstring already contains it (#94)
  • Module/type qualifiers (e.g. Graphs in Graphs.nv(...)) no longer flagged as undefined variables (#94)
  • False “Undefined variable” warning for functions defined in included files when used as values (e.g. Base.invokelatest(residual!, ...)) (#92)
  • Noisy WARN log for macro names passed to module registry silenced to DEBUG

We are jumping ahead to release 2026.9.13.

Call hierarchy a nice addition if you want to trace who calls what across your codebase. Type CTRL+ALT+H (or right click) on any function and it will give you a structured view of it all across the codebase.

Apart from that there’s also been many documentation & grammar performance improvements.



@ufechner7: Thanks for the detailed reports on hover docs and undefined variable false positives - this release is basically dedicated to your issues!

Version will take ~24hrs to be approved by JetBrains

3 Likes

You must be a wizard. The amazing updates just keep coming at such an unbelievable pace. Thank you very much indeed. This is a great addition to the tooling.

8 Likes

I spent a few days testing out the new version of Flexible Julia and here are my thoughts on it and what I feel are still missing.

Thoughts regarding Hot swapping:

Interesting concept, it does mean that code takes a long time to write, since it is updating on the fly. Which I am not quite sure is really what you want.
Maybe make it optional to auto-update like that? I think I would prefer to have a shortcut I can use to update either the function I am in or the entire file rather than it happening automatically.

I think hot swapping has some of the core elements of the debugging experience that I am used to from python, but it is not the same and I am still a bit unsure how to actually use it effectively.

The way I understand it in python is that you have the console window that you can write whatever you want into while a session is ongoing. However, in python, the code in your files does not actually hotswap while a session is started. That means that I can change a file however I want according to what I see in the debugger without contaminating my current session. And then if I want to actually update a function or a variable I just put it into the console and it updates it. This way I can very quickly change a parameter I realized I did not set correctly at the beginning when starting the debugging session or make any other changes I want. Thus my debugging session becomes extremely interactive and explorative.
Hot swapping in julia seems to also enable interactive and explorative debugging, but so far I have not found a good way to really debug with it.

My biggest pain points when debugging in julia

  1. Every time I step a line in julia, the julia window changes back to Data tab (rather than the variable tab) - There is likely an easy fix for this, but so far I have not found it.

  2. Julia debugger is very slow to start. (From python I am used to my debugger starting in less than a second, and because of this my development process involves restarting sessions often. In julia this approach is severely slowing me down in my development. Partly this is probably me that needs to change my development style and generally just do less restarts. However this is hard since I find that the Julia debugger disconnects more easily than the python debugger and since the interactive debugging is much harder in Julia I am still forced to restart a lot.)

  3. Julia debugger fails to start sometimes:

Starting Julia debugger...
[Julia] === Julia Debug Bootstrap ===
[Julia] Julia version: 1.12.5
[Julia] Process ID: 29157
[Julia] Working directory: /home/tue/Projects/JuliaProjects/Glimb
[Julia] Loading IPC channel...
Failed to start debugger: Failed to launch Julia DAP server: Failed to connect to DAP server after 15 attempts

The only way to fix this seems to be to restart my IDE

  1. If I debug-step over a function that causes julia to crash, I would love for julia to take me to whatever line in my code that julia crashed on. Also the debugging message I am receiving are often unhelpful and filled with useless information. Here is an example:
Starting Julia debugger...
[Julia] === Julia Debug Bootstrap ===
[Julia] Julia version: 1.12.5
[Julia] Process ID: 33946
[Julia] Working directory: /home/tue/Projects/JuliaProjects/Glimb
[Julia] Loading IPC channel...
[Julia] [ Info: FlexibleIPC: Connected to IDE on port 43881
[Julia] IPC channel loaded.
[Julia] Loading IDE display hook...
[Julia] [ Flexible Julia IDE integration active ]
[Julia] IDE display hook loaded.
[Julia] DAP mode enabled for display hook.
[Julia] Loading Sockets...
[Julia] Loading DebugAdapter...
[Julia] All dependencies loaded.
[Julia] Activating project at `~/Projects/JuliaProjects/Glimb`
[Julia] Activated user project: /home/tue/Projects/JuliaProjects/Glimb
[Julia] Attempting to listen on port 39997...
[Julia] Listening on port 39997
[Julia] Waiting for IDE connection...
Connected to Debug Adapter
[Julia] IDE connected, creating debug session...
[Julia] Debug session created, running...
[Julia] Activating project at `~/Projects/JuliaProjects/Glimb`
â–¶ Script is executing in COMPILED (fast, stdlib not debuggable) mode
Breakpoints are active. Will pause when hit.
Debugger stopped: step
Debugger stopped: step
[Julia] starting reading 0.015059 seconds (1.41 k allocations: 967.219 KiB)
[Julia] Debug session ended with error:
[Julia] UndefVarError: `S0` not defined in `Main`
[Julia] Suggestion: check for spelling errors or missing imports.
[Julia] Stacktrace:
[Julia] [1] #invokelatest_gr#232
[Julia] @ ./reflection.jl:1295 [inlined]
[Julia] [2] invokelatest_gr
[Julia] @ ./reflection.jl:1289 [inlined]
[Julia] [3] lookup_var
[Julia] @ ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:5 [inlined]
[Julia] [4] lookup(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, node::Any)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:36
[Julia] [5] step_expr!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, node::Any, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:597
[Julia] [6] step_expr!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:627
[Julia] [7] finish!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:14
[Julia] [8] finish_and_return!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:30
[Julia] [9] evaluate_call!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, fargs::Vector{Any}, enter_generated::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:290
[Julia] [10] evaluate_call!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, call_expr::Expr, enter_generated::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:256
[Julia] [11] evaluate_call!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, call_expr::Expr)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:249
[Julia] [12] eval_rhs(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, node::Expr)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:406
[Julia] [13] step_expr!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, node::Any, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:564
[Julia] [14] step_expr!
[Julia] @ ~/.julia/packages/JuliaInterpreter/j9HeJ/src/interpret.jl:627 [inlined]
[Julia] [15] next_until!(predicate::Any, interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:102
[Julia] [16] _next_line!
[Julia] @ ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:187 [inlined]
[Julia] [17] next_line!(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, istoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:184
[Julia] [18] debug_command(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, cmd::Symbol, rootistoplevel::Bool; line::Nothing)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:498
[Julia] [19] debug_command(interp::JuliaInterpreter.RecursiveInterpreter, frame::JuliaInterpreter.Frame, cmd::Symbol, rootistoplevel::Bool)
[Julia] @ JuliaInterpreter ~/.julia/packages/JuliaInterpreter/j9HeJ/src/commands.jl:478
[Julia] [20] our_debug_command(debug_engine::DebugAdapter.DebugEngines.DebugEngine, cmd::Symbol)
[Julia] @ DebugAdapter.DebugEngines ~/.julia/packages/DebugAdapter/6PfG9/src/DebugEngines.jl:246
[Julia] [21] run(debug_engine::DebugAdapter.DebugEngines.DebugEngine)
[Julia] @ DebugAdapter.DebugEngines ~/.julia/packages/DebugAdapter/6PfG9/src/DebugEngines.jl:335
[Julia] [22] run(debug_session::DebugAdapter.DebugSession, error_handler::Nothing)
[Julia] @ DebugAdapter ~/.julia/packages/DebugAdapter/6PfG9/src/packagedef.jl:162
[Julia] [23] run
[Julia] @ ~/.julia/packages/DebugAdapter/6PfG9/src/packagedef.jl:60 [inlined]
[Julia] [24] start_dap_server(base_port::Int64, max_attempts::Int64)
[Julia] @ Main /tmp/julia_dap_bootstrap_11940535368932068447.jl:131
[Julia] [25] start_dap_server(base_port::Int64)
[Julia] @ Main /tmp/julia_dap_bootstrap_11940535368932068447.jl:102
[Julia] [26] top-level scope
[Julia] @ /tmp/julia_dap_bootstrap_11940535368932068447.jl:147
[Julia] [27] include(mod::Module, _path::String)
[Julia] @ Base ./Base.jl:306
[Julia] [28] exec_options(opts::Base.JLOptions)
[Julia] @ Base ./client.jl:317
[Julia] [29] _start()
[Julia] @ Base ./client.jl:550

[Debugger] Connection to debug adapter lost.
[Julia] Done reading

I would expect to be able to read at the bottom of this message essentially what failed and where. However there is nothing useful for me in this debugging message at the bottom and I have to scroll up and eventually I find this:
[Julia] Debug session ended with error:
[Julia] UndefVarError: S0 not defined in Main

Which is obviously the information I want, except it does not have a line number associated with it, so I will have to manually try and search my code for where this variable might be used

Overall flexible Julia seems like the best debugging environment for Julia, but it still falls short of debugging in many other languages.

Finally, thank you for developing this @madppiper I think it is sorely needed!

2 Likes

Awesome feedback! Thank you for that @tue and for taking the time to really put some thought into it.

Here’s what we’re going to do: there are certain things I have some control over, so let’s address them next week:

  1. The idea that you get to choose when to hot-swap makes a lot of sense to me. Just need to find a good UI element for it. But that should speed up the experience in editor.
  2. jumping back and forth with the tab (I find it also annoying - it’s a default by JetBrains.) I know how to switch back, but need to check where to put that
  3. improvements on the Debug log itself - i have some control over it. Perhaps not scrolling but I will see what I can do
  4. fix the startup session issue

For the debugger crash: there is actually an option now in the settings that you can turn on, it will stop the debugger from auto-exiting. That will then keep you in the session (but probably jump to the catch block you might have)


Now the remaining things about performance could be partially caused by compiled mode or not - you can start a session with or without it. Compiling makes startup slower but processing faster. Perhaps it is better to start without the compiler on? Certainly something for us to play around with.

For anything else, I really need to wrap or redevelop the DAP some more (Debugger.jl - sometimes in combination Inspection.jl). I am doing that already, to set breakpoints and mess with the Debug session for hot-swapping but obviously it is always a challenge to do that…

Anyway, sounds like we got a plan :slight_smile:

2 Likes

New Release: Flexible Julia 2026.9.14

Fixes:

  • Hover documentation now extracts parameter types from docstrings (indented signature or # Arguments section) when no explicit ::Type annotation exists (#94)
  • Hovering over a parameter inside a function body now shows its type and description from the docstring (#94)
  • Hovering over an argument in a function call (e.g. sim in calcFlowField(sim, ...)) now shows the corresponding parameter name, type, and description (#94)
  • Hover documentation for functions from non-selective using Module imports now correctly resolves to the source definition (#94)

This is just a small bugfix release while working on the debugger. More hover documentation improvements based on @ufechner7’s feedback.


@ufechner7: Thanks again for the detailed reports and for keeping me focused :slight_smile:

3 Likes

One thing I have noticed is Flexible Julia seems to apply automatic formatting in certain situations where I don’t want it to. I’m not using JuliaFormatter.jl and I don’t have any kind of formatting enabled.

For example, if I define a module and have some code inside the module block, I often find that Flexible Julia seems to automatically indent its not indented. For example, save this snippet asmwe.jl and open it.

# ---------------------------------------------------------------------------
# Encoded image types
#
# We work with two different image decoding backends depending on the format:
#   1. LJPGProcessor (via FFI to a C++ library) — handles Lossless JPEG (.ljpg)
#      images, a common format in medical imaging not supported by standard
#      image libraries.
#   2. ImageIO.jl — handles all common image formats (PNG, JPG, BMP, TIFF, etc.).
#
# Each backend has its own encoded wrapper type so that `decode_and_standardize_uint8`
# can dispatch to the correct decoder. `EncodedUnionImage` provides a single
# unified type that holds exactly one of the two, determined at construction
# time from the file extension. This lets the rest of the codebase treat all
# images uniformly without caring which decoder is needed.
# ---------------------------------------------------------------------------

"""Holds raw bytes of a Lossless JPEG (.ljpg) image, decoded via LJPGProcessor."""
struct EncodedLJPGImage
    data::Vector{UInt8}
end
sizeof_bytes(x::EncodedLJPGImage) = length(x.data)
function decode_and_standardize_uint8(x::EncodedLJPGImage)::Matrix{UInt8}
    xdec = ljpg_imdecode(x.data)
    standardize_uint8(xdec)
end

If you edit this and save with CTRL+S adding a whitespace in one of the comments, sizeof_bytes(x::EncodedLJPGImage) = length(x.data) will be indented one level.

I also observed some behavior yesterday where a ternary expression was being automatically squashed in a way that actually stopped the compiler from working:

# Started like this
result = expr ? a : b
# Ended like this after saving
result = expr ? a:b

This seems to easily reproduce as well.

1 Like

Oh, I will need to fix some of that. (the compiler complaining shouldn’t happen for sure.

I will also see if I can make some of those rules optional - as in: you get to turn it off.

One thing you can always do already - if you right click and select “paste special” it will keep the original formatting. More of a workaround, but perhaps good to know.

Thanks for that, I will fix it by next week :slight_smile:

2 Likes

New Release: Flexible Julia 2026.9.15

New Features:

  • Julia Code Style Settings: Configurable spacing for operators, ternary/range colons, type annotations, and module body indentation (Settings > Editor > Code Style > Julia) (#99)
  • Project Dependencies Browser: Documentation browser now shows dependencies parsed from Project.toml (#98)
  • Clickable Cross-References: Links in doc popups are now clickable (#96)

Fixes:

  • Formatter no longer collapses ternary a ? b : c into a ? b:c (#99)
  • Formatter no longer indents compact functions inside module blocks (#99)
  • Pop-up help formatting and wrong-docstring resolution (#95, #97)
  • False “Unused variable” inside macro begin blocks (#100, #102)
  • False “Undefined variable” for @enum values across files (#101)


So, based on @csvance feedback, I improved formatting and added a code style settings panel for customizations. You can now configure how the formatter handles operator spacing, ternary colons, type annotations, and module indentation.

Documentation browser also got some love with project dependencies from Project.toml and clickable cross-references in popups and again a few bugfixes for the reverse lookups of elements.


@ufechner7: Thanks for the extensive reports on documentation and inspections - seven issues addressed in this release! (you also managed to break the first 100 tickets :slight_smile: )
@csvance: Adding a formatter panel was the right idea - thanks!

3 Likes

Hi,

When trying this I notice that a couple of of cores are running non-stop. Even after half an hour after the start it still shows LANGUAGESERVER (indexing). Don’t know if it is related but having having (some) cores running at 100% is, as you’ll understand, a killing feature. But I want to thank you for making this available and constant support for improvements.

1 Like

Well, you can disable the Language Server in the settings:

It still works quite well without it.

And you can also try JETLS.jl instead of the old language server. But for JETLS you need to have Julia 1.12 installed.

1 Like