DEV Community

taku25
taku25

Posted on

[Neovim] Unreal Engine Plugin Weekly Update (2025/10/24)

Here are this week's updates for the suite of plugins, including UEP.nvim, designed to enhance your Unreal Engine development environment in Neovim.

This week's focus is on crucial bug fixes based on recent feedback and a reorganization of the plugin structure (including a new plugin) to improve future extensibility!

🐛 Bug Fixes

1. UNL.nvim: Fixed .bat file character encoding issue on Windows

We received a report that commands were failing on Windows environments due to the encoding of .bat files. (A huge thank you for the report!)

This issue occurred because cmd.exe expects Shift_JIS (CP932) encoding, while the .bat files generated by the plugin were created with UTF-8.

To fix this, we've implemented a fundamental solution to ensure stable operation across all Windows environments. We now force the character code to UTF-8 by executing chcp 65001 > nul at the beginning of the bat file and have also configured .gitattributes in the repository to enforce CRLF line endings.
(I wasn't able to reproduce the bug on my end, so please let me know if this fix doesn't work for you.)

2. UEP.nvim: Fixed issue where :UEP files missed search targets

We've fixed a bug where shader files (.ush, .usf) were not appearing in the search results of the :UEP files command.

Please run :UEP files! (with a ! at the end) to rebuild your file cache.

files_shader


✨ New Features & Changes

1. Created a Dedicated Syntax Plugin: USX.nvim

Previously, the syntax highlighting files (queries, etc.) for Unreal C++ were bundled with the tree-sitter-unreal-cpp parser itself.

We have now completely separated this into a lightweight plugin, USX.nvim, which only contains syntax definitions. Additionally, by using USX.nvim, .uproject files are treated as JSON. By installing the JSON Tree-sitter parser, you can now visually identify syntax errors.

urpject.png

  • Benefit: If you only need syntax highlighting, you no longer need to install the heavy tree-sitter-unreal-cpp parser as a separate plugin in your lazy.nvim setup, aside from the regular tree-sitter installation.

cppdescription

2. Added Highlighting for Unreal Shaders (.ush, .usf)

We've created a new tree-sitter-unreal-shader parser for Unreal Engine's shader files (.ush, .usf)!

By installing it via tree-sitter and using USX.nvim, you can now get syntax-aware highlighting for your shader files.

usfdescription

We've also updated the main tree-sitter-unreal-cpp parser to improve the accuracy of UObject analysis.

If you are using the main tree-sitter repository, please install them as follows:

    config = function(_, opts)
      vim.api.nvim_create_autocmd('User', { pattern = 'TSUpdate',
      callback = function()
          local parsers = require('nvim-treesitter.parsers')
          parsers.cpp = {
            install_info = {
              url  = 'https://github.com/taku25/tree-sitter-unreal-cpp',
              revision  = '89f3408b2f701a8b002c9ea690ae2d24bb2aae49',
            },
          }
          parsers.ushader = {
            install_info = {
              url  = 'https://github.com/taku25/tree-sitter-unreal-shader',
              revision  = '26f0617475bb5d5accb4d55bd4cc5facbca81bbd',
            },
          }
      end})

      local langs = {"cpp", "ushader","json"}
      require("nvim-treesitter").install(langs)
      local group = vim.api.nvim_create_augroup('MyTreesitter', { clear = true })
      vim.api.nvim_create_autocmd('FileType', {
        group = group,
        pattern = langs,
        callback = function(args)
          vim.treesitter.start(args.buf)
          vim.bo[args.buf].indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
        end,
      })
    end
Enter fullscreen mode Exit fullscreen mode

3. ✨ Added Search for Classes and Structs! (classes, structs)

In Unreal Engine, the filename often differs from the class name. For such cases, we've added dedicated commands to jump to definitions using symbol names instead of filenames. Thanks to parser enhancements, structs are now also included.

  • :UEP classes[!]: Displays a list of project classes in a picker and jumps to the definition file of the selected class.
  • :UEP structs[!]: Displays a list of project structs in a picker and jumps to the definition file of the selected struct.
  • Caching Strategy: Similar to :UEP files, it uses the cache if it exists. Adding a ! will force a cache rebuild.
  • Scope: Supports [Game|Engine|Editor] and [--no-deps|--all-deps] flags.

classesdescription

4. ✨ Added Go to Definition command! (goto_definition)

When you use LSP's go-to-definition (:LspDefinition or gd) in Unreal C++, you often end up at a forward declaration (class AMyActor;), right? It's a minor but persistent annoyance.

