Skip to content

Commit

Permalink
Merge pull request #752 from puremourning/nvim-winbar
Browse files Browse the repository at this point in the history
Neovim: Support winbar
  • Loading branch information
mergify[bot] authored Apr 17, 2023
2 parents 83ccd02 + b3b5d40 commit 544c7af
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 146 deletions.
59 changes: 19 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,52 +250,20 @@ The following sections expand on the above brief overview.
Vimspector requires:

* One of:
* Vim 8.2 Huge build compiled with Python 3.6 or later
* Neovim 0.4.3 with Python 3.6 or later (experimental)
* Vim 8.2 Huge build compiled with Python 3.10 or later
* Neovim 0.8 with Python 3.10 or later (experimental)
* One of the following operating systems:
* Linux
* macOS Mojave or later
* Windows (experimental)

Why such a new vim? Well 2 reasons:
Which Linux versions? I only test on Ubuntu 20.04 and later and RHEL 7.

1. Because vimspector uses a lot of new Vim features
2. Because there are Vim bugs that vimspector triggers that will frustrate you
if you hit them.
### Neovim limitations

Why is neovim experimental? Because the author doesn't use neovim regularly, and
there are no regression tests for vimspector in neovim, so it may break
occasionally. Issue reports are handled on best-efforts basis, and PRs are
welcome to fix bugs. See also the next section describing differences for neovim
vs vim.
Why is Windows support experimental? Because it's effort and it's not a priority
for the author. PRs are welcome to fix bugs. Windows will not be regularly
tested.
Which Linux versions? I only test on Ubuntu 18.04 and later and RHEL 7.
## Neovim differences
neovim doesn't implement some features Vimspector relies on:

