simrat39 / rust-tools.nvim

Tools for better development in rust using neovim's builtin lsp
MIT License
2.16k stars 158 forks source link

Improve debugging configuration (displaying local variables, etc) #45

Closed elkowar closed 3 years ago

elkowar commented 3 years ago

Rust is known to be,... difficult with dap. rust-lldb apparently promises to aid the formatting and displaying of variables, although documentation on that is sparse.

For reference, currently values like strings or enums are diplayed like this: image which is obviously suboptimal. Firstly, the string content is displayed,... badly. secondly, the value of an enum variable is completely invisible.

Looking through several repos and projects where this has been discussed, it always sounds as though there was some solution that some people manage to get to work, although I've not yet found any concrete "this is what you need to do" solution that I could provide and propose here.

Rust-tools uses lldb-vscode for their debugging. Looking at the rust langauge support section of the CodeLLDB repo, proper displaying of these values is promised. Surely enough, in VSCode, values do actually get shown correctly.

I'm not quite sure if this means that there is some magic that the VSCode plugin does on top of lldb-vscode to manipulate how the data is shown / sourced, or if this is achieved by some magical configuration that can be passed to lldb-vscode directly. Given that setting this up for nvim-dap seems to be an unsolved problem currently, the rust-tools.nvim project might be the chance to figure out a reference solution for this, and then potentially upstream that to the nvim-dap repo itself.

This is not a concrete proposal, but just me throwing out some thoughts and hoping that someone more knowledgeable about the debug adapter situation will read this ^^' I played around with the mentioned "sourceLanguages": ["rust"] option, but that alone did not change anything for me at least.

simrat39 commented 3 years ago

Thanks for the issue. I'll check out what vscode does to see if its any different

simrat39 commented 3 years ago

fwiw, does vimspector work any different?

elkowar commented 3 years ago

Haven't played around with vimspector much, so I can't tell you. I think I remember it working better though, yes. It relies on the VSCode stuff more directly as far as I can tell, so it might make use of the same logic.

In general, I'd love to see the "standard" that neovim debugging tries to reach to stay the best-case (VSCode) rather than the best-case-in-vim (vimspector) - and of course, to at some point become "nvim-dap with rust-tools.nvim" ^^

robashton commented 3 years ago

Okay - My colleague and I have spent a day playing with our nvim/rust experience and I think we have a handle on this.

At the root of it, the key discovery is that vscode-lldb extension is not using lldb-vscode from LLVM. It has its own adapter which does its own interpretation/understanding of rust structures.

So yes, you can launch lldb-vscode and ask to debug rust, and you will get unintelligible structures back like everybody is presently seeing.

You can also launch the wrapper that the vscode-lldb extension includes in its repo, and use that instead, resulting in the expected/desired pretty printing.

An example of this can be found over on my fork of rust-tools.nvim https://github.com/robashton/rust-tools.nvim/commit/64af19183e51911886f3fc82b23cb2430ababcaf

In that case, codelldb is the wrapper that the vscode-lldb extension uses for dap. (It is actually a wrapper of that wrapper, as the wrapper would like to know where lldb is located and I am using nixos and this becomes a bit of a dance).

#!/nix/store/9ywr69qi622lrmx5nn88gk8jpmihy0dz-bash-4.4-p23/bin/bash
/nix/store/i7bg6iwh0sw4nib08yhwla47zxlh2ifq-vscode-extension-vadimcn-vscode-lldb-1.6.5/share/vscode/extensions/vadimcn.vscode-lldb/adapter/.codelldb-wrapped_ \
--liblldb /nix/store/i7bg6iwh0sw4nib08yhwla47zxlh2ifq-vscode-extension-vadimcn-vscode-lldb-1.6.5/share/vscode/extensions/vadimcn.vscode-lldb/lldb/lib/liblldb.so $@

That itself was generated in my nix config using the following runes

    ( writeScriptBin "codelldb" ''
      #!${pkgs.bash}/bin/bash
      ${nixPackages.vscode-extensions.vadimcn.vscode-lldb}/share/vscode/extensions/vadimcn.vscode-lldb/adapter/.codelldb-wrapped_ \
      --liblldb ${nixPackages.vscode-extensions.vadimcn.vscode-lldb}/share/vscode/extensions/vadimcn.vscode-lldb/lldb/lib/liblldb.so $@
    ''
    )

