I'm trying to use nvim-dap to debugger, but there is only option to gdscript, with c# the breakpoints don't pause the program, so I'm trying to use netcoredbg, someone know how can I configure the netcoredbg to debug source on godot using nvim-dap?
How can I use netcoredbg to debug c# on Godot?
I have found a solution that runs my main scene through trial and error,
return {
'mfussenegger/nvim-dap',
dependencies = {
'rcarriga/nvim-dap-ui',
'nvim-neotest/nvim-nio',
'theHamsta/nvim-dap-virtual-text',
'nvim-treesitter/nvim-treesitter',
},
lazy = false,
keys = {
{
'<F5>',
mode = { 'n' },
function()
require('dap').continue()
end,
desc = 'F5 dap ~ [c]ontinue',
},
{
'<F10>',
mode = { 'n' },
function()
require('dap').step_over()
end,
desc = 'dap ~ step [o]ver',
},
{
'<F11>',
mode = { 'n' },
function()
require('dap').step_into()
end,
desc = 'F11 dap ~ step into',
},
{
'<S-F11>',
mode = { 'n' },
function()
require('dap').step_out()
end,
desc = 'Shift F11 dap ~ Step [O]ut',
},
{
'<Leader>b',
mode = { 'n' },
function()
require('dap').toggle_breakpoint()
end,
desc = 'dap ~ toggle [b]reakpoint',
},
},
config = function()
local dap = require 'dap'
local dapui = require 'dapui'
-- Configure dapui
dapui.setup {
layouts = {
{
elements = {
{ id = 'scopes', size = 0.25 },
'breakpoints',
'stacks',
'watches',
},
size = 40,
position = 'left',
},
{
elements = {
'repl',
'console',
},
size = 0.25,
position = 'bottom',
},
},
}
-- Automatically open/close dapui
dap.listeners.before.attach.dapui_config = function()
dapui.open()
end
dap.listeners.before.launch.dapui_config = function()
dapui.open()
end
dap.listeners.before.event_terminated.dapui_config = function()
dapui.close()
end
dap.listeners.before.event_exited.dapui_config = function()
dapui.close()
end
-- Helper function to find Godot project file and directory
local function find_godot_project()
-- Create cache to avoid repeated lookups
if not _G.godot_project_cache then
_G.godot_project_cache = {}
end
-- Start with current working directory
local current_dir = vim.fn.getcwd()
-- Check cache first
if _G.godot_project_cache[current_dir] then
return _G.godot_project_cache[current_dir].file_path, _G.godot_project_cache[current_dir].dir_path
end
-- Function to check if a directory contains a project.godot file
local function has_project_file(dir)
local project_file = dir .. '/project.godot'
local stat = vim.uv.fs_stat(project_file)
if stat and stat.type == 'file' then
return project_file, dir
else
return nil, nil
end
end
-- Check current directory first
local project_file, project_dir = has_project_file(current_dir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
vim.notify('Found Godot project at: ' .. project_file, vim.log.levels.INFO)
return project_file, project_dir
end
-- Search in parent directories up to a reasonable limit
local max_depth = 5
local dir = current_dir
for i = 1, max_depth do
-- Get parent directory
local parent = vim.fn.fnamemodify(dir, ':h')
-- Stop if we've reached the root
if parent == dir then
break
end
dir = parent
-- Check if this directory has a project.godot file
local project_file, project_dir = has_project_file(dir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
vim.notify('Found Godot project in parent directory: ' .. project_file, vim.log.levels.INFO)
return project_file, project_dir
end
end
-- Search in immediate subdirectories (first level only)
local handle = vim.uv.fs_scandir(current_dir)
if handle then
while true do
local name, type = vim.uv.fs_scandir_next(handle)
if not name then
break
end
-- Only check directories
if type == 'directory' then
local subdir = current_dir .. '/' .. name
local project_file, project_dir = has_project_file(subdir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
vim.notify('Found Godot project in subdirectory: ' .. project_file, vim.log.levels.INFO)
return project_file, project_dir
end
end
end
end
-- If still not found, ask the user
local input_dir = vim.fn.input('Godot project directory: ', current_dir, 'dir')
-- Validate the input path
if input_dir ~= '' then
local project_file, project_dir = has_project_file(input_dir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
return project_file, project_dir
end
end
vim.notify('No valid Godot project found. Using current directory.', vim.log.levels.WARN)
return current_dir .. '/project.godot', current_dir
end
-- Function to debug and print the full command that will be executed
local function debug_command(executable, args)
local full_command = executable
for _, arg in ipairs(args) do
-- Properly quote arguments with spaces
if arg:find ' ' then
full_command = full_command .. ' "' .. arg .. '"'
else
full_command = full_command .. ' ' .. arg
end
end
local debug_msg = 'Executing: ' .. full_command
vim.notify(debug_msg, vim.log.levels.INFO)
vim.notify(debug_msg)
-- Debug environment info
vim.notify('Current working directory: ' .. vim.fn.getcwd())
vim.notify('HOME env: ' .. (os.getenv 'HOME' or 'not set'))
vim.notify('DISPLAY env: ' .. (os.getenv 'DISPLAY' or 'not set'))
vim.notify('XDG_SESSION_TYPE env: ' .. (os.getenv 'XDG_SESSION_TYPE' or 'not set'))
return args
end
-- Path to the Godot executable
local godot_executable = '/usr/lib/godot-mono/godot.linuxbsd.editor.x86_64.mono'
-- Get important environment variables
local function get_env_vars()
return {
-- Graphics-related variables (crucial for GUI apps)
DISPLAY = os.getenv 'DISPLAY' or ':0',
WAYLAND_DISPLAY = os.getenv 'WAYLAND_DISPLAY',
XDG_SESSION_TYPE = os.getenv 'XDG_SESSION_TYPE',
XAUTHORITY = os.getenv 'XAUTHORITY',
-- Audio-related variables
PULSE_SERVER = os.getenv 'PULSE_SERVER',
-- User-related variables
HOME = os.getenv 'HOME',
USER = os.getenv 'USER',
LOGNAME = os.getenv 'LOGNAME',
-- Path-related variables
PATH = os.getenv 'PATH',
LD_LIBRARY_PATH = os.getenv 'LD_LIBRARY_PATH',
-- Locale variables
LANG = os.getenv 'LANG' or 'en_US.UTF-8',
LC_ALL = os.getenv 'LC_ALL',
-- XDG variables
XDG_RUNTIME_DIR = os.getenv 'XDG_RUNTIME_DIR',
XDG_DATA_HOME = os.getenv 'XDG_DATA_HOME',
XDG_CONFIG_HOME = os.getenv 'XDG_CONFIG_HOME',
-- Other potentially relevant variables
SHELL = os.getenv 'SHELL',
TERM = os.getenv 'TERM',
DBUS_SESSION_BUS_ADDRESS = os.getenv 'DBUS_SESSION_BUS_ADDRESS',
}
end
-- Standard GDScript adapter for non-C# projects
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,
},
}
-- Direct launch approach using netcoredbg to start Godot-Mono
dap.adapters.coreclr = {
type = 'executable',
command = '/home/jamie/.local/share/nvim/mason/bin/netcoredbg',
args = {
'--interpreter=vscode',
'--',
godot_executable,
},
}
dap.configurations.cs = {
-- Launch Godot editor with project - simple approach
{
type = 'coreclr',
request = 'launch',
name = 'Simple Editor Launch',
cwd = function()
local project_file,project_dir = find_godot_project()
vim.notify("cwd " .. project_dir)
return project_dir
end,
env = get_env_vars(), -- Pass environment variables
args = function()
local project_file,project_dir = find_godot_project()
return {" --editor " .. project_file}
end,
},
}
-- Add visual indicators for breakpoints
vim.fn.sign_define('DapBreakpoint', { text = '●', texthl = 'DapBreakpoint', linehl = '', numhl = '' })
vim.fn.sign_define('DapBreakpointCondition', { text = '◆', texthl = 'DapBreakpointCondition', linehl = '', numhl = '' })
vim.fn.sign_define('DapLogPoint', { text = '◆', texthl = 'DapLogPoint', linehl = '', numhl = '' })
vim.fn.sign_define('DapStopped', { text = '→', texthl = 'DapStopped', linehl = 'DapStopped', numhl = 'DapStopped' })
vim.fn.sign_define('DapBreakpointRejected', { text = '●', texthl = 'DapBreakpointRejected', linehl = '', numhl = '' })
end,
}
you want to find either your godot-mono command or the executable. and replace the paths as specified. If you find out how to connect to a already running instance please share it.
budtard I can confirm this works with Godot-Mono on an Arch-based Linux environment. Just make sure your paths are correct. Make sure to replace "jamie" in command = '/home/jamie/.local/share/nvim/mason/bin/netcoredbg' with your username at a minimum. Other than that, I didn't have to change anything to make this work. Thank you! I've been trying to get this working on and off for a while now.
did anybody using lazyvim here?
i'm config based on the default implementation of lazyvim, but the Snacks.picker keep say No results found for select
-- Helper function to find Godot project file and directory
local function find_godot_project()
-- Create cache to avoid repeated lookups
if not _G.godot_project_cache then
_G.godot_project_cache = {}
end
-- Start with current working directory
local current_dir = vim.fn.getcwd()
-- Check cache first
if _G.godot_project_cache[current_dir] then
return _G.godot_project_cache[current_dir].file_path, _G.godot_project_cache[current_dir].dir_path
end
-- Function to check if a directory contains a project.godot file
local function has_project_file(dir)
local project_file = dir .. "/project.godot"
local stat = vim.uv.fs_stat(project_file)
if stat and stat.type == "file" then
return project_file, dir
else
return nil, nil
end
end
-- Check current directory first
local project_file, project_dir = has_project_file(current_dir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
Snacks.notifier.notify("Found Godot project at: " .. project_file, vim.log.levels.INFO)
return project_file, project_dir
end
-- Search in parent directories up to a reasonable limit
local max_depth = 5
local dir = current_dir
for _ = 1, max_depth do
-- Get parent directory
local parent = vim.fn.fnamemodify(dir, ":h")
-- Stop if we've reached the root
if parent == dir then
break
end
dir = parent
-- Check if this directory has a project.godot file
local project_file, project_dir = has_project_file(dir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
Snacks.notifier.notify("Found Godot project in parent directory: " .. project_file, vim.log.levels.INFO)
return project_file, project_dir
end
end
-- Search in immediate subdirectories (first level only)
local handle = vim.uv.fs_scandir(current_dir)
if handle then
while true do
local name, type = vim.uv.fs_scandir_next(handle)
if not name then
break
end
-- Only check directories
if type == "directory" then
local subdir = current_dir .. "/" .. name
local project_file, project_dir = has_project_file(subdir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
Snacks.notifier.notify("Found Godot project in subdirectory: " .. project_file, vim.log.levels.INFO)
return project_file, project_dir
end
end
end
end
-- If still not found, ask the user
local input_dir = vim.fn.input("Godot project directory: ", current_dir, "dir")
-- Validate the input path
if input_dir ~= "" then
local project_file, project_dir = has_project_file(input_dir)
if project_file then
_G.godot_project_cache[current_dir] = { file_path = project_file, dir_path = project_dir }
return project_file, project_dir
end
end
Snacks.notifier.notify("No valid Godot project found. Using current directory.", vim.log.levels.WARN)
return current_dir .. "/project.godot", current_dir
end
-- Get important environment variables for Godot
local function get_env_vars()
return {
-- Graphics-related variables
DISPLAY = os.getenv("DISPLAY") or ":0",
WAYLAND_DISPLAY = os.getenv("WAYLAND_DISPLAY"),
XDG_SESSION_TYPE = os.getenv("XDG_SESSION_TYPE"),
XAUTHORITY = os.getenv("XAUTHORITY"),
-- User-related variables
HOME = os.getenv("HOME"),
USER = os.getenv("USER"),
LOGNAME = os.getenv("LOGNAME"),
-- Path-related variables
PATH = os.getenv("PATH"),
LD_LIBRARY_PATH = os.getenv("LD_LIBRARY_PATH"),
-- Locale variables
LANG = os.getenv("LANG") or "en_US.UTF-8",
LC_ALL = os.getenv("LC_ALL"),
-- XDG variables
XDG_RUNTIME_DIR = os.getenv("XDG_RUNTIME_DIR"),
XDG_DATA_HOME = os.getenv("XDG_DATA_HOME"),
XDG_CONFIG_HOME = os.getenv("XDG_CONFIG_HOME"),
-- Other potentially relevant variables
DBUS_SESSION_BUS_ADDRESS = os.getenv("DBUS_SESSION_BUS_ADDRESS"),
}
end
return {
{
"Saghen/blink.cmp",
opts = {
keymap = {
preset = "super-tab",
},
signature = { window = { border = "rounded" } },
completion = {
menu = { border = "rounded" },
documentation = { window = { border = "rounded" } },
trigger = {
show_on_insert_on_trigger_character = false,
},
},
},
},
{
"neovim/nvim-lspconfig",
opts = {
servers = {
omnisharp = {
enable_editor_config_support = true,
settings = {
EnableEditorConfigSupport = true,
},
},
},
},
},
{
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
cs = {},
},
formatters = {
csharpier = {
command = "",
},
},
},
},
{
"mfussenegger/nvim-dap",
opts = {
adapters = {
coreclr = {
type = "executable",
command = vim.fn.exepath("netcoredbg") or "/home/fm39hz/.local/share/nvim/mason/bin/netcoredbg",
args = {
"--interpreter=vscode",
"--",
os.getenv("GODOT") or "/home/fm39hz/.config/godotenv/godot/bin/godot",
},
},
},
configurations = {
cs = {
{
type = "coreclr",
request = "launch",
name = "Simple Editor Launch",
cwd = function()
local project_file, project_dir = find_godot_project()
Snacks.notifier.notify("cwd " .. project_dir, "info")
Snacks.notifier.notify("file " .. project_file, "info")
return project_dir
end,
env = get_env_vars(),
args = function()
local project_file, project_dir = find_godot_project()
Snacks.notifier.notify("cwd " .. project_dir, "info")
return { " --editor " .. project_file }
end,
},
},
},
},
},
{
"rcarriga/nvim-dap-ui",
opts = {
expand_lines = true,
icons = { expanded = "", collapsed = "", circular = "" },
layouts = {
{
elements = {
{ id = "watches", size = 0.24 },
{ id = "scopes", size = 0.24 },
{ id = "breakpoints", size = 0.24 },
{ id = "stacks", size = 0.28 },
},
size = 0.23,
position = "right",
},
{
elements = {
{ id = "repl", size = 0.55 },
{ id = "console", size = 0.45 },
},
size = 0.27,
position = "bottom",
},
},
floating = {
max_height = 0.9,
max_width = 0.5,
border = "rounded",
},
},
},
}
why do people stray away from gdscript? C# is unreadable
budtard
Hi, ive tried your config but i keep getting this error:
This is he trace logs:
[INFO] 2025-03-27 21:33:46 dap/session.lua:1593 "Process exit" "/usr/bin/netcoredbg" 0 15814
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1533 "Spawning debug adapter" {
args = { "--interpreter=vscode", "--", "/home/shaka/.config/godotenv/godot/bin/godot" },
command = "/usr/bin/netcoredbg",
type = "executable"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1872 "request" {
arguments = {
adapterID = "nvim-dap",
clientID = "neovim",
clientName = "neovim",
columnsStartAt1 = true,
linesStartAt1 = true,
locale = "en_US.UTF-8",
pathFormat = "path",
supportsProgressReporting = true,
supportsRunInTerminalRequest = true,
supportsStartDebuggingRequest = true,
supportsVariableType = true
},
command = "initialize",
seq = 1,
type = "request"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1068 2 {
body = {
capabilities = {
exceptionBreakpointFilters = { {
filter = "user-unhandled",
label = "user-unhandled"
}, {
filter = "all",
label = "all"
} },
supportTerminateDebuggee = true,
supportsCancelRequest = true,
supportsConditionalBreakpoints = true,
supportsConfigurationDoneRequest = true,
supportsExceptionFilterOptions = true,
supportsExceptionInfoRequest = true,
supportsExceptionOptions = false,
supportsFunctionBreakpoints = true,
supportsSetExpression = true,
supportsSetVariable = true,
supportsTerminateRequest = true
}
},
event = "capabilities",
seq = "1",
type = "event"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1068 2 {
body = {
exceptionBreakpointFilters = { {
filter = "user-unhandled",
label = "user-unhandled"
}, {
filter = "all",
label = "all"
} },
supportTerminateDebuggee = true,
supportsCancelRequest = true,
supportsConditionalBreakpoints = true,
supportsConfigurationDoneRequest = true,
supportsExceptionFilterOptions = true,
supportsExceptionInfoRequest = true,
supportsExceptionOptions = false,
supportsFunctionBreakpoints = true,
supportsSetExpression = true,
supportsSetVariable = true,
supportsTerminateRequest = true
},
command = "initialize",
request_seq = 1,
seq = "2",
success = true,
type = "response"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1068 2 {
body = vim.empty_dict(),
event = "initialized",
seq = "3",
type = "event"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1872 "request" {
arguments = {
args = { " --editor /home/shaka/Projects/Nova/Nova.Game/project.godot" },
cwd = "/home/shaka/Projects/Nova/Nova.Game",
env = {
DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus",
DISPLAY = ":0",
HOME = "/home/shaka",
LANG = "en_US.UTF-8",
LOGNAME = "shaka",
PATH = "/home/shaka/.nvm/versions/node/v22.14.0/bin:/home/shaka/.config/godotenv/godot/bin:/home/shaka/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/opt/nvim:/home/shaka/.dotnet:/home/shaka/.dotnet/tools",
SHELL = "/bin/bash",
TERM = "xterm-256color",
USER = "shaka",
XAUTHORITY = "/tmp/xauth_ZxyWEi",
XDG_RUNTIME_DIR = "/run/user/1000",
XDG_SESSION_TYPE = "x11"
},
name = "Simple Editor Launch",
request = "launch",
type = "coreclr"
},
command = "launch",
seq = 2,
type = "request"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1872 "request" {
arguments = {
filters = {}
},
command = "setExceptionBreakpoints",
seq = 3,
type = "request"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1068 2 {
body = vim.empty_dict(),
command = "launch",
request_seq = 2,
seq = "4",
success = true,
type = "response"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1068 2 {
body = vim.empty_dict(),
command = "setExceptionBreakpoints",
request_seq = 3,
seq = "5",
success = true,
type = "response"
}
[DEBUG] 2025-03-27 21:34:06 dap/session.lua:1872 "request" {
command = "co