DEV Community

taku25
taku25

Posted on

Title: Bridging the "Last Mile" for LSP: The Story of My Custom blink.cmp Source for Neovim + Unreal Engine

blink.cmp custom source

TL;DR

LSP in Neovim fails to complete many of Unreal Engine's specific macros and specifiers. To bridge this "final gap," I created blink-cmp-unreal, a custom source for blink.cmp. By adding it, you get proper completion for UE-specific keywords, greatly improving the development experience.


Introduction

Hello! As always, I'm absorbed in creating plugins to make developing with Unreal Engine in Neovim a little bit easier. (Honestly, I feel like I'm drifting further away from my original goal of "actually making something in UE," but that's a story for another day...!)

This time, I'd like to share the story of a new plugin I've completed: blink-cmp-unreal, a custom completion source for my favorite completion plugin, blink.cmp.

The Wall You Can't Get Over with Just LSP

Developing with Unreal Engine involves a host of special macros like UCLASS, UPROPERTY, and UFUNCTION, along with countless "specifiers" used within them, such as BlueprintReadWrite and meta.

Usually, if you include headers like #include "CoreMinimal.h" at the top of your .h files, your LSP will do its best to interpret some of them. However, it often fails to trace all the definitions, frequently leaving you without completion candidates right when you need them most.

blink-cmp-unreal was born to bridge this frustrating "last mile."

Installation and Setup

Getting started is very simple if you're using lazy.nvim.

return {
  {
    "Saghen/blink.cmp",
    dependencies = {
      -- Add blink-cmp-unreal as a dependency
      { "taku25/blink-cmp-unreal" },
    },
    opts = {
      sources = {
        -- Enable the "unreal" source
        default = { "lsp", "buffer", "path", "unreal" },
        providers = {
          unreal = {
            module = "blink-cmp-unreal",
            name = "unreal",
            -- Adjust the score if you want to prioritize it over LSP
            score_offset = 15,
          },
        },
      },
      --... other blink.cmp settings
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

With just this setup, UE macro specifiers will start completing smoothly inside places like UCLASS().

Flexible Customization

What if some completions overlap with your LSP? No problem. You can disable specific completion groups through the plugin's options.
Simply add an opts table to the providers.unreal section with any of the following settings:

Option Default Description
enable_uclass true Enables completion for UCLASS specifiers.
enable_uproperty true Enables completion for UPROPERTY specifiers.
enable_ufunction true Enables completion for UFUNCTION specifiers.
enable_ustruct true Enables completion for USTRUCT specifiers.
enable_uenum true Enables completion for UENUM specifiers.
enable_uinterface true Enables completion for UINTERFACE specifiers.
enable_meta_specifiers true Enables completion for keywords inside meta specifiers (e.g., DisplayName).
enable_delegate_macros true Enables completion for delegate-related macros (e.g., DECLARE_DELEGATE).
enable_module_macros true Enables completion for module-related macros (e.g., IMPLEMENT_MODULE).
enable_log_levels true Enables completion for log levels used in UE_LOG (e.g., Log, Warning).
enable_slate_macros true Enables completion for Slate UI framework macros (e.g., SLATE_BEGIN_ARGS).

Conclusion and Future Outlook

With the completion of this plugin, I feel like the suite of tools I've been building has come together to cover most of the basic needs for UE development in Neovim: Builds, Class Creation, File Searching, Logging, Highlighting, and now Completion.

Of course, there are still advanced features found in full-fledged IDEs like Rider, such as showing which Blueprint assets are using a specific C++ class. However, achieving that would likely require binary analysis, which is a daunting task for a solo developer.

Instead, my more immediate priority is cross-platform support. Currently, I only develop and test in a Windows environment, so I'm eager to ensure all these plugins work correctly on Mac and Linux as well.

I hope this article is helpful for anyone else taking on the challenge of developing for Unreal Engine in Neovim.


What tricks or tools do you use for UE development in Neovim? If you have any useful plugins or configurations, I'd love to hear about them in the comments!

Top comments (0)