* WinBar - used for the buttons at the top of the code window and for changing
the output window's current output.
* Prompt Buffers - used to send commands in the Console and add Watches.
(*Note*: prompt buffers are available in neovim nightly)
* Balloons - this allows for the variable evaluation popup to be displayed when
hovering the mouse. See below for how to create a keyboard mapping instead.
Workarounds are in place as follows:
* WinBar - There are [mappings](#mappings),
[`:VimspectorShowOutput`](#program-output) and
[`:VimspectorReset`](#closing-debugger)
* Prompt Buffers - There are [`:VimspectorEval`](#console)
and [`:VimspectorWatch`](#watches)
* Balloons - There is the `<Plug>VimspectorBalloonEval` mapping. There is no
default mapping for this, so I recommend something like this to get variable
display in a popup:
neovim doesn't implement mouse hover balloons. Instead there is the
`<Plug>VimspectorBalloonEval` mapping. There is no default mapping for this, so
I recommend something like this to get variable display in a popup:
```viml
" mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!)
Expand All @@ -306,7 +274,7 @@ nmap <Leader>di <Plug>VimspectorBalloonEval
xmap <Leader>di <Plug>VimspectorBalloonEval
```
## Windows differences
### Windows differences
The following features are not implemented for Windows:
Expand Down Expand Up @@ -2455,6 +2423,17 @@ NOTE: This is a fairly advanced feature requiring some nontrivial vimscript.
It's possible that this feature will be incorporated into Vimspector in future
as it is a common requirement.
## Disabling the WinBar
You can tell vimspector not to draw the WinBar (the toolbars in the code,
variables, output, etc. windows) by setting:
```viml
let g:vimspector_enable_winbar=0
```
The WinBar is in any case not displayed if the mouse is not enabled.
## Advanced UI customisation
> ***Please Note***: This customisation API is ***unstable***, meaning that it may
Expand Down
33 changes: 33 additions & 0 deletions autoload/vimspector/internal/neowinbar.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
" vimspector - A multi-language debugging system for Vim
" Copyright 2020 Ben Jackson
"
" Licensed under the Apache License, Version 2.0 (the "License");
" you may not use this file except in compliance with the License.
" You may obtain a copy of the License at
"
" http://www.apache.org/licenses/LICENSE-2.0
"
" Unless required by applicable law or agreed to in writing, software
" distributed under the License is distributed on an "AS IS" BASIS,
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
" See the License for the specific language governing permissions and
" limitations under the License.


" Boilerplate {{{
let s:save_cpo = &cpoptions
set cpoptions&vim
" }}}
"
function! vimspector#internal#neowinbar#Do( idx, nclick, btn, mods ) abort
py3 __import__( "vimspector",
\ fromlist = [ "utils" ] ).utils.DoWinBarAction(
\ int( vim.eval( 'getmousepos().winid' ) ),
\ int( vim.eval( 'a:idx' ) ) )
endfunction

" Boilerplate {{{
let &cpoptions=s:save_cpo
unlet s:save_cpo
" }}}

42 changes: 19 additions & 23 deletions python3/vimspector/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,24 @@ def __init__( self,
self._current_frame = None
self._scratch_buffers = []

with utils.LetCurrentWindow( self._window ):
if utils.UseWinBar():
# Buggy neovim doesn't render correctly when the WinBar is defined:
# https://github.com/neovim/neovim/issues/12689
vim.command( 'nnoremenu WinBar.■\\ Stop '
':call vimspector#Stop()<CR>' )
vim.command( 'nnoremenu WinBar.▶\\ Cont '
':call vimspector#Continue()<CR>' )
vim.command( 'nnoremenu WinBar.▷\\ Pause '
':call vimspector#Pause()<CR>' )
vim.command( 'nnoremenu WinBar.↷\\ Next '
':call vimspector#StepSOver()<CR>' )
vim.command( 'nnoremenu WinBar.→\\ Step '
':call vimspector#StepSInto()<CR>' )
vim.command( 'nnoremenu WinBar.←\\ Out '
':call vimspector#StepSOut()<CR>' )
vim.command( 'nnoremenu WinBar.↺ '
':call vimspector#Restart()<CR>' )
vim.command( 'nnoremenu WinBar.✕ '
':call vimspector#Reset()<CR>' )

self._RenderWinBar()
signs.DefineProgramCounterSigns()


def _RenderWinBar( self ):
with utils.LetCurrentWindow( self._window ):
if utils.UseWinBar():
utils.SetWinBar(
( '■ Stop', 'vimspector#Stop()', ),
( '▶ Cont', 'vimspector#Continue()', ),
( '▷ Pause', 'vimspector#Pause()', ),
( '↷ Next', 'vimspector#StepSOver()', ),
( '→ Step', 'vimspector#StepSInto()', ),
( '← Out', 'vimspector#StepSOut()', ),
( '↺', 'vimspector#Restart()', ),
( '✕', 'vimspector#Reset()', )
)

def _UndisplayPC( self, clear_pc = True ):
if clear_pc:
self._current_frame = None
Expand Down Expand Up @@ -138,7 +132,10 @@ def SetCurrentFrame( self, frame, should_jump_to_location ):

with utils.LetCurrentWindow( self._window ):
try:
utils.OpenFileInCurrentWindow( frame[ 'source' ][ 'path' ] )
if utils.OpenFileInCurrentWindow( frame[ 'source' ][ 'path' ] ):
if utils.VimIsNeovim():
# Sigh: https://github.com/neovim/neovim/issues/23165
self._RenderWinBar()
vim.command( 'doautocmd <nomodeline> User VimspectorJumpedToFrame' )
except vim.error:
self._logger.exception( 'Unexpected vim error opening file {}'.format(
Expand Down Expand Up @@ -170,7 +167,6 @@ def SetCurrentFrame( self, frame, should_jump_to_location ):
vim.current.buffer.options[ 'syntax' ] )

self._DisplayPC()

return True

def Clear( self ):
Expand Down
37 changes: 19 additions & 18 deletions python3/vimspector/disassembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,9 @@ def __init__( self, window, api_prefix, render_event_emitter ):
'vimspectorPC': None,
}

with utils.LetCurrentWindow( self._window ):
if utils.UseWinBar():
vim.command( 'nnoremenu WinBar.■\\ Stop '
':call vimspector#Stop()<CR>' )
vim.command( 'nnoremenu WinBar.▶\\ Cont '
':call vimspector#Continue()<CR>' )
vim.command( 'nnoremenu WinBar.▷\\ Pause '
':call vimspector#Pause()<CR>' )
vim.command( 'nnoremenu WinBar.↷\\ NextI '
':call vimspector#StepIOver()<CR>' )
vim.command( 'nnoremenu WinBar.→\\ StepI '
':call vimspector#StepIInto()<CR>' )
vim.command( 'nnoremenu WinBar.←\\ OutI '
':call vimspector#StepIOut()<CR>' )
vim.command( 'nnoremenu WinBar.⟲: '
':call vimspector#Restart()<CR>' )
vim.command( 'nnoremenu WinBar.✕ '
':call vimspector#Reset()<CR>' )
self._RenderWinBar()

with utils.LetCurrentWindow( self._window ):
vim.command( 'augroup VimspectorDisassembly' )
vim.command( 'autocmd!' )
vim.command( f'autocmd WinScrolled { utils.WindowID( self._window ) } '
Expand All @@ -75,6 +59,21 @@ def __init__( self, window, api_prefix, render_event_emitter ):
signs.DefineProgramCounterSigns()


def _RenderWinBar( self ):
with utils.LetCurrentWindow( self._window ):
if utils.UseWinBar():
utils.SetWinBar(
( '■ Stop', 'vimspector#Stop()', ),
( '▶ Cont', 'vimspector#Continue()', ),
( '▷ Pause', 'vimspector#Pause()', ),
( '↷ Next', 'vimspector#StepIOver()', ),
( '→ Step', 'vimspector#StepIInto()', ),
( '← Out', 'vimspector#StepIOut()', ),
( '↺', 'vimspector#Restart()', ),
( '✕', 'vimspector#Reset()', )
)


def ConnectionClosed( self, connection: DebugAdapterConnection ):
if connection != self.current_connection:
return
Expand Down Expand Up @@ -299,6 +298,8 @@ def _DrawInstructions( self,

with utils.LetCurrentWindow( self._window ):
utils.OpenFileInCurrentWindow( buf_name )
if utils.VimIsNeovim():
self._RenderWinBar()
utils.SetUpUIWindow( self._window )
self._window.options[ 'signcolumn' ] = 'yes'

Expand Down
48 changes: 20 additions & 28 deletions python3/vimspector/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,6 @@ def Reset( self ):
def Clear( self ):
for category, tab_buffer in self._buffers.items():
self._CleanUpBuffer( category, tab_buffer )

# FIXME: nunmenu the WinBar ?
self._buffers = {}


Expand All @@ -139,9 +137,7 @@ def WindowIsValid( self ):
def UseWindow( self, win ):
assert not self._window.valid
self._window = win
# TODO: Sorting of the WinBar ?
for category, _ in self._buffers.items():
self._RenderWinBar( category )
self._RenderWinBar()


def _ShowOutput( self, category ):
Expand All @@ -153,6 +149,10 @@ def _ShowOutput( self, category ):
vim.current.buffer = self._buffers[ category ].buf
vim.command( 'normal! G' )

if utils.VimIsNeovim():
# Sigh: https://github.com/neovim/neovim/issues/23165
self._RenderWinBar()

def ShowOutput( self, category ):
self._ToggleFlag( category, False )
self._ShowOutput( category )
Expand All @@ -163,7 +163,7 @@ def _ToggleFlag( self, category, flag ):

if self._window.valid:
with utils.LetCurrentWindow( self._window ):
self._RenderWinBar( category )
self._RenderWinBar()


def RunJobWithOutput( self, category, cmd, **kwargs ):
Expand Down Expand Up @@ -205,7 +205,6 @@ def _CreateBuffer( self,

self._buffers[ category ] = TabBuffer( out, len( self._buffers ) )
self._buffers[ category ].is_job = True
self._RenderWinBar( category )
else:
if category == 'Console':
name = 'vimspector.Console'
Expand All @@ -227,7 +226,7 @@ def _CreateBuffer( self,
else:
utils.SetUpHiddenBuffer( tab_buffer.buf, name )

self._RenderWinBar( category )
self._RenderWinBar()

self._buffers[ category ].syntax = utils.SetSyntax(
self._buffers[ category ].syntax,
Expand All @@ -239,33 +238,26 @@ def _CreateBuffer( self,
self._ShowOutput( category )
utils.CleanUpHiddenBuffer( buf_to_delete )

def _RenderWinBar( self, category ):
def _RenderWinBar( self ):
if not utils.UseWinBar():
return

if not self._window.valid:
return

with utils.LetCurrentWindow( self._window ):
tab_buffer = self._buffers[ category ]

try:
if tab_buffer.flag:
vim.command( 'nunmenu WinBar.{}'.format( utils.Escape( category ) ) )
else:
vim.command( 'nunmenu WinBar.{}*'.format( utils.Escape( category ) ) )
except vim.error as e:
# E329 means the menu doesn't exist; ignore that.
if 'E329' not in str( e ):
raise

vim.command(
"nnoremenu <silent> 1.{0} WinBar.{1}{2} "
":call vimspector#ShowOutputInWindow( {3}, '{1}' )<CR>".format(
tab_buffer.index,
utils.Escape( category ),
'*' if tab_buffer.flag else '',
utils.WindowID( self._window ) ) )
tab_buffers = sorted( self._buffers.items(),
key = lambda i: i[ 1 ].index )

buttons = []
for category, tab_buffer in tab_buffers:
buttons.append(
( category + ( '*' if tab_buffer.flag else '' ),
"vimspector#ShowOutputInWindow( {}, '{}' )".format(
utils.WindowID( self._window ),
utils.Escape( category ) ) )
)
utils.SetWinBar( *buttons )

def GetCategories( self ):
return list( self._buffers.keys() )
Expand Down
3 changes: 3 additions & 0 deletions python3/vimspector/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
'terminal_maxheight': 15,
'terminal_minheight': 5,

# WinBar
'enable_winbar': True,

# Session files
'session_file_name': '.vimspector.session',

Expand Down
Loading

0 comments on commit 544c7af

Please sign in to comment.