Merge pull request #197 from puremourning/use-buffers-not-windows

Allow users to close UI windows
This commit is contained in:
mergify[bot] 2020-07-11 13:50:34 +00:00 • committed by GitHub
commit fe58b94bb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 244 additions and 112 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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(

View file

@ -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

View file

@ -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,

View file

@ -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 )

View file

@ -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

View file

@ -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

View file

@ -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": {

View 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>

View file

@ -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>

View file

@ -0,0 +1,8 @@
package com.vimspector.test;
class Base {
public String DoSomething()
{
return "";
}
}

View file

@ -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();