jbyuki / one-small-step-for-vimkind Goto Github PK
View Code? Open in Web Editor NEWDebug adapter for Neovim plugins
License: MIT License
Debug adapter for Neovim plugins
License: MIT License
Suppose I have a standalone main.lua
with #!/usr/bin/lua
which does some smart and tricky suftt and therefore it is complicated and therefore I need a debugger with breakpoints to debug it. How to run main.lua
under OSV? Maybe there should be an instruction for that
one-small-step-for-vimkind/doc/osv.txt
Line 71 in fa0df0a
port number is 8088
But in README.md;
8086
.
It worked correctly with 8086
.
Hello,
I was able to set it up using the provided default config:
local dap = require"dap"
dap.configurations.lua = {
{
type = 'nlua',
request = 'attach',
name = "Attach to running Neovim instance",
host = function()
local value = vim.fn.input('Host [127.0.0.1]: ')
if value ~= "" then
return value
end
return '127.0.0.1'
end,
port = function()
local val = tonumber(vim.fn.input('Port: '))
assert(val, "Please provide a port number")
return val
end,
}
}
dap.adapters.nlua = function(callback, config)
callback({ type = 'server', host = config.host, port = config.port })
end
I started debugging a lua file (adding breakpoints) and I started the server (with require"osv".launch()
) and I was able to go through and debug + get print outputs from the file.
However, I closed neovim and now when I reopen it, I keep getting the complete output of my test file on start-up.
I am not able to relaunch the server (require"osv".launch()
or require"osv".run_this()
) as each time it reports Neovim is waiting for input at startup. Aborting.
.
I have tried uninstalling this plugin but this still occurs when opening neovim (I tried running it in headless, and it still prints the file test output on startup without any errors)
How would I be able to "unblock" this situation and get back to using the plugin?
(Just to add, it is possible that I ran require"osv".launch()
from the same nvim instance that I had the debugged file open in - if that is possible? At this stage I don't remember the initial launch run)
Thanks
if i using this to auto enable the osv
vim.api.nvim_create_autocmd({ "FileType" }, {
pattern = "lua",
callback = function ()
require "osv".launch({
host = '127.0.0.1',
port = 8088,
log = false
})
end
})
then i will get this error messages
Error detected while processing CursorMoved Autocommands for "*":
E5108: Error executing lua ...vim/site/pack/packer/opt/packer.nvim/lua/packer/load.lua:165: Vim(echomsg):E114: Missing quote: "Error in packer_compiled: ...vim/site/pack/packer/opt/packer.nvim/lu
a/packer/load.lua:155: Vim(append):Error executing lua callback: /usr/share/nvim/runtime/filetype.lua:20: Vim(append):Error executing lua callback: Vim:Error invoking 'nvim_exec_lua' on channel 7
:
stack traceback:
[C]: in function 'cmd'
...vim/site/pack/packer/opt/packer.nvim/lua/packer/load.lua:165: in function <...vim/site/pack/packer/opt/packer.nvim/lua/packer/load.lua:161>
[string ":lua"]:1: in main chunk
First, ty for this really wonderful plugin, I was able to set it up nicely to work when running lua require'dap'.continue()
so I can avoid calling run_this()
or the triple instance logistics (A+B+launch()
instaces) and it works fairly well.
In case you're interested, my one-small-step-for-vimkind
configuration can be found in my config's lua/plugins/dap/lua.lua
.
Admittedly I haven't gotten deep into the code of this plugin yet but perhaps there are simple answers for my questions:
Is there an easy way to know when the luafile <file>
is done so I can shut down the server? I tried all nvim-dap events and none of them seem to fire when execution is done (e.g. event_terminated
, event_stopped
, etc), which brings me to the 2nd question/issue:
Running continue
when execution is done brings up the Session active, but not stopped at breakpoint
prompt which requires to terminate before being able to run the debug configuration again, however sending terminate fails with E5560: vimL function must not be called in a lua loop callback
at the call to vim.fn.sign_unplace
.
I believe it is an issue with
nvim-dap
and opened the below PR which solves the issue:
mfussenegger/nvim-dap#486
print
statements in the [dap-repl]
buffer? when using a double instance setup (A being the DAP server) and running :luafile myscript.lua
on A I am able to see the print statements output on the :messages
of A but not in the [dap-repl]
on B - is that a bug/setup issue or even possible?I haven't checked, but this may only be specific to callbacks (e.g. autocmd callback, timer callback). It looks like the current impl only uses debug.getlocal()
while traversing the current call stack (which may not necessarily contain all of the values the current frame/fn has access to, e.g. its upvalues from its defining context).
Also, I'm not sure if this is 100% correct regardless, as the outer frame often contains locals which shouldn't technically/normally be accessible from the current frame (although I view this issue as somewhat secondary to the issue concerning a lack of access to upvalues).
When evaluating (at least for the repl context, maybe for hover context too?), only collect the locals of the current frame/fn. Then, use debug.getupvalue()
in a loop to get/collect all of the upvalues of the current frame/fn.
Precedence/fallback order should be:
Matching Local w/ Highest Index || Matching Upvalue || Matching fenv value || nil
using the first non-nil value found.
Note
There can be multiple locals with the same name in a given frame/fn, which is why the one with the highest index wins. Simply using a foreword/increasing loop and collecting the values into a table map should be sufficient, as locals at later/higher indices will naturally overwrite earlier ones.
Note
Also note how it ends by trying to resolve against the function's env, not _G itself. The env is usually _G, but not always.
There's also a webpage on lua.org describing how to accomplish just this and precisely mimic Lua's usual value retrieval algorithm (i.e. when evaluating/executing some chunk/fn) here.
I am using one-small-step-for-vimkind in a LazyVim setup, altogether with nvim-dap and nvim-dap-ui.
Almost everything works fine (breakpoints, step-into, widgets, ...). However, the output to stdout (either via print or io.write) doesn't apper in the dap-repl or DAP Console.
Any ideas? Or this is the expected behavior?
Hi, When executing Disconnect Request
or Terminate Request
in dap-client, the response or event cannot be received.
I execute the dap.terminate()
method after successfully connecting to the debug adapter, but none of the listeners I set up are running properly.
This is my config, Modified form @ibhagwan
local ok, dap = pcall(require, 'dap')
local ok, util = pcall(require, 'util')
local function dap_server_lua(opts)
local terminal = vim.fn.split(os.getenv("TERM"), '-', 1)[1]
local pipe = vim.fn.tempname()
local cmd = string.format('%s -e nvim --listen %s', terminal, pipe)
local debugee_id = vim.fn.jobstart(cmd)
assert(debugee_id ~= 0 or debugee_id ~= -1, 'fail')
local ok, adapter_id
ok = vim.wait(5000, function ()
ok, adapter_id = pcall(vim.fn.sockconnect,'pipe', pipe, {rpc = true})
return ok and adapter_id > 0
end)
assert(ok, 'timeout')
vim.fn.rpcrequest(
adapter_id,
'nvim_create_autocmd',
'vimleavepre',
{ command = [[lua require('osv').stop()]] }
)
local server = vim.fn.rpcrequest(
adapter_id,
"nvim_exec_lua",
[[return require"osv".launch(...)]],
{ opts }
) or {}
server.adapter_id = adapter_id
server.debugee_id = debugee_id
return server
end
dap.configurations.lua = {
{
type = "nlua",
request = "attach",
name = "current file",
server = function() return dap_server_lua(nil) end,
},
}
local nlua_server_by_session_id = {}
dap.adapters.nlua = function(callback, config)
assert(config.server.host and config.server.port, 'fail')
callback({ type = 'server', host = config.server.host, port = config.server.port })
local session = dap.session() or {}
assert(session.id and session.filetype == 'lua', 'fail')
nlua_server_by_session_id[session.id] = config.server
if not dap.listeners.after['Terminate']['osv'] then
print('00')
dap.listeners.after['Terminate']['osv'] = function(session, err, respond, request_payload, mes_id)
if session.filetype ~= 'lua' then
print('11')
return
end
local server = nlua_server_by_session_id[session.id]
if not server then
print('22')
return
end
vim.fn.rpcrequest(
server.adapter_id,
"nvim_exec_lua",
[[require"osv".stop()]]
)
vim.fn.jobstop(server.debugee_id)
end
end
if not dap.listeners.after['Disconnect']['osv'] then
print('00')
dap.listeners.after['Disconnect']['osv'] = function(session, err, respond, request_payload, mes_id)
if session.filetype ~= 'lua' then
print('11')
return
end
local server = nlua_server_by_session_id[session.id]
if not server then
print('22')
return
end
vim.fn.rpcrequest(
server.adapter_id,
"nvim_exec_lua",
[[require"osv".stop()]]
)
vim.fn.jobstop(server.debugee_id)
end
end
end
local map_bak_list = {}
vim.keymap.set('n', 'dp', function() dap.toggle_breakpoint() end)
vim.keymap.set('n', 'd<cr>', function()
dap.continue({ new = true })
if #dap.sessions() > 1 then
return
end
map_bak_list = {}
for _, map in ipairs({
{ 'n', '<a-p>', function() dap.toggle_breakpoint() end },
{ 'n', '<a-c>', function() dap.toggle_breakpoint(vim.fn.input('c :')) end },
{ 'n', '<a-e>', function() dap.set_exception_breakpoints() end },
{ 'n', 'qp', function() dap.list_breakpoints() end },
{ 'n', 'cp', function() dap.clear_breakpoints() end },
{ 'n', '<a-j>', function() dap.step_into({ askForTargets = true }) end },
{ 'n', '<a-k>', function() dap.step_back({ askForTargets = true }) end },
{ 'n', '<a-l>', function() dap.step_over({ askForTargets = true }) end },
{ 'n', '<a-o>', function() dap.step_out({ askForTargets = true }) end },
{ 'n', '<a-g>', function() dap.run_to_cursor() end },
{ 'n', '<a-G>', function() dap.goto_() end },
{ 'n', '<cr>', function() dap.continue() end },
{ 'n', '<bs>', function() dap.reverse_continue() end },
{ 'n', '<a-r>', function() dap.restart() end },
{ 'n', '<space>', function() dap.pause() end },
{ 'n', '<c-n>', function() dap.down() end },
{ 'n', '<c-p>', function() dap.up() end },
{ 'n', '<c-m>', function() dap.focus_frame() end },
{ 'n', '<c-r>', function() dap.restart_frame() end },
{ 'n', 'rp', function() dap.repl.toggle() end },
{ 'n', '@>m-.<@', function()
dap.terminate()
if #dap.sessions() > 0 then
return
end
for _, map in ipairs(map_bak_list) do
util.restore_map(map)
end
end },
}) do
table.insert(map_bak_list, util.save_map(map[1], map[2]))
vim.keymap.set(map[1], map[2], map[3])
end
end)
With Python and Rust, when doing dap continue it is able to launch the debugger.
With osv I could only achieve debugging using require'osv'.run_this() to achieve the same.
This means that key maps need to be different between lua and other languages.
Is there a way to configure osv or dap so the same technique of dap continue will work also for lua debugging?
If set breakpoint on function that will be called after the lua file loaded, seems the breakpoint not work.
In the latest nightly build NVIM v0.7.0-dev+667-g419e0d117d
:lua require"osv".run_this()
or :lua require"osv".launch()
results in the following error
E5108: Error executing lua Vim:Error invoking 'nvim_exec_lua' on channel 10:
Error executing lua: [string "<nvim>"]:1: module 'osv' not found: no field package.preload['osv'] no file './osv.lua' no file '/usr/share/luajit-2.0.5/osv.lua' no file '/usr/local/share/lua/5.1/osv.lua' no file '/usr/local/share/lua/5.1/osv/init.lua' no file '/usr/share/lua/5.1/osv.lua' no file '/usr/share/lua/5.1/osv/init.lua' no file './osv.so' no file '/usr/local/lib/lua/5.1/osv.so' no file '/usr/lib/lua/5.1/osv.so' no file '/usr/local/lib/lua/5.1/loadall.so'stack traceback: [C]: in function 'require' [string "<nvim>"]:1: in main chunkstack traceback: [C]: in function 'rpcrequest' ...packer/start/one-small-step-for-vimkind/lua/osv/init.lua:706: in function 'run_this' [string ":lua"]:1: in main chunk
idk if this is possible or easy to fix but I thought I'd go ahead and create this issue anyway for reference/help/feedback. It's not a huge deal, but it does keep me from (or makes it harder at least) debugging tests (which are typically run in headless mode).
I haven't investigated this a ton yet; any ideas? Perhaps it has something to do with how nvim operates internally while in headless mode (e.g. not allowed to start a job or rpc client/server until after the ui channel/client/server/job has started)? Maybe it would require changing the rpc/server/client functions that are used for communication (e.g. to use libuv instead) in order to fix this? Or is this something that is supposed to work and is an issue on my end? Thanks
I have two files
test.lua
mycode.lua
I run server than set breakpoint inside mycode.lua
. But when I run lua require"dap".continue()
it gets me this massage 'session active but not stopped at breakpoint'
I run lua require"osv".run_this()
sometime it work and stop in breakpoint but get this massage Debug adapter diconnected
do i something wrong?
Can you add more example to documentation?
Hi, i get error message when i execute dap.restart()
, this is my config #31 (comment)
E5113: Error while calling lua chunk: Vim:E475: Invalid argument: Channel id must be a positive integer
stack traceback:
[C]: in function 'rpcnotify'
...packer/start/one-small-step-for-vimkind/lua/osv/init.lua:55: in function 'sendProxyDAP
'
...packer/start/one-small-step-for-vimkind/lua/osv/init.lua:166: in function 'f'
...packer/start/one-small-step-for-vimkind/lua/osv/init.lua:631: in function '__index'
t.lua:13: in main chunk
Sorry I haven't pinpointed the cause of this yet, but I believe it's either this plugin or nvim-dap causing it because I've only noticed this recently and only as I've been doing debug sessions over the past few days.
This just happened to me for the 2nd or 3rd time in the last 2 days, and both times I had left a debug session stay open and stopped on a breakpoint for several hours on-end (e.g. 12 hours) (including letting my computer go to sleep and waking it back up with the session still running). Anyway, I'll go to invoke a shell command and get an EAGAIN
error, and when I check my processes, there will be a very large number of nvim instances eating up all 64gb of my ram (even though I'm only running 2 or 3 myself). I am not running anything that spawns nvim processes automatically afaik (unless barebones neovim is doing that itself for some reason, which I doubt). So it is therefore likely that the cause is this plugin or nvim-dap I believe. I haven't had much chance to investigate the issue because every time it happens, by the time I realize it, my terminal freezes due to being out of ram/resources/process slots etc. Maybe it has something to do with leaving a debug session open while my computer goes to sleep? Not sure.
Note
Both times I had also toggled the dap repl, used it, and left it open as well.
I am using macOS Ventura 13.5 and neovim 0.9.1. Recently I've updated my OS and installed the dap-virtual-text
plugin.
I'll try to reproduce this or investigate it further when I get the chance.
The last time it happened to me, I had launched the debuggee using this sh script:
# I use `defer_fn()` because otherwise nvim freezes if `osv.launch()`
# is called without it, `osv.launch()` also freezes nvim if called anytime
# before `VimEnter` fires. Replacing the `defer_fn()` below with `schedule()`
# likewise freezes nvim it seems, but this behavior is another issue not related
# to this topic afaik.
nvim \
-n \
-i NONE \
-u NONE \
'+set rtp^=.' \
"+autocmd VimEnter * ++once ++nested lua vim.defer_fn(function() require'osv'.launch{ port = 8086 } end, 1e3)" \
"$@"
local api = vim.api
local dap = require 'dap'
local wk = require 'which-key'
-- DEBUGGEE CONFIGURATION
-- key: filetype of current buf
-- type: key of dap.adapters
dap.configurations.lua = {
{
type = 'nlua',
request = 'attach',
name = 'Attach to running Neovim instance',
},
}
-- ADAPTER CONFIGURATION
-- Configure nvim-dap to connect to or launch a debug adapter
dap.adapters.nlua = function(callback, config)
callback {
type = 'server',
host = config.host or '127.0.0.1',
port = config.port or 8086,
}
end
-- {{{ Mappings
local last_action
local function expand_aliases(t)
local ret = {}
for keys, def in pairs(t) do
for _, key in ipairs(type(keys) == 'table' and keys or { keys }) do
assert(ret[key] == nil, 'duplicate key/mapping: ' .. key)
ret[key] = def
end
end
return ret
end
local function step_over()
last_action = 'n'
require('dap').step_over()
end
wk.register(
expand_aliases {
name = 'DAP/Debugger',
['\\'] = {
function()
return last_action and '\\' .. last_action
or [[<Cmd>lua api.nvim_err_writeln "no previous command to reference"<CR>]]
end,
'Repeat last action',
expr = true,
noremap = false,
},
[{ 'si', 'i' }] = {
function()
last_action = 'i'
require('dap').step_into {
-- steppingGranularity = nil,
askForTargets = true,
}
end,
'Step (i)nto',
},
[{ 'so', 'o' }] = {
function()
last_action = 'o'
require('dap').step_out {
-- steppingGranularity = nil,
askForTargets = true,
}
end,
'Step (o)ut',
},
n = {
step_over,
'Step over/(n)ext',
},
c = {
function()
last_action = 'c'
require('dap').continue()
end,
'(C)ontinue',
},
['<CR>'] = {
function()
last_action = '<CR>'
require('dap').run_to_cursor()
end,
'Run to cursor',
},
p = {
function() require('dap').pause() end,
'(P)ause thread',
},
-- Breakpoints
[{ 'bt', 'bb' }] = {
function() require('dap').toggle_breakpoint() end,
'(T)oggle (b)reakpoint',
},
bl = {
function() require('dap').list_breakpoints(true) end,
'(L)ist (b)reakpoints',
},
bc = {
function() require('dap').clear_breakpoints() end,
'(C)lear (b)reakpoints',
},
[{ 'be', 'eb' }] = {
function() require('dap').set_exception_breakpoints() end,
'Set (e)xception (b)reakpoint',
},
-- gt = {
-- function()
-- require("dap").goto_(vim.v.count ~= 0 and vim.v.count or nil)
-- end,
-- "Go to cursor line",
-- },
h = {
function() require('dap.ui.widgets').hover() end,
'(H)over',
},
l = {
function()
require('osv').launch {
-- args = vim.tbl_filter(
-- (function(i)
-- return function(v)
-- i = i + 1
-- return i ~= 1
-- and v ~= "--embed"
-- and v ~= "--headless"
-- end
-- end)(0),
-- vim.v.argv
-- ),
port = 8086,
}
end,
'(L)aunch DAP Server',
},
f = {
function()
require('dap').focus_frame()
vim.cmd 'normal! zz'
end,
'(F)ocus/jump to curr frame',
},
q = {
function() require('dap').terminate() end,
'Quit/Terminate',
},
-- },
},
{
-- buffer = nil,
expr = false,
mode = 'n',
noremap = true,
nowait = false,
prefix = '\\',
silent = false,
}
)
wk.register({
['<M-Up>'] = {
function() require('dap').up() end,
'Go up in stacktrace',
},
['<M-Down>'] = {
function() require('dap').down() end,
'Go down in stacktrace',
},
['<M-Right>'] = { step_over, 'Step over' },
}, {
-- buffer = nil,
expr = false,
mode = 'n',
noremap = true,
nowait = false,
-- prefix = "\\",
silent = false,
})
-- }}}
-- {{{ Signs
for _, val in
ipairs(vim.fn.sign_define(vim.tbl_map(function(signdef)
signdef.linehl = signdef.name .. 'SignLine'
signdef.numhl = signdef.name .. 'SignNr'
signdef.texthl = signdef.name .. 'Sign'
signdef.culhl = signdef.name .. 'SignCul'
return signdef
end, {
-- For breakpoints (default: `B`)
{ name = 'DapBreakpoint' },
-- For conditional breakpoints (default: `C`)
{ name = 'DapBreakpointCondition' },
-- For log points (default: `L`)
{ name = 'DapLogPoint' },
-- To indicate where the debugee is stopped (default: `→`)
{
name = 'DapStopped',
-- icon = "",
text = '',
},
-- To indicate breakpoints rejected by the debug adapter (default: R`)
{ name = 'DapBreakpointRejected' },
})))
do
assert(val == 0, 'failed to define sign')
end
-- }}}
local liskey = 'tmillr'
dap.listeners.after.event_stopped[liskey] = function(session, ev_payload)
vim.cmd 'normal! zz'
end
require("nvim-dap-virtual-text").setup {
enabled = true, -- enable this plugin (the default)
enabled_commands = true, -- create commands DapVirtualTextEnable, DapVirtualTextDisable, DapVirtualTextToggle, (DapVirtualTextForceRefresh for refreshing when debug adapter did not notify its termination)
highlight_changed_variables = true, -- highlight changed values with NvimDapVirtualTextChanged, else always NvimDapVirtualText
highlight_new_as_changed = false, -- highlight new variables in the same way as changed variables (if highlight_changed_variables)
show_stop_reason = true, -- show stop reason when stopped for exceptions
commented = false, -- prefix virtual text with comment string
only_first_definition = false, -- only show virtual text at first definition (if there are multiple)
all_references = true, -- show virtual text on all all references of the variable (not only definitions)
clear_on_continue = true, -- clear virtual text on "continue" (might cause flickering when stepping)
--- A callback that determines how a variable is displayed or whether it should be omitted
--- @param variable Variable https://microsoft.github.io/debug-adapter-protocol/specification#Types_Variable
--- @param buf number
--- @param stackframe dap.StackFrame https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame
--- @param node userdata tree-sitter node identified as variable definition of reference (see `:h tsnode`)
--- @param options nvim_dap_virtual_text_options Current options for nvim-dap-virtual-text
--- @return string|nil A text how the virtual text should be displayed or nil, if this variable shouldn't be displayed
-- display_callback = function(variable, buf, stackframe, node, options)
-- if options.virt_text_pos == 'inline' then
-- return ' = ' .. variable.value
-- else
-- return variable.name .. ' = ' .. variable.value
-- end
-- end,
-- position of virtual text, see `:h nvim_buf_set_extmark()`, default tries to inline the virtual text. Use 'eol' to set to end of line
-- virt_text_pos = vim.fn.has 'nvim-0.10' == 1 and 'inline' or 'eol',
virt_text_pos = 'eol',
-- Experimental Features
all_frames = false, -- show virtual text for all stack frames not only current. Only works for debugpy on my machine.
virt_lines = false, -- show virtual lines instead of virtual text (will flicker!)
-- virt_text_win_col = nil -- position the virtual text at a fixed window column (starting from the first text column) ,
-- e.g. 80 to position at column 80, see `:h nvim_buf_set_extmark()`
}
Hi, I'm having trouble launching the server when I have another plugin flatten.nvim which connects to the nvim rpc server. Is there a solution to ensure both plugins work at the same time?
E5108: Error executing lua Vim:Error invoking 'nvim_exec_lua' on channel 3:
ch 3 was closed by the client
stack traceback:
[C]: in function 'rpcrequest'
...re/nvim/lazy/one-small-step-for-vimkind/lua/osv/init.lua:134: in function 'launch'
[string ":lua"]:1: in main chunk
Hi!
In README.md reads
Install
After installing one-small-step-for-vimkind, you will also need a DAP plugin which will allow you to interact with the adapter.
Please update Install instruction!
If I do the following:
nvim my_file.lua
:lua require 'osv'.launch()
nvim my_file.lua
:lua require 'dap'.continue()
→ enter the host/port:luafile %
in the first client...then execution stops at the breakpoint that I set, as it should. However, if I add or remove breakpoints in the second nvim
client, it seems to have no effect. If I change the breakpoints and :luafile %
in the first client, then execution stops at exactly the same set of breakpoints that were on when require'dap'.continue
was called.
Is this expected?
Hi, I'm trying to debug some plugins I've written, which inevitably use some key mapping and automatic commands, but I can't debug it.For example, here is the file I want to debug, I hit the breakpoint to the third line, when I run lua require'dap'.continue()
and then run lua require'dap'.step_into()
, I get the message: No stopped threads. Cannot move
vim.keymap.set('n', '<BS>',
function()
print("start")
for i=1,10 do
print(i)
end
print("end")
end
)
This is my dap config
local ok, dap = pcall(require, 'dap')
if not ok then
vim.notify('load module dap faild')
return
end
local nvim_server
local nvim_chanID
local function dap_server(opts)
assert(dap.adapters.nlua,
"nvim-dap adapter configuration for nlua not found. "..
"Please refer to the README.md or :help osv.txt")
if nvim_chanID then
local pid = vim.fn.jobpid(nvim_chanID)
vim.fn.rpcnotify(nvim_chanID, "nvim_exec_lua", [[return require"osv".stop()]])
vim.fn.jobstop(nvim_chanID)
if type(vim.loop.os_getpriority(pid)) == 'number' then
vim.loop.kill(pid, 9)
end
nvim_chanID = nil
end
nvim_chanID = vim.fn.jobstart({vim.v.progpath, '--embed', '--headless'}, {rpc = true})
assert(nvim_chanID, "Could not create neovim instance with jobstart!")
local mode = vim.fn.rpcrequest(nvim_chanID, "nvim_get_mode")
assert(not mode.blocking, "Neovim is waiting for input at startup. Aborting.")
vim.fn.rpcrequest(nvim_chanID, "nvim_command", "packadd one-small-step-for-vimkind")
nvim_server = vim.fn.rpcrequest(nvim_chanID,
"nvim_exec_lua",
[[return require"osv".launch(...)]],
{ opts })
vim.wait(100)
return nvim_server
end
dap.adapters.nlua = function(callback, config)
if not config.port then
local server = dap_server()
config.host = server.host
config.port = server.port
end
callback({ type = 'server', host = config.host, port = config.port })
if type(config.post) == 'function' then
config.post()
end
end
dap.configurations.lua = {
{
type = "nlua",
request = "attach",
name = "debug current file",
post = function()
dap.listeners.after['setBreakpoints']['osv'] = function(session, body)
assert(nvim_chanID, "Fatal: neovim RPC channel is nil!")
vim.fn.rpcnotify(nvim_chanID, "nvim_command", "luafile " .. vim.fn.expand("%:p"))
dap.listeners.after['setBreakpoints']['osv'] = nil
end
end
},
{
type = 'nlua',
request = 'attach',
name = "attach to nvim",
host = function()
local value = vim.fn.input('Host [127.0.0.1]: ')
if value ~= "" then
return value
end
return '127.0.0.1'
end,
port = function()
local val = tonumber(vim.fn.input('Port: '))
assert(val, "Please provide a port number")
return val
end,
}
}
The readme mentions that one of vimspector or nvim-dap can be used. There's no information how to configure this plugin to work with vimspector. Can you please provide one?
I am using LunarVim and would love to try the debugger but as mentioned something needs to be done with a config file. I am not sure what to do!!!
I have installed the debugger and when i try to launch the debugger i get the following error message:
E5108: Error executing lua Vim:Error invoking 'nvim_exec_lua' on channel 517:
Error executing lua: [string "<nvim>"]:1: module 'osv' not found:
Hi,
sorry this is (probably) more of a usage question than a bug report, but I didn't know where to ask questions.
I'm using this plugin with some success, but I noticed that in the REPL, I can only print the value of function-local variables (variables of the function where the debugger is currently stopped). When I try to print a variable of the enclosing scope (the module), I get "nil". Is there a way around that?
After I've finished debugging, I'd like to stop the debugger and associated processes. Currently with osv that doesn't seem possible.
Update: never mind, I reread and what I thought was missing is discussed adequately. Closing.
I followed your example and I can get dap to stop at breakpoints. (not always, sometimes it doesn't work with the simple example.)
I wanted to ask how I can use dam with larger projects? I'd like to debug Telescope to help me writing an extension.
I've added a breakpoint which should stop when I open my Telescope picker but it never stops.
In this case I don't use `luafile myscript.lua' as that's not how the function would be called.
Neovim pre-compiles a couple of it's modules.
See https://github.com/neovim/neovim/blob/0fe0cf5adaab06b92250eb350306de63c4d4f36f/CONTRIBUTING.md?plain=1#L259-L268
If you try to step into a function that's defined in such a pre-compiled module like vim.validate
(https://github.com/neovim/neovim/blob/0fe0cf5adaab06b92250eb350306de63c4d4f36f/runtime/lua/vim/shared.lua#L849-L854), the debug adapter reports frames like:
stackFrames = { {
column = 0,
id = 31,
line = 0,
name = "validate",
source = {
name = "@vim/shared.lua",
path = "/path/to/dev/project/a/vim/shared.lua"
}
}, {
/project/a
is not the folder containing neovim, but a different project I was debugging. It looks like it resolves this as relative path against the working directory?
These frames currently lead to two errors with nvim-dap:
The first is because it tries to place a sign at line 0. The second because it tries to jump to its position. Neither works in an empty document. (Signs are 1 based, and nvim-dap sets linesStartAt1 = true
, so 0 is invalid anyways)
The specification says 0 line should be ignored, but under the condition that the source attribute is missing:
https://microsoft.github.io/debug-adapter-protocol/specification#Types_StackFrame
/**
* The line within the source of the frame. If the source attribute is missing
* or doesn't exist, `line` is 0 and should be ignored by the client.
*/
line: number;
So I'm a bit reluctant to simply ignore line=0 frames.
Is there a way osv could resolve the proper source, or maybe skip them?
Self-debugging, variables are ok, the output function will not be printed to the console
How to debug unlua of Unreal Engine, this is a very interesting thing, he uses Luapanda
I see that document has suggested opening file in symlinked position to solve the problem:
one-small-step-for-vimkind/doc/osv.txt
Lines 181 to 189 in 0e87072
But actually it should not work since (neo)vim will auto resolve the symlink when opening the file: vim/vim#4942
And i've tried the following patch to always resolve link, which works for me:
diff --git a/lua/osv/init.lua b/lua/osv/init.lua
index 7fd405f..a6c5cc8 100644
--- a/lua/osv/init.lua
+++ b/lua/osv/init.lua
@@ -332,7 +332,7 @@ function M.wait_attach()
if info.source:sub(1, 1) == '@' then
stack_frame.source = {
name = info.source,
- path = vim.fn.fnamemodify(info.source:sub(2), ":p"),
+ path = vim.fn.resolve(vim.fn.fnamemodify(info.source:sub(2), ":p")),
}
stack_frame.line = info.currentline
stack_frame.column = 0
@@ -517,6 +517,7 @@ function M.wait_attach()
local path = source_path:sub(2)
local succ, path = pcall(vim.fn.fnamemodify, path, ":p")
if succ then
+ path = vim.fn.resolve(path)
path = vim.uri_from_fname(path:lower())
if bps[path] then
log("breakpoint hit")
Hope this will give help for a better solution.
Using osv with vimspector, adapter configuration:
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json#",
"adapters": {
"nlua": {
"host": "127.0.0.1",
"port": "8086"
}
},
"configurations": {
"osv": {
"adapter": "nlua",
"configuration": {
"request": "attach"
}
}
}
}
Vimspector errors, and gives the logs
2023-01-29 14:06:00,878 - INFO - **** INITIALISING NEW VIMSPECTOR SESSION ****
2023-01-29 14:06:00,878 - INFO - API is: neo
2023-01-29 14:06:00,878 - INFO - VIMSPECTOR_HOME = /home/ppeb/.local/share/nvim/site/pack/packer/start/vimspector
2023-01-29 14:06:00,878 - INFO - gadgetDir = /home/ppeb/.local/share/nvim/site/pack/packer/start/vimspector/gadgets/linux
2023-01-29 14:06:00,880 - INFO - User Msg: Loaded /home/ppeb/.cache/vimspector
2023-01-29 14:06:02,840 - INFO - User requested start debug session with {}
2023-01-29 14:06:02,842 - DEBUG - Reading configurations from: None
2023-01-29 14:06:02,842 - DEBUG - Reading configurations from: /home/ppeb/gitclone/ppebboard/.vimspector.json
2023-01-29 14:06:02,843 - DEBUG - Reading gadget config: /home/ppeb/.local/share/nvim/site/pack/packer/start/vimspector/gadgets/linux/.gadgets.json
2023-01-29 14:06:02,850 - DEBUG - Reading gadget config: None
2023-01-29 14:06:02,851 - INFO - Configuration: {"adapter": "nlua", "configuration": {"request": "attach"}}
2023-01-29 14:06:02,851 - INFO - Adapter: {"host": "127.0.0.1", "port": "8086"}
2023-01-29 14:06:02,854 - DEBUG - min_width/height: 149/50, actual: 283/70 - result: horizontal
2023-01-29 14:06:02,968 - DEBUG - LAUNCH!
2023-01-29 14:06:02,974 - INFO - Starting debug adapter with: {"host": "127.0.0.1", "port": "8086"}
2023-01-29 14:06:02,974 - DEBUG - Connection Type: neochannel
2023-01-29 14:06:02,989 - INFO - Debug Adapter Started
2023-01-29 14:06:02,990 - DEBUG - Sending Message: {"command": "initialize", "arguments": {"adapterID": "adapter", "clientID": "vimspector", "clientName": "vimspector", "linesStartAt1": true, "columnsStartAt1": true, "locale": "en_GB", "pathFormat": "path", "supportsVariableType": true, "supportsVariablePaging": false, "supportsRunInTerminalRequest": true, "supportsMemoryReferences": true}, "seq": 0, "type": "request"}
2023-01-29 14:06:03,024 - DEBUG - Message received: {'seq': 1, 'request_seq': 0, 'type': 'response', 'success': True, 'body': [], 'command': 'initialize'}
2023-01-29 14:06:03,025 - DEBUG - Sending Message: {"command": "attach", "arguments": {"request": "attach", "name": "test"}, "seq": 1, "type": "request"}
2023-01-29 14:06:03,025 - DEBUG - Message received: {'seq': 2, 'type': 'event', 'event': 'initialized'}
2023-01-29 14:06:03,025 - DEBUG - Sending Message: {"command": "setBreakpoints", "arguments": {"source": {"name": "gen.lua", "path": "/home/ppeb/gitclone/ppebboard/lua/ppebboard/gen.lua"}, "breakpoints": [{"line": 37}], "sourceModified": false}, "seq": 2, "type": "request"}
2023-01-29 14:06:03,026 - DEBUG - Sending Message: {"command": "setExceptionBreakpoints", "arguments": {"filters": []}, "seq": 3, "type": "request"}
2023-01-29 14:06:03,091 - DEBUG - Message received: {'seq': 1, 'request_seq': 1, 'type': 'response', 'success': True, 'command': 'attach'}
2023-01-29 14:06:03,135 - DEBUG - Message received: {'seq': 2, 'request_seq': 2, 'type': 'response', 'success': True, 'body': {'breakpoints': [{'verified': True}]}, 'command': 'setBreakpoints'}
2023-01-29 14:06:03,135 - DEBUG - Message received: {'seq': 3, 'request_seq': 3, 'type': 'response', 'success': True, 'body': {'breakpoints': []}, 'command': 'setExceptionBreakpoints'}
2023-01-29 14:06:03,139 - DEBUG - Sending Message: {"command": "threads", "seq": 4, "type": "request"}
2023-01-29 14:06:03,141 - DEBUG - Message received: {'seq': 4, 'request_seq': 4, 'type': 'response', 'success': True, 'body': {'threads': [{'id': 1, 'name': 'main'}]}, 'command': 'threads'}
2023-01-29 14:06:06,493 - DEBUG - Message received: {'seq': 5, 'type': 'event', 'event': 'stopped', 'body': {'reason': 'breakpoint', 'threadId': 1}}
2023-01-29 14:06:06,494 - WARNING - User Msg: Paused in thread 1 due to breakpoint
2023-01-29 14:06:06,504 - DEBUG - Sending Message: {"command": "threads", "seq": 5, "type": "request"}
2023-01-29 14:06:06,544 - DEBUG - Message received: {'seq': 6, 'request_seq': 5, 'type': 'response', 'success': True, 'body': {'threads': [{'id': 1, 'name': 'main'}]}, 'command': 'threads'}
2023-01-29 14:06:06,545 - DEBUG - Sending Message: {"command": "stackTrace", "arguments": {"threadId": 1}, "seq": 6, "type": "request"}
2023-01-29 14:06:06,595 - DEBUG - Message received: {'seq': 7, 'request_seq': 6, 'type': 'response', 'success': True, 'body': {'stackFrames': [{'id': 1, 'name': 'create_board', 'column': 0, 'line': 37, 'source': {'path': '/home/ppeb/gitclone/ppebboard/lua/ppebboard/gen.lua', 'name': '@/home/ppeb/.local/share/nvim/site/pack/packer/start/ppebboard/lua/ppebboard/gen.lua'}}, {'id': 2, 'name': 'main'}], 'totalFrames': 2}, 'command': 'stackTrace'}
In the last line, 'stackFrames': [], the second one, {'id': 2, 'name': 'main'}
is missing the line field, which is required in a StackFrame
I just installed this plugin and followed all the instructions precisely to get it set up and start debugging. As soon as I ran launch()
however, I received an error:
E5108: Error executing lua: Vim:Error invoking 'nvim_exec_lua' on channel 4:
Error executing lua: [string "<nvim>"]:1: module 'osv' not found:
no field package.preload['osv']
no file '/nix/store/rnjjjd25ms18dmyb47mpnfw17jn5lzss-luajit-2.1.0-2022-10-04-env/share/lua/5.1/osv.lua'
no file '/nix/store/rnjjjd25ms18dmyb47mpnfw17jn5lzss-luajit-2.1.0-2022-10-04-env/share/lua/5.1/osv/init.lua'
no file '/nix/store/rnjjjd25ms18dmyb47mpnfw17jn5lzss-luajit-2.1.0-2022-10-04-env/lib/lua/5.1/osv.so'
stack traceback:
[C]: in function 'require'
[string "<nvim>"]:1: in main chunk
stack traceback:
[C]: in function 'rpcrequest'
...rt/vimplugin-one-small-step-for-vimkind/lua/osv/init.lua:143: in function 'launch'
I think I know what the issue is, because this is something that I've run into recently with plenary. My nvim and plugins are all managed and installed by the nix pkg manager. To install Neovim, Nix builds a static/readonly wrapper shell script that wraps and exec's the actual nvim
binary, and then links this script into PATH
as nvim
. The reason for the wrapper is to pass several environment vars and cli args automatically directly to nvim
, for example to set 'packpath'
to the appropriate value to bootstrap plugin loading. Anyway, the crux of the issue comes down to the use of v:progpath
which is a readonly variable that is resolved and set internally by nvim. Even when nvim
is/points to a wrapper executable/bash script around the actual binary and exec -a "$0" ...
is used within the wrapper to invoke it, vim/neovim still sets v:progpath
to the actual underlying binary instead of the wrapper script, meaning that none of my plugins get loaded automatically (leading to the error above).
Perhaps it would be possible to allow for the nvim binary spawned by this plugin to be specified/configured (whether via a function arg, or env var, etc.)? This would help out anyone who's using nix or a wrapped nvim
binary.
On an unrelated note, I was also curious if this plugin allows configuring the communication with the server in order to have it go over a unix domain socket/pipe instead of tcp? The former should be more secure and performant and is also recommended over tcp in the neovim docs. I think nvim actually defaults to using a pipe as well (see :h rpc-connecting
).
Thanks
To start, this is an amazing plugin :)
However I am noticing quite often that my breakpoints are treated more as suggestions as opposed to hard breakpoints. They aren't ignored, but the debugger likes to first stop inside the osv project before it stops in whatever code I have added a breakpoint to. Additionally, often the debugger will use the step over
command to jump into some other running code before coming back to the section I care about (the next line in my project).
Its really cool to see all the different plugins that are running and such, but not really useful when I am trying to hunt down a bug in my own code. The Visual Studio debugger has an option for "justMyCode" where it doesn't traverse into "outside project" code, I was wondering if this is a thing I can enable for osv?
Hi, I am trying to set it up to debug my nvim lua plugins.
suppose I am trying to debug lua_test.lua. Flowed the instruction in README.md
I will open lua_test.lua in nvim instance 1 and run launch. it will echo a port (e.g. 64929) debug server is on.
In another nvim open lua_test.lua. and run lua require'dap'.countine
. I will be ask to input the debug server port.
But after I input the port. There is no message to indicate I connected to the server or not. If I run require'dap'.continue, I saw
no stopped thread, Can not move`
Is anything missed in my steps?
Hi, I'm trying to use OSV for the first time. I'm following the setup / quick-start instructions verbatim and getting an error:
E5108: Error executing lua Vim:Error invoking 'nvim_get_mode' on channel 3:
ch 3 sent an invalid message, closed.
stack traceback:
[C]: in function 'rpcrequest'
...nvim/plugged/one-small-step-for-vimkind/lua/osv/init.lua:95: in function 'launch'
[string ":lua"]:1: in main chunk
I'm using Neovim 0.7 from Homebrew and the latest versions of OSV and nvim-dap
as of today. My nvim-dap
is confirmed working (I can successfully use nvim-dap-python
, for example).
NVIM v0.5.0-dev+1300-g7fcc59655
Hi, I'm having some trouble trying to get the plugin working and I'm not sure if it's the plugin, nvim or something else with my set up. When I try to launch(), nvim is locking up - I can see the new spawned instance of embedded/headless vim in the process table, but it goes no further. A bit of debugging shows the problem lies with the rpcrequest blocking and never returning:
https://github.com/jbyuki/one-small-step-for-vimkind/blob/main/lua/osv/init.lua#L86
if I comment that line out, the same problem occurs at:
https://github.com/jbyuki/one-small-step-for-vimkind/blob/main/lua/osv/init.lua#L90
I'm using nvim nightly. Not sure if it's broken or maybe it has changed the way rpcrequests are handled, so the problem may be with nvim rather than the plugin.
I am trying to setup one-small-step-for-vimkind and make it work with nvim-dap, and it seems like everything is working, but I do not manage to make the plugin add a watch or evaluate a value on the fly :
Since I manage to do it with a Python debugger and the same nvim-dap, I guess the issue comes from either one-small-step-for-vimkind or (probably) my configuration.
Versions/Commits hashes :
one-small-step-for-vimkind : 27e5f59
nvim-dap : 6cedcb5
My config for the DAP is the following :
local dap = require('dap')
dap.configurations.lua = {
{
type = "nlua",
request = "attach",
name = "Attach to running Neovim instance",
host = function()
local value = vim.fn.input "Host [127.0.0.1]: "
if value ~= "" then
return value
end
return "127.0.0.1"
end,
port = function()
local val = tonumber(vim.fn.input("Port: ", "54321"))
assert(val, "Please provide a port number")
return val
end,
},
}
dap.adapters.nlua = function(callback, config)
callback { type = "server", host = config.host, port = config.port, log = true }
end
Obviously, I don't exclude having made a stupid mistake somewhere due to my lack of experience with configuring vim and LUA 😬
I recently started to use lazyvim and quickly became interested in debugging plugins. I tried lazyvim default nvim lua debug setup. But every time I was trying to attach a debugger to nvim instance I get: Couldn't connect to 127.0.0.1:8086: ECONNREFUSED.
Debugger will work
v0.9.4
MacOS 14.1.2 (23B92)
-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")
-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end
-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)
vim.g.mapleader = " "
-- install plugins
local plugins = {
"folke/tokyonight.nvim",
{
"mfussenegger/nvim-dap",
dependencies = {
{
"jbyuki/one-small-step-for-vimkind",
config = function()
local dap = require("dap")
dap.configurations.lua = {
{
type = "nlua",
request = "attach",
name = "Attach to running Neovim instance",
},
}
dap.adapters.nlua = function(callback, config)
callback({ type = "server", host = config.host or "127.0.0.1", port = config.port or 8086 })
end
end,
},
},
keys = {
{
"<leader>db",
function()
require("dap").toggle_breakpoint()
end,
desc = "Toggle Breakpoint",
},
{
"<leader>dc",
function()
require("dap").continue()
end,
desc = "Continue",
},
},
},
}
require("lazy").setup(plugins, {
root = root .. "/plugins",
})
vim.cmd.colorscheme("tokyonight")
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.