That's why we've added the :UDEV goto_definition command! 🎉 This command leverages UEP.nvim's cached information of the entire project's classes and module dependencies to elegantly bypass forward declarations and jump directly to the header file definition!

  • How does it work?: It intelligently finds the definition file for the class name under your cursor (e.g., AMyActor).
    1. First, it searches within the current module.
    2. If not found, it searches in directly dependent modules (Shallow Dependencies).
    3. If still not found, it extends the search to indirectly dependent modules (Deep Dependencies).
  • What if it's not found?: If the class isn't in the UEP cache, it safely falls back to calling the standard LSP go-to-definition. 👍
  • Pick a class to jump!: If you run the command with a ! (:UDEV goto_definition!), it ignores the cursor position and lets you choose the destination from a list of all classes in the project.

Example Keymaps:
It's convenient to use it alongside the standard gd (LSP)!

-- LSP Go to Definition (as before)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, { desc = "LSP Definition" })
-- UEP Go to Definition (Jump on the word under the cursor!)
vim.keymap.set('n', '<leader><C-]>', function() require('UnrealDev.api').goto_definition({ has_bang = false }) end, { desc = "UEP: Go to Definition (Cursor)" })
-- UEP Go to Definition (Pick a class to jump!)
vim.keymap.set('n', '<leader>gD', function() require('UnrealDev.api').goto_definition({ has_bang = true }) end, { desc = "UEP: Go to Definition (Picker)" })
Enter fullscreen mode Exit fullscreen mode

goto_definitiondescription

5. Introducing the Integrated Wrapper Plugin: UnrealDev.nvim

To solve the hassle of managing and loading multiple plugins like UEP.nvim, UCM.nvim, UBT.nvim individually, we've created a thin wrapper plugin: UnrealDev.nvim.

  • Benefit 1 (Installation): When setting up your plugins with lazy.nvim, you can now add a single line for UnrealDev.nvim and list the related plugins (like UBT.nvim) in its dependencies to load them all at once.
return {
  'taku25/UnrealDev.nvim',
  ft = { "cpp", "c" },
  cmd = {
    "UDEV",
  },
  dependencies = {
    "j-hui/fidget.nvim",
    "nvim-telescope/telescope.nvim",
    'taku25/UNL.nvim',
    'taku25/UEP.nvim',
    'taku25/UBT.nvim',
    'taku25/UCM.nvim',
    'taku25/USH.nvim',
    'taku25/ULG.nvim',
    {
        'taku25/USX.nvim',
        lazy=false,
    },
  },
}
Enter fullscreen mode Exit fullscreen mode
  • Benefit 2 (Unified Commands): Commands that were previously separate, like :UBT Build and :UCM New, have been unified under a common prefix, :UDEV. Now you can access all functionalities with commands like :UDEV Build and :UDEV New.

This plugin is simply a thin wrapper for commands and APIs. You can continue to use the individual plugins directly just as you always have without any issues.

udev_refreshdescription

udev_filesdescription

Please Note:
Some command names have been changed to avoid conflicts. Please see the GitHub repository for details.

The plugin wraps not only commands but also APIs, so you can use them via UnrealDev.api just as before:

local is_open_ui = false
  config = function(_, opts)
    require("UnrealDev").setup(opts)
     vim.keymap.set("n", "<leader>a",
       function()
         require("UnrealDev.api").switch_file()
       end,
       { noremap = true, silent = true })


     vim.keymap.set('n', '<leader>gf', require('UEP.api').open_file, { noremap = true, silent = true })

     vim.keymap.set("n", "<C-s>",
       function()

          require("UnrealDev.api").is_process_running(
         {
           process_name = "UnrealEditor",
           on_complete = function(is_runing)
             if is_runing == false then
               require("UnrealDev.api").build({})
             else
               require("UnrealDev.api").remote_command("livecoding.compile")
             end
          end
         })
       end,
       { noremap = true, silent = true })


     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("UnrealDev.api").tree()
         require("UnrealDev.api").start_log()
         is_open_ui = true
       end
     end


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

  end,
Enter fullscreen mode Exit fullscreen mode

🚀 What's Next

This week was mainly about foundational improvements. In the coming weeks, we plan to develop the following features to bring Neovim even closer to Rider and Visual Studio:

  • Refactoring Features
    • Automatic Forward Declaration: A forward declaration version of the recently added "auto-include" feature.
    • Enhanced File Renaming: When a file is renamed, automatically update the corresponding #include statements.
  • UProject
    • Accurate Cache Generation: The current cache files group things broadly into Game/Engine, making it difficult to distinguish Editor modules. We plan to accurately parse .uproject files to differentiate between Editor and Runtime modules. We also hope to automate build configurations.

If you have any feature requests or ideas, please feel free to post them on the GitHub Issues or in the comments of this article. English is perfectly fine!


☕ Casual Talk and Announcements

One final announcement.
Due to personal reasons, it will be difficult for me to secure a large block of time for development next week, so development and updates will be temporarily paused.

Please don't worry, this is definitely not because I've lost my motivation!
(If anything, my motivation is high, but since the plugins now have more than enough features for my own use, I'm spending more time wondering what to build next—and what problems you all are facing.)

That's all for this week's update

Top comments (0)