Merge pull request #197 from puremourning/use-buffers-not-windows
Allow users to close UI windows
This commit is contained in:
commit
fe58b94bb0
16 changed files with 244 additions and 112 deletions
|
|
@ -20,12 +20,20 @@ set cpoptions&vim
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
function! s:_OnServerData( channel, data ) abort
|
function! s:_OnServerData( channel, data ) abort
|
||||||
|
if !exists( 's:ch' ) || s:ch isnot a:channel
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
py3 << EOF
|
py3 << EOF
|
||||||
_vimspector_session.OnChannelData( vim.eval( 'a:data' ) )
|
_vimspector_session.OnChannelData( vim.eval( 'a:data' ) )
|
||||||
EOF
|
EOF
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_OnClose( channel ) abort
|
function! s:_OnClose( channel ) abort
|
||||||
|
if !exists( 's:ch' ) || s:ch isnot a:channel
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
echom 'Channel closed'
|
echom 'Channel closed'
|
||||||
redraw
|
redraw
|
||||||
unlet s:ch
|
unlet s:ch
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ set cpoptions&vim
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
function! s:_OnServerData( channel, data ) abort
|
function! s:_OnServerData( channel, data ) abort
|
||||||
if !exists( 's:job' )
|
if !exists( 's:job' ) || ch_getjob( a:channel ) isnot s:job
|
||||||
call ch_log( 'Get data after process exit' )
|
call ch_log( 'Get data after process exit' )
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
@ -29,7 +29,7 @@ function! s:_OnServerData( channel, data ) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_OnServerError( channel, data ) abort
|
function! s:_OnServerError( channel, data ) abort
|
||||||
if !exists( 's:job' )
|
if !exists( 's:job' ) || ch_getjob( a:channel ) isnot s:job
|
||||||
call ch_log( 'Get data after process exit' )
|
call ch_log( 'Get data after process exit' )
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
@ -37,7 +37,16 @@ function! s:_OnServerError( channel, data ) abort
|
||||||
py3 _vimspector_session.OnServerStderr( vim.eval( 'a:data' ) )
|
py3 _vimspector_session.OnServerStderr( vim.eval( 'a:data' ) )
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
" FIXME: We should wait until both the exit_cb _and_ the channel closed callback
|
||||||
|
" have been received before OnServerExit?
|
||||||
|
|
||||||
function! s:_OnExit( channel, status ) abort
|
function! s:_OnExit( channel, status ) abort
|
||||||
|
if !exists( 's:job' ) || ch_getjob( a:channel ) isnot s:job
|
||||||
|
call ch_log( 'Unexpected exit callback' )
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
echom 'Channel exit with status ' . a:status
|
echom 'Channel exit with status ' . a:status
|
||||||
redraw
|
redraw
|
||||||
if exists( 's:job' )
|
if exists( 's:job' )
|
||||||
|
|
@ -47,6 +56,11 @@ function! s:_OnExit( channel, status ) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_OnClose( channel ) abort
|
function! s:_OnClose( channel ) abort
|
||||||
|
if !exists( 's:job' ) || job_getchannel( s:job ) != a:channel
|
||||||
|
call ch_log( 'Channel closed after exit' )
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
echom 'Channel closed'
|
echom 'Channel closed'
|
||||||
redraw
|
redraw
|
||||||
endfunction
|
endfunction
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,14 @@ set cpoptions&vim
|
||||||
|
|
||||||
|
|
||||||
function! s:_OnEvent( chan_id, data, event ) abort
|
function! s:_OnEvent( chan_id, data, event ) abort
|
||||||
|
if v:exiting isnot# v:null
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists( 's:ch' ) || a:chan_id != s:ch
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
if a:data == ['']
|
if a:data == ['']
|
||||||
echom 'Channel closed'
|
echom 'Channel closed'
|
||||||
redraw
|
redraw
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,14 @@ set cpoptions&vim
|
||||||
|
|
||||||
|
|
||||||
function! s:_OnEvent( chan_id, data, event ) abort
|
function! s:_OnEvent( chan_id, data, event ) abort
|
||||||
|
if v:exiting isnot# v:null
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !exists( 's:job' ) || a:chan_id != s:job
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
" In neovim, the data argument is a list.
|
" In neovim, the data argument is a list.
|
||||||
if a:event ==# 'stdout'
|
if a:event ==# 'stdout'
|
||||||
py3 _vimspector_session.OnChannelData( '\n'.join( vim.eval( 'a:data' ) ) )
|
py3 _vimspector_session.OnChannelData( '\n'.join( vim.eval( 'a:data' ) ) )
|
||||||
|
|
@ -30,11 +38,7 @@ function! s:_OnEvent( chan_id, data, event ) abort
|
||||||
elseif a:event ==# 'exit'
|
elseif a:event ==# 'exit'
|
||||||
echom 'Channel exit with status ' . a:data
|
echom 'Channel exit with status ' . a:data
|
||||||
redraw
|
redraw
|
||||||
if exists( 's:job' )
|
unlet s:job
|
||||||
unlet s:job
|
|
||||||
endif
|
|
||||||
" This causes terminal spam in neovim due to
|
|
||||||
" https://github.com/neovim/neovim/issues/11725
|
|
||||||
py3 _vimspector_session.OnServerExit( vim.eval( 'a:data' ) )
|
py3 _vimspector_session.OnServerExit( vim.eval( 'a:data' ) )
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
@ -108,10 +112,22 @@ function! vimspector#internal#neojob#Reset() abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:_OnCommandEvent( category, id, data, event ) abort
|
function! s:_OnCommandEvent( category, id, data, event ) abort
|
||||||
|
if v:exiting isnot# v:null
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
if a:data == ['']
|
if a:data == ['']
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if !has_key( s:commands, a:category )
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if !has_key( s:commands[ a:category ], a:id )
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
if a:event ==# 'stdout'
|
if a:event ==# 'stdout'
|
||||||
let buffer = s:commands[ a:category ][ a:id ].stdout
|
let buffer = s:commands[ a:category ][ a:id ].stdout
|
||||||
elseif a:event ==# 'stderr'
|
elseif a:event ==# 'stderr'
|
||||||
|
|
@ -212,8 +228,8 @@ function! vimspector#internal#neojob#CleanUpCommand( category ) abort
|
||||||
endif
|
endif
|
||||||
|
|
||||||
for id in keys( s:commands[ a:category ] )
|
for id in keys( s:commands[ a:category ] )
|
||||||
call jobstop( id )
|
call jobstop( str2nr( id ) )
|
||||||
call jobwait( id )
|
call jobwait( [ str2nr( id ) ] )
|
||||||
endfor
|
endfor
|
||||||
unlet! s:commands[ a:category ]
|
unlet! s:commands[ a:category ]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,17 @@ function! vimspector#internal#neoterm#ResetEnvironment( env, old_env ) abort
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! vimspector#internal#neoterm#Start( cmd, opts ) abort
|
function! vimspector#internal#neoterm#Start( cmd, opts ) abort
|
||||||
|
" Prepare current buffer to be turned into a term if curwin is not set
|
||||||
if ! get( a:opts, 'curwin', 0 )
|
if ! get( a:opts, 'curwin', 0 )
|
||||||
|
let mods = ''
|
||||||
if get( a:opts, 'vertical', 0 )
|
if get( a:opts, 'vertical', 0 )
|
||||||
vnew
|
let mods .= 'vertical '
|
||||||
|
let mods .= get( a:opts, 'term_cols', '' )
|
||||||
else
|
else
|
||||||
new
|
let mods .= get( a:opts, 'term_rows', '' )
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
execute mods . 'new'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" HACK: Neovim's termopen doesn't support env
|
" HACK: Neovim's termopen doesn't support env
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ class CodeView( object ):
|
||||||
'breakpoints': []
|
'breakpoints': []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
with utils.LetCurrentWindow( self._window ):
|
with utils.LetCurrentWindow( self._window ):
|
||||||
vim.command( 'nnoremenu WinBar.Continue :call vimspector#Continue()<CR>' )
|
vim.command( 'nnoremenu WinBar.Continue :call vimspector#Continue()<CR>' )
|
||||||
vim.command( 'nnoremenu WinBar.Next :call vimspector#StepOver()<CR>' )
|
vim.command( 'nnoremenu WinBar.Next :call vimspector#StepOver()<CR>' )
|
||||||
|
|
@ -56,6 +55,10 @@ class CodeView( object ):
|
||||||
|
|
||||||
|
|
||||||
def SetCurrentFrame( self, frame ):
|
def SetCurrentFrame( self, frame ):
|
||||||
|
"""Returns True if the code window was updated with the frame, False
|
||||||
|
otherwise. False means either the frame is junk, we couldn't find the file
|
||||||
|
(or don't have the data) or the code window no longer exits."""
|
||||||
|
|
||||||
if self._signs[ 'vimspectorPC' ]:
|
if self._signs[ 'vimspectorPC' ]:
|
||||||
vim.command( 'sign unplace {} group=VimspectorCode'.format(
|
vim.command( 'sign unplace {} group=VimspectorCode'.format(
|
||||||
self._signs[ 'vimspectorPC' ] ) )
|
self._signs[ 'vimspectorPC' ] ) )
|
||||||
|
|
@ -67,8 +70,25 @@ class CodeView( object ):
|
||||||
if 'path' not in frame[ 'source' ]:
|
if 'path' not in frame[ 'source' ]:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
utils.JumpToWindow( self._window )
|
self._signs[ 'vimspectorPC' ] = self._next_sign_id
|
||||||
|
self._next_sign_id += 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
vim.command( 'sign place {0} group=VimspectorCode priority=20 '
|
||||||
|
'line={1} name=vimspectorPC '
|
||||||
|
'file={2}'.format(
|
||||||
|
self._signs[ 'vimspectorPC' ],
|
||||||
|
frame[ 'line' ],
|
||||||
|
frame[ 'source' ][ 'path' ] ) )
|
||||||
|
except vim.error as e:
|
||||||
|
# Ignore 'invalid buffer name'
|
||||||
|
if 'E158' not in str( e ):
|
||||||
|
raise
|
||||||
|
|
||||||
|
if not self._window.valid:
|
||||||
|
return False
|
||||||
|
|
||||||
|
utils.JumpToWindow( self._window )
|
||||||
try:
|
try:
|
||||||
utils.OpenFileInCurrentWindow( frame[ 'source' ][ 'path' ] )
|
utils.OpenFileInCurrentWindow( frame[ 'source' ][ 'path' ] )
|
||||||
except vim.error:
|
except vim.error:
|
||||||
|
|
@ -89,16 +109,6 @@ class CodeView( object ):
|
||||||
frame[ 'source' ][ 'path' ] )
|
frame[ 'source' ][ 'path' ] )
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._signs[ 'vimspectorPC' ] = self._next_sign_id
|
|
||||||
self._next_sign_id += 1
|
|
||||||
|
|
||||||
vim.command( 'sign place {0} group=VimspectorCode priority=20 '
|
|
||||||
'line={1} name=vimspectorPC '
|
|
||||||
'file={2}'.format(
|
|
||||||
self._signs[ 'vimspectorPC' ],
|
|
||||||
frame[ 'line' ],
|
|
||||||
frame[ 'source' ][ 'path' ] ) )
|
|
||||||
|
|
||||||
self.current_syntax = utils.ToUnicode(
|
self.current_syntax = utils.ToUnicode(
|
||||||
vim.current.buffer.options[ 'syntax' ] )
|
vim.current.buffer.options[ 'syntax' ] )
|
||||||
|
|
||||||
|
|
@ -210,13 +220,19 @@ class CodeView( object ):
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'vertical': 1,
|
'vertical': 1,
|
||||||
|
'term_cols': 80,
|
||||||
'norestore': 1,
|
'norestore': 1,
|
||||||
'cwd': cwd,
|
'cwd': cwd,
|
||||||
'env': env,
|
'env': env,
|
||||||
}
|
}
|
||||||
|
|
||||||
window_for_start = self._window
|
if self._window.valid:
|
||||||
if self._terminal_window is not None:
|
window_for_start = self._window
|
||||||
|
else:
|
||||||
|
# TOOD: Where?
|
||||||
|
window_for_start = vim.current.window
|
||||||
|
|
||||||
|
if self._terminal_window is not None and self._terminal_window.valid:
|
||||||
assert self._terminal_buffer_number
|
assert self._terminal_buffer_number
|
||||||
if ( self._terminal_window.buffer.number == self._terminal_buffer_number
|
if ( self._terminal_window.buffer.number == self._terminal_buffer_number
|
||||||
and int( utils.Call( 'vimspector#internal#{}term#IsFinished'.format(
|
and int( utils.Call( 'vimspector#internal#{}term#IsFinished'.format(
|
||||||
|
|
|
||||||
|
|
@ -518,6 +518,10 @@ class DebugSession( object ):
|
||||||
self.SetCurrentFrame( None )
|
self.SetCurrentFrame( None )
|
||||||
|
|
||||||
def SetCurrentFrame( self, frame ):
|
def SetCurrentFrame( self, frame ):
|
||||||
|
if not frame:
|
||||||
|
self._stackTraceView.Clear()
|
||||||
|
self._variablesView.Clear()
|
||||||
|
|
||||||
if not self._codeView.SetCurrentFrame( frame ):
|
if not self._codeView.SetCurrentFrame( frame ):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -526,9 +530,6 @@ class DebugSession( object ):
|
||||||
self._stackTraceView.SetSyntax( self._codeView.current_syntax )
|
self._stackTraceView.SetSyntax( self._codeView.current_syntax )
|
||||||
self._variablesView.LoadScopes( frame )
|
self._variablesView.LoadScopes( frame )
|
||||||
self._variablesView.EvaluateWatches()
|
self._variablesView.EvaluateWatches()
|
||||||
else:
|
|
||||||
self._stackTraceView.Clear()
|
|
||||||
self._variablesView.Clear()
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,10 @@ class OutputView( object ):
|
||||||
self._ToggleFlag( category, True )
|
self._ToggleFlag( category, True )
|
||||||
|
|
||||||
# Scroll the buffer
|
# Scroll the buffer
|
||||||
with utils.RestoreCurrentWindow():
|
if self._window.valid:
|
||||||
with utils.RestoreCurrentBuffer( self._window ):
|
with utils.RestoreCurrentWindow():
|
||||||
self._ShowOutput( category )
|
with utils.RestoreCurrentBuffer( self._window ):
|
||||||
|
self._ShowOutput( category )
|
||||||
|
|
||||||
def ConnectionUp( self, connection ):
|
def ConnectionUp( self, connection ):
|
||||||
self._connection = connection
|
self._connection = connection
|
||||||
|
|
@ -96,18 +97,17 @@ class OutputView( object ):
|
||||||
if tab_buffer.is_job:
|
if tab_buffer.is_job:
|
||||||
utils.CleanUpCommand( tab_buffer.job_category or category,
|
utils.CleanUpCommand( tab_buffer.job_category or category,
|
||||||
self._api_prefix )
|
self._api_prefix )
|
||||||
try:
|
utils.CleanUpHiddenBuffer( tab_buffer.buf )
|
||||||
vim.command( 'bdelete! {0}'.format( tab_buffer.buf.number ) )
|
|
||||||
except vim.error as e:
|
|
||||||
# FIXME: For now just ignore the "no buffers were deleted" error
|
|
||||||
if 'E516' not in str( e ):
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
# FIXME: nunmenu the WinBar ?
|
||||||
self._buffers = {}
|
self._buffers = {}
|
||||||
|
|
||||||
def _ShowOutput( self, category ):
|
def _ShowOutput( self, category ):
|
||||||
|
if not self._window.valid:
|
||||||
|
return
|
||||||
|
|
||||||
utils.JumpToWindow( self._window )
|
utils.JumpToWindow( self._window )
|
||||||
vim.command( 'bu {0}'.format( self._buffers[ category ].buf.name ) )
|
vim.current.buffer = self._buffers[ category ].buf
|
||||||
vim.command( 'normal G' )
|
vim.command( 'normal G' )
|
||||||
|
|
||||||
def ShowOutput( self, category ):
|
def ShowOutput( self, category ):
|
||||||
|
|
@ -146,8 +146,10 @@ class OutputView( object ):
|
||||||
def _ToggleFlag( self, category, flag ):
|
def _ToggleFlag( self, category, flag ):
|
||||||
if self._buffers[ category ].flag != flag:
|
if self._buffers[ category ].flag != flag:
|
||||||
self._buffers[ category ].flag = flag
|
self._buffers[ category ].flag = flag
|
||||||
with utils.LetCurrentWindow( self._window ):
|
|
||||||
self._RenderWinBar( category )
|
if self._window.valid:
|
||||||
|
with utils.LetCurrentWindow( self._window ):
|
||||||
|
self._RenderWinBar( category )
|
||||||
|
|
||||||
|
|
||||||
def RunJobWithOutput( self, category, cmd ):
|
def RunJobWithOutput( self, category, cmd ):
|
||||||
|
|
@ -155,6 +157,9 @@ class OutputView( object ):
|
||||||
|
|
||||||
|
|
||||||
def _CreateBuffer( self, category, file_name = None, cmd = None ):
|
def _CreateBuffer( self, category, file_name = None, cmd = None ):
|
||||||
|
if not self._window.valid:
|
||||||
|
return
|
||||||
|
|
||||||
with utils.LetCurrentWindow( self._window ):
|
with utils.LetCurrentWindow( self._window ):
|
||||||
with utils.RestoreCurrentBuffer( self._window ):
|
with utils.RestoreCurrentBuffer( self._window ):
|
||||||
|
|
||||||
|
|
@ -185,8 +190,7 @@ class OutputView( object ):
|
||||||
utils.SetUpPromptBuffer( tab_buffer.buf,
|
utils.SetUpPromptBuffer( tab_buffer.buf,
|
||||||
'vimspector.Console',
|
'vimspector.Console',
|
||||||
'> ',
|
'> ',
|
||||||
'vimspector#EvaluateConsole',
|
'vimspector#EvaluateConsole' )
|
||||||
hidden=True )
|
|
||||||
else:
|
else:
|
||||||
utils.SetUpHiddenBuffer(
|
utils.SetUpHiddenBuffer(
|
||||||
tab_buffer.buf,
|
tab_buffer.buf,
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,10 @@ class StackTraceView( object ):
|
||||||
self._threads = []
|
self._threads = []
|
||||||
self._sources = {}
|
self._sources = {}
|
||||||
|
|
||||||
utils.SetUpScratchBuffer( self._buf, 'vimspector.StackTrace' )
|
utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' )
|
||||||
|
|
||||||
vim.current.buffer = self._buf
|
vim.current.buffer = self._buf
|
||||||
# FIXME: Remove all usage of "Windown" and just use buffers to prevent all
|
utils.SetUpUIWindow( vim.current.window )
|
||||||
# the bugs around the window being closed.
|
|
||||||
self._win = vim.current.window
|
|
||||||
utils.SetUpUIWindow( self._win )
|
|
||||||
|
|
||||||
vim.command( 'nnoremap <buffer> <CR> :call vimspector#GoToFrame()<CR>' )
|
vim.command( 'nnoremap <buffer> <CR> :call vimspector#GoToFrame()<CR>' )
|
||||||
|
|
||||||
|
|
@ -84,7 +81,7 @@ class StackTraceView( object ):
|
||||||
|
|
||||||
def Reset( self ):
|
def Reset( self ):
|
||||||
self.Clear()
|
self.Clear()
|
||||||
# TODO: delete the buffer ?
|
utils.CleanUpHiddenBuffer( self._buf )
|
||||||
|
|
||||||
def LoadThreads( self, infer_current_frame ):
|
def LoadThreads( self, infer_current_frame ):
|
||||||
pending_request = False
|
pending_request = False
|
||||||
|
|
@ -311,4 +308,4 @@ class StackTraceView( object ):
|
||||||
def SetSyntax( self, syntax ):
|
def SetSyntax( self, syntax ):
|
||||||
self._current_syntax = utils.SetSyntax( self._current_syntax,
|
self._current_syntax = utils.SetSyntax( self._current_syntax,
|
||||||
syntax,
|
syntax,
|
||||||
self._win )
|
self._buf )
|
||||||
|
|
|
||||||
|
|
@ -86,15 +86,18 @@ def CleanUpCommand( name, api_prefix ):
|
||||||
name ) )
|
name ) )
|
||||||
|
|
||||||
|
|
||||||
|
def CleanUpHiddenBuffer( buf ):
|
||||||
|
try:
|
||||||
|
vim.command( 'bdelete! {}'.format( buf.number ) )
|
||||||
|
except vim.error as e:
|
||||||
|
# FIXME: For now just ignore the "no buffers were deleted" error
|
||||||
|
if 'E516' not in str( e ):
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def SetUpScratchBuffer( buf, name ):
|
def SetUpScratchBuffer( buf, name ):
|
||||||
buf.options[ 'buftype' ] = 'nofile'
|
SetUpHiddenBuffer( buf, name )
|
||||||
buf.options[ 'swapfile' ] = False
|
|
||||||
buf.options[ 'modifiable' ] = False
|
|
||||||
buf.options[ 'modified' ] = False
|
|
||||||
buf.options[ 'readonly' ] = True
|
|
||||||
buf.options[ 'buflisted' ] = False
|
|
||||||
buf.options[ 'bufhidden' ] = 'wipe'
|
buf.options[ 'bufhidden' ] = 'wipe'
|
||||||
buf.name = name
|
|
||||||
|
|
||||||
|
|
||||||
def SetUpHiddenBuffer( buf, name ):
|
def SetUpHiddenBuffer( buf, name ):
|
||||||
|
|
@ -108,7 +111,7 @@ def SetUpHiddenBuffer( buf, name ):
|
||||||
buf.name = name
|
buf.name = name
|
||||||
|
|
||||||
|
|
||||||
def SetUpPromptBuffer( buf, name, prompt, callback, hidden=False ):
|
def SetUpPromptBuffer( buf, name, prompt, callback ):
|
||||||
# This feature is _super_ new, so only enable when available
|
# This feature is _super_ new, so only enable when available
|
||||||
if not Exists( '*prompt_setprompt' ):
|
if not Exists( '*prompt_setprompt' ):
|
||||||
return SetUpHiddenBuffer( buf, name )
|
return SetUpHiddenBuffer( buf, name )
|
||||||
|
|
@ -119,7 +122,8 @@ def SetUpPromptBuffer( buf, name, prompt, callback, hidden=False ):
|
||||||
buf.options[ 'modified' ] = False
|
buf.options[ 'modified' ] = False
|
||||||
buf.options[ 'readonly' ] = False
|
buf.options[ 'readonly' ] = False
|
||||||
buf.options[ 'buflisted' ] = False
|
buf.options[ 'buflisted' ] = False
|
||||||
buf.options[ 'bufhidden' ] = 'wipe' if not hidden else 'hide'
|
buf.options[ 'bufhidden' ] = 'hide'
|
||||||
|
buf.options[ 'textwidth' ] = 0
|
||||||
buf.name = name
|
buf.name = name
|
||||||
|
|
||||||
vim.eval( "prompt_setprompt( {0}, '{1}' )".format( buf.number,
|
vim.eval( "prompt_setprompt( {0}, '{1}' )".format( buf.number,
|
||||||
|
|
@ -177,7 +181,6 @@ def RestoreCurrentWindow():
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def RestoreCurrentBuffer( window ):
|
def RestoreCurrentBuffer( window ):
|
||||||
# TODO: Don't trigger autoccommands when shifting buffers
|
|
||||||
old_buffer = window.buffer
|
old_buffer = window.buffer
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
|
|
@ -194,6 +197,14 @@ def LetCurrentWindow( window ):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def LetCurrentBuffer( buf ):
|
||||||
|
with RestoreCursorPosition():
|
||||||
|
with RestoreCurrentBuffer( vim.current.window ):
|
||||||
|
vim.current.buffer = buf
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
def JumpToWindow( window ):
|
def JumpToWindow( window ):
|
||||||
vim.current.tabpage = window.tabpage
|
vim.current.tabpage = window.tabpage
|
||||||
vim.current.window = window
|
vim.current.window = window
|
||||||
|
|
@ -555,8 +566,11 @@ def SetSyntax( current_syntax, syntax, *args ):
|
||||||
if current_syntax == syntax:
|
if current_syntax == syntax:
|
||||||
return
|
return
|
||||||
|
|
||||||
for win in args:
|
for buf in args:
|
||||||
with LetCurrentWindow( win ):
|
with LetCurrentBuffer( buf ):
|
||||||
|
# We use set syn= because just setting vim.Buffer.options[ 'syntax' ]
|
||||||
|
# doesn't actually trigger the Syntax autocommand, and i'm not sure that
|
||||||
|
# 'doautocmd Syntax' is the right solution or not
|
||||||
vim.command( 'set syntax={}'.format( Escape( syntax ) ) )
|
vim.command( 'set syntax={}'.format( Escape( syntax ) ) )
|
||||||
|
|
||||||
return syntax
|
return syntax
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,11 @@
|
||||||
import abc
|
import abc
|
||||||
import vim
|
import vim
|
||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from vimspector import utils
|
from vimspector import utils
|
||||||
|
|
||||||
View = namedtuple( 'View', [ 'win', 'lines', 'draw' ] )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Expandable:
|
class Expandable:
|
||||||
"""Base for anything which might contain a hierarchy of values represented by
|
"""Base for anything which might contain a hierarchy of values represented by
|
||||||
|
|
@ -104,7 +100,6 @@ class Variable( Expandable ):
|
||||||
self.variable = variable
|
self.variable = variable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Watch:
|
class Watch:
|
||||||
"""Holds a user watch expression (DAP request) and the result (WatchResult)"""
|
"""Holds a user watch expression (DAP request) and the result (WatchResult)"""
|
||||||
def __init__( self, expression: dict ):
|
def __init__( self, expression: dict ):
|
||||||
|
|
@ -114,29 +109,43 @@ class Watch:
|
||||||
self.result = None
|
self.result = None
|
||||||
|
|
||||||
|
|
||||||
|
class View:
|
||||||
|
lines: typing.Dict[ int, Expandable ]
|
||||||
|
draw: typing.Callable
|
||||||
|
|
||||||
|
def __init__( self, win, lines, draw ):
|
||||||
|
self.lines = lines
|
||||||
|
self.draw = draw
|
||||||
|
self.buf = win.buffer
|
||||||
|
|
||||||
|
utils.SetUpUIWindow( win )
|
||||||
|
|
||||||
|
|
||||||
class VariablesView( object ):
|
class VariablesView( object ):
|
||||||
def __init__( self, connection, variables_win, watches_win ):
|
def __init__( self, connection, variables_win, watches_win ):
|
||||||
self._logger = logging.getLogger( __name__ )
|
self._logger = logging.getLogger( __name__ )
|
||||||
utils.SetUpLogging( self._logger )
|
utils.SetUpLogging( self._logger )
|
||||||
|
|
||||||
self._vars = View( variables_win, {}, self._DrawScopes )
|
|
||||||
self._watch = View( watches_win, {}, self._DrawWatches )
|
|
||||||
self._connection = connection
|
self._connection = connection
|
||||||
self._current_syntax = ''
|
self._current_syntax = ''
|
||||||
|
|
||||||
# Allows us to hit <CR> to expand/collapse variables
|
# Set up the "Variables" buffer in the variables_win
|
||||||
with utils.LetCurrentWindow( self._vars.win ):
|
self._scopes: typing.List[ Scope ] = []
|
||||||
|
self._vars = View( variables_win, {}, self._DrawScopes )
|
||||||
|
utils.SetUpHiddenBuffer( self._vars.buf, 'vimspector.Variables' )
|
||||||
|
with utils.LetCurrentWindow( variables_win ):
|
||||||
vim.command(
|
vim.command(
|
||||||
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
||||||
|
|
||||||
# List of current scopes of type Scope
|
# Set up the "Watches" buffer in the watches_win (and create a WinBar in
|
||||||
self._scopes: typing.List[ 'Scope' ] = []
|
# there)
|
||||||
|
self._watches: typing.List[ Watch ] = []
|
||||||
# List of current Watches of type Watch
|
self._watch = View( watches_win, {}, self._DrawWatches )
|
||||||
self._watches: typing.List[ 'Watch' ] = []
|
utils.SetUpPromptBuffer( self._watch.buf,
|
||||||
|
'vimspector.Watches',
|
||||||
# Allows us to hit <CR> to expand/collapse variables
|
'Expression: ',
|
||||||
with utils.LetCurrentWindow( self._watch.win ):
|
'vimspector#AddWatchPrompt' )
|
||||||
|
with utils.LetCurrentWindow( watches_win ):
|
||||||
vim.command(
|
vim.command(
|
||||||
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
|
||||||
vim.command(
|
vim.command(
|
||||||
|
|
@ -149,15 +158,7 @@ class VariablesView( object ):
|
||||||
vim.command( 'nnoremenu 1.3 WinBar.Delete '
|
vim.command( 'nnoremenu 1.3 WinBar.Delete '
|
||||||
':call vimspector#DeleteWatch()<CR>' )
|
':call vimspector#DeleteWatch()<CR>' )
|
||||||
|
|
||||||
utils.SetUpScratchBuffer( self._vars.win.buffer, 'vimspector.Variables' )
|
# Set the (global!) balloon expr if supported
|
||||||
utils.SetUpPromptBuffer( self._watch.win.buffer,
|
|
||||||
'vimspector.Watches',
|
|
||||||
'Expression: ',
|
|
||||||
'vimspector#AddWatchPrompt' )
|
|
||||||
|
|
||||||
utils.SetUpUIWindow( self._vars.win )
|
|
||||||
utils.SetUpUIWindow( self._watch.win )
|
|
||||||
|
|
||||||
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
|
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
|
||||||
has_balloon_term = int( vim.eval( "has( 'balloon_eval_term' )" ) )
|
has_balloon_term = int( vim.eval( "has( 'balloon_eval_term' )" ) )
|
||||||
|
|
||||||
|
|
@ -181,10 +182,10 @@ class VariablesView( object ):
|
||||||
self._is_term = not bool( int( vim.eval( "has( 'gui_running' )" ) ) )
|
self._is_term = not bool( int( vim.eval( "has( 'gui_running' )" ) ) )
|
||||||
|
|
||||||
def Clear( self ):
|
def Clear( self ):
|
||||||
with utils.ModifiableScratchBuffer( self._vars.win.buffer ):
|
with utils.ModifiableScratchBuffer( self._vars.buf ):
|
||||||
utils.ClearBuffer( self._vars.win.buffer )
|
utils.ClearBuffer( self._vars.buf )
|
||||||
with utils.ModifiableScratchBuffer( self._watch.win.buffer ):
|
with utils.ModifiableScratchBuffer( self._watch.buf ):
|
||||||
utils.ClearBuffer( self._watch.win.buffer )
|
utils.ClearBuffer( self._watch.buf )
|
||||||
self._current_syntax = ''
|
self._current_syntax = ''
|
||||||
|
|
||||||
def ConnectionUp( self, connection ):
|
def ConnectionUp( self, connection ):
|
||||||
|
|
@ -198,8 +199,8 @@ class VariablesView( object ):
|
||||||
for k, v in self._oldoptions.items():
|
for k, v in self._oldoptions.items():
|
||||||
vim.options[ k ] = v
|
vim.options[ k ] = v
|
||||||
|
|
||||||
vim.command( 'bdelete! ' + str( self._watch.win.buffer.number ) )
|
utils.CleanUpHiddenBuffer( self._vars.buf )
|
||||||
vim.command( 'bdelete! ' + str( self._vars.win.buffer.number ) )
|
utils.CleanUpHiddenBuffer( self._watch.buf )
|
||||||
|
|
||||||
def LoadScopes( self, frame ):
|
def LoadScopes( self, frame ):
|
||||||
def scopes_consumer( message ):
|
def scopes_consumer( message ):
|
||||||
|
|
@ -256,8 +257,8 @@ class VariablesView( object ):
|
||||||
self.EvaluateWatches()
|
self.EvaluateWatches()
|
||||||
|
|
||||||
def DeleteWatch( self ):
|
def DeleteWatch( self ):
|
||||||
if vim.current.window != self._watch.win:
|
if vim.current.buffer != self._watch.buf:
|
||||||
utils.UserMessage( 'Not a watch window' )
|
utils.UserMessage( 'Not a watch buffer' )
|
||||||
return
|
return
|
||||||
|
|
||||||
current_line = vim.current.window.cursor[ 0 ]
|
current_line = vim.current.window.cursor[ 0 ]
|
||||||
|
|
@ -305,9 +306,9 @@ class VariablesView( object ):
|
||||||
self._DrawWatches()
|
self._DrawWatches()
|
||||||
|
|
||||||
def ExpandVariable( self ):
|
def ExpandVariable( self ):
|
||||||
if vim.current.window == self._vars.win:
|
if vim.current.buffer == self._vars.buf:
|
||||||
view = self._vars
|
view = self._vars
|
||||||
elif vim.current.window == self._watch.win:
|
elif vim.current.buffer == self._watch.buf:
|
||||||
view = self._watch
|
view = self._watch
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
@ -341,7 +342,7 @@ class VariablesView( object ):
|
||||||
assert indent > 0
|
assert indent > 0
|
||||||
for variable in variables:
|
for variable in variables:
|
||||||
line = utils.AppendToBuffer(
|
line = utils.AppendToBuffer(
|
||||||
view.win.buffer,
|
view.buf,
|
||||||
'{indent}{marker}{icon} {name} ({type_}): {value}'.format(
|
'{indent}{marker}{icon} {name} ({type_}): {value}'.format(
|
||||||
# We borrow 1 space of indent to draw the change marker
|
# We borrow 1 space of indent to draw the change marker
|
||||||
indent = ' ' * ( indent - 1 ),
|
indent = ' ' * ( indent - 1 ),
|
||||||
|
|
@ -363,8 +364,8 @@ class VariablesView( object ):
|
||||||
# However it is pretty inefficient.
|
# However it is pretty inefficient.
|
||||||
self._vars.lines.clear()
|
self._vars.lines.clear()
|
||||||
with utils.RestoreCursorPosition():
|
with utils.RestoreCursorPosition():
|
||||||
with utils.ModifiableScratchBuffer( self._vars.win.buffer ):
|
with utils.ModifiableScratchBuffer( self._vars.buf ):
|
||||||
utils.ClearBuffer( self._vars.win.buffer )
|
utils.ClearBuffer( self._vars.buf )
|
||||||
for scope in self._scopes:
|
for scope in self._scopes:
|
||||||
self._DrawScope( 0, scope )
|
self._DrawScope( 0, scope )
|
||||||
|
|
||||||
|
|
@ -374,11 +375,11 @@ class VariablesView( object ):
|
||||||
# However it is pretty inefficient.
|
# However it is pretty inefficient.
|
||||||
self._watch.lines.clear()
|
self._watch.lines.clear()
|
||||||
with utils.RestoreCursorPosition():
|
with utils.RestoreCursorPosition():
|
||||||
with utils.ModifiableScratchBuffer( self._watch.win.buffer ):
|
with utils.ModifiableScratchBuffer( self._watch.buf ):
|
||||||
utils.ClearBuffer( self._watch.win.buffer )
|
utils.ClearBuffer( self._watch.buf )
|
||||||
utils.AppendToBuffer( self._watch.win.buffer, 'Watches: ----' )
|
utils.AppendToBuffer( self._watch.buf, 'Watches: ----' )
|
||||||
for watch in self._watches:
|
for watch in self._watches:
|
||||||
line = utils.AppendToBuffer( self._watch.win.buffer,
|
line = utils.AppendToBuffer( self._watch.buf,
|
||||||
'Expression: '
|
'Expression: '
|
||||||
+ watch.expression[ 'expression' ] )
|
+ watch.expression[ 'expression' ] )
|
||||||
watch.line = line
|
watch.line = line
|
||||||
|
|
@ -387,7 +388,7 @@ class VariablesView( object ):
|
||||||
def _DrawScope( self, indent, scope ):
|
def _DrawScope( self, indent, scope ):
|
||||||
icon = '+' if scope.IsExpandable() and not scope.IsExpandedByUser() else '-'
|
icon = '+' if scope.IsExpandable() and not scope.IsExpandedByUser() else '-'
|
||||||
|
|
||||||
line = utils.AppendToBuffer( self._vars.win.buffer,
|
line = utils.AppendToBuffer( self._vars.buf,
|
||||||
'{0}{1} Scope: {2}'.format(
|
'{0}{1} Scope: {2}'.format(
|
||||||
' ' * indent,
|
' ' * indent,
|
||||||
icon,
|
icon,
|
||||||
|
|
@ -413,7 +414,7 @@ class VariablesView( object ):
|
||||||
icon = icon,
|
icon = icon,
|
||||||
result = watch.result.result.get( 'result', '<unknown>' ) )
|
result = watch.result.result.get( 'result', '<unknown>' ) )
|
||||||
|
|
||||||
line = utils.AppendToBuffer( self._watch.win.buffer, line.split( '\n' ) )
|
line = utils.AppendToBuffer( self._watch.buf, line.split( '\n' ) )
|
||||||
self._watch.lines[ line ] = watch.result
|
self._watch.lines[ line ] = watch.result
|
||||||
|
|
||||||
if watch.result.ShouldDrawDrillDown():
|
if watch.result.ShouldDrawDrillDown():
|
||||||
|
|
@ -495,7 +496,7 @@ class VariablesView( object ):
|
||||||
def SetSyntax( self, syntax ):
|
def SetSyntax( self, syntax ):
|
||||||
self._current_syntax = utils.SetSyntax( self._current_syntax,
|
self._current_syntax = utils.SetSyntax( self._current_syntax,
|
||||||
syntax,
|
syntax,
|
||||||
self._vars.win,
|
self._vars.buf,
|
||||||
self._watch.win )
|
self._watch.buf )
|
||||||
|
|
||||||
# vim: sw=2
|
# vim: sw=2
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@
|
||||||
"classPaths": [ "${workspaceRoot}/target/classes" ],
|
"classPaths": [ "${workspaceRoot}/target/classes" ],
|
||||||
"args": "hello world!",
|
"args": "hello world!",
|
||||||
"stopOnEntry": true,
|
"stopOnEntry": true,
|
||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal",
|
||||||
|
"stepFilters": {
|
||||||
|
"skipClasses": [ "$$JDK" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Java Attach": {
|
"Java Attach": {
|
||||||
|
|
@ -19,7 +22,10 @@
|
||||||
"sourcePaths": [ "${workspaceRoot}/src/main/java" ],
|
"sourcePaths": [ "${workspaceRoot}/src/main/java" ],
|
||||||
"stopOnEntry": true,
|
"stopOnEntry": true,
|
||||||
"hostName": "localhost",
|
"hostName": "localhost",
|
||||||
"port": "${JVMDebugPort}"
|
"port": "${JVMDebugPort}",
|
||||||
|
"stepFilters": {
|
||||||
|
"skipClasses": [ "$$JDK" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Attach with vscode-javac": {
|
"Attach with vscode-javac": {
|
||||||
|
|
|
||||||
24
support/test/java/test_project/java.vim
Normal file
24
support/test/java/test_project/java.vim
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
let g:ycm_java_jdtls_extension_path = [
|
||||||
|
\ expand( '<sfile>:p:h:h:h:h:h' ) . '/gadgets/macos'
|
||||||
|
\ ]
|
||||||
|
|
||||||
|
let s:jdt_ls_debugger_port = 0
|
||||||
|
function! s:StartDebugging()
|
||||||
|
if s:jdt_ls_debugger_port <= 0
|
||||||
|
" Get the DAP port
|
||||||
|
let s:jdt_ls_debugger_port = youcompleteme#GetCommandResponse(
|
||||||
|
\ 'ExecuteCommand',
|
||||||
|
\ 'vscode.java.startDebugSession' )
|
||||||
|
|
||||||
|
if s:jdt_ls_debugger_port == ''
|
||||||
|
echom "Unable to get DAP port - is YCM initialized?"
|
||||||
|
let s:jdt_ls_debugger_port = 0
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
" Start debugging with the DAP port
|
||||||
|
call vimspector#LaunchWithSettings( { 'DAPPort': s:jdt_ls_debugger_port } )
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
nnoremap <silent> <buffer> <Leader><F5> :call <SID>StartDebugging()<CR>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<artifactId>TestApplication</artifactId>
|
<artifactId>TestApplication</artifactId>
|
||||||
<version>1</version>
|
<version>1</version>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.vimspector.test;
|
||||||
|
|
||||||
|
class Base {
|
||||||
|
public String DoSomething()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,16 @@ public class TestApplication {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TestGeneric<T extends Base > {
|
||||||
|
T t;
|
||||||
|
public TestGeneric( T t ) {
|
||||||
|
this.t = t;
|
||||||
|
}
|
||||||
|
public void DoSomethingUseful() {
|
||||||
|
System.out.println( t.DoSomething() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static <T extends Base> void DoGeneric( T b ) {
|
private static <T extends Base> void DoGeneric( T b ) {
|
||||||
TestGeneric<T> foo = new TestGeneric<>( b );
|
TestGeneric<T> foo = new TestGeneric<>( b );
|
||||||
foo.DoSomethingUseful();
|
foo.DoSomethingUseful();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue