From 4d7d1097ac481fabd6c3154b1caa86b53d969dcc Mon Sep 17 00:00:00 2001 From: mathijs-bakker Date: Thu, 21 Aug 2025 16:37:05 +0200 Subject: [PATCH] gdshader support (highlighting, tree-sitter, LSP) --- README.md | 125 +++++++++++++++----------------- ftdetect/gdshader.lua | 5 ++ lua/godotdev/setup.lua | 2 + lua/godotdev/tree-sitter.lua | 32 ++++++++ queries/gdshader/highlights.scm | 55 ++++++++++++++ queries/gdshader/injections.scm | 20 +++++ 6 files changed, 172 insertions(+), 67 deletions(-) create mode 100644 ftdetect/gdshader.lua create mode 100644 lua/godotdev/tree-sitter.lua create mode 100644 queries/gdshader/highlights.scm create mode 100644 queries/gdshader/injections.scm diff --git a/README.md b/README.md index 05ddcf9..8ee7ccb 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,84 @@ # godotdev.nvim -A Neovim plugin for connecting to the Godot editor LSP server to provide code navigation, diagnostics, and LSP features for GDScript projects. Supports Windows, macOS, and Linux. +Batteries-included Neovim plugin for **Godot game development** (Godot 4.3+), using Neovim as an external editor. Provides LSP support for GDScript and Godot shaders, DAP debugging, and Treesitter syntax highlighting. ## Features -- Connect to a running Godot editor's TCP LSP server. -- LSP-based code navigation for GDScript (`gd`/`gdscript`). -- Diagnostics, hover documentation, workspace symbols, and more. -- Healthcheck to validate editor LSP and required tools. -- OS-aware handling for TCP connection (`ncat` required on Windows). +- Connect to Godot editor LSP over TCP (`127.0.0.1:6005` by default) +- Full GDScript language support +- `.gdshader` syntax highlighting via Treesitter +- Debug GDScript with `nvim-dap` (`127.0.0.1:6006` by default) +- Keymaps for common LSP actions +- Batteries included: everything you need for Godot development in Neovim ## Requirements -- Neovim 0.11+ -- Godot editor with TCP LSP server enabled (Editor Settings → Network → Enable TCP LSP server). -- **Windows:** `ncat` must be installed (via Scoop or Chocolatey). -- **macOS/Linux:** optional `nc` for port check; otherwise assumed reachable. +- Neovim 0.9+ +- Godot 4.3+ with TCP LSP enabled +- `nvim-lspconfig` +- `nvim-dap` and `nvim-dap-ui` for debugging +- `nvim-treesitter` +- Windows users must have [`ncat`](https://nmap.org/ncat/) in PATH -## Installation +## Installation (Lazy.nvim) -Using [Lazy.nvim](https://github.com/folke/lazy.nvim): ```lua -`return { +{ 'Mathijs-Bakker/godotdev.nvim', lazy = false, + dependencies = { 'nvim-lspconfig', 'nvim-dap', 'nvim-dap-ui', 'nvim-treesitter' }, config = function() - require("godotdev").setup { - editor_port = 6005, -- optional, default is 6005 - editor_host = "127.0.0.1" -- optional, default is localhost - } - end -} -``` - -## Quickstart - -```lua --- Lazy.nvim -return { - 'Mathijs-Bakker/godotdev.nvim', - config = function() - require("godotdev").setup({ - editor_host = "127.0.0.1", -- Default: 127.0.0.1 - editor_port = 6005, -- GDScript language server, default: 6005 - debug_port = 6006, -- Debug adapter server, default: 6006 - }) + require("godotdev").setup() end, } ``` +## Quickstart + +1. Open your Godot project in Neovim +1. Start Godot editor with TCP LSP enabled (Editor Settings → Network → Enable TCP LSP server) +1. Open a .gd or .gdshader file +1. LSP will automatically attach +1. Use rn to rename, gd to go to definition, gr for references, etc. +1. Start debugging with DAP (Launch scene configuration) + +## Configuration + +```lua +require("godotdev").setup({ + editor_host = "127.0.0.1", -- Godot editor host + editor_port = 6005, -- LSP port + debug_port = 6006, -- DAP port +}) +``` +# Keymaps ### LSP - -- Open any `.gd` or `.gdscript` file in your Godot project. -- The plugin connects automatically to the running Godot editor LSP. -- Keymaps for LSP features (definitions, references, symbols, etc.) are attached per buffer. +`gd` → Go to definition +`gD` → Go to declaration +`gy` → Type definition +`gi` → Go to implementation +`gr` → List references +`K` → Hover +`` → Signature help +`rn` → Rename symbol +`ca` → Code action +`f` → Format buffer +`gl` → Show diagnostics +`[d` / `]d` → Previous/next diagnostic ### DAP + `F5` -> Continue/Start + `F10` -> Step over + `F11` -> Step into + `F12` -> Step out + `db` -> Toggle Breakpoint + `dB` -> Conditional breakpoint -- Requires `nvim-dap` and `nvim-dap-ui`. -- Launch your game or scene directly from Neovim: - 1. Make sure Godot is running with the debugger server enabled. - 1. Open a `.gd` or `.gdscript` file. - 1. Use DAP commands: - - `:DapContinue` – Start/Continue debugging - - `:DapStepOver`, `:DapStepInto`, `:DapStepOut` - 1. The DAP UI automatically opens when debugging starts. +### DAP UI + `du` -> , Toggle UI + `dr` -> , Open REPL -### Healthcheck - -``` -:checkhealth godotdev -``` -- Checks if the Godot editor LSP port is reachable. -- On Windows, also checks if `ncat` is installed. -- Gives clear instructions to fix missing dependencies or misconfigured ports. - -## Configuration Options -```lua -`require("godotdev").setup { - editor_host = "127.0.0.1", -- default - editor_port = 6005, -- default -}` -``` - -## Notes - -- The plugin does **not** start a Godot instance automatically; the Godot editor must be running with TCP LSP enabled. -- On Windows, `ncat` is required for the TCP LSP connection. On macOS/Linux, the plugin assumes the port is reachable. ## License -MIT License +MI diff --git a/ftdetect/gdshader.lua b/ftdetect/gdshader.lua new file mode 100644 index 0000000..b8ae97f --- /dev/null +++ b/ftdetect/gdshader.lua @@ -0,0 +1,5 @@ +vim.filetype.add({ + extension = { + gdshader = "gdshader", + }, +}) diff --git a/lua/godotdev/setup.lua b/lua/godotdev/setup.lua index 2ad574e..91b1715 100644 --- a/lua/godotdev/setup.lua +++ b/lua/godotdev/setup.lua @@ -23,6 +23,8 @@ function M.setup(opts) host = M.opts.editor_host, port = M.opts.debug_port, }) + + require("godotdev.tree-sitter") end return M diff --git a/lua/godotdev/tree-sitter.lua b/lua/godotdev/tree-sitter.lua new file mode 100644 index 0000000..6e93ced --- /dev/null +++ b/lua/godotdev/tree-sitter.lua @@ -0,0 +1,32 @@ +local ok, ts_configs = pcall(require, "nvim-treesitter.configs") +if not ok then + return +end + +ts_configs.setup({ + ensure_installed = { "gdscript" }, + highlight = { + enable = true, + additional_vim_regex_highlighting = false, + }, +}) + +vim.filetype.add({ + extension = { + gdshader = "gdshader", + }, +}) + +local parsers_ok, ts_parsers = pcall(require, "nvim-treesitter.parsers") +if parsers_ok then + local parser_configs = ts_parsers.get_parser_configs() + parser_configs.gdshader = { + used_by = { "gdshader" }, -- filetype + install_info = { + url = "", -- no external parser + files = {}, -- no parser files + generate_requires_npm = false, + requires_generate_from_grammar = false, + }, + } +end diff --git a/queries/gdshader/highlights.scm b/queries/gdshader/highlights.scm new file mode 100644 index 0000000..6335925 --- /dev/null +++ b/queries/gdshader/highlights.scm @@ -0,0 +1,55 @@ +;; =========================== +;; Godot Shader (GDShader) Highlights +;; Extended: multi-line comments + preprocessor +;; =========================== + +;; --- Shader types --- +((identifier) @type + (#match? @type "^(spatial|canvas_item|particles|sky)$")) + +;; --- Shader stages --- +((identifier) @keyword + (#match? @keyword "^(vertex|fragment|light|start)$")) + +;; --- Built-in functions --- +((identifier) @function.builtin + (#match? @function.builtin + "^(abs|acos|asin|atan|ceil|clamp|cos|cross|cross2d|distance|dot|exp|floor|fract|inverse|length|lerp|max|min|normalize|pow|reflect|refract|round|sign|sin|sqrt|step|tan|transpose)$")) + +;; --- Godot-specific built-in functions --- +((identifier) @function.builtin + (#match? @function.builtin + "^(NODE_POSITION_WORLD|VIEWPORT_SIZE|VIEWPORT_TEXTURE|INV_CAMERA_MATRIX|CAMERA_MATRIX|NODE_MATRIX|NODE_MATRIX_INVERSE|WORLD_MATRIX|WORLD_MATRIX_INVERSE|CAMERA_DIRECTION|SCREEN_TEXTURE|TIME)$")) + +;; --- Built-in constants / vars --- +((identifier) @constant.builtin + (#match? @constant.builtin + "^(TIME|PI|TAU|E|FRAGCOORD|VERTEX|NORMAL|UV|UV2|COLOR|INSTANCE_ID|POINT_COORD|SCREEN_UV|SCREEN_PIXEL_SIZE|FRONT_FACING)$")) + +;; --- Keywords --- +((identifier) @keyword + (#match? @keyword "^(uniform|varying|const|if|else|elif|for|while|break|continue|return|discard|void|in|out|inout)$")) + +;; --- Types --- +((identifier) @type + (#match? @type "^(bool|int|float|vec2|vec3|vec4|mat3|mat4|sampler2D|samplerCube)$")) + +;; --- Operators --- +((operator) @operator + (#match? @operator "^[+\\-*/%=!<>&|^~]+$")) + +;; --- Numbers --- +((number) @number + (#match? @number "^[0-9]+(\\.[0-9]+)?$")) + +;; --- Single-line comments --- +((comment) @comment + (#match? @comment "^//.*$")) + +;; --- Multi-line comments --- +((comment) @comment + (#match? @comment "^/\\*.*\\*/$")) + +;; --- Preprocessor / directives --- +((preproc) @keyword + (#match? @preproc "^#(version|ifdef|ifndef|else|elif|endif|define|undef|extension|error|pragma)$")) diff --git a/queries/gdshader/injections.scm b/queries/gdshader/injections.scm new file mode 100644 index 0000000..bd9e9ca --- /dev/null +++ b/queries/gdshader/injections.scm @@ -0,0 +1,20 @@ +;; =========================== +;; GDShader Injections +;; =========================== + +;; Highlight expressions inside parentheses as code +((call_expression + function: (identifier) @function + arguments: (argument_list) @parameter)) + +;; Highlight numbers inside function calls +((number) @number + (#match? @number "^[0-9]+(\\.[0-9]+)?$")) + +;; Highlight vector constructors like vec2, vec3, vec4 +((identifier) @type + (#match? @type "^(vec2|vec3|vec4|mat3|mat4)$")) + +;; Highlight boolean literals inside expressions +((true) @boolean) +((false) @boolean)