Posted on

Writing GDScript with Neovim

Neovim is by far my favorite text editor. The clutter-free interface and keyboard-only navigation are what keep me productive in my daily programming. In an earlier post, I explained how I configure it into a minimalist development environment. Today, I will show you how to use it with Godot and GDScript.

A dramatic vim screenshot

Configure Godot

First, we need to tell Godot to use nvim as a text editor instead of the built-in one. Open Godot, and head to Editor Settings > General > Text Editor > External. There, you will need to tick the box Use external editor, indicate your Neovim installation path, and use --server /tmp/godothost --remote-send "<C-\><C-N>:n {file}<CR>{line}G{col}|" as execution flags.

The editor settings

While in the settings, head to Network > Language Server and note down the remote port Godot is using. By default, it should be 6005. We will need that value later.

Connecting to Godot with vim-godot

Neovim will be able to access Godot features by using a plugin called vim-godot. We will need to edit the nvim configuration file to install plugins and configure Neovim. On Mac and Linux, it is located at ~/.config/nvim/init.vim

I use vim-plug to manage my plugins, so I can just add it to my configuration like this:

call plug#begin('~/.vim/plugged')
" ...
Plug 'habamax/vim-godot'
" ...
call plug#end()

Once the configuration file is modified and saved, use the :PlugInstall command to install it.

You’ll also need to indicate Godot’s executable path. Add this line to your init.vim:

let g:godot_executable = '/Applications/Godot.app/Contents/MacOS/Godot'

For vim-godot to communicate with the Godot editor, it will need to listen to the /tmp/godothost file we configured in the editor previously. To do that, simply launch nvim with the flag --listen /tmp/godothost.

To save you some precious keypress, I suggest creating a new alias in your bashrc/zshrc like this:

alias gvim="nvim --listen /tmp/godothost"

Getting autocompletion with coc.nvim

Godot ships with a language server. It means the Godot editor can provide autocompletion, syntax highlighting, and advanced navigation to external editors like nvim.

While Neovim now has built-in support for the language server protocol, I’ve used the plugin coc.nvim to obtain these functionalities for years and see no reason to change. You can also install it with vim-plug by adding the following line to your plugin list:

Plug 'neoclide/coc.nvim', {'branch':'release'}

Run :PlugInstall again to install it.

You’ll need to indicate the Godot language server address and port using the command :CocConfig. It should open Coc’s configuration file, which is a JSON file normally located at ~/.config/nvim/coc-settings.json. In this file enter the following data, and make sure the port number matches the one located in your editor:

{
    "languageserver": {
        "godot": {
            "host": "127.0.0.1",
            "filetypes": ["gdscript"],
            "port": 6005
        }
    }
}

I recommend adding Coc’s example configuration to your init.vim file. You can find it on GitHub. It will provide you with a lot of useful shortcuts, such as using gd to go to a function definition and gr to list its references.

Debugging using nvim-dap

If you want to use the debugger from inside Neovim, you’ll need to install another plugin called nvim-dap. Add the following to your plugins list:

Plug 'mfussenegger/nvim-dap'

The plugin authors suggest configuring it using Lua, so let’s do that by adding the following in your init.vim:

lua <<EOF
local dap = require("dap")
dap.adapters.godot = {
	type = "server",
	host = "127.0.0.1",
	port = 6006,
}

dap.configurations.gdscript = {
	{
		type = "godot",
		request = "launch",
		name = "Launch scene",
		project = "${workspaceFolder}",
		launch_scene = true,
	},
}

vim.api.nvim_create_user_command("Breakpoint", "lua require'dap'.toggle_breakpoint()", {})
vim.api.nvim_create_user_command("Continue", "lua require'dap'.continue()", {})
vim.api.nvim_create_user_command("StepOver", "lua require'dap'.step_over()", {})
vim.api.nvim_create_user_command("StepInto", "lua require'dap'.step_into()", {})
vim.api.nvim_create_user_command("REPL", "lua require'dap'.repl.open()", {})
EOF

This will connect to the language server (here on port 6005), and allow you to pilot the debugger using the following commands:

  • :Breakpoint to create (or remove) a breakpoint
  • :Continue to launch the game or run until the next breakpoint
  • :StepOver to step over a line
  • :StepInto to step inside a function definition
  • :REPL to launch a REPL (useful if you want to examine values)

Conclusion

I hope you’ll have a great time developing Godot games with Neovim. If it helps you, you can check out my entire init.vim file on GitHub gist.