diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 468421f..3886924 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -171,11 +171,18 @@ function! vimspector#Pause() abort py3 _vimspector_session.Pause() endfunction -function! vimspector#PauseThread() abort +function! vimspector#PauseContinueThread() abort if !s:Enabled() return endif - py3 _vimspector_session.PauseThread() + py3 _vimspector_session.PauseContinueThread() +endfunction + +function! vimspector#SetCurrentThread() abort + if !s:Enabled() + return + endif + py3 _vimspector_session.SetCurrentThread() endfunction function! vimspector#Stop() abort diff --git a/python3/vimspector/code.py b/python3/vimspector/code.py index 628fa63..d3c6324 100644 --- a/python3/vimspector/code.py +++ b/python3/vimspector/code.py @@ -32,6 +32,7 @@ class CodeView( object ): self._logger = logging.getLogger( __name__ ) utils.SetUpLogging( self._logger ) + # FIXME: This ID is by group, so should be module scope self._next_sign_id = 1 self._breakpoints = defaultdict( list ) self._signs = { diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 3a24f9d..67ec6a1 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -492,18 +492,12 @@ class DebugSession( object ): } ) @IfConnected() - def PauseThread( self ): - threadId = self._stackTraceView.GetSelectedThreadId() - if threadId is None: - utils.UserMessage( 'No thread selected' ) - return + def PauseContinueThread( self ): + self._stackTraceView.PauseContinueThread() - self._connection.DoRequest( None, { - 'command': 'pause', - 'arguments': { - 'threadId': threadId, - }, - } ) + @IfConnected() + def SetCurrentThread( self ): + self._stackTraceView.SetCurrentThread() @IfConnected() def ExpandVariable( self ): diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index 18101f8..5ff729b 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -28,11 +28,12 @@ DEFAULTS = { # Signs 'sign_priority': { - 'vimspectorPC': 200, - 'vimspectorPCBP': 200, - 'vimspectorBP': 9, - 'vimspectorBPCond': 9, - 'vimspectorBPDisabled': 9, + 'vimspectorPC': 200, + 'vimspectorPCBP': 200, + 'vimspectorBP': 9, + 'vimspectorBPCond': 9, + 'vimspectorBPDisabled': 9, + 'vimspectorCurrentThread': 200 }, # Installer diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index 55e9bd9..f039dde 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -18,7 +18,7 @@ import os import logging import typing -from vimspector import utils +from vimspector import utils, signs class Thread: @@ -100,6 +100,9 @@ class StackTraceView( object ): self._sources = {} self._scratch_buffers = [] + # FIXME: This ID is by group, so should be module scope + self._next_sign_id = 1 + utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' ) utils.SetUpUIWindow( win ) @@ -110,11 +113,22 @@ class StackTraceView( object ): ':call vimspector#GoToFrame()' ) if utils.UseWinBar(): - vim.command( 'nnoremenu 1.2 WinBar.Open ' + vim.command( 'nnoremenu 1.1 WinBar.Pause/Continue ' + ':call vimspector#PauseContinueThread()' ) + vim.command( 'nnoremenu 1.2 WinBar.Expand/Collapse ' ':call vimspector#GoToFrame()' ) - vim.command( 'nnoremenu 1.1 WinBar.Pause ' - ':call vimspector#PauseThread()' ) + vim.command( 'nnoremenu 1.3 WinBar.Focus ' + ':call vimspector#SetCurrentThread()' ) + win.options[ 'cursorline' ] = False + + + if not signs.SignDefined( 'vimspectorCurrentThread' ): + signs.DefineSign( 'vimspectorCurrentThread', + text = '▶ ', + double_text = '▶', + texthl = 'MatchParen', + linehl = 'CursorLine' ) self._line_to_frame = {} self._line_to_thread = {} @@ -137,6 +151,10 @@ class StackTraceView( object ): self._sources = {} self._requesting_threads = StackTraceView.ThreadRequestState.NO self._pending_thread_request = None + if self._next_sign_id: + signs.UnplaceSign( self._next_sign_id, 'VimspectorStackTrace' ) + self._next_sign_id = 0 + with utils.ModifiableScratchBuffer( self._buf ): utils.ClearBuffer( self._buf ) @@ -241,20 +259,28 @@ class StackTraceView( object ): self._line_to_frame.clear() self._line_to_thread.clear() + if self._next_sign_id: + signs.UnplaceSign( self._next_sign_id, 'VimspectorStackTrace' ) + else: + self._next_sign_id = 1 + with ( utils.ModifiableScratchBuffer( self._buf ), utils.RestoreCursorPosition() ): utils.ClearBuffer( self._buf ) for thread in self._threads: - if self._current_thread == thread.id: - icon = '^' if not thread.IsExpanded() else '>' - else: - icon = '+' if not thread.IsExpanded() else '-' - + icon = '+' if not thread.IsExpanded() else '-' line = utils.AppendToBuffer( self._buf, f'{icon} Thread: {thread.thread["name"]} ({thread.State()})' ) + if self._current_thread == thread.id: + signs.PlaceSign( self._next_sign_id, + 'VimspectorStackTrace', + 'vimspectorCurrentThread', + self._buf.name, + line ) + self._line_to_thread[ line ] = thread self._DrawStackTrace( thread ) @@ -280,27 +306,32 @@ class StackTraceView( object ): } ) - def GetSelectedThreadId( self ): + def _GetSelectedThread( self ) -> Thread: if vim.current.buffer != self._buf: return None - thread = self._line_to_thread.get( vim.current.window.cursor[ 0 ] ) - if not thread: - return None + return self._line_to_thread.get( vim.current.window.cursor[ 0 ] ) - return thread.id + + def GetSelectedThreadId( self ): + thread = self._GetSelectedThread() + return thread.id if thread else thread + + + def SetCurrentThread( self ): + thread = self._GetSelectedThread() + if not thread: + utils.UserMessage( "No thread selected" ) + else: + self._current_thread = thread.id + + self._DrawThreads() def ExpandFrameOrThread( self ): - if vim.current.buffer != self._buf: - return + thread = self._GetSelectedThread() - current_line = vim.current.window.cursor[ 0 ] - - if current_line in self._line_to_frame: - self._JumpToFrame( self._line_to_frame[ current_line ] ) - elif current_line in self._line_to_thread: - thread = self._line_to_thread[ current_line ] + if thread: if thread.IsExpanded(): thread.Collapse() self._DrawThreads() @@ -308,6 +339,10 @@ class StackTraceView( object ): self._LoadStackTrace( thread, False ) else: utils.UserMessage( "Thread is not stopped" ) + elif vim.current.buffer != self._buf: + return + elif vim.current.window.cursor[ 0 ] in self._line_to_frame: + self._JumpToFrame( self._line_to_frame[ vim.current.window.cursor[ 0 ] ] ) def _JumpToFrame( self, frame, reason = '' ): @@ -329,6 +364,31 @@ class StackTraceView( object ): else: return do_jump() + + + def PauseContinueThread( self ): + thread = self._GetSelectedThread() + if thread is None: + utils.UserMessage( 'No thread selected' ) + elif thread.state == Thread.PAUSED: + self._session._connection.DoRequest( None, { + 'command': 'continue', + 'arguments': { + 'threadId': thread.id, + }, + } ) + elif thread.state == Thread.RUNNING: + self._session._connection.DoRequest( None, { + 'command': 'pause', + 'arguments': { + 'threadId': thread.id, + }, + } ) + else: + utils.UserMessage( + f'Thread cannot be modified in state {thread.State()}' ) + + def OnContinued( self, event = None ): threadId = None allThreadsContinued = True diff --git a/tests/stack_trace.test.vim b/tests/stack_trace.test.vim index 1475874..d88b081 100644 --- a/tests/stack_trace.test.vim +++ b/tests/stack_trace.test.vim @@ -16,7 +16,6 @@ function! s:StartDebugging() endfunction function! Test_Multiple_Threads_Continue() - let thread_l = 67 let notify_l = 74 @@ -33,7 +32,7 @@ function! Test_Multiple_Threads_Continue() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( thread_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -48,7 +47,7 @@ function! Test_Multiple_Threads_Continue() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( thread_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -73,7 +72,7 @@ function! Test_Multiple_Threads_Continue() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( thread_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -98,7 +97,7 @@ function! Test_Multiple_Threads_Continue() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( thread_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -124,7 +123,7 @@ function! Test_Multiple_Threads_Continue() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( thread_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -149,7 +148,7 @@ function! Test_Multiple_Threads_Continue() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( notify_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -189,7 +188,7 @@ function! Test_Multiple_Threads_Step() call WaitForAssert( {-> \ AssertMatchist( \ [ - \ '> Thread: Thread #1 (paused)', + \ '- Thread: Thread #1 (paused)', \ ' .*: threads!main@threads.cpp:' . string( thread_l ) \ ], \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), @@ -347,5 +346,3 @@ function! Test_Multiple_Threads_Step() call vimspector#test#setup#Reset() %bwipe! endfunction - -" TODO: Set current frame while thread is running sets the PC