From bb3909c16f24ff85ac76943b90a9aa2fbd83bf82 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 12 Feb 2019 09:04:52 +0000 Subject: [PATCH] Improve output view; use jobs to display logs and remote commands --- autoload/vimspector/internal/job.vim | 19 ----------- python3/vimspector/debug_session.py | 43 +++++++++++++++-------- python3/vimspector/output.py | 36 ++++++++++++-------- python3/vimspector/utils.py | 51 ++++++++++++++++++++-------- 4 files changed, 86 insertions(+), 63 deletions(-) diff --git a/autoload/vimspector/internal/job.vim b/autoload/vimspector/internal/job.vim index c0785de..374c9a6 100644 --- a/autoload/vimspector/internal/job.vim +++ b/autoload/vimspector/internal/job.vim @@ -58,25 +58,6 @@ function! s:_Send( msg ) abort return 1 endfunction -function! vimspector#internal#job#RunCommand( cmd ) abort - return job_start( a:cmd, - \ { - \ 'in_mode': 'raw', - \ 'out_mode': 'raw', - \ 'err_mode': 'raw', - \ 'out_cb': funcref( 's:_OnServerError' ), - \ 'err_cb': funcref( 's:_OnServerError' ), - \ 'stoponexit': 'term', - \ } - \ ) -endfunction - -function! vimspector#internal#job#KillCommand( job ) abort - if job_status( a:job ) == 'run' - call job_stop( a:job, 'term' ) - endif -endfunction - function! vimspector#internal#job#StartDebugSession( config ) abort if exists( 's:job' ) echom "Not starging: Job is already running" diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index b3bc2b1..d1d0cd9 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -211,7 +211,8 @@ class DebugSession( object ): def OnServerStderr( self, data ): self._logger.info( "Server stderr: %s", data ) if self._outputView: - self._outputView.ServerEcho( data ) + self._outputView.Print( 'server', data ) + def OnRequestTimeout( self, timer_id ): if self._connection: @@ -461,11 +462,8 @@ class DebugSession( object ): for index, item in enumerate( cmd ): cmd[ index ] = item.replace( '%PID%', pid ) - # TODO: Log files, etc. ? self._logger.debug( 'Running remote app: %s', cmd ) - self._attach_process = vim.eval( - 'vimspector#internal#job#RunCommand( {} )'.format( - json.dumps( cmd ) ) ) + self._outputView.RunJobWithOutput( 'Remote', cmd ) else: if atttach_config[ 'pidSelect' ] == 'ask': pid = utils.AskForInput( 'Enter PID to attach to: ' ) @@ -478,7 +476,7 @@ class DebugSession( object ): atttach_config[ 'pidSelect' ] ) ) - def _PrepareRun( self, adapter_config, launch_config ): + def _PrepareLaunch( self, command_line, adapter_config, launch_config ): run_config = adapter_config.get( 'launch', {} ) if 'remote' in run_config: @@ -490,10 +488,18 @@ class DebugSession( object ): ssh.append( remote[ 'host' ] ) cmd = ssh + remote[ 'runCommand' ][:] - self._logger.debug( 'Running remote app: %s', cmd ) - self._attach_process = vim.eval( - 'vimspector#internal#job#RunCommand( {} )'.format( - json.dumps( cmd ) ) ) + full_cmd = [] + for item in cmd: + if isinstance( command_line, list ): + if item == '%CMD%': + full_cmd.extend( command_line ) + else: + full_cmd.append( item ) + else: + full_cmd.append( item.replace( '%CMD%', command_line ) ) + + self._logger.debug( 'Running remote app: %s', full_cmd ) + self._outputView.RunJobWithOutput( 'Remote', full_cmd ) def _Initialise( self ): @@ -518,17 +524,24 @@ class DebugSession( object ): def OnFailure( self, reason, message ): msg = "Request for '{}' failed: {}".format( message[ 'command' ], reason ) - self._outputView.ServerEcho( msg ) + self._outputView.Print( 'server', msg ) def _Launch( self ): self._logger.debug( "LAUNCH!" ) adapter_config = self._adapter launch_config = self._configuration[ 'configuration' ] - if launch_config.get( 'request' ) == "attach": + request = self._configuration.get( + 'remote-request', + launch_config.get( 'request', 'launch' ) ) + + if request == "attach": self._PrepareAttach( adapter_config, launch_config ) - elif launch_config.get( 'request' ) == "run": - self._PrepareRun( adapter_config, launch_config ) + elif request == "launch": + # FIXME: This cmdLine hack is not fun. + self._PrepareLaunch( self._configuration.get( 'remote-cmdLine', [] ), + adapter_config, + launch_config ) # FIXME: name is mandatory. Forcefully add it (we should really use the # _actual_ name, but that isn't actually remembered at this point) @@ -730,6 +743,6 @@ class DebugSession( object ): utils.UserMessage( msg, persist = True ) if self._outputView: - self._outputView.ServerEcho( msg ) + self._outputView.Print( 'server', msg ) self._stackTraceView.OnStopped( event ) diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index b2502a3..d522c7b 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -24,7 +24,7 @@ class TabBuffer( object ): self.buf = buf self.index = index self.flag = False - self.job = None + self.is_job = False BUFFER_MAP = { @@ -54,7 +54,7 @@ class OutputView( object ): self._ShowOutput( 'Console' ) - def ServerEcho( self, text ): + def Print( self, categroy, text ): self._Print( 'server', text.splitlines() ) def OnOutput( self, event ): @@ -93,12 +93,10 @@ class OutputView( object ): self.Clear() def Clear( self ): - for buf in self._buffers: - vim.command( 'bwipeout! {0}'.format( self._buffers[ buf ].buf.name ) ) - - if 'Vimspector' in self._buffers: - if self._buffers[ 'Vimspector' ].job is not None: - utils.TerminateJob( self._buffers[ 'Vimspector' ].job ) + for category, tab_buffer in self._buffers.items(): + if tab_buffer.is_job: + utils.CleanUpCommand( category ) + vim.command( 'bdelete! {0}'.format( tab_buffer.buf.number ) ) self._buffers.clear() @@ -113,6 +111,7 @@ class OutputView( object ): def Evaluate( self, frame, expression ): if not frame: + self.Print( 'Console', 'There is no current stack frame' ) return console = self._buffers[ 'Console' ].buf @@ -144,17 +143,26 @@ class OutputView( object ): vim.current.window = self._window self._RenderWinBar( category ) - def _CreateBuffer( self, category, file_name = None ): + + def RunJobWithOutput( self, category, cmd ): + self._CreateBuffer( category, cmd = cmd ) + + + def _CreateBuffer( self, category, file_name = None, cmd = None ): with utils.RestoreCurrentWindow(): vim.current.window = self._window with utils.RestoreCurrentBuffer( self._window ): if file_name is not None: - tab_buffer = TabBuffer( utils.BufferForFile( file_name ), - len( self._buffers ) ) - tab_buffer.job = utils.SetUpTailBuffer( tab_buffer.buf, file_name ) - self._buffers[ category ] = tab_buffer + assert cmd is None + cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ] + + if cmd is not None: + buf = utils.SetUpCommandBuffer( cmd, category ) + self._buffers[ category ] = TabBuffer( buf, len( self._buffers ) ) + self._buffers[ category ].is_job = True + self._RenderWinBar( category ) else: vim.command( 'enew' ) tab_buffer = TabBuffer( vim.current.buffer, len( self._buffers ) ) @@ -170,7 +178,7 @@ class OutputView( object ): tab_buffer.buf, 'vimspector.Output:{0}'.format( category ) ) - self._RenderWinBar( category ) + self._RenderWinBar( category ) def _RenderWinBar( self, category ): tab_buffer = self._buffers[ category ] diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 6d2213e..5313cff 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -51,15 +51,39 @@ def OpenFileInCurrentWindow( file_name ): return vim.buffers[ buffer_number ] -def SetUpTailBuffer( buf, path ): - cmd = [ 'tail', '-F', '-n', '0', '--', path ] - return vim.eval( 'job_start( {}, {{ "out_io": "buffer",' - ' "out_buf": {},' - ' "in_io": "null",' - ' "err_io": "null",' - ' "stoponexit": "term",' - ' "out_modifiable": 0 }} )'.format( - json.dumps( cmd ), buf.number ) ) +def SetUpCommandBuffer( cmd, name ): + vim.command( + 'let g:vimspector_command_job_{name} = job_start(' + ' {cmd},' + ' {{' + ' "out_io": "buffer",' + ' "in_io": "null",' + ' "err_io": "buffer",' + ' "out_name": "_vimspector_log_{name}",' + ' "err_name": "_vimspector_log_{name}",' + ' "out_modifiable": 0,' + ' "err_modifiable": 0,' + ' "stoponexit": "term",' + ' }} )'.format( name = name, + cmd = json.dumps( cmd ) ) ) + + stdout = vim.eval( 'ch_getbufnr( ' + ' job_getchannel( g:vimspector_command_job_{name} ), ' + ' "out"' + ')'.format( name = name ) ) + stderr = vim.eval( 'ch_getbufnr( ' + ' job_getchannel( g:vimspector_command_job_{name} ), ' + ' "err"' + ')'.format( name = name ) ) + + assert stdout == stderr + return vim.buffers[ int( stdout ) ] + + +def CleanUpCommand( name ): + cmd = 'job_stop( g:vimspector_command_job_{name}, "kill" )'.format( + name = name ) + vim.eval( cmd ) def TerminateJob( job ): @@ -253,14 +277,11 @@ def AppendToBuffer( buf, line_or_lines, modified=False ): else: line = 1 buf[:] = line_or_lines - except vim.error as e: + except: # There seem to be a lot of Vim bugs that lead to E351, whose help says that # this is an internal error. Ignore the error, but write a trace to the log. - if 'E315' in str( e ): - logging.getLogger( __name__ ).exception( - 'Internal error while updating buffer' ) - else: - raise e + logging.getLogger( __name__ ).exception( + 'Internal error while updating buffer %s (%s)', buf.name, buf.number ) finally: if not modified: buf.options[ 'modified' ] = False