Macro Support

Unlike most Clojure editors, Cursive works by analysing source code rather than introspecting a REPL for editor functionality. This has many advantages, but it has one major disadvantage - Cursive is generally unaware of which local bindings and vars are defined by macro forms. Cursive ships with built-in support for all core macro forms and for many popular libraries, but for in-house macros or open source libraries that Cursive doesn't yet support this can be annoying. It mostly manifests as false positive warnings about unresolved symbols and things like completions not working correctly, but it can also show up as incorrect arity warnings and so on.

Customising symbol resolution

Many custom macro forms are very similar to built-in forms. def-type macros are very common, as are forms that mostly work like let. Cursive allows you to customise the symbol resolution for custom macros to mimic these common forms. When the caret is the head symbol of a macro form which is not handling the symbol resolution correctly, you'll see the intention lightbulb near the left margin and you can use Alt+Enter to customise how that form is interpreted:

This UI can be confusing - make sure you select this option by pressing Enter, not by pressing right arrow - that arrow at the right of the menu item can be tempting. Pressing Enter allows you to choose which existing form the form you're customising should be interpreted as:

Note that this will only change how Cursive interprets the form, it has no effect on how your program actually runs. Currently you can choose to interpret the form as def, defn, let, for, -> or ->>. Choosing def means that Cursive will look for a name symbol as the second element in the form, and will create var metadata using that name. It will also treat a string following that symbol as a docstring, if present. Choosing let or for will assume that your form looks like the built-in equivalents, and will set up the local bindings in the corresponding way. Choosing -> or ->> will prevent spurious arity warnings when creating custom threading forms. Your custom form will also be formatted in the same way as the built-in form, but if you customise the formatting as described here that will be overridden as normal.

If your form doesn't look like these but does look like another form that Cursive supports, you can customise further by choosing "Specify...". Then start entering the name of the form you'd like to customise as, and you'll get a list to choose from:

If none of the existing options work well for your macro and you're getting a lot of false positive warnings, you can also choose "None" from the drop-down list instead. What that will do is disable all unresolved symbol warnings from the body of that particular macro, which will help for macros which define a lot of local symbols in their body.

This support will work in a lot of cases, but we'll be adding more sophisticated support to allow users to help Cursive understand more complicated forms.

Stub generation

There are still some cases that are impossible for Cursive to analyse the source, for example when vars are dynamically created at runtime, or in cases such as Datomic which are distributed without source at all. For these cases, Cursive supports stub generation. This will run a process and load the problematic namespaces into it, introspect the var metadata and then generate source files containing empty function stubs which it can index for use in the editor.

Currently this is only supported for a hard-coded list of namespaces for projects which are known to be problematic. If your project uses one of these namespaces, Cursive will prompt you with a notification:

Click "Generate now" and after a short delay Cursive will reindex the new files, and then things should resolve correctly:

If you don't want to be clicking this every time, you can choose to always have stubs generated rather than having to use the notification all the time at Settings | Languages & Frameworks | Clojure | Stubs Generation Options | Always generate stubs without prompting, or you can also use the item from the notification menu.

There are also several per-module options for controlling the stubs generation. You can find these using Ctrl+Alt+Shift+S (File→Project Structure...), select "Modules" and then select the the module you'd like to configure, and finally select the "Clojure" tab.

Here, if "Create stubs if required" is not selected, stubs will never be generated for this module. "Warn if stub creation outputs to stderr" can be used to disable warnings if you know the stub generation will produce error output for some reason. Finally, you can shorten the classpath if required, a full description of what this option means can be found in the IntelliJ documentation. However, usually you won't use these options from this dialog, there are options you'll be offered in the relevant notifications, which will set these flags for you.


Test Integration Working with Babashka