Use prompt buffer for Console

Like VSCode does, compbine console and stdout, and allow you to enter
commands in the console. It's all a bit janky right now and the
insertion point isn't ideal (as not all output is interactive) and some
output is asynchronous via a somewhat different channel.
This commit is contained in:
Ben Jackson 2018-06-10 18:32:16 +01:00
commit b72bc7dfbf
4 changed files with 79 additions and 17 deletions

View file

@ -89,6 +89,12 @@ function! vimspector#AddWatchPrompt( expr ) abort
call vimspector#AddWatch( a:expr ) call vimspector#AddWatch( a:expr )
endfunction endfunction
function! vimspector#EvaluateConsole( expr ) abort
stopinsert
setlocal nomodified
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) )
endfunction
function! vimspector#ShowOutput( category ) abort function! vimspector#ShowOutput( category ) abort
py3 _vimspector_session.ShowOutput( vim.eval( 'a:category' ) ) py3 _vimspector_session.ShowOutput( vim.eval( 'a:category' ) )
endfunction endfunction

View file

@ -243,6 +243,10 @@ class DebugSession( object ):
self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(), self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(),
expression ) expression )
def EvaluateConsole( self, expression ):
self._outputView.Evaluate( self._stackTraceView.GetCurrentFrame(),
expression )
def DeleteWatch( self ): def DeleteWatch( self ):
self._variablesView.DeleteWatch() self._variablesView.DeleteWatch()
@ -304,7 +308,8 @@ class DebugSession( object ):
# Output/logging # Output/logging
vim.command( '10spl' ) vim.command( '10spl' )
vim.command( 'enew' ) vim.command( 'enew' )
self._outputView = output.OutputView( vim.current.window ) self._outputView = output.OutputView( self._connection,
vim.current.window )
def ClearCurrentFrame( self ): def ClearCurrentFrame( self ):
self.SetCurrentFrame( None ) self.SetCurrentFrame( None )
@ -371,6 +376,7 @@ class DebugSession( object ):
self._connection = None self._connection = None
self._stackTraceView.ConnectionClosed() self._stackTraceView.ConnectionClosed()
self._variablesView.ConnectionClosed() self._variablesView.ConnectionClosed()
self._outputView.ConnectionClosed()
if callback: if callback:
callback() callback()

View file

