DEV Community

taku25
taku25

Posted on

Turning Neovim into a True Unreal Engine IDE: My One-Week Dogfooding Sprint

Hey everyone! As a developer juggling subscriptions to Gemini, GitHub Copilot, and JetBrains, I'm always looking for the right tool for the job. This past week, I've been in the trenches with my own suite of Neovim plugins for Unreal Engine development. It's one thing to build a tool; it's another to actually live in it.

This is the story of my one-week dogfooding sprint, the painful discoveries I made, and the improvements that followed.

The Brutal Truth: My Own Plugin Was Unusable

After using my plugins full-time for a few days, one conclusion hit me hard:

ULG.nvim was hopelessly unusable and fundamentally lacked features.

A plugin designed for viewing logs was failing at its primary job. I couldn't in good conscience continue developing it without making it a tool I'd actually want to use myself. So, I spent the week focused on fixing it.

The Fixes: What I Added to ULG.nvim

Here are the key improvements I implemented to make the plugin genuinely useful.

1. Build Log Highlighting

I added color-coding for error and warning lines. This seems basic, but it makes a world of difference when you're trying to spot problems in a massive wall of text from the build system.

2. Go-to-Error on a Single Keystroke

This was a must-have. I implemented a feature to jump directly from an error line in the log to the corresponding source file and line number. It's a fundamental IDE feature that was sorely missing.

3. Taming Live Coding Logs

Live Coding is a critical feature for fast iteration in Unreal C++. I made several changes to integrate it properly:

  • Improved tail processing: The real-time log monitoring is now more robust.
  • Path resolution: The plugin now correctly handles the different log paths used by the Epic Games Launcher version of the engine vs. a source-built version from GitHub.
  • User-configurable path: I added an option for users to specify a custom log file path directly in the plugin's settings, making it adaptable to any environment.

4. Running stat Commands from Anywhere

I added a dedicated command to run console commands like stat fps and stat unit directly from Neovim, without needing to have the Unreal Editor's output log window open and focused.

With these changes, ULG.nvim finally feels like a practical and powerful tool.

My lazy.nvim Setup: The Grand Unification

With the improvements in place, here is my current lazy.nvim configuration. It manages all my Unreal Engine plugins in one place.

-- lua/plugins/unreal.lua

local is_open_ui = false
return {
  -- UEP.nvim is in development, so I'm using a local path
  dir = '~/Documents/git/UEP.nvim/',
  dev = true,

  -- Load when a C++/C file is opened
  ft = { "cpp", "c" },

  -- Allow loading via command
  cmd = { "UEP" },

  -- Allow loading via keymap
  keys = {
    { '<c-f>', '<cmd>UEP files --all-deps<CR>', mode = 'n' },
  },

  -- Dependencies
  dependencies = {
    "j-hui/fidget.nvim",
    "nvim-telescope/telescope.nvim",
    "taku25/UNL.nvim",
    "taku25/UBT.nvim",
    "taku25/UCM.nvim",
    "taku25/USH.nvim",
  },
  opts = {},
  config = function(_, opts)
    require("UEP").setup(opts)

    -- Keymap for switching between header/source files
    vim.keymap.set("n", "<leader>a", function()
      require("UCM.api").switch_file()
    end, { noremap = true, silent = true })

    -- A smart keymap for build / live coding
    vim.keymap.set("n", "<C-s>", function()
      local unl_api = require("UNL.api")
      -- Check if the Unreal Editor process is running
      unl_api.is_process_running("UnrealEditor", function(is_running)
        if is_running then
          -- If it's running, trigger a Live Coding compile
          require("ULG.api").remote_command("livecoding.compile")
        else
          -- If not, run a normal build
          require("UBT.api").build({})
        end
      end)
    end, { noremap = true, silent = true })

    -- Auto-open IDE-like UI
    local open_ui = function()
      if is_open_ui == true then
        return
      end
      local project = require("UNL.api").find_project(vim.loop.cwd())
      if project and project.root then
        require("UEP.api").tree() -- Show project tree in neo-tree
        require("ULG.api").start()  -- Show the log window
        is_open_ui = true
      end
    end

    vim.api.nvim_create_autocmd("FileType", {
      pattern = { "cpp", "c" },
      callback = function()
        open_ui()
      end,
    })
    open_ui()
  end,
}
Enter fullscreen mode Exit fullscreen mode

Here are the key takeaways from this setup:

  • Lazy-loading based on filetype: All the Unreal Engine plugins are loaded together as soon as I open a C++ or C file.
  • IDE-like automatic UI: When I open a C++/C file inside a .uproject directory, it automatically opens a neo-tree view of my project and the ULG.nvim log window. It’s a little heavy, but it's still way faster than launching a full IDE.
  • Header/Source Switching: A simple <leader>a lets me instantly toggle between .cpp and .h files.
  • Smart Build/Live Coding Key: My favorite feature. <C-s> is now a context-aware build key. It checks if Unreal Editor is running. If it is, it triggers a Live Coding compile. If not, it runs a full build. This lets me use a single key for the optimal build action in any situation.

Putting It All Together: Live Coding in Action

Here’s a look at the workflow, triggering a Live Compile from Neovim with <C-s> while the editor is running.

I think this is starting to get pretty convenient!

A New Challenger Appears: USH.nvim

While working on this, I learned about an official interactive shell called ushell from a post on Reddit. This inspired me to create a new plugin to integrate it with Neovim.

I'll be writing more about this one soon!

Wrapping Up

There's still a lot of room for improvement, but the environment for using Neovim as a main IDE for Unreal Engine development is steadily coming together.

To a great "Unreal Engine on Neovim" life, Cheers! 🍻

Top comments (0)