I've not sent this as a pull request because quite frankly, I don't know that this is what you want in rust-tools.nvim - a dependency on a VS code extension and having to build that in a way that it was not designed to be built. But it does answer the above question as to why the behaviour in VSCode is different to everything else using lldb-vscode.

It is nice having the above code set up, as it means the rust-tools integration for debugging from the menu just works, perhaps allowing override how that rt_lldb is setup might be useful, or some other option.

I'll be interested in what opinions are floating around over this, I don't have strong ones of my own - perhaps reaching out to the author of the VScode extension might be fruitful.

robashton commented 3 years ago

(As an addendum, as stated above - this is precisely what vimspector is doing, so there is indeed precedence https://github.com/puremourning/vimspector#rust )

simrat39 commented 3 years ago

I've not sent this as a pull request because quite frankly, I don't know that this is what you want in rust-tools.nvim - a dependency on a VS code extension and having to build that in a way that it was not designed to be built. But it does answer the above question as to why the behaviour in VSCode is different to everything else using lldb-vscode.

I think the optimal solution would be the ability to customize the default adapter, this way people who wanna use the wacky setup of Codelldb can do so

robashton commented 3 years ago

wacky setup is about right - it might be more palatable if the adapter was packaged as a thing in its own right and didn't need the janky lldb setup, it would also be somewhat better if the adapter could run using stdio instead of having to spawn it up and then connect to it as a server - but these things are what they are and it has no doubt been done how it is done because it is convenient and easy to do this in the original environment for which it was designed (the VS code experience is very good out of the box, having spun it up to compare whilst investigating this).

Being able to simply supply/override the adapter setup seems ideal to me - the most important thing here is that the codelldb setup was at least documented, as searching around yielded plenty of results where people wanting this, without any solutions actually forthcoming!

simrat39 commented 3 years ago

Oke we can customize the default adapter now. I'll update the readme once I get a handle on how this stuff actually works, or if you're down for it, feel free to send a PR!

robashton commented 3 years ago

neat - I'll pull down latest, update my config and see what's what

simrat39 commented 3 years ago

image I got it working :) thanks to @robashton 's work. I made a small change though. We don't know what port is gonna be free, so we parse that when codelldb runs. Here's my implementation:

function M.get_codelldb_adapter(codelldb_path, liblldb_path)
    return function(callback, _)
        local stdout = vim.loop.new_pipe(false)
        local handle
        local pid_or_err
        local port

        local opts = {
            stdio = {nil, stdout},
            args = {"--liblldb", liblldb_path},
            detached = true
        }

        handle, pid_or_err = vim.loop.spawn(codelldb_path, opts, function(code)
            stdout:close()
            handle:close()
            if code ~= 0 then
                print('codelldb exited with code', code)
            end
        end)

        assert(handle, 'Error running codelldb: ' .. tostring(pid_or_err))

        stdout:read_start(function(err, chunk)
            assert(not err, err)
            if chunk then
                if not port then
                    local chunks = {}
                    for substring in chunk:gmatch("%S+") do
                       table.insert(chunks, substring)
                    end
                    port = tonumber(chunks[#chunks])
                else
                    vim.schedule(function()
                        require('dap.repl').append(chunk)
                    end)
                end
            end
        end)

        vim.defer_fn(function()
            callback({type = "server", host = "127.0.0.1", port = port})
        end, 100)
    end
end

I'll add this as a helper function.

simrat39 commented 3 years ago

https://github.com/simrat39/rust-tools.nvim#a-better-debugging-experience @elkowar try this and let us know!

robashton commented 3 years ago

Oh nice! I’ll update my config and try it out when I’m next at a computer

lasse16 commented 3 years ago

Hi, This is very similar to something I found in an issue on the nvim-dap repo here. And the wiki page created for CodeLLDB setup.

I am going to edit the nvim-dap wiki. Could you read through that, too please? In order to avoid any unnecessary duplication?

Also, is there any way to reuse the adapter definitions from nvim-dap, without redefining them in the rust-tools config? Currently, RustDebuggables fails for me, as it looks for the lldb-vscode binary.

simrat39 commented 3 years ago

Hi, This is very similar to something I found in an issue on the nvim-dap repo here. And the wiki page created for CodeLLDB setup.

I am going to edit the nvim-dap wiki. Could you read through that, too please? In order to avoid any unnecessary duplication?

Also, is there any way to reuse the adapter definitions from nvim-dap, without redefining them in the rust-tools config? Currently, RustDebuggables fails for me, as it looks for the lldb-vscode binary.

Well you can use the adapter or that function wherever you want, just do a require('blah blah').blah(). rust-tools uses the adapter provided in the config so you need to read your adapter from dap and put it to rust-tools' config.

simrat39 commented 3 years ago

Also the wiki looks good on a quick glance!

lasse16 commented 3 years ago

I found the Better-Debugging config from the README and re-using my nvim-dap adapter definition to not work, when looking for RustDebuggables.

The error message is still "lldb-vscode not found. Please install lldb.".

Looking through the source code, I found this section, that looks for the lldb-vscode binary in the PATH. I think this might be the faulty section.

https://github.com/simrat39/rust-tools.nvim/blob/c2aacb9cd51907ec6cce65a683cb2df6ae78a227/lua/rust-tools/dap.lua#L93-L96

When using a custom adapter, the hardcoded binary name and the presence in PATH might not be given, e.g. the CodeLLDB binary is called codelldb.

lasse16 commented 3 years ago

Also, thanks for your feedback on the wiki ☺️

simrat39 commented 3 years ago

@lasse16 yes I should probably remove that

lasse16 commented 3 years ago

👍 CodeLLDB and Debuggables are working on my setup.

Just in case anybody else stumbles on this thread. I used the CodeLLDB setup as described in the nvim-dap wiki, and then reused the adapter configuration with rust-tools like so

require'rust-tools'.setup({
-- ...
-- rust tool setup
-- ...
    dap = {
      adapter = require('dap').adapters.lldb
    }
})
simrat39 commented 3 years ago

That's great, I'll close this in a couple of days

simrat39 commented 3 years ago

Closing because the stuff is done :+1:

elkowar commented 3 years ago

This all looks really nice indeed, thanks a lot already! However, trying the setup mentioned in the readme and trying to start a debugging session, I just get codelldb exited with code 1 - running debugging in VScode however just works. Where am I messing up here? ^^' any help would be appreciated

lasse16 commented 3 years ago

Don't know if I can really help here. 😅 I am using reusing the setup from nvim-dap, as described here.

Feel free to reference my dotfiles, if you want to copy my setup. The relevant sections are dap-adapter configuration and reusing definition for rust-tools.

simrat39 commented 3 years ago

@elkowar could you show your rust-tools config please?

elkowar commented 3 years ago

@simrat39 i hope the Fennel here is basic enough to understand: https://github.com/elkowar/dots-of-war/blob/a7b6ba71df915da879a909f5cbb6a7e1200f9284/nvim/.config/nvim/fnl/dots/plugins/lsp.fnl#L100 Should be directly equivalent to what's shown in the readme (except the minor version difference of codelldb - assuming that's not the issue?)

simrat39 commented 3 years ago

@elkowar the config looks fine. Could you try running the codelldb adapter from your terminal and see what it outputs?

lasse16 commented 3 years ago

I tested the function from the README on my setup and it is working.

Check PR #75, I added the logging mechanism to stderr, so its output is now printed to the nvim.dap.repl and the default vim messages, i.e. :messages. With that change, debugging the setup should be easier.

Should also note, that the get_codelldb_adapter() function is now almost identical to the one written in the nvim-dap wiki.

elkowar commented 3 years ago

https://github.com/elkowar/dots-of-war/commit/0d87f0c2476a20d98cd2bd5532deafe5a3b4da8d wow I'm stupid, I'll go find a corner to hide in ^^ Thanks folks, nevermind me

robashton commented 3 years ago

I didn't see that, and I honest to god thought "I wonder if it's just a typo" and explicitly checked those two lines