diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1788c04..f01a833 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -17,12 +17,12 @@ assignees: '' > Please answer the following questions -* Does your issue reproduce using `vim -Nu /path/to/vimspector/support/minimal_vimrc` ? \[Yes/No] +* Does your issue reproduce using `vim --clean -Nu /path/to/vimspector/support/minimal_vimrc` ? \[Yes/No] * If you are using Neovim, does your issue reproduce using Vim? \[Yes/No] > List of steps to reproduce: -> 1. Run `vim -Nu /path/to/vimspector/support/minimal_vimrc` +> 1. Run `vim ---clean Nu /path/to/vimspector/support/minimal_vimrc` > 2. Open _this project_... > 3. Press _this sequence of keys_ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 578fd8f..1866974 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,7 +83,7 @@ in the issue report. The minimal vimrc is in `support/test/minimal_vimrc` and can be used as follows: ``` -vim -Nu /path/to/vimspector/support/minimal_vimrc +vim --clean -Nu /path/to/vimspector/support/minimal_vimrc ``` ## Pull Requests diff --git a/README.md b/README.md index 42d4765..2152a9c 100644 --- a/README.md +++ b/README.md @@ -656,18 +656,23 @@ personal and so you should work out what you like and use vim's powerful mapping features to set your own mappings. To that end, Vimspector defines the following `` mappings: -* `VimspectorContinue` -* `VimspectorStop` -* `VimspectorRestart` -* `VimspectorPause` -* `VimspectorToggleBreakpoint` -* `VimspectorToggleConditionalBreakpoint` -* `VimspectorAddFunctionBreakpoint` -* `VimspectorStepOver` -* `VimspectorStepInto` -* `VimspectorStepOut` -* `VimspectorRunToCursor` -* `VimspectorBalloonEval` +| Mapping | Function | API | +| --- | --- | --- | +| `VimspectorContinue` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | +| `VimspectorStop` | Stop debugging. | `vimspector#Stop()` | +| `VimpectorRestart` | Restart debugging with the same configuration. | `vimspector#Restart()` | +| `VimspectorPause` | Pause debuggee. | `vimspector#Pause()` | +| `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | +| `VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | +| `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | +| `VimspectorRunToCursor` | Run to Cursor | `vimspector#RunToCursor()` | +| `VimspectorStepOver` | Step Over | `vimspector#StepOver()` | +| `VimspectorStepInto` | Step Into | `vimspector#StepInto()` | +| `VimspectorStepOut` | Step out of current function scope | `vimspector#StepOut()` | +| `VimspectorUpFrame` | Move up a frame in the current call stack | `vimspector#UpFrame()` | +| `VimspectorDownFrame` | Move down a frame in the current call stack | `vimspector#DownFrame()` | +| `VimspectorBalloonEval` | Evaluate expression under cursor (or visual) in popup | *internal* | + These map roughly 1-1 with the API functions below. @@ -695,17 +700,17 @@ loading vimspector**: let g:vimspector_enable_mappings = 'VISUAL_STUDIO' ``` -| Key | Function | API | -| --- | --- | --- | -| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | -| `Shift F5` | Stop debugging. | `vimspector#Stop()` | -| `Ctrl Shift F5` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debuggee. | `vimspector#Pause()` | -| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | -| `Shift F9` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | -| `F10` | Step Over | `vimspector#StepOver()` | -| `F11` | Step Into | `vimspector#StepInto()` | -| `Shift F11` | Step out of current function scope | `vimspector#StepOut()` | +| Key | Mapping | Function +| --- | --- | --- +| `F5` | `VimspectorContinue` | When debugging, continue. Otherwise start debugging. +| `Shift F5` | `VimspectorStop` | Stop debugging. +| `Ctrl Shift F5` | `VimspectorRestart` | Restart debugging with the same configuration. +| `F6` | `VimspectorPause` | Pause debuggee. +| `F9` | `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. +| `Shift F9` | `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor +| `F10` | `VimspectorStepOver` | Step Over +| `F11` | `VimspectorStepInto` | Step Into +| `Shift F11` | `VimspectorStepOut` | Step out of current function scope ## Human Mode @@ -720,19 +725,19 @@ loading vimspector**: let g:vimspector_enable_mappings = 'HUMAN' ``` -| Key | Function | API | -| --- | --- | --- | -| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | -| `F3` | Stop debugging. | `vimspector#Stop()` | -| `F4` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debuggee. | `vimspector#Pause()` | -| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | -| `F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | -| `F8` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | -| `F8` | Run to Cursor | `vimspector#RunToCursor()` | -| `F10` | Step Over | `vimspector#StepOver()` | -| `F11` | Step Into | `vimspector#StepInto()` | -| `F12` | Step out of current function scope | `vimspector#StepOut()` | +| Key | Mapping | Function +| --- | --- | --- +| `F5` | `VimspectorContinue` | When debugging, continue. Otherwise start debugging. +| `F3` | `VimspectorStop` | Stop debugging. +| `F4` | `VimspectorRestart` | Restart debugging with the same configuration. +| `F6` | `VimspectorPause` | Pause debuggee. +| `F9` | `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. +| `F9` | `VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. +| `F8` | `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor +| `F8` | `VimspectorRunToCursor` | Run to Cursor +| `F10` | `VimspectorStepOver` | Step Over +| `F11` | `VimspectorStepInto` | Step Into +| `F12` | `VimspectorStepOut` | Step out of current function scope In addition, I recommend adding a mapping to `VimspectorBalloonEval`, in normal and visual modes, for example: @@ -746,6 +751,13 @@ nmap di VimspectorBalloonEval xmap di VimspectorBalloonEval ``` +You may also wish to add mappings for up/down the stack, for example: + +```viml +nmap VimspectorUpFrame +nmap VimspectorDownFrame +``` + # Usage and API This section defines detailed usage instructions, organised by feature. For most diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index e94a177..a547e5c 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -234,6 +234,20 @@ function! vimspector#GoToFrame() abort py3 _vimspector_session.ExpandFrameOrThread() endfunction +function! vimspector#UpFrame() abort + if !s:Enabled() + return + endif + py3 _vimspector_session.UpFrame() +endfunction + +function! vimspector#DownFrame() abort + if !s:Enabled() + return + endif + py3 _vimspector_session.DownFrame() +endfunction + function! vimspector#AddWatch( ... ) abort if !s:Enabled() return diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 32d17ab..f7ed9d7 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -69,7 +69,6 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort \ 'resize': 1, \ 'close': 'button', \ 'callback': 'vimspector#internal#balloon#CloseCallback', - \ 'mapping': 0 \ } " When ambiwidth is single, use prettier characters for the border. This @@ -86,6 +85,7 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort let config[ 'filter' ] = 'vimspector#internal#balloon#CursorFilter' let config[ 'moved' ] = 'any' let config[ 'cursorline' ] = 1 + let config[ 'mapping' ] = 0 let s:popup_win_id = popup_atcursor( body, config ) endif diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 53855ef..37509a7 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -67,6 +67,11 @@ nnoremap VimspectorBalloonEval xnoremap VimspectorBalloonEval \ :call vimspector#ShowEvalBalloon( 1 ) +nnoremap VimspectorUpFrame + \ :call vimspector#UpFrame() +nnoremap VimspectorDownFrame + \ :call vimspector#DownFrame() + if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorContinue nmap VimspectorStop diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 6fb0b16..4d8c816 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -571,6 +571,14 @@ class DebugSession( object ): def ExpandFrameOrThread( self ): self._stackTraceView.ExpandFrameOrThread() + @IfConnected() + def UpFrame( self ): + self._stackTraceView.UpFrame() + + @IfConnected() + def DownFrame( self ): + self._stackTraceView.DownFrame() + def ToggleLog( self ): if self._HasUI(): return self.ShowOutput( 'Vimspector' ) @@ -655,6 +663,45 @@ class DebugSession( object ): vim.command( 'tab split' ) self._uiTab = vim.current.tabpage + mode = settings.Get( 'ui_mode' ) + + if mode == 'auto': + # Go vertical if there isn't enough horizontal space for at least: + # the left bar width + # + the code min width + # + the terminal min width + # + enough space for a sign column and number column? + min_width = ( settings.Int( 'sidebar_width' ) + + 1 + 2 + 3 + + settings.Int( 'code_minwidth' ) + + 1 + settings.Int( 'terminal_minwidth' ) ) + + min_height = ( settings.Int( 'code_minheight' ) + 1 + + settings.Int( 'topbar_height' ) + 1 + + settings.Int( 'bottombar_height' ) + 1 + + 2 ) + + mode = ( 'vertical' + if vim.options[ 'columns' ] < min_width + else 'horizontal' ) + + if vim.options[ 'lines' ] < min_height: + mode = 'horizontal' + + self._logger.debug( 'min_width/height: %s/%s, actual: %s/%s - result: %s', + min_width, + min_height, + vim.options[ 'columns' ], + vim.options[ 'lines' ], + mode ) + + if mode == 'vertical': + self._SetUpUIVertical() + else: + self._SetUpUIHorizontal() + + + def _SetUpUIHorizontal( self ): # Code window code_window = vim.current.window self._codeView = code.CodeView( code_window, self._api_prefix ) @@ -695,6 +742,66 @@ class DebugSession( object ): # TODO: If/when we support multiple sessions, we'll need some way to # indicate which tab was created and store all the tabs vim.vars[ 'vimspector_session_windows' ] = { + 'mode': 'horizontal', + 'tabpage': self._uiTab.number, + 'code': utils.WindowID( code_window, self._uiTab ), + 'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ), + 'variables': utils.WindowID( vars_window, self._uiTab ), + 'watches': utils.WindowID( watch_window, self._uiTab ), + 'output': utils.WindowID( output_window, self._uiTab ), + 'eval': None # this is going to be updated every time eval popup is opened + } + with utils.RestoreCursorPosition(): + with utils.RestoreCurrentWindow(): + with utils.RestoreCurrentBuffer( vim.current.window ): + vim.command( 'doautocmd User VimspectorUICreated' ) + + + def _SetUpUIVertical( self ): + # Code window + code_window = vim.current.window + self._codeView = code.CodeView( code_window, self._api_prefix ) + + # Call stack + vim.command( + f'topleft { settings.Int( "topbar_height" ) }new' ) + stack_trace_window = vim.current.window + one_third = int( vim.eval( 'winwidth( 0 )' ) ) / 3 + self._stackTraceView = stack_trace.StackTraceView( self, + stack_trace_window ) + + + # Watches + vim.command( 'leftabove vertical new' ) + watch_window = vim.current.window + + # Variables + vim.command( 'leftabove vertical new' ) + vars_window = vim.current.window + + + with utils.LetCurrentWindow( vars_window ): + vim.command( f'{ one_third }wincmd |' ) + with utils.LetCurrentWindow( watch_window ): + vim.command( f'{ one_third }wincmd |' ) + with utils.LetCurrentWindow( stack_trace_window ): + vim.command( f'{ one_third }wincmd |' ) + + self._variablesView = variables.VariablesView( vars_window, + watch_window ) + + + # Output/logging + vim.current.window = code_window + vim.command( f'rightbelow { settings.Int( "bottombar_height" ) }new' ) + output_window = vim.current.window + self._outputView = output.DAPOutputView( output_window, + self._api_prefix ) + + # TODO: If/when we support multiple sessions, we'll need some way to + # indicate which tab was created and store all the tabs + vim.vars[ 'vimspector_session_windows' ] = { + 'mode': 'vertical', 'tabpage': self._uiTab.number, 'code': utils.WindowID( code_window, self._uiTab ), 'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ), diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index 9ad9e41..e9e76ea 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -20,11 +20,20 @@ from vimspector import utils DEFAULTS = { # UI - 'bottombar_height': 10, - 'sidebar_width': 50, - 'code_minwidth': 82, - 'terminal_maxwidth': 80, - 'terminal_minwidth': 10, + 'ui_mode': 'auto', + 'bottombar_height': 10, + + # For ui_mode = 'horizontal': + 'sidebar_width': 50, + 'code_minwidth': 82, + 'terminal_maxwidth': 80, + 'terminal_minwidth': 10, + + # For ui_mode = 'vertical': + 'topbar_height': 15, + 'code_minheight': 20, + 'terminal_maxheight': 15, + 'terminal_minheight': 5, # Signs 'sign_priority': { diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index c32cead..ae14e68 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -367,6 +367,46 @@ class StackTraceView( object ): self._JumpToFrame( frame ) + + def _GetFrameOffset( self, delta ): + thread: Thread + for thread in self._threads: + if thread.id != self._current_thread: + continue + + if not thread.stacktrace: + return + + frame_idx = None + for index, frame in enumerate( thread.stacktrace ): + if frame == self._current_frame: + frame_idx = index + break + + if frame_idx is not None: + target_idx = frame_idx + delta + if target_idx >= 0 and target_idx < len( thread.stacktrace ): + return thread.stacktrace[ target_idx ] + + break + + + def UpFrame( self ): + frame = self._GetFrameOffset( 1 ) + if not frame: + utils.UserMessage( 'Top of stack' ) + else: + self._JumpToFrame( frame, 'up' ) + + + def DownFrame( self ): + frame = self._GetFrameOffset( -1 ) + if not frame: + utils.UserMessage( 'Bottom of stack' ) + else: + self._JumpToFrame( frame, 'down' ) + + def AnyThreadsRunning( self ): for thread in self._threads: if thread.state != Thread.TERMINATED: diff --git a/python3/vimspector/terminal.py b/python3/vimspector/terminal.py index 6ffd56a..0c84704 100644 --- a/python3/vimspector/terminal.py +++ b/python3/vimspector/terminal.py @@ -23,12 +23,53 @@ def LaunchTerminal( api_prefix, env = params.get( 'env' ) or {} term_options = { - 'vertical': 1, 'norestore': 1, 'cwd': cwd, 'env': env, } + if settings.Get( 'ui_mode' ) == 'horizontal': + # force-horizontal + term_options[ 'vertical' ] = 1 + elif utils.GetVimValue( vim.vars[ 'vimspector_session_windows' ], + 'mode' ) == 'horizontal': + # horizontal, which means that we should have enough space for: + # - sidebar + # - code min + # - term min width + # - + 2 vertical spaders + # - + 3 columns for signs + term_options[ 'vertical' ] = 1 + + # if we don't have enough space for terminal_maxwidth, then see if we have + # enough vertically for terminal_maxheight, in which case, + # that seems a better fit + term_horiz_max = ( settings.Int( 'sidebar_width' ) + + 1 + 2 + 3 + + settings.Int( 'code_minwidth' ) + + 1 + settings.Int( 'terminal_maxwidth' ) ) + term_vert_max = ( settings.Int( 'bottombar_height' ) + 1 + + settings.Int( 'code_minheight' ) + 1 + + settings.Int( 'terminal_minheight' ) ) + + if ( vim.options[ 'columns' ] < term_horiz_max and + vim.options[ 'lines' ] >= term_vert_max ): + # Looks like it, let's try that layout + term_options[ 'vertical' ] = 0 + + + else: + # vertical - we need enough space horizontally for the code+terminal, but we + # may fit better with code above terminal + term_options[ 'vertical' ] = 0 + + term_horiz_max = ( settings.Int( 'code_minwidth' ) + 3 + + settings.Int( 'terminal_maxwidth' ) + 1 ) + + if vim.options[ 'columns' ] > term_horiz_max: + term_options[ 'vertical' ] = 1 + + if not window_for_start or not window_for_start.valid: # TOOD: Where? Maybe we should just use botright vertical ... window_for_start = vim.current.window @@ -50,13 +91,23 @@ def LaunchTerminal( api_prefix, # If we're making a vertical split from the code window, make it no more # than 80 columns and no fewer than 10. Also try and keep the code window # at least 82 columns - if term_options[ 'vertical' ] and not term_options.get( 'curwin', 0 ): + if term_options.get( 'curwin', 0 ): + pass + elif term_options[ 'vertical' ]: term_options[ 'term_cols' ] = max( min ( int( vim.eval( 'winwidth( 0 )' ) ) - settings.Int( 'code_minwidth' ), settings.Int( 'terminal_maxwidth' ) ), settings.Int( 'terminal_minwidth' ) ) + else: + term_options[ 'term_rows' ] = max( + min ( int( vim.eval( 'winheight( 0 )' ) ) + - settings.Int( 'code_minheight' ), + settings.Int( 'terminal_maxheight' ) ), + settings.Int( 'terminal_minheight' ) + ) + buffer_number = int( utils.Call( diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index e7cb537..d8dd345 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -494,7 +494,6 @@ def _Substitute( template, mapping ): if mo.group( 'braceddefault' ) is not None: named = mo.group( 'defname' ) if named not in mapping: - '' raise MissingSubstitution( named, mo.group( 'default' ).replace( '\\}', '}' ) ) @@ -536,8 +535,11 @@ def ExpandReferencesInString( orig_s, if default_value is None and e.default_value is not None: try: default_value = _Substitute( e.default_value, mapping ) - except MissingSubstitution: - default_value = e.default_value + except MissingSubstitution as e2: + if e2.name in calculus: + default_value = calculus[ e2.name ]() + else: + default_value = e.default_value mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ), default_value ) diff --git a/tests/lib/autoload/vimspector/test/setup.vim b/tests/lib/autoload/vimspector/test/setup.vim index b0296e0..6ab220c 100644 --- a/tests/lib/autoload/vimspector/test/setup.vim +++ b/tests/lib/autoload/vimspector/test/setup.vim @@ -50,3 +50,59 @@ function! vimspector#test#setup#Reset() abort call popup_clear() endfunction +let s:g_stack = {} + +function! vimspector#test#setup#PushGlobal( name, value ) abort + if !has_key( s:g_stack, a:name ) + let s:g_stack[ a:name ] = [] + endif + + let old_value = get( g:, a:name, v:null ) + call add( s:g_stack[ a:name ], old_value ) + let g:[ a:name ] = a:value + + return old_value +endfunction + +function! vimspector#test#setup#PopGlobal( name ) abort + if !has_key( s:g_stack, a:name ) || len( s:g_stack[ a:name ] ) == 0 + return v:null + endif + + let old_value = s:g_stack[ a:name ][ -1 ] + call remove( s:g_stack[ a:name ], -1 ) + + if old_value is v:null + silent! call remove( g:, a:name ) + else + let g:[ a:name ] = old_value + endif + + return old_value +endfunction + +let s:o_stack = {} + +function! vimspector#test#setup#PushOption( name, value ) abort + if !has_key( s:o_stack, a:name ) + let s:o_stack[ a:name ] = [] + endif + + let old_value = v:null + execute 'let old_value = &' . a:name + call add( s:o_stack[ a:name ], old_value ) + execute 'set ' . a:name . '=' . a:value + return old_value +endfunction + +function! vimspector#test#setup#PopOption( name ) abort + if !has_key( s:o_stack, a:name ) || len( s:o_stack[ a:name ] ) == 0 + return v:null + endif + + let old_value = s:o_stack[ a:name ][ -1 ] + call remove( s:o_stack[ a:name ], -1 ) + + execute 'set ' . a:name . '=' . old_value + return old_value +endfunction diff --git a/tests/python/Test_ExpandReferencesInDict.py b/tests/python/Test_ExpandReferencesInDict.py index 4998350..15fb11b 100644 --- a/tests/python/Test_ExpandReferencesInDict.py +++ b/tests/python/Test_ExpandReferencesInDict.py @@ -35,6 +35,7 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'one': '${one}', 'two': '${one} and ${two}', 'three': '${three}', + 'three_with_default': '${three_with_default:${three\\}}', # uses calculus 'four': '${four}', 'five': '${five}', 'list': [ '*${words}' ], @@ -58,6 +59,7 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'one': 'one', 'two': 'one and TWO', 'three': '3', + 'three_with_default': '3', 'four': 'typed text', 'five': '5ive!', 'list': [ 'these', 'are', 'some', 'words' ], diff --git a/tests/stack_trace.test.vim b/tests/stack_trace.test.vim index 569376c..a65ea5e 100644 --- a/tests/stack_trace.test.vim +++ b/tests/stack_trace.test.vim @@ -356,3 +356,117 @@ function! Test_Multiple_Threads_Step() call vimspector#test#setup#Reset() %bwipe! endfunction + +function! Test_UpDownStack() + let fn='../support/test/python/simple_python/main.py' + exe 'edit ' . fn + call setpos( '.', [ 0, 6, 1 ] ) + + call vimspector#SetLineBreakpoint( fn, 15 ) + call vimspector#LaunchWithSettings( { 'configuration': 'run' } ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#DownFrame() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#UpFrame() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call feedkeys( "\VimspectorUpFrame", 'x' ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 23, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call feedkeys( "\VimspectorDownFrame", 'x' ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#DownFrame() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + + call vimspector#ClearBreakpoints() + call vimspector#test#setup#Reset() + %bwipe! +endfunction diff --git a/tests/ui.test.vim b/tests/ui.test.vim index f251539..5ba2f9c 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -1,6 +1,7 @@ let s:fn='../support/test/python/simple_python/main.py' function! SetUp() + let g:vimspector_ui_mode = get( s:, 'vimspector_ui_mode', 'horizontal' ) call vimspector#test#setup#SetUpWithMappings( 'HUMAN' ) endfunction @@ -16,12 +17,17 @@ function! s:StartDebugging() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 23, 1 ) endfunction +function! SetUp_Test_StandardLayout() + call vimspector#test#setup#PushOption( 'columns', 200 ) +endfunction + function! Test_StandardLayout() call s:StartDebugging() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) call assert_equal( \ [ 'row', [ \ [ 'col', [ @@ -43,6 +49,247 @@ function! Test_StandardLayout() %bwipe! endfunction +function! TearDown_Test_StandardLayout() + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_NarrowLayout() + call vimspector#test#setup#PushOption( 'columns', 100 ) + let s:vimspector_ui_mode = 'vertical' +endfunction + +function! Test_NarrowLayout() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'vertical', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_NarrowLayout() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalVert() + let s:vimspector_ui_mode = 'auto' + call vimspector#test#setup#PushOption( 'columns', 250 ) + call vimspector#test#setup#PushOption( 'lines', 30 ) +endfunction + +function! Test_AutoLayoutTerminalVert() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'row', [ + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ] + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalVert() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalHorizVert() + let s:vimspector_ui_mode = 'auto' + " Wide enough to be horizontal layout, but not wide enough to fully fit the + " terminal, with enough rows to fit the max terminal below + call vimspector#test#setup#PushOption( 'columns', + \ 50 + 82 + 3 + 2 + 12 ) + call vimspector#test#setup#PushOption( 'lines', 50 ) +endfunction + +function! Test_AutoLayoutTerminalHorizVert() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'row', [ + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ] + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalHorizVert() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalHorizVertButNotEnoughLines() + let s:vimspector_ui_mode = 'auto' + " Wide enough to be horizontal layout, but not wide enough to fully fit the + " terminal, with enough rows to fit the max terminal below, but there are not + " enough lines to do this + call vimspector#test#setup#PushOption( 'columns', + \ 50 + 82 + 3 + 2 + 12 ) + call vimspector#test#setup#PushOption( 'lines', 20 ) +endfunction + +function! Test_AutoLayoutTerminalHorizVertButNotEnoughLines() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'row', [ + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalHorizVertButNotEnoughLines() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalHoriz() + let s:vimspector_ui_mode = 'vertical' + " Vertical layout, but we split the terminal horizonally + call vimspector#test#setup#PushOption( 'columns', 200 ) + call vimspector#test#setup#PushOption( 'lines', 50 ) +endfunction + +function! Test_AutoLayoutTerminalHoriz() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'vertical', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalHoriz() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalVertVert() + let s:vimspector_ui_mode = 'auto' + " Not wide enough to go horizontal, but wide enough to put the terminal and + " code vertically split + call vimspector#test#setup#PushOption( 'columns', 80 ) + call vimspector#test#setup#PushOption( 'lines', 50 ) +endfunction + +function! Test_AutoLayoutTerminalVertVert() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'vertical', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalVertVert() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + + function! Test_CloseVariables() call s:StartDebugging()