start to track individual thread state

This commit is contained in:
Ben Jackson 2020-11-19 23:49:29 +00:00
commit 2399a79cae
2 changed files with 68 additions and 54 deletions

View file

@ -16,26 +16,22 @@
import vim import vim
import os import os
import logging import logging
import typing
from vimspector import utils from vimspector import utils
# TODO: Need to do something a bit like the Variables stuff class Thread:
# PAUSED = 0
# class Thread: RUNNING = 1
# PAUSED = 0 state = RUNNING
# RUNNING = 1
# state = RUNNING thread: typing.Dict
# stacktrace: typing.List[ typing.Dict ]
# thread: dict
# stacktrace: list def __init__( self, thread ):
# self.thread = thread
# def __init__( self, thread ): self.stacktrace = None
# self.thread = thread
# self.stacktrace = None
#
# def ShouldExpand( self, current_thread_id ):
# return self.thread[ 'id' ] == current_thread_id
class StackTraceView( object ): class StackTraceView( object ):
@ -44,6 +40,9 @@ class StackTraceView( object ):
REQUESTING = 1 REQUESTING = 1
PENDING = 2 PENDING = 2
_threads: list[ Thread ]
_line_to_thread = dict[ int, Thread ]
def __init__( self, session, win ): def __init__( self, session, win ):
self._logger = logging.getLogger( __name__ ) self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger ) utils.SetUpLogging( self._logger )
@ -63,10 +62,11 @@ class StackTraceView( object ):
utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' ) utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' )
utils.SetUpUIWindow( win ) utils.SetUpUIWindow( win )
vim.command( 'nnoremap <silent> <buffer> <CR> ' with utils.LetCurrentWindow( win ):
':<C-U>call vimspector#GoToFrame()<CR>' ) vim.command( 'nnoremap <silent> <buffer> <CR> '
vim.command( 'nnoremap <silent> <buffer> <2-LeftMouse> ' ':<C-U>call vimspector#GoToFrame()<CR>' )
':<C-U>call vimspector#GoToFrame()<CR>' ) vim.command( 'nnoremap <silent> <buffer> <2-LeftMouse> '
':<C-U>call vimspector#GoToFrame()<CR>' )
self._line_to_frame = {} self._line_to_frame = {}
self._line_to_thread = {} self._line_to_thread = {}
@ -85,7 +85,7 @@ class StackTraceView( object ):
self._current_frame = None self._current_frame = None
self._current_thread = None self._current_thread = None
self._current_syntax = "" self._current_syntax = ""
self._threads = [] self._threads.clear()
self._sources = {} self._sources = {}
with utils.ModifiableScratchBuffer( self._buf ): with utils.ModifiableScratchBuffer( self._buf ):
utils.ClearBuffer( self._buf ) utils.ClearBuffer( self._buf )
@ -134,16 +134,18 @@ class StackTraceView( object ):
self._threads.clear() self._threads.clear()
requesting = False requesting = False
for thread in message[ 'body' ][ 'threads' ]: for t in message[ 'body' ][ 'threads' ]:
thread = Thread( t )
self._threads.append( thread ) self._threads.append( thread )
if infer_current_frame and thread[ 'id' ] == self._current_thread: if infer_current_frame:
self._LoadStackTrace( thread, True, reason ) if thread.thread[ 'id' ] == self._current_thread:
requesting = True self._LoadStackTrace( thread, True, reason )
elif infer_current_frame and self._current_thread is None: requesting = True
self._current_thread = thread[ 'id' ] elif self._current_thread is None:
self._LoadStackTrace( thread, True, reason ) self._current_thread = thread.thread[ 'id' ]
requesting = True self._LoadStackTrace( thread, True, reason )
requesting = True
if not requesting: if not requesting:
self._DrawThreads() self._DrawThreads()
@ -158,7 +160,7 @@ class StackTraceView( object ):
'command': 'threads', 'command': 'threads',
}, failure_handler ) }, failure_handler )
def _DrawThreads( self, running = False ): def _DrawThreads( self ):
self._line_to_frame.clear() self._line_to_frame.clear()
self._line_to_thread.clear() self._line_to_thread.clear()
@ -167,32 +169,33 @@ class StackTraceView( object ):
utils.ClearBuffer( self._buf ) utils.ClearBuffer( self._buf )
for thread in self._threads: for thread in self._threads:
if self._current_thread == thread[ 'id' ]: if self._current_thread == thread.thread[ 'id' ]:
icon = '^' if '_frames' not in thread else '>' icon = '^' if thread.stacktrace is None else '>'
else: else:
icon = '+' if '_frames' not in thread else '-' icon = '+' if thread.stacktrace is None else '-'
# FIXME: We probably need per-thread status here # FIXME: We probably need per-thread status here
if running: if thread.state == Thread.RUNNING:
status = ' (running)' status = ' (running)'
else: else:
status = '' status = ''
line = utils.AppendToBuffer( line = utils.AppendToBuffer(
self._buf, self._buf,
f'{icon} Thread: {thread["name"]}{status}' ) f'{icon} Thread: {thread.thread["name"]}{status}' )
self._line_to_thread[ line ] = thread self._line_to_thread[ line ] = thread
self._DrawStackTrace( thread ) self._DrawStackTrace( thread )
def _LoadStackTrace( self, def _LoadStackTrace( self,
thread, thread: Thread,
infer_current_frame, infer_current_frame,
reason = '' ): reason = '' ):
def consume_stacktrace( message ): def consume_stacktrace( message ):
thread[ '_frames' ] = message[ 'body' ][ 'stackFrames' ] thread.stacktrace = message[ 'body' ][ 'stackFrames' ]
if infer_current_frame: if infer_current_frame:
for frame in thread[ '_frames' ]: for frame in thread.stacktrace:
if self._JumpToFrame( frame, reason ): if self._JumpToFrame( frame, reason ):
break break
@ -201,7 +204,7 @@ class StackTraceView( object ):
self._connection.DoRequest( consume_stacktrace, { self._connection.DoRequest( consume_stacktrace, {
'command': 'stackTrace', 'command': 'stackTrace',
'arguments': { 'arguments': {
'threadId': thread[ 'id' ], 'threadId': thread.thread[ 'id' ],
} }
} ) } )
@ -215,8 +218,8 @@ class StackTraceView( object ):
self._JumpToFrame( self._line_to_frame[ current_line ] ) self._JumpToFrame( self._line_to_frame[ current_line ] )
elif current_line in self._line_to_thread: elif current_line in self._line_to_thread:
thread = self._line_to_thread[ current_line ] thread = self._line_to_thread[ current_line ]
if '_frames' in thread: if thread.stacktrace is not None:
del thread[ '_frames' ] thread.stacktrace = None
self._DrawThreads() self._DrawThreads()
else: else:
self._LoadStackTrace( thread, False ) self._LoadStackTrace( thread, False )
@ -241,18 +244,29 @@ class StackTraceView( object ):
return do_jump() return do_jump()
def OnContinued( self, threadId = None ): def OnContinued( self, threadId = None ):
# FIXME: This tends to create a very flickery stack trace when steppping. for thread in self._threads:
# Maybe we shouldn't remove the frames, but just update the running status? if threadId is None:
# for thread in self._threads: thread.state = Thread.RUNNING
# if threadId is None or thread[ 'id' ] == threadId: elif thread.thread[ 'id' ] == threadId:
# thread.pop( '_frames', None ) thread.state = Thread.RUNNING
self._DrawThreads( running=True ) break
self._DrawThreads()
def OnStopped( self, event ): def OnStopped( self, event ):
if 'threadId' in event: if 'threadId' in event:
self._current_thread = event[ 'threadId' ] self._current_thread = event[ 'threadId' ]
elif event.get( 'allThreadsStopped', False ) and self._threads:
self._current_thread = self._threads[ 0 ][ 'id' ] for thread in self._threads:
if thread.thread[ 'id' ] == event[ 'threadId' ]:
thread.state = Thread.PAUSED
break
elif event.get( 'allThreadsStopped', False ):
if self._threads:
self._current_thread = self._threads[ 0 ].thread[ 'id' ]
for thread in self._threads:
thread.state = Thread.PAUSED
self.LoadThreads( True, 'stopped' ) self.LoadThreads( True, 'stopped' )
@ -263,13 +277,11 @@ class StackTraceView( object ):
else: else:
self.LoadThreads( False ) self.LoadThreads( False )
def _DrawStackTrace( self, thread ): def _DrawStackTrace( self, thread: Thread ):
if '_frames' not in thread: if thread.stacktrace is None:
return return
stackFrames = thread[ '_frames' ] for frame in thread.stacktrace:
for frame in stackFrames:
if frame.get( 'source' ): if frame.get( 'source' ):
source = frame[ 'source' ] source = frame[ 'source' ]
else: else:

View file

@ -347,3 +347,5 @@ function! Test_Multiple_Threads_Step()
call vimspector#test#setup#Reset() call vimspector#test#setup#Reset()
%bwipe! %bwipe!
endfunction endfunction
" TODO: Set current frame while thread is running sets the PC