@ -18,22 +18,44 @@ from vimspector import utils
import vim import vim
BUFFER_MAP = {
'console': 'Console',
'stdout': 'Console'
}
def CategoryToBuffer( category ):
return BUFFER_MAP.get( category, category )
class OutputView( object ): class OutputView( object ):
def __init__( self, window ): def __init__( self, connection, window ):
self._window = window self._window = window
self._connection = connection
self._buffers = {} self._buffers = {}
self._CreateBuffer( 'stdout' ) for b in set( BUFFER_MAP.values() ):
self.ShowOutput( 'stdout' ) self._CreateBuffer( b )
self.ShowOutput( 'Console' )
def OnOutput( self, event ): def OnOutput( self, event ):
category = event.get( 'category' ) or 'output' category = CategoryToBuffer( event.get( 'category' ) or 'output' )
if category not in self._buffers: if category not in self._buffers:
self._CreateBuffer( category ) self._CreateBuffer( category )
with utils.ModifiableScratchBuffer( self._buffers[ category ] ): buf = self._buffers[ category ]
utils.AppendToBuffer( self._buffers[ category ], with utils.ModifiableScratchBuffer( buf ):
event[ 'output' ].splitlines() ) utils.AppendToBuffer( buf, event[ 'output' ].splitlines() )
# Scroll the buffer
with utils.RestoreCurrentWindow():
with utils.RestoreCurrentBuffer( self._window ):
self.ShowOutput( category )
vim.command( 'normal G' )
def ConnectionClosed( self ):
self._connection = None
def Reset( self ): def Reset( self ):
self.Clear() self.Clear()
@ -48,18 +70,42 @@ class OutputView( object ):
vim.current.window = self._window vim.current.window = self._window
vim.command( 'bu {0}'.format( self._buffers[ category ].name ) ) vim.command( 'bu {0}'.format( self._buffers[ category ].name ) )
def Evaluate( self, frame, expression ):
if not frame:
return
console = self._buffers[ 'Console' ]
utils.AppendToBuffer( console, expression )
def print_result( message ):
utils.AppendToBuffer( console, message[ 'body' ][ 'result' ] )
self._connection.DoRequest( print_result, {
'command': 'evaluate',
'arguments': {
'expression': expression,
'context': 'repl',
'frameId': frame[ 'id' ],
}
} )
def _CreateBuffer( self, category ): def _CreateBuffer( self, category ):
with utils.RestorCurrentWindow(): with utils.RestoreCurrentWindow():
vim.current.window = self._window vim.current.window = self._window
with utils.RestoreCurrentBuffer( self._window ): with utils.RestoreCurrentBuffer( self._window ):
vim.command( 'enew' ) vim.command( 'enew' )
self._buffers[ category ] = vim.current.buffer self._buffers[ category ] = vim.current.buffer
utils.AppendToBuffer( self._buffers[ category ],
category + '-----' )
utils.SetUpHiddenBuffer( self._buffers[ category ], if category == 'Console':
'vimspector.Output:{0}'.format( category ) ) utils.SetUpPromptBuffer( self._buffers[ category ],
'vimspector.Console',
'> ',
'vimspector#EvaluateConsole',
hidden = True )
else:
utils.SetUpHiddenBuffer( self._buffers[ category ],
'vimspector.Output:{0}'.format( category ) )
vim.command( "nnoremenu WinBar.{0} " vim.command( "nnoremenu WinBar.{0} "
":call vimspector#ShowOutput( '{0}' )<CR>".format( ":call vimspector#ShowOutput( '{0}' )<CR>".format(

View file

@ -52,7 +52,7 @@ def SetUpHiddenBuffer( buf, name ):
buf.options[ 'bufhidden' ] = 'hide' buf.options[ 'bufhidden' ] = 'hide'
buf.name = name buf.name = name
def SetUpPromptBuffer( buf, name, prompt, callback ): def SetUpPromptBuffer( buf, name, prompt, callback, hidden=False ):
# This feature is _super_ new, so only enable when available # This feature is _super_ new, so only enable when available
if not int( vim.eval( "exists( '*prompt_setprompt' )" ) ): if not int( vim.eval( "exists( '*prompt_setprompt' )" ) ):
return SetUpScratchBuffer( buf, name ) return SetUpScratchBuffer( buf, name )
@ -63,7 +63,7 @@ def SetUpPromptBuffer( buf, name, prompt, callback ):
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' buf.options[ 'bufhidden' ] = 'wipe' if not hidden else 'hide'
buf.name = name buf.name = name
vim.eval( "prompt_setprompt( {0}, '{1}' )".format( buf.number, vim.eval( "prompt_setprompt( {0}, '{1}' )".format( buf.number,
@ -101,7 +101,7 @@ def RestoreCursorPosition():
@contextlib.contextmanager @contextlib.contextmanager
def RestorCurrentWindow(): def RestoreCurrentWindow():
# TODO: Don't trigger autoccommands when shifting windows # TODO: Don't trigger autoccommands when shifting windows
old_window = vim.current.window old_window = vim.current.window
try: try:
@ -117,7 +117,7 @@ def RestoreCurrentBuffer( window ):
try: try:
yield yield
finally: finally:
with RestorCurrentWindow(): with RestoreCurrentWindow():
vim.current.window = window vim.current.window = window
vim.current.buffer = old_buffer vim.current.buffer = old_buffer
@ -218,3 +218,7 @@ def AppendToBuffer( buf, line_or_lines ):
def ClearBuffer( buf ): def ClearBuffer( buf ):
buf[:] = None buf[:] = None
def IsCurrent( window, buf ):
return vim.current.window == window and vim.current.window.buffer == buf