puremourning / vimspector

vimspector - A multi-language debugging system for Vim
http://puremourning.github.io/vimspector-web
Apache License 2.0
4.11k stars 175 forks source link

[Feature Request]: Console window improvements #52

Open doronbehar opened 5 years ago

doronbehar commented 5 years ago

So today I gave the first test drive for vimspector and I have a few comments.

First of all, Ideally, I'd expect the plugin to provide a visual mode mapping that will put the currently selected text in the console. That doesn't exist for AFAIK.

The above wouldn't have been such of an inconvenience if the console window was more comfortable. It's not clear (to me) whether it's a terminal, or a normal buffer with very special mappings.. For example, there's no undo and C-c doesn't cancel the current line entered and the up-down arrows don't put the previous commands in the line..

Wouldn't it have been better to use Vim's input("Vimspector > ")? I'm just speculating that other Vim plugins have found a better way for sending arbitrary input to other programs / jobs' stdin. Maybe it would be better to have a script that will connect (somehow - I'm not saying it'll be easy) to the debugger and launch this script inside a :terminal? I think it'll take down most of the hassle that has been put down to make that console window in the first place.

BTW, what else does the vimspector.Console window does? I'm just curios whether it's worth the space it takes from the window.

Besides that, I must say that the debugging tab is designed excellently! Was this inspired by Vs-code? I haven't used yet the watches but the stacktrace window getting updated all the time is truly awesome. Also being able to play the buttons at the top of the code window is pretty cool :+1:.

I don't want to sound too critical, I just feel like this plugin is the true (the one :ring: ) plugin that will finally bring standardized debugging capabilities to Vim in that {DA,LS}P way. That's why I'm putting my time into suggesting ideas that will hopefully improve it.

puremourning commented 5 years ago

Thanks for the feedback! Quick response because on mobile....

The console window is a Prompt Buffer. :help prompt-buffer. I’m not too interested in complex vimscript that’s emulating things.

It’s functionality is essentially limited to what DAP allows. There are some threads about better REPL/Console support on DAP github but nothing concrete.

As the console is a normal buffer you can use any buffer command, and make your own mappings. Thought when in insert mode commands like <C-r>” to insert from the yank buffer are useful.

doronbehar commented 5 years ago

The console window is a Prompt Buffer. :help prompt-buffer. I’m not too interested in complex vimscript that’s emulating things.

Wow, so that's how prompt buffers act and this is what #30 and https://github.com/neovim/neovim/pull/10433 are all about!

So I read the following in :help prompt-buffer:

If you want to type input for the job in a Vim window you have a few options:
- Use a normal buffer and handle all possible commands yourself.
  This will be complicated, since there are so many possible commands.
- Use a terminal window.  This works well if what you type goes directly to
  the job and the job output is directly displayed in the window.
  See |terminal-window|.
- Use a prompt window. This works well when entering a line for the job in Vim
  while displaying (possibly filtered) output from the job.

As far as I can see, there shouldn't be a reason to use prompt buffer unless it's desired to filter the output from the job right?

I noticed you do filter it a little bit here:

https://github.com/puremourning/vimspector/blob/4de1269baa1930184e8a175b81f457e89061c0a3/python3/vimspector/output.py#L117-L142

TBH, I think these little enhancements to the IO experience of the prompt are pretty cool but I don't think they justify the use of a prompt with such a bad UI. When I'm saying "bad UI". I'm talking about the following complaints:

As far as I can see, pretty much every readline feature one can expect, is not implemented in prompt buffers.

As the console is a normal buffer you can use any buffer command, and make your own mappings. Though when in insert mode commands like ” to insert from the yank buffer are useful.

I guess there are merits to edit a line in a prompt the Vim way and not the GNU Readline way. However, if using <C-r>" is the only usecase for this kind of things, I know for sure that Neovim's :terminal supports pasting from arbitrary registers. I'm not sure about Vim's :terminal capabilities but I'm sure it has such a capability as well.

The point is, that I think people are more 'used to' :terminals and that they'll be able to deal with whatever they'd like to enter there more comfortably then with prompt buffers. Prompt buffers are a nice idea / feature but I don't feel like they are mature enough.

Further more, replacing the prompt buffers with something else will help a lot #30.

I hope you'll appreciate my opinion. In case I've managed to influence you with my arguments, would you be interested in a PR that will replace the prompt buffers with :terminals?

puremourning commented 5 years ago

I think you might be missing that the contents of the prompt buffer are not a job in Vimspector. The content is strictly what the server sends us, and the REPL-a-like is strictly the evaluate request and reply. It's not a "job" in any sense, so you can't use a terminal buffer for it (or at least not in the way you might think - there's no shell or gnu readline-based thing running).

Prompt buffers are pretty new, and certainly not perfect, but they are afaik the best vim has to offer right now.

I'm not saying that I disagree - I actually would like a proper Pty or REPL interface but that's not possible in DAP right now, and the discussion on the referenced issue degraded due to some IMO unhelpful input.

As far as I can see, pretty much every readline feature one can expect, is not implemented in prompt buffers.

Inserting text in a prompt-buffer uses vim insert mode, which has all of the vim insert-mode commands available. You can even go back to normal mode, edit the text, etc. etc.. The command is triggered only why you press <CR> in insert mode. This is also true of the watches window which is also a prompt buffer (as explained in the docs).

C-c doesn't cancel the currently inserted line.

It exits insert mode, at which point you can "dd", just like in any other buffer.

Undo doesn't work.

Not sure exactly what it would do. But yeah, u in the normal mode could be useful. Could raise as a vim enhancement.

Up/down arrows don't bring the previous commands to the current line.

yeah, that would be nice. I tend to just use something like kky$i<C-R>" (yank the command, enter insert mode, paste the command).

TBH in most usage I don't use the console a lot. The watches window does almost everything it does and it more convenient for inspecting the results because it expands the values.

I hope you'll appreciate my opinion.

I certainly do!

In case I've managed to influence you with my arguments, would you be interested in a PR that will replace the prompt buffers with :terminals?

I would be happy to discuss concrete alternative proposals, but as mentioned I don't want to maintain a lot of complex UI logic for this sort of thing, particularly as it would seem from the linked discussion that DAP doesn't really consider the REPL interface a primary use case (although as mentioned I do).

puremourning commented 5 years ago

For the record, I would rather implement improvements to prompt-buffers in Vim than implement something in vimspector that lives in vim script or python land and attempts to emulate gnu-readline or any such.

puremourning commented 5 years ago

I’ve added a card to the trello. Please feel free to add your vote :) I will maybe start a conversation on vim-dev to try to add some useful features to vim to make prompt buffers better.

doronbehar commented 5 years ago

I think you might be missing that the contents of the prompt buffer are not a job in Vimspector. The content is strictly what the server sends us, and the REPL-a-like is strictly the evaluate request and reply. It's not a "job" in any sense, so you can't use a terminal buffer for it (or at least not in the way you might think - there's no shell or gnu readline-based thing running).

I understand, that's why I tend to think of the following, perhaps ambitious idea:

Write a Python executable that will launch a command line interpreter using cmd.py and it will connect to the debugger through a socket/RPC.

For the record, I would rather implement improvements to prompt-buffers in Vim than implement something in vimspector that lives in vim script or python land and attempts to emulate gnu-readline or any such.

I agree you shouldn't try to emulate GNU Readline. But by creating such an executable, you won't need to handle all of those GNU Readline details as the libraries that help you create such executables have already implemented them.

If we'll launch this executable instead of the prompt buffer etc., we'll benefit an interpreter that will have all readline features people are already used to. As a bonus, we can even use python-prompt-toolkit instead, and have syntax highlighting (according to the debugged language) using Pygments as exemplified here.

The harder part in this idea I think is the socket/RPC handling but I think it's doable.

doronbehar commented 5 years ago

BTW,

I’ve added a card to the trello. Please feel free to add your vote :) I will maybe start a conversation on vim-dev to try to add some useful features to vim to make prompt buffers better.

Sounds great! Is there a link to this trello calendar / TODO list?

puremourning commented 5 years ago

Sounds great! Is there a link to this trello calendar / TODO list?

Linked from the README.md

Write a Python executable that will launch a command line interpreter using cmd.py and it will connect to the debugger through a socket/RPC.

The Debug Adapter is communicating with Vimspector over stdio (or in one case a socket) using DAP, and the only things that vimspector can say to it are the contents of the DAP protocol. So we can't talk directly to "the debugger", and I'm absolutely not willing to have downstream-debugger-specifics in vimspector. It's just not manageable for 1 person in spare time, and it would mean necessarily changes to all actual downstream debuggers.

I mean I see where you're thinking. We could have some process, running in a terminal which essentially just implements the "R" and "P" parts of the "REPL" and speaks to vimspector via a socket, which forwards the resulting requests to the Debug Adapter and sends the evaluation result back to the other process. I suppose this is plausible, but it actually prevents some (somewhat) planned features, such as expanding variables printed in the console in the same way we do in the "watches" window, and possibly other things that interface provides. It also just feels wrong to run an external process to emulate a command line. Maybe we should just drop the idea and require everyone to use the Vim command line e.g. with :Vimspector console <command>; that satisfies the requirements of having the usual input-style bindings etc, but IMO feels janky.

Given that Vimspector features shall strictly be limited to the intersection of Vim features and DAP features, maybe we can do both.

doronbehar commented 5 years ago

I suppose this is plausible, but it actually prevents some (somewhat) planned features, such as expanding variables printed in the console in the same way we do in the "watches" window, and possibly other things that interface provides.

I noticed now that the Watches window is also a prompt buffer.. The idea you are presenting definitely sounds cool but it's so sad that this feature is not in Neovim yet and that even in Vim there's no history (accessible with up / down arrows). I'm considering opening an issue in vim's issue tracker about this.

Maybe we should just drop the idea and require everyone to use the Vim command line e.g. with :Vimspector console ; that satisfies the requirements of having the usual input-style bindings etc, but IMO feels janky.

I really like this idea because it will enable editing previous console commands thanks to Vim's natural command line history. I don't think this should come instead of the prompt buffers. Please tell me what do you think about the following idea:

Read a Vim g: variable that will set whether prompt buffers are to be used or not. If the variable is unset, the UI will stay the same.

But, if it's set, normal buffers will be used instead of the prompt buffers and the user will be able add watches or evaluate commands only with :Vimspector console <command> or :Vimspector watch <variable>.

Implementing this will much ease support for Neovim because you won't strictly depend upon prompt buffers.

puremourning commented 5 years ago

Read a Vim g: variable that will set whether prompt buffers are to be used or not. If the variable is unset, the UI will stay the same.

i'm generally against 2 behaviours, and strongly against switches. TBH i'm not that keen on supporting 2 different editors. it just doubles, then quadruples my testing requirements. i know from experience with YCM that the more options you add and the more clients you support the more work you generate. I suspect for neovim, vimspector will be like YCM: "sorry it's not supported, if it works, great! if it breaks, keep the pieces".

prompt buffers are being ported to neovim in the next 'release' last i heard.

For the ex-command :Vimspector, we could also implement tab-completion too (which DAP supports). I had this grand idea that i would write an omnifunc for the "console" buffer, and therein hook into (YCM's/insert-completion-plugin here) completion system within the prompt buffer as well.

OTOH, i'm not totally against adding something along the lines of "if prompt-buffers-are-supported, use them for watches and console, otherwise use standard buffers" and also supporting the :Vimspector commands if that allows more users to benefit. I sort of assumed i would have to do this at one point because a lot of vim users will expect ex-commands for things.

console or not, prompt-buffer for the wathes window IMO works great. i use it pretty much every debug session.

puremourning commented 5 years ago

btw if you want to discuss more real-time, there's a Gitter channel

doronbehar commented 5 years ago

TBH i'm not that keen on supporting 2 different editors. it just doubles, then quadruples my testing requirements.

OTOH, i'm not totally against adding something along the lines of "if prompt-buffers-are-supported, use them for watches and console, otherwise use standard buffers" and also supporting the :Vimspector commands if that allows more users to benefit.

I understand your apprehension from a 2x2 environments to test, and moreover because Neovim and Vim are, in a sence, different editors. Yet, I don't see my suggestion as a pure 2x2 cross of options. I imagine the logic of it like this:

if has('nvim') || get(g:, 'vimspector_use_normal_buffers', 0)
  " Implement :Vimspector commands ...
  " Use regular buffers ...
else
  " Do everything as before (no need to define Vimspector commands)
endif

console or not, prompt-buffer for the watches window IMO works great. i use it pretty much every debug session.

I've used the watches window now and I liked it too :smile: yet what makes me like the idea of having a :Vimspector watch command is the fact I'll be able to define a visual mode mapping that will add the selected text right away to the watch window.

It's much easier IMO then typing it from scratch in the prompt buffer or even using the clipboard. I guess it should be possible to write a function that will: Copy the selection to a certain register; Identify the watches window; Switch to it; Enter insert mode there; And finally, paste that register's contents there.

I think this is much less elegant then having a :Vimspector watch command that will talk to the adapter directly.

doronbehar commented 5 years ago

btw if you want to discuss more real-time, there's a Gitter channel

Thanks :) but it takes me a while to articulate what I write, and I'm doing several things in parallel..

puremourning commented 5 years ago

Copy the selection to a certain register

the * register ? :help quotestar

puremourning commented 5 years ago

for the record, i'm pretty strongly against if neovim in the code. i much prefer if has( 'prompt-buffer' ) or equivalent has_patch.

doronbehar commented 5 years ago

Copy the selection to a certain register

the * register ? :help quotestar

It could be any register.

for the record, i'm pretty strongly against if neovim in the code. i much prefer if has( 'prompt-buffer' ) or equivalent has_patch.

Whatever makes you comfortable. The point is that the logic and the amount of scenarios to test is not that big.

puremourning commented 5 years ago

It could be any register.

I mean, the * register does what you want already.

doronbehar commented 5 years ago

@puremourning I'd like to converge our debate if I may. My conclusions are:

We've had a number of ideas I feel may improve my experience and possibly other users' as well. I think I'll be able to make a difference if I'll create several PRs, following the MVC paradigm and hoping you'd be interested in merging at least some of them. The following, lists the subjects for each PR I'd like to address:

  1. Create a :VimspectorEval command that will evaluate variables in the console window.
  2. Create a :VimspectorWatch command that will add variables to the watch window.

This way, users will be able to prefer using these commands instead of the prompt buffers' UI. Perhaps afterwards, we could discuss Neovim support through changing the console and watch windows' buffer type. But I hope the Neovim team will merge this until then.

puremourning commented 5 years ago

👍 sounds good

eyalz800 commented 4 years ago

@puremourning @doronbehar if you are interested here is my attempt to get command history in the vimspector prompt buffer:

augroup vimspector_command_history
    autocmd!
    autocmd FileType VimspectorPrompt call InitializeVimspectorCommandHistory()
augroup end
function! InitializeVimspectorCommandHistory()
    if !exists('b:vimspector_command_history')
        inoremap <silent> <buffer> <CR> <C-o>:call VimspectorCommandHistoryAdd()<CR>
        inoremap <silent> <buffer> <Up> <C-o>:call VimspectorCommandHistoryUp()<CR>
        inoremap <silent> <buffer> <Down> <C-o>:call VimspectorCommandHistoryDown()<CR>
        let b:vimspector_command_history = []
        let b:vimspector_command_history_pos = 0
    endif
endfunction
function! VimspectorCommandHistoryAdd()
    call add(b:vimspector_command_history, getline('.'))
    let b:vimspector_command_history_pos = len(b:vimspector_command_history)
    call feedkeys("\<CR>", 'tn')
endfunction
function! VimspectorCommandHistoryUp()
    if len(b:vimspector_command_history) == 0 || b:vimspector_command_history_pos == 0
        return
    endif
    call setline('.', b:vimspector_command_history[b:vimspector_command_history_pos - 1])
    call feedkeys("\<C-o>A", 'tn')
    let b:vimspector_command_history_pos = b:vimspector_command_history_pos - 1
endfunction
function! VimspectorCommandHistoryDown()
    if b:vimspector_command_history_pos == len(b:vimspector_command_history)
        return
    endif
    call setline('.', b:vimspector_command_history[b:vimspector_command_history_pos - 1])
    call feedkeys("\<C-o>A", 'tn')
    let b:vimspector_command_history_pos = b:vimspector_command_history_pos + 1
endfunction
puremourning commented 4 years ago

I was wondering if <C-x><C-l> was enough

but that does looks surprisingly simple. It would be possible to implement something like that in vimspector (as it is in control of the prompt buffer call-back, it always gets the commands).

I might try it out, as it would be useful indeed. thanks for the ideas.

IzhakJakov commented 3 years ago

If the console window was a terminal I assume some things would output more accurately for example colors. Also, it would not show line numbers since it would be a terminal.

I give 👍 for this feature and wish there was an option to select a tty so that I could even use a separated tmux pane for console output :)

I tried using this

"args": [ ">/dev/ttys006", "2>&1" ]

However, it did not work :/

The program I am working on has a lot of color output which appear as shell color codes which makes the output very hard to read so I end up doing :w/dev/ttys006 every time which is a bit annoying 😅

puremourning commented 3 years ago

for apps that require a tty I almost always tell the debug adapter to launch the app using an the integratedTerminal or an external terminal. never the console window. That's always going to be better, and the console window for DAP is never going to be a terminal, because it can't be.

IzhakJakov commented 3 years ago

I tried adding "console": "externalTerminal" or "console": "integratedTerminal" and neither worked for me Example of what I did:

{
  "configurations": {
    "run": {
      "adapter": "vscode-go",
      "default": true,
      "configuration": {
        "request": "launch",
        "program": "${workspaceRoot}/cmd/viewer",
        "mode": "debug",
        "dlvToolPath": "$HOME/go/bin/dlv",
        "trace": true,
        "args": [
          "-keyfile", "myKeys"
        ],
        "console": "integratedTerminal"
      }
    }
  }
}

Later I also tried it with "externalConsole": false or "externalConsole": true but nothing works :/

puremourning commented 3 years ago

Possible options https://github.com/golang/vscode-go/blob/master/docs/debugging.md#launch-configurations

appears to be a limitation of vscode-go or delve. Nothing I can do about that.

IzhakJakov commented 3 years ago

I see, too bad. Thank you for your reply and creating the plugin :)