Merge pull request #198 from puremourning/ui-custom

UI customisation
This commit is contained in:
mergify[bot] 2020-07-18 14:20:18 +00:00 committed by GitHub
commit c1e29be9b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 1629 additions and 221 deletions

295
README.md
View file

@ -6,69 +6,74 @@ For a tutorial and usage overview, take a look at the
[![Build Status](https://dev.azure.com/puremouron/Vimspector/_apis/build/status/puremourning.vimspector?branchName=master)](https://dev.azure.com/puremouron/Vimspector/_build/latest?definitionId=1&branchName=master) [![Gitter](https://badges.gitter.im/vimspector/Lobby.svg)](https://gitter.im/vimspector/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
<!--ts-->
* [Features and Usage](#features-and-usage)
* [Supported debugging features](#supported-debugging-features)
* [Supported languages:](#supported-languages)
* [Languages known to work](#languages-known-to-work)
* [Languages known not to work](#languages-known-not-to-work)
* [Other languages](#other-languages)
* [Installation](#installation)
* [Dependencies](#dependencies)
* [Neovim differences](#neovim-differences)
* [Windows differences](#windows-differences)
* [Language dependencies](#language-dependencies)
* [Clone the plugin](#clone-the-plugin)
* [Install some gadgets](#install-some-gadgets)
* [Manual gadget installation](#manual-gadget-installation)
* [The gadget directory](#the-gadget-directory)
* [Trying it out](#trying-it-out)
* [About](#about)
* [Background](#background)
* [Status](#status)
* [Experimental](#experimental)
* [Mappings](#mappings)
* [Visual Studio / VSCode](#visual-studio--vscode)
* [Human Mode](#human-mode)
* [Usage](#usage)
* [Launch and attach by PID:](#launch-and-attach-by-pid)
* [Launch with options](#launch-with-options)
* [Breakpoints](#breakpoints)
* [Exception breakpoints](#exception-breakpoints)
* [Clear breakpoints](#clear-breakpoints)
* [Stepping](#stepping)
* [Variables and scopes](#variables-and-scopes)
* [Watches](#watches)
* [Stack Traces](#stack-traces)
* [Program Output](#program-output)
* [Console](#console)
* [Closing debugger](#closing-debugger)
* [Debug adapter configuration](#debug-adapter-configuration)
* [C, C , Rust, etc.](#c-c-rust-etc)
* [Remote debugging](#remote-debugging)
* [Remote launch and attach](#remote-launch-and-attach)
* [Python](#python)
* [Remote Debugging](#remote-debugging-1)
* [Remote launch and attach](#remote-launch-and-attach-1)
* [Legacy: vscode-python](#legacy-vscode-python)
* [TCL](#tcl)
* [C♯](#c)
* [Go](#go)
* [PHP](#php)
* [Debug web application](#debug-web-application)
* [Debug cli application](#debug-cli-application)
* [JavaScript, TypeScript, etc.](#javascript-typescript-etc)
* [Java](#java)
* [Usage with YouCompleteMe](#usage-with-youcompleteme)
* [Other LSP clients](#other-lsp-clients)
* [Rust](#rust)
* [Other servers](#other-servers)
* [Customisation](#customisation)
* [Changing the default signs](#changing-the-default-signs)
* [FAQ](#faq)
* [Motivation](#motivation)
* [License](#license)
* [Features and Usage](#features-and-usage)
* [Supported debugging features](#supported-debugging-features)
* [Supported languages:](#supported-languages)
* [Languages known to work](#languages-known-to-work)
* [Languages known not to work](#languages-known-not-to-work)
* [Other languages](#other-languages)
* [Installation](#installation)
* [Dependencies](#dependencies)
* [Neovim differences](#neovim-differences)
* [Windows differences](#windows-differences)
* [Language dependencies](#language-dependencies)
* [Clone the plugin](#clone-the-plugin)
* [Install some gadgets](#install-some-gadgets)
* [Manual gadget installation](#manual-gadget-installation)
* [The gadget directory](#the-gadget-directory)
* [Trying it out](#trying-it-out)
* [About](#about)
* [Background](#background)
* [Status](#status)
* [Experimental](#experimental)
* [Mappings](#mappings)
* [Visual Studio / VSCode](#visual-studio--vscode)
* [Human Mode](#human-mode)
* [Usage](#usage)
* [Launch and attach by PID:](#launch-and-attach-by-pid)
* [Launch with options](#launch-with-options)
* [Debug configuration selection](#debug-configuration-selection)
* [Breakpoints](#breakpoints)
* [Exception breakpoints](#exception-breakpoints)
* [Clear breakpoints](#clear-breakpoints)
* [Stepping](#stepping)
* [Variables and scopes](#variables-and-scopes)
* [Watches](#watches)
* [Stack Traces](#stack-traces)
* [Program Output](#program-output)
* [Console](#console)
* [Closing debugger](#closing-debugger)
* [Debug adapter configuration](#debug-adapter-configuration)
* [C, C , Rust, etc.](#c-c-rust-etc)
* [Remote debugging](#remote-debugging)
* [Remote launch and attach](#remote-launch-and-attach)
* [Python](#python)
* [Remote Debugging](#remote-debugging-1)
* [Remote launch and attach](#remote-launch-and-attach-1)
* [Legacy: vscode-python](#legacy-vscode-python)
* [TCL](#tcl)
* [C♯](#c)
* [Go](#go)
* [PHP](#php)
* [Debug web application](#debug-web-application)
* [Debug cli application](#debug-cli-application)
* [JavaScript, TypeScript, etc.](#javascript-typescript-etc)
* [Java](#java)
* [Usage with YouCompleteMe](#usage-with-youcompleteme)
* [Other LSP clients](#other-lsp-clients)
* [Rust](#rust)
* [Other servers](#other-servers)
* [Customisation](#customisation)
* [Changing the default signs](#changing-the-default-signs)
* [Changing the default window sizes](#changing-the-default-window-sizes)
* [Changing the terminal size](#changing-the-terminal-size)
* [Advanced UI customisation](#advanced-ui-customisation)
* [Example](#example)
* [FAQ](#faq)
* [Motivation](#motivation)
* [License](#license)
<!-- Added by: ben, at: Thu 9 Jul 2020 18:19:20 BST -->
<!-- Added by: ben, at: Sat 18 Jul 2020 12:58:35 BST -->
<!--te-->
@ -601,6 +606,19 @@ See [our YouCompleteMe integration guide](#usage-with-youcompleteme) for
another example where it can be used to specify the port to connect the [java
debugger](#java---partially-supported)
### Debug configuration selection
Vimspector uses the following logic to choose a configuration to launch:
1. If a configuration was specified in the launch options (as above), use that.
2. Otherwise if there's only one configuration and it doesn't have `autoselect`
set to `false`, use that.
3. Otherwise if there's exactly one configuration with `default` set to `true`
and without `autoselect` set to `false`, use that.
4. Otherwise, prompt the user to select a configuration.
See [the reference guide][vimspector-ref-config-selection] for details.
## Breakpoints
* Use `vimspector#ToggleBreakpoint([ { 'condition': '<condition expr>' } ])`
@ -659,6 +677,8 @@ You can configure your choices in the `.vimspector.json`. See
![locals window](https://puremourning.github.io/vimspector-web/img/vimspector-locals-window.png)
Scopes and variables are represented by the buffer `vimspector.Variables`.
## Watches
The watches window is a prompt buffer, where that's available. Enter insert mode
@ -673,6 +693,8 @@ to add a new watch expression.
![watch window](https://puremourning.github.io/vimspector-web/img/vimspector-watch-window.png)
The watches are represented by the buffer `vimspector.StackTrace`.
## Stack Traces
* In the threads window, use `<CR>` to expand/collapse.
@ -680,6 +702,8 @@ to add a new watch expression.
![stack trace](https://puremourning.github.io/vimspector-web/img/vimspector-callstack-window.png)
The stack trace is represented by the buffer `vimspector.StackTrace`.
## Program Output
* In the outputs window use the WinBar to select the output channel.
@ -690,6 +714,10 @@ to add a new watch expression.
![output window](https://puremourning.github.io/vimspector-web/img/vimspector-output-window.png)
If the output window is closed, a new one can be opened with
`:VimspectorShowOutput <category>` (use tab-completion - `wildmenu` to see the
options).
### Console
The console window is a prompt buffer, where that's available, and can be used
@ -704,6 +732,9 @@ adapters.
NOTE: See also [Watches](#watches) above.
If the output window is closed, a new one can be opened with
`:VimspectorShowOutput Console`.
## Closing debugger
To close the debugger, use:
@ -1284,6 +1315,145 @@ sign define vimspectorBPDisabled text=🔵 texthl=Normal
sign define vimspectorPC text=🔶 texthl=SpellBad
```
## Changing the default window sizes
> ***Please Note***: This cusomiation API is ***unstable***, meaning that it may
change at any time. I will endeavour to reduce the impact of this and annouce
changes in Gitter.
The following options control the default sizes of the UI windows (all of them
are numbers)
- `g:vimspector_sidebar_width` (default: 50 columns):
The width in columns of the left utility windows (variables, watches, stack
trace)
- `g:vimspector_bottombar_height` (default 10 lines):
The height in rows of the output window below the code window.
Example:
```viml
let g:vimspector_sidebar_width = 75
let g:vimspector_bottombar_height = 15
```
## Changing the terminal size
The terminal is typically created as a vertical split to the righ of the code
window, and that window is re-used for subsequent terminal buffers.
The following control the sizing of the terminal window used
for debuggee input/output when using Vim's built-in terminal.
- `g:vimspector_code_minwidth` (default: 82 columns):
Minimum number of columns to try and maintain for the code window when
splitting to create the terminal window.
- `g:vimspector_terminal_maxwidth` (default: 80 columns):
Maximum number of columns to use for the terminal.
- `g:vimspector_terminal_minwidth` (default: 10 columns):
Minimum number of columns to use when it is not possible to fit
`g:vimspector_terminal_maxwidth` columns for the terminal.
That's a lot of options, but essentially we try to make sure that there are at
least `g:vimspector_code_minwidth` columns for the main code window and that the
terminal is no wider than `g:vimspector_terminal_maxwidth` columns.
`g:vimspector_terminal_minwidth` is there to ensure that there's a reasonable
number of columns for the terminal even when there isn't enough horizontal space
to satisfy the other contraints.
Example:
```viml
let g:vimspector_code_minwidth = 90
let g:vimspector_terminal_maxwidth = 75
let g:vimspector_terminal_minwidth = 20
```
## Advanced UI customisation
> ***Please Note***: This cusomiation API is ***unstable***, meaning that it may
change at any time. I will endeavour to reduce the impact of this and annouce
changes in Gitter.
The above customisation of window sizes is limited intentionally to keep things
simple. Vimspector also provides a way for you to customise the UI without
restrictions, by running a `User` autocommand just after creating the UI or
opening the terminal. This requires you to write some vimscript, but allows you
to do things like:
* Hide a particular window or windows
* Move a particular window or windows
* Resize windows
* Have multiple windows for a particular buffer (say, you want 2 watch windows)
* etc.
You can essentially do anything you could do manually by writing a little
vimscript code.
The `User` autocommand is raised with `pattern` set with the following values:
* `VimspectorUICreated`: Just after setting up the UI for a debug session
* `VimspectorTerminalOpened`: Just after opening the terminal window for program
input/output.
The following global variable is set up for you to get access to the UI
elements: `g:vimspector_session_windows`. This is a `dict` with the following
keys:
* `g:vimspector_session_windows.tagpage`: The tab page for the session
* `g:vimspector_session_windows.variables`: Window ID of the variables window,
containing the `vimspector.Variables` buffer.
* `g:vimspector_session_windows.watches`: Window ID of the watches window,
containng the `vimspector.Watches` buffer.
* `g:vimspector_session_windows.stack_trace`: Window ID of the stack trade
window containing the `vimspector.StackTrace` buffer.
* `g:vimspector_session_windows.code`: Window ID of the code window.
* `g:vimspector_session_windows.output`: Window ID of the output window.
In addition, the following key is added when triggering the
`VimspectorTerminalOpened` event:
* `g:vimspector_session_windows.terminal`: Window ID of the terminal window
## Example
There is some example code in `support/custom_ui_vimrc` showing how you can use
the window IDs to modify various aspects of the UI using some basic vim
commands, primarily `win_gotoid` funciton and the `wincmd` ex command.
To try this out `vim -Nu support/custom_ui_vimrc <some file>`.
Here's a rather smaller example. A simple way to use this is to drop it into a
file named `my_vimspector_ui.vim` in `~/.vim/plugin` (or paste into your
`vimrc`):
```viml
" Set the basic sizes
let g:vimspector_sidebar_width = 80
let g:vimspector_code_minwidth = 85
let g:vimspector_terminal_minwidth = 75
function! s:CustomiseUI()
" Customise the basic UI...
" Close the output window
call win_gotoid( g:vimspector_session_windows.output )
q
endfunction
function s:SetUpTerminal()
" Customise the terminal window size/position
" For some reasons terminal buffers in Neovim have line numbers
call win_gotoid( g:vimspector_session_windows.terminal )
set norelativenumber nonumber
endfunction
augroup MyVimspectorUICustomistaion
autocmd!
autocmd User VimspectorUICreated call s:CustomiseUI()
autocmd User VimspectorTerminalOpened call s:SetUpTerminal()
augroup END
```
# FAQ
1. Q: Does it work? A: Yeah. It's a bit unpolished.
@ -1366,6 +1536,7 @@ Copyright © 2018 Ben Jackson
[vimspector-ref]: https://puremourning.github.io/vimspector/configuration.html
[vimspector-ref-var]: https://puremourning.github.io/vimspector/configuration.html#replacements-and-variables
[vimspector-ref-exception]: https://puremourning.github.io/vimspector/configuration.html#exception-breakpoints
[vimspector-ref-config-selection]: https://puremourning.github.io/vimspector/configuration.html#configuration-selection
[debugpy]: https://github.com/microsoft/debugpy
[YouCompleteMe]: https://github.com/ycm-core/YouCompleteMe#java-semantic-completion
[remote-debugging]: https://puremourning.github.io/vimspector/configuration.html#remote-debugging-support

View file

@ -137,14 +137,16 @@ function! vimspector#ListBreakpoints() abort
endfunction
function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort
let buffers = py3eval( '_vimspector_session.GetOutputBuffers()' )
let buffers = py3eval( '_vimspector_session.GetOutputBuffers() '
\ . ' if _vimspector_session else []' )
return join( buffers, "\n" )
endfunction
function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort
return join( py3eval( '_vimspector_session.GetCompletionsSync( '
\.' vim.eval( "a:CmdLine" ),'
\.' int( vim.eval( "a:CursorPos" ) ) )' ),
\.' int( vim.eval( "a:CursorPos" ) ) )'
\. ' if _vimspector_session else []' ),
\ "\n" )
endfunction

View file

@ -48,7 +48,7 @@ endfunction
function! vimspector#internal#neoterm#Start( cmd, opts ) abort
" Prepare current buffer to be turned into a term if curwin is not set
if ! get( a:opts, 'curwin', 0 )
let mods = ''
let mods = 'rightbelow '
if get( a:opts, 'vertical', 0 )
let mods .= 'vertical '
let mods .= get( a:opts, 'term_cols', '' )

View file

@ -20,7 +20,7 @@ set cpoptions&vim
" }}}
function! vimspector#internal#term#Start( cmd, opts ) abort
return term_start( a:cmd, a:opts )
rightbelow return term_start( a:cmd, a:opts )
endfunction
function! vimspector#internal#term#IsFinished( bufno ) abort

View file

@ -58,11 +58,10 @@ stages:
- bash: |
eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
export GOPATH=$HOME/go
./run_tests
./run_tests --report messages --quiet
displayName: 'Run the tests'
env:
VIMSPECTOR_MIMODE: gdb
VIMSPECTOR_TEST_STDOUT: true
- bash: ./make_package linux $(Build.SourceVersion)
displayName: 'Package'
@ -103,11 +102,10 @@ stages:
- bash: vim --version
displayName: 'Print vim version information'
- bash: ./run_tests
- bash: ./run_tests --report messages --quiet
displayName: 'Run the tests'
env:
VIMSPECTOR_MIMODE: lldb
VIMSPECTOR_TEST_STDOUT: true
- bash: ./make_package macos $(Build.SourceVersion)
displayName: 'Package'

View file

@ -92,7 +92,7 @@ function! s:RunTestUnderCursor()
let l:cwd = getcwd()
execute 'lcd ' . s:root_dir
try
execute s:make_cmd . ' '
execute s:make_cmd . ' --report messages '
\ . get( g:, 'vimspector_test_args', '' ) . ' '
\ . l:test_arg
finally
@ -105,7 +105,7 @@ function! s:RunTest()
let l:cwd = getcwd()
execute 'lcd ' . s:root_dir
try
execute s:make_cmd . ' '
execute s:make_cmd . ' --report messages '
\ . get( g:, 'vimspector_test_args', '' )
\ . ' %:p:t'
finally
@ -118,7 +118,7 @@ function! s:RunAllTests()
let l:cwd = getcwd()
execute 'lcd ' . s:root_dir
try
execute s:make_cmd . ' '
execute s:make_cmd . ' --report messages '
\ . get( g:, 'vimspector_test_args', '' )
finally
execute 'lcd ' . l:cwd

View file

@ -1,4 +1,6 @@
flake8==3.8.3
vim-vint==0.3.21
flake8-comprehensions==3.2.3
flake8-ycm>= 0.1.0
# Use fork of vint which is up to date
git+https://github.com/puremourning/vint

View file

@ -16,6 +16,9 @@ for Vimspector.
* [Files and locations](#files-and-locations)
* [Adapter configurations](#adapter-configurations)
* [Debug configurations](#debug-configurations)
* [Configuration selection](#configuration-selection)
* [Specifying a default configuration](#specifying-a-default-configuration)
* [Preventing automatic selection](#preventing-automatic-selection)
* [Exception breakpionts](#exception-breakpionts)
* [Predefined Variables](#predefined-variables)
* [Remote Debugging Support](#remote-debugging-support)
@ -25,7 +28,7 @@ for Vimspector.
* [Appendix: Configuration file format](#appendix-configuration-file-format)
* [Appendix: Editor configuration](#appendix-editor-configuration)
<!-- Added by: ben, at: Thu 9 Jul 2020 18:19:39 BST -->
<!-- Added by: ben, at: Sun 12 Jul 2020 16:46:18 BST -->
<!--te-->
@ -321,6 +324,62 @@ typical example looks like this:
}
```
### Configuration selection
When starting debugging, you can specify which debug configuration to launch
with `call vimspector#LaunchWithSettings( #{ configuration: 'name here' } )`.
Otherwise, if there's only one configuration found, Vimspector will use that
configuration, unless it contains a key `"autoselect": false`.
If multiple debug configurations are found, and no explicit configuration was
selected on Launch, the user is prompted to select a configuration, unless a
single debug configuration is found with a key `"default": true`.
#### Specifying a default configuration
As noted, you can specify a default configuration with `"default": true`:
```json
{
"configurations": {
"use this one": {
"default": true,
"adapter": " ... ",
"configuation": {
// ...
}
},
"don't use this one": {
// ...
}
}
}
```
If multiple conifigurations are found with `default` set to `true`, then the
user is prompted anyway.
#### Preventing automatic selection
If you don't want a configuration to be selected automatically, then set
`"autoselect": false`. This particularly useful for configurations in the
central (as opposed to project-local) directory. For example:
```json
"configurations": {
"Don't use this by default!": {
"autoselect": false,
"adapter": " ... ",
"configuation": {
// ...
}
}
}
```
Setting `autoselect` to `false` overrides setting `default` to `true`.
### Exception breakpionts
Debug adapters have arbitrary configuration for exception breakpoints. Normally
@ -426,12 +485,12 @@ where the development is done on one host and the runtime is
some other host, account, container, etc.
In order for it to work, you have to set up passwordless SSH between the local
and remote machines/accounts. Then just tell Vimsector how to remotely launch
and remote machines/accounts. Then just tell Vimspector how to remotely launch
and/or attach to the app.
This is presented as examples with commentary, as it's a fairly advanced/niche
case. If you're not already familiar with remote debugging tools (such as
gdbserver) or not familar with ssh or such, you might need to independently
gdbserver) or not familiar with ssh or such, you might need to independently
research that.
Vimspector's tools are intended to automate your existing process for setting

View file

@ -97,6 +97,13 @@ command! -bar
\ VimspectorReset
\ call vimspector#Reset()
" Dummy autocommands so that we can call this whenever
augroup VimspectorUserAutoCmds
au!
au User VimspectorUICreated silent
au User VimspectorTerminalOpened silent
augroup END
" boilerplate {{{
call s:restore_cpo()
" }}}

View file

@ -342,11 +342,14 @@ class ProjectBreakpoints( object ):
f"Invalid value for exception breakpoint filter '{f}': "
f"'{result}'. Must be boolean, 'Y', 'N' or '' (default)" )
else:
result = utils.AskForInput(
"{}: Break on {} (Y/N/default: {})? ".format( f[ 'filter' ],
f[ 'label' ],
default_value ),
default_value )
try:
result = utils.AskForInput(
"{}: Break on {} (Y/N/default: {})? ".format( f[ 'filter' ],
f[ 'label' ],
default_value ),
default_value )
except KeyboardInterrupt:
result = ''
if result == 'Y':
exception_filters.append( f[ 'filter' ] )

View file

@ -18,7 +18,7 @@ import logging
import json
from collections import defaultdict
from vimspector import utils
from vimspector import utils, settings
class CodeView( object ):
@ -218,7 +218,7 @@ class CodeView( object ):
args = params[ 'args' ]
env = params.get( 'env', {} )
options = {
term_options = {
'vertical': 1,
'norestore': 1,
'cwd': cwd,
@ -228,35 +228,54 @@ class CodeView( object ):
if self._window.valid:
window_for_start = self._window
else:
# TOOD: Where?
# TOOD: Where? Maybe we should just use botright vertical ...
window_for_start = vim.current.window
if self._terminal_window is not None and self._terminal_window.valid:
assert self._terminal_buffer_number
window_for_start = self._terminal_window
if ( self._terminal_window.buffer.number == self._terminal_buffer_number
and int( utils.Call( 'vimspector#internal#{}term#IsFinished'.format(
self._api_prefix ),
self._terminal_buffer_number ) ) ):
window_for_start = self._terminal_window
options[ 'curwin' ] = 1
term_options[ 'curwin' ] = 1
else:
term_options[ 'vertical' ] = 0
buffer_number = None
terminal_window = None
with utils.TemporaryVimOptions( { 'splitright': True,
'equalalways': False } ):
with utils.LetCurrentWindow( window_for_start ):
buffer_number = int(
utils.Call(
'vimspector#internal#{}term#Start'.format( self._api_prefix ),
args,
options ) )
terminal_window = vim.current.window
with utils.LetCurrentWindow( window_for_start ):
# 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 ):
term_options[ 'term_cols' ] = max(
min ( int( vim.eval( 'winwidth( 0 )' ) )
- settings.Int( 'code_minwidth', 82 ),
settings.Int( 'terminal_maxwidth', 80 ) ),
settings.Int( 'terminal_minwidth' , 10 )
)
buffer_number = int(
utils.Call(
'vimspector#internal#{}term#Start'.format( self._api_prefix ),
args,
term_options ) )
terminal_window = vim.current.window
if buffer_number is None or buffer_number <= 0:
# TODO: Do something better like reject the request?
raise ValueError( "Unable to start terminal" )
else:
self._terminal_window = terminal_window
self._terminal_buffer_number = buffer_number
self._terminal_window = terminal_window
self._terminal_buffer_number = buffer_number
vim.vars[ 'vimspector_session_windows' ][ 'terminal' ] = utils.WindowID(
self._terminal_window,
vim.current.tabpage )
with utils.RestoreCursorPosition():
with utils.RestoreCurrentWindow():
with utils.RestoreCurrentBuffer( vim.current.window ):
vim.command( 'doautocmd User VimspectorTerminalOpened' )
return buffer_number

View file

@ -29,7 +29,8 @@ from vimspector import ( breakpoints,
output,
stack_trace,
utils,
variables )
variables,
settings )
from vimspector.vendor.json_minify import minify
# We cache this once, and don't allow it to change (FIXME?)
@ -125,9 +126,17 @@ class DebugSession( object ):
next( iter( configurations.values() ) ).get( "autoselect", True ) ):
configuration_name = next( iter( configurations.keys() ) )
else:
configuration_name = utils.SelectFromList(
'Which launch configuration?',
sorted( configurations.keys() ) )
# Find a single configuration with 'default' True and autoselect not False
defaults = { n: c for n, c in configurations.items()
if c.get( 'default', False ) is True
and c.get( 'autoselect', True ) is not False }
if len( defaults ) == 1:
configuration_name = next( iter( defaults.keys() ) )
else:
configuration_name = utils.SelectFromList(
'Which launch configuration?',
sorted( configurations.keys() ) )
if not configuration_name or configuration_name not in configurations:
return
@ -206,26 +215,30 @@ class DebugSession( object ):
USER_CHOICES.update( launch_variables )
variables.update( launch_variables )
variables.update(
utils.ParseVariables( adapter.get( 'variables', {} ),
variables,
calculus,
USER_CHOICES ) )
variables.update(
utils.ParseVariables( configuration.get( 'variables', {} ),
variables,
calculus,
USER_CHOICES ) )
try:
variables.update(
utils.ParseVariables( adapter.get( 'variables', {} ),
variables,
calculus,
USER_CHOICES ) )
variables.update(
utils.ParseVariables( configuration.get( 'variables', {} ),
variables,
calculus,
USER_CHOICES ) )
utils.ExpandReferencesInDict( configuration,
variables,
calculus,
USER_CHOICES )
utils.ExpandReferencesInDict( adapter,
variables,
calculus,
USER_CHOICES )
utils.ExpandReferencesInDict( configuration,
variables,
calculus,
USER_CHOICES )
utils.ExpandReferencesInDict( adapter,
variables,
calculus,
USER_CHOICES )
except KeyboardInterrupt:
self._Reset()
return
if not adapter:
utils.UserMessage( 'No adapter configured for {}'.format(
@ -285,18 +298,35 @@ class DebugSession( object ):
self._StartWithConfiguration( self._configuration, self._adapter )
def IfConnected( fct ):
def IfConnected( otherwise=None ):
def decorator( fct ):
"""Decorator, call fct if self._connected else echo warning"""
@functools.wraps( fct )
def wrapper( self, *args, **kwargs ):
if not self._connection:
utils.UserMessage(
'Vimspector not connected, start a debug session first',
persist=False,
error=True )
return otherwise
return fct( self, *args, **kwargs )
return wrapper
return decorator
def RequiresUI( otherwise=None ):
"""Decorator, call fct if self._connected else echo warning"""
@functools.wraps( fct )
def wrapper( self, *args, **kwargs ):
if not self._connection:
utils.UserMessage(
'Vimspector not connected, start a debug session first',
persist=True,
error=True )
return
return fct( self, *args, **kwargs )
return wrapper
def decorator( fct ):
@functools.wraps( fct )
def wrapper( self, *args, **kwargs ):
if not self._uiTab or not self._uiTab.valid:
utils.UserMessage(
'Vimspector is not active',
persist=False,
error=True )
return otherwise
return fct( self, *args, **kwargs )
return wrapper
return decorator
def OnChannelData( self, data ):
if self._connection is None:
@ -319,7 +349,7 @@ class DebugSession( object ):
# TODO: Not calld
self._connection = None
@IfConnected
@IfConnected()
def Stop( self ):
self._logger.debug( "Stop debug adapter with no callback" )
self._StopDebugAdapter()
@ -335,6 +365,8 @@ class DebugSession( object ):
self._logger.info( "Debugging complete." )
if self._uiTab:
self._logger.debug( "Clearing down UI" )
del vim.vars[ 'vimspector_session_windows' ]
vim.current.tabpage = self._uiTab
self._splash_screen = utils.HideSplash( self._api_prefix,
@ -354,7 +386,7 @@ class DebugSession( object ):
# make sure that we're displaying signs in any still-open buffers
self._breakpoints.UpdateUI()
@IfConnected
@IfConnected()
def StepOver( self ):
if self._stackTraceView.GetCurrentThreadId() is None:
return
@ -366,7 +398,7 @@ class DebugSession( object ):
},
} )
@IfConnected
@IfConnected()
def StepInto( self ):
if self._stackTraceView.GetCurrentThreadId() is None:
return
@ -378,7 +410,7 @@ class DebugSession( object ):
},
} )
@IfConnected
@IfConnected()
def StepOut( self ):
if self._stackTraceView.GetCurrentThreadId() is None:
return
@ -396,29 +428,29 @@ class DebugSession( object ):
else:
self.Start()
@IfConnected
@IfConnected()
def Pause( self ):
self._stackTraceView.Pause()
@IfConnected
@IfConnected()
def ExpandVariable( self ):
self._variablesView.ExpandVariable()
@IfConnected
@IfConnected()
def AddWatch( self, expression ):
self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(),
expression )
@IfConnected
@IfConnected()
def EvaluateConsole( self, expression ):
self._outputView.Evaluate( self._stackTraceView.GetCurrentFrame(),
expression )
@IfConnected
@IfConnected()
def DeleteWatch( self ):
self._variablesView.DeleteWatch()
@IfConnected
@IfConnected()
def ShowBalloon( self, winnr, expression ):
"""Proxy: ballonexpr -> variables.ShowBallon"""
frame = self._stackTraceView.GetCurrentFrame()
@ -437,17 +469,32 @@ class DebugSession( object ):
# Return variable aware function
return self._variablesView.ShowBalloon( frame, expression )
@IfConnected
@IfConnected()
def ExpandFrameOrThread( self ):
self._stackTraceView.ExpandFrameOrThread()
@RequiresUI()
def ShowOutput( self, category ):
if not self._outputView.WindowIsValid():
# TODO: The UI code is too scattered. Re-organise into a UI class that
# just deals with these thigns like window layout and custmisattion.
# currently, this class and the CodeView share some responsiblity for this
# and poking into each View class to check its window is valid also feels
# wrong.
with utils.LetCurrentTabpage( self._uiTab ):
vim.command( f'botright { settings.Int( "bottombar_height", 10 ) }new' )
self._outputView.UseWindow( vim.current.window )
vim.vars[ 'vimspector_session_windows' ][ 'output' ] = utils.WindowID(
vim.current.window,
self._uiTab )
self._outputView.ShowOutput( category )
@RequiresUI( otherwise=[] )
def GetOutputBuffers( self ):
return self._outputView.GetCategories()
@IfConnected
@IfConnected( otherwise=[] )
def GetCompletionsSync( self, text_line, column_in_bytes ):
if not self._server_capabilities.get( 'supportsCompletionsRequest' ):
return []
@ -473,49 +520,66 @@ class DebugSession( object ):
self._uiTab = vim.current.tabpage
# Code window
self._codeView = code.CodeView( vim.current.window,
self._api_prefix )
code_window = vim.current.window
self._codeView = code.CodeView( code_window, self._api_prefix )
# Call stack
with utils.TemporaryVimOptions( { 'splitright': False,
'equalalways': False, } ):
vim.command( 'topleft 50vspl' )
vim.command( 'enew' )
self._stackTraceView = stack_trace.StackTraceView( self,
self._connection,
vim.current.buffer )
vim.command(
f'topleft vertical { settings.Int( "sidebar_width", 50 ) }new' )
stack_trace_window = vim.current.window
one_third = int( vim.eval( 'winheight( 0 )' ) ) / 3
self._stackTraceView = stack_trace.StackTraceView( self,
self._connection,
stack_trace_window )
with utils.TemporaryVimOptions( { 'splitbelow': False,
'eadirection': 'ver',
'equalalways': True } ):
# Watches
vim.command( 'spl' )
vim.command( 'enew' )
watch_win = vim.current.window
# Watches
vim.command( 'leftabove new' )
watch_window = vim.current.window
# Variables
vim.command( 'spl' )
vim.command( 'enew' )
vars_win = vim.current.window
# Variables
vim.command( 'leftabove new' )
vars_window = vim.current.window
self._variablesView = variables.VariablesView( self._connection,
vars_win,
watch_win )
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( self._connection,
vars_window,
watch_window )
# Output/logging
vim.current.window = code_window
vim.command( f'rightbelow { settings.Int( "bottombar_height", 10 ) }new' )
output_window = vim.current.window
self._outputView = output.OutputView( self._connection,
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' ] = {
'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 ),
}
with utils.RestoreCursorPosition():
with utils.RestoreCurrentWindow():
with utils.RestoreCurrentBuffer( vim.current.window ):
vim.command( 'doautocmd User VimspectorUICreated' )
with utils.TemporaryVimOption( 'splitbelow', True ):
vim.current.window = self._codeView._window
# Output/logging
vim.command( '10spl' )
vim.command( 'enew' )
self._outputView = output.OutputView( self._connection,
vim.current.window,
self._api_prefix )
@RequiresUI()
def ClearCurrentFrame( self ):
self.SetCurrentFrame( None )
@RequiresUI()
def SetCurrentFrame( self, frame ):
if not frame:
self._stackTraceView.Clear()
@ -557,6 +621,9 @@ class DebugSession( object ):
if self._adapter[ 'port' ] == 'ask':
port = utils.AskForInput( 'Enter port to connect to: ' )
if port is None:
self._Reset()
return
self._adapter[ 'port' ] = port
self._connection_type = self._api_prefix + self._connection_type
@ -666,6 +733,8 @@ class DebugSession( object ):
prop = atttach_config[ 'pidProperty' ]
if prop not in launch_config:
pid = utils.AskForInput( 'Enter PID to attach to: ' )
if pid is None:
return
launch_config[ prop ] = pid
return
elif atttach_config[ 'pidSelect' ] == 'none':

View file

@ -102,6 +102,17 @@ class OutputView( object ):
# FIXME: nunmenu the WinBar ?
self._buffers = {}
def WindowIsValid( self ):
return self._window.valid
def UseWindow( self, win ):
assert not self._window.valid
self._window = win
# TODO: Sorting of the WinBar ?
for category, _ in self._buffers.items():
self._RenderWinBar( category )
def _ShowOutput( self, category ):
if not self._window.valid:
return
@ -157,11 +168,13 @@ class OutputView( object ):
def _CreateBuffer( self, category, file_name = None, cmd = None ):
if not self._window.valid:
return
win = self._window
if not win.valid:
# We need to borrow the current window
win = vim.current.window
with utils.LetCurrentWindow( self._window ):
with utils.RestoreCurrentBuffer( self._window ):
with utils.LetCurrentWindow( win ):
with utils.RestoreCurrentBuffer( win ):
if file_name is not None:
assert cmd is None

View file

@ -0,0 +1,26 @@
# vimspector - A multi-language debugging system for Vim
# Copyright 2020 Ben Jackson
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import vim
import builtins
def Get( option: str, default=None, cls=str ):
return cls( vim.vars.get( f'vimspector_{ option }', default ) )
def Int( option: str, default=0 ):
return Get( option, default=default, cls=builtins.int )

View file

@ -21,11 +21,11 @@ from vimspector import utils
class StackTraceView( object ):
def __init__( self, session, connection, buf ):
def __init__( self, session, connection, win ):
self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger )
self._buf = buf
self._buf = win.buffer
self._session = session
self._connection = connection
@ -38,9 +38,7 @@ class StackTraceView( object ):
self._scratch_buffers = []
utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' )
vim.current.buffer = self._buf
utils.SetUpUIWindow( vim.current.window )
utils.SetUpUIWindow( win )
vim.command( 'nnoremap <buffer> <CR> :call vimspector#GoToFrame()<CR>' )

View file

@ -184,8 +184,10 @@ def RestoreCurrentWindow():
try:
yield
finally:
vim.current.tabpage = old_tabpage
vim.current.window = old_window
if old_tabpage.valid:
vim.current.tabpage = old_tabpage
if old_window.valid:
vim.current.window = old_window
@contextlib.contextmanager
@ -194,9 +196,10 @@ def RestoreCurrentBuffer( window ):
try:
yield
finally:
with RestoreCurrentWindow():
vim.current.window = window
vim.current.buffer = old_buffer
if window.valid:
with RestoreCurrentWindow():
vim.current.window = window
vim.current.buffer = old_buffer
@contextlib.contextmanager
@ -211,6 +214,13 @@ def AnyWindowForBuffer( buf ):
yield
@contextlib.contextmanager
def LetCurrentTabpage( tabpage ):
with RestoreCurrentWindow():
vim.current.tabpage = tabpage
yield
@contextlib.contextmanager
def LetCurrentWindow( window ):
with RestoreCurrentWindow():
@ -329,7 +339,7 @@ def AskForInput( prompt, default_value = None ):
return vim.eval( "input( '{}' {} )".format( Escape( prompt ),
default_option ) )
except KeyboardInterrupt:
return ''
return None
def AppendToBuffer( buf, line_or_lines, modified=False ):
@ -437,6 +447,10 @@ def ExpandReferencesInString( orig_s,
default_value = user_choices.get( key, None )
mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ),
default_value )
if mapping[ key ] is None:
raise KeyboardInterrupt
user_choices[ key ] = mapping[ key ]
_logger.debug( "Value for %s not set in %s (from %s): set to %s",
key,
@ -639,3 +653,7 @@ def GetUnusedLocalPort():
port = sock.getsockname()[ 1 ]
sock.close()
return port
def WindowID( window, tab ):
return int( Call( 'win_getid', window.number, tab.number ) )

View file

@ -1,51 +1,76 @@
#!/usr/bin/env bash
if [ "$1" == "--help" ]; then
echo "$(basename $0) [--basedir <basedir>] [--install] <optional list of tests in form file:func>"
echo ""
echo " --basedir <basedir> path to runtime directory like the optino to install_gadget.py"
echo " --install run install_gadget.py, useful with --basedir"
echo "e.g.: "
echo " - run all tests: $0"
echo " - run specific tests script: $0 signature_help.test.vim"
echo " - run specific tests fun: $0 signature_help.test.vim:Test_signatures_TopLine\(\)"
echo " - run all tests in a clean env: $0 --basedir \$(mktemp -d) --install"
exit 0
fi
BASEDIR=$(dirname $0)
INSTALL=0
RUN_VIM="vim -N --clean --not-a-term"
RUN_TEST="${RUN_VIM} -S lib/run_test.vim"
BASEDIR_CMD='py3 pass'
# 1 is stdout
out_fd=1
while [ -n "$1" ]; do
case "$1" in
"--basedir")
BASEDIR=$2
shift
BASEDIR=$1
shift
if [[ ! $BASEDIR = /* ]]; then
# Relative
BASEDIR=$(pwd)/${BASEDIR}
fi
BASEDIR_CMD="let g:vimspector_base_dir='${BASEDIR}'"
shift
shift
;;
"--install")
INSTALL=1
shift
;;
"--report")
shift
VIMSPECTOR_TEST_STDOUT=$1
shift
;;
"--quiet")
shift
# send the output to /dev/null
# https://stackoverflow.com/a/47553900
# Note we can't use {out_fd} here because the bash version in CI is too
# old on macOS
out_fd=3
exec 3>/dev/null
;;
"--")
shift
break
;;
"--help")
shift
echo "$(basename $0) [--basedir <basedir>] [--report output] [--quiet] [--install] <optional list of tests in form file:func>"
echo ""
echo " --basedir <basedir> path to runtime directory like the optino to install_gadget.py"
echo " --install run install_gadget.py, useful with --basedir"
echo " --report <messages|all> which logs to dump to stdout after a test"
echo " --quiet suppress vim's stdout"
echo "e.g.: "
echo " - run all tests: $0"
echo " - run specific tests script: $0 signature_help.test.vim"
echo " - run specific tests fun: $0 signature_help.test.vim:Test_signatures_TopLine\(\)"
echo " - run all tests in a clean env: $0 --basedir \$(mktemp -d) --install"
exit 0
;;
*)
break
;;
esac
done
# We use fd 3 for vim's output. Send it to stdout if not already redirected
# Note: can't use ${out_fd} in a redirect because redirects happen before
# variable substitution
if [ "${out_fd}" = "1" ]; then
exec 3>&1
fi
if [ $INSTALL = 1 ]; then
python3 $(dirname $0)/install_gadget.py --basedir ${BASEDIR} --all
fi
@ -71,7 +96,7 @@ echo " * BASEDIR_CMD=$BASEDIR_CMD"
echo "%SETUP - Building test programs..."
set -e
pushd tests/testdata/cpp/simple
make clean simple
make clean all
popd
set +e
echo "%DONE - built test programs"
@ -99,6 +124,7 @@ for t in ${TESTS}; do
if ${RUN_TEST} --cmd "${BASEDIR_CMD}" \
--cmd 'au SwapExists * let v:swapchoice = "e"' $t $T \
>&3\
&& [ -f $t.res ]; then
echo "%PASS: $t PASSED"
else
@ -109,10 +135,22 @@ for t in ${TESTS}; do
rm -rf $TESTLOGDIR
mkdir -p $TESTLOGDIR
${RUN_VIM} --version > ${TESTLOGDIR}/vimversion
if [ "$VIMSPECTOR_TEST_STDOUT" = "messages" ]; then
if [ -f messages ]; then
echo "%MESSAGES"
cat messages
echo "%END"
else
echo "%MESSAGES"
echo "No messages found"
echo "%END"
fi
fi
for l in messages debuglog test.log *.testlog; do
# In CI we can't view the output files, so we just have to cat them
if [ -f $l ]; then
if [ "$VIMSPECTOR_TEST_STDOUT" ]; then
if [ "$VIMSPECTOR_TEST_STDOUT" = "all" ]; then
echo ""
echo ""
echo "*** START: $l ***"
@ -126,11 +164,14 @@ for t in ${TESTS}; do
rm -f $t.res
done
# close out_fd if it's not stdout/stderr/
(( out_fd > 2 )) && exec 3>&-
echo "Done running tests"
popd > /dev/null
echo ""
echo "All done."
echo "All done. Exit with ${RESULT}"
exit $RESULT

53
support/custom_ui_vimrc Normal file
View file

@ -0,0 +1,53 @@
execute 'source' expand( '<sfile>:p:h' ) . '/minimal_vimrc'
set noequalalways
function! s:CustomiseUI()
let wins = g:vimspector_session_windows
" Close the Variables window
if has( 'nvim' )
" No win_execute in neovim
call win_gotoid( wins.variables )
quit
else
call win_execute( wins.variables, 'q' )
endif
" Put the stack trace at the top of the "left bar" (rotate)
call win_gotoid( wins.stack_trace )
wincmd r
" Make the left column at least 70 chars
70wincmd |
" Make the code window at least 80 chars
call win_gotoid( wins.code )
80wincmd |
" Make the output window 10 lines high and right at the top of the screen
call win_gotoid( wins.output )
10wincmd _
wincmd K
endfunction
function s:SetUpTerminal()
let terminal_win = g:vimspector_session_windows.terminal
" Make the terminal window at most 80 columns wide, ensuring there is enough
" sapce for our code window (80 columns) and the left bar (70 columns)
" Padding is 2 for the 2 vertical split markers and 2 for the sign column in
" the code window.
let left_bar = 70
let code = 80
let padding = 4
let cols = max( [ min( [ &columns - left_bar - code - padding, 80 ] ), 10 ] )
call win_gotoid( terminal_win )
execute cols . 'wincmd |'
endfunction
augroup TestUICustomistaion
autocmd!
autocmd User VimspectorUICreated call s:CustomiseUI()
autocmd User VimspectorTerminalOpened call s:SetUpTerminal()
augroup END

4
support/minimal_vimrc Normal file
View file

@ -0,0 +1,4 @@
let s:vimspector_path = expand( '<sfile>:p:h:h' )
let g:vimspector_enable_mappings = 'HUMAN'
exe 'source ' . s:vimspector_path . '/tests/vimrc'

View file

@ -11,6 +11,12 @@ function! vimspector#test#setup#SetUpWithMappings( mappings ) abort
" This is a bit of a hack
runtime! plugin/**/*.vim
augroup VimspectorTestSwap
au!
au SwapExists * let v:swapchoice = 'e'
augroup END
endfunction
function! vimspector#test#setup#ClearDown() abort

View file

@ -2,7 +2,9 @@ function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer,
\ line,
\ column ) abort
call WaitForAssert( {->
\ assert_equal( a:buffer, bufname( '%' ), 'Current buffer' )
\ assert_equal( fnamemodify( a:buffer, ':p' ),
\ fnamemodify( bufname( '%' ), ':p' ),
\ 'Current buffer' )
\ }, 10000 )
call WaitForAssert( {->
\ assert_equal( a:line, line( '.' ), 'Current line' )

View file

@ -94,7 +94,7 @@ func StopVimInTerminal(buf)
" In Command-line it's inserted, the CTRL-U removes it again.
call term_sendkeys(a:buf, "\<C-O>:\<C-U>qa!\<cr>")
call WaitForAssert({-> assert_equal("finished", term_getstatus(a:buf))})
call WaitForAssert({-> assert_equal('finished', term_getstatus(a:buf))})
only!
endfunc

View file

@ -73,7 +73,7 @@ func s:WaitForCommon(expr, assert, timeout)
" Remove the errors added by the assert function.
let errors_added = len( v:errors ) - errors_before
if errors_added > 0
call remove(v:errors, -1 * errors_added )
call remove( v:errors, -1 * errors_added, -1 )
endif
endif

View file

@ -1,2 +1,3 @@
simple
variables
struct

View file

@ -1,17 +1,38 @@
{
"configurations": {
"cpptools-run": {
"run-to-entry": {
"adapter": "vscode-cpptools",
// This makes this configuration the default. Only one default can be set
// (having two is the same as having none)
"default": true,
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/${fileBasenameNoExtension}",
"externalConsole": false,
"stopAtEntry": true,
"stopOnEntry": true,
"MImode": "${VIMSPECTOR_MIMODE}",
"logging": {
"engineLogging": true
"MImode": "${VIMSPECTOR_MIMODE}"
},
"breakpoints": {
"exception": {
"cpp_catch": "",
"cpp_throw": "",
"objc_catch": "",
"objc_throw": "",
"swift_catch": "",
"swift_throw": ""
}
}
},
"run-to-breakpoint": {
"adapter": "vscode-cpptools",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/${fileBasenameNoExtension}",
"externalConsole": false,
"stopAtEntry": false,
"stopOnEntry": false,
"MImode": "${VIMSPECTOR_MIMODE}"
},
"breakpoints": {
"exception": {

View file

@ -2,7 +2,7 @@ CXXFLAGS=-g -O0 -std=c++17
.PHONY: all
TARGETS=simple variables
TARGETS=simple variables struct
all: $(TARGETS)

33
tests/testdata/cpp/simple/struct.cpp vendored Normal file
View file

@ -0,0 +1,33 @@
struct AnotherTest
{
char choo;
int ints[5];
};
struct Test
{
int i;
char c;
float fffff;
AnotherTest another_test;
};
static Test SetUp( Test t )
{
t.another_test.choo = 'p';
t.another_test.ints[ 0 ] = t.i; return t;
}
int main( int , char ** )
{
Test t = {};
t.i = 1;
t.c = 'c';
t.fffff = 3.14;
t = SetUp( t );
return t.another_test.ints[ 0 ];
}

380
tests/ui.test.vim Normal file
View file

@ -0,0 +1,380 @@
let s:fn='../support/test/python/simple_python/main.py'
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( 'HUMAN' )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! s:StartDebugging()
exe 'edit ' . s:fn
call setpos( '.', [ 0, 23, 1 ] )
call vimspector#ToggleBreakpoint()
call vimspector#LaunchWithSettings( { 'configuration': 'run' } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 23, 1 )
endfunction
function! Test_StandardLayout()
call s:StartDebugging()
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
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! Test_CloseVariables()
call s:StartDebugging()
call win_execute( g:vimspector_session_windows.variables, 'q' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
call assert_equal(
\ [ 'row', [
\ [ 'col', [
\ [ '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! Test_CloseWatches()
call s:StartDebugging()
call win_execute( g:vimspector_session_windows.watches, 'q' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
" Add a wtch
call vimspector#AddWatch( 't' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 26, 1 )
call assert_equal(
\ [ 'row', [
\ [ 'col', [
\ [ 'leaf', g:vimspector_session_windows.variables ],
\ [ '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 ) )
" Replace the variables view with a watches view!
call win_execute( g:vimspector_session_windows.variables,
\ 'bu vimspector.Watches' )
" Delete a watch expression
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 3, 1 ] )
call feedkeys( "\<Del>", 'xt' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#StepInto()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 13, 1 )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 14, 1 )
call vimspector#AddWatch( 'i' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' *- Result: 0',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#AddWatch( 'i+1' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+1',
\ ' *- Result: 1',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#AddWatch( 'i+2' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+1',
\ ' - Result: 1',
\ 'Expression: i+2',
\ ' *- Result: 2',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Delete that middle watch
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 4, 1 ] )
call vimspector#DeleteWatch()
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+2',
\ ' *- Result: 2',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 15, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+2',
\ ' - Result: 2',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Delete the top watch
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 3, 1 ] )
call vimspector#DeleteWatch()
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 13, 1 )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 14, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i+2',
\ ' *- Result: 3',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#test#setup#Reset()
%bwipe!
endfunction
function! Test_CloseStackTrace()
call s:StartDebugging()
call win_execute( g:vimspector_session_windows.stack_trace, 'q' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
call assert_equal(
\ [ 'row', [
\ [ 'col', [
\ [ 'leaf', g:vimspector_session_windows.variables ],
\ [ 'leaf', g:vimspector_session_windows.watches ],
\ ] ],
\ [ '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! Test_CloseOutput()
call s:StartDebugging()
call win_execute( g:vimspector_session_windows.output, 'q' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
call assert_equal(
\ [ 'row', [
\ [ 'col', [
\ [ '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 ],
\ ] ],
\ winlayout( g:vimspector_session_windows.tabpage ) )
call vimspector#test#setup#Reset()
%bwipe!
endfunction
function! Test_CloseOutput_Early()
augroup TestCustomUI
au!
au User VimspectorUICreated
\ call win_execute( g:vimspector_session_windows.output, 'q' )
augroup END
call s:StartDebugging()
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
call assert_equal(
\ [ 'row', [
\ [ 'col', [
\ [ '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 ],
\ ] ],
\ winlayout( g:vimspector_session_windows.tabpage ) )
" Open it again!
let g:vimspector_bottombar_height = 5
VimspectorShowOutput Console
call assert_equal(
\ [ 'col', [
\ [ 'row', [
\ [ 'col', [
\ [ '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 ) )
" The actual height reported is the number of lines visible. The WinBar takes
" 1 screen row, so g:vimspector_bottombar_height -1
call assert_equal( 4, winheight( g:vimspector_session_windows.output ) )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 26, 1 )
au! TestCustomUI
call vimspector#test#setup#Reset()
%bwipe!
endfunction
function! Test_CustomUI()
augroup TestCustomUI
au!
au User VimspectorUICreated
\ call win_execute( g:vimspector_session_windows.watches, 'q' )
augroup END
call s:StartDebugging()
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
" Add a watch
call vimspector#AddWatch( 't' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 26, 1 )
call assert_equal(
\ [ 'row', [
\ [ 'col', [
\ [ 'leaf', g:vimspector_session_windows.variables ],
\ [ '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 ) )
au! TestCustomUI
call vimspector#test#setup#Reset()
%bwipe!
endfunction

481
tests/variables.test.vim Normal file
View file

@ -0,0 +1,481 @@
let s:fn='../support/test/python/simple_python/main.py'
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( 'HUMAN' )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! s:assert_match_list( expected, actual ) abort
let ret = assert_equal( len( a:expected ), len( a:actual ) )
let len = min( [ len( a:expected ), len( a:actual ) ] )
let idx = 0
while idx < len
let ret += assert_match( a:expected[ idx ], a:actual[ idx ] )
let idx += 1
endwhile
return ret
endfunction
function! s:StartDebugging( ... )
if a:0 == 0
let config = #{
\ fn: s:fn,
\ line: 23,
\ col: 1,
\ launch: #{ configuration: 'run' }
\ }
else
let config = a:1
endif
execute 'edit' config.fn
call setpos( '.', [ 0, config.line, config.col ] )
call vimspector#ToggleBreakpoint()
call vimspector#LaunchWithSettings( config.launch )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer(
\ config.fn,
\ config.line,
\ config.col )
endfunction
function! Test_SimpleWatches()
call s:StartDebugging()
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 )
" Add a wtch
call vimspector#AddWatch( 't' )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 26, 1 )
" Delete a watch expression
call win_gotoid( g:vimspector_session_windows.watches )
call setpos( '.', [ 0, 3, 1 ] )
call feedkeys( "\<Del>", 'xt' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call assert_equal( 'python',
\ getbufvar(
\ winbufnr( g:vimspector_session_windows.watches ),
\ '&syntax' ) )
call vimspector#StepInto()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 13, 1 )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 14, 1 )
call vimspector#AddWatch( 'i' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' *- Result: 0',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#AddWatch( 'i+1' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+1',
\ ' *- Result: 1',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#AddWatch( 'i+2' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+1',
\ ' - Result: 1',
\ 'Expression: i+2',
\ ' *- Result: 2',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
" Delete that middle watch
call win_gotoid( g:vimspector_session_windows.watches )
call setpos( '.', [ 0, 4, 1 ] )
call vimspector#DeleteWatch()
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+2',
\ ' *- Result: 2',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 15, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i',
\ ' - Result: 0',
\ 'Expression: i+2',
\ ' - Result: 2',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
" Delete the top watch
call win_gotoid( g:vimspector_session_windows.watches )
call setpos( '.', [ 0, 3, 1 ] )
call vimspector#DeleteWatch()
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 13, 1 )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 14, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: i+2',
\ ' *- Result: 3',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#test#setup#Reset()
%bwipe!
endfunction
function! Test_ExpandVariables()
let fn = 'testdata/cpp/simple/struct.cpp'
call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{
\ configuration: 'run-to-breakpoint'
\ } } )
" Make sure the Test t is initialised
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ '- Scope: Locals',
\ ' *+ t (Test): {...}',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call assert_equal( 'cpp',
\ getbufvar(
\ winbufnr( g:vimspector_session_windows.variables ),
\ '&syntax' ) )
" Expand
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 2, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ s:assert_match_list(
\ [
\ '- Scope: Locals',
\ ' \*- t (Test): {...}',
\ ' \*- i (int): 0',
\ ' \*- c (char): 0 ''\\0\{1,3}''',
\ ' \*- fffff (float): 0',
\ ' \*+ another_test (AnotherTest):\( {...}\)\?',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Step - stays expanded
call vimspector#StepOver()
call WaitForAssert( {->
\ s:assert_match_list(
\ [
\ '- Scope: Locals',
\ ' - t (Test): {...}',
\ ' \*- i (int): 1',
\ ' - c (char): 0 ''\\0\{1,3}''',
\ ' - fffff (float): 0',
\ ' + another_test (AnotherTest):\( {...}\)\?',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Collapse
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 2, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ '- Scope: Locals',
\ ' + t (Test): {...}',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 28, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ '- Scope: Locals',
\ ' + t (Test): {...}',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 2, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ s:assert_match_list(
\ [
\ '- Scope: Locals',
\ ' - t (Test): {...}',
\ ' \*- i (int): 1',
\ ' \*- c (char): 99 ''c''',
\ ' \*- fffff (float): 0',
\ ' \*+ another_test (AnotherTest):\( {...}\)\?',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Collapse the 'inexpensive' scope and see that it stays collapsed
" Exapand - see that the changed value is highlighted
call win_gotoid( g:vimspector_session_windows.variables )
call setpos( '.', [ 0, 1, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ '+ Scope: Locals',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Stays collpased through step
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 30, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ '+ Scope: Locals',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
" Cpptools keeps the same "Locals" scope, so it stays collapsed even throught
" step-in
call vimspector#StepInto()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 18, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ '+ Scope: Locals',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.variables ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#test#setup#Reset()
%bwipe!
endfunction
function! Test_ExpandWatch()
let fn = 'testdata/cpp/simple/struct.cpp'
call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{
\ configuration: 'run-to-breakpoint'
\ } } )
" Make sure the Test t is initialised
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 )
call win_gotoid( g:vimspector_session_windows.watches )
call feedkeys( "it\<CR>", 'xt' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: t',
\ ' *+ Result: {...}',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call assert_equal( 'cpp',
\ getbufvar(
\ winbufnr( g:vimspector_session_windows.watches ),
\ '&syntax' ) )
" Expand
call win_gotoid( g:vimspector_session_windows.watches )
call setpos( '.', [ 0, 3, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ s:assert_match_list(
\ [
\ 'Watches: ----',
\ 'Expression: t',
\ ' \*- Result: {...}',
\ ' \*- i (int): 0',
\ ' \*- c (char): 0 ''\\0\{1,3}''',
\ ' \*- fffff (float): 0',
\ ' \*+ another_test (AnotherTest):\( {...}\)\?',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
" Step - stays expanded
call vimspector#StepOver()
call WaitForAssert( {->
\ s:assert_match_list(
\ [
\ 'Watches: ----',
\ 'Expression: t',
\ ' - Result: {...}',
\ ' \*- i (int): 1',
\ ' - c (char): 0 ''\\0\{1,3}''',
\ ' - fffff (float): 0',
\ ' + another_test (AnotherTest):\( {...}\)\?',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
" Collapse
call win_gotoid( g:vimspector_session_windows.watches )
call setpos( '.', [ 0, 3, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: t',
\ ' + Result: {...}',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 28, 1 )
call WaitForAssert( {->
\ assert_equal(
\ [
\ 'Watches: ----',
\ 'Expression: t',
\ ' + Result: {...}',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call win_gotoid( g:vimspector_session_windows.watches )
call setpos( '.', [ 0, 3, 1 ] )
call feedkeys( "\<CR>", 'xt' )
call WaitForAssert( {->
\ s:assert_match_list(
\ [
\ 'Watches: ----',
\ 'Expression: t',
\ ' - Result: {...}',
\ ' - i (int): 1',
\ ' - c (char): 99 ''c''',
\ ' - fffff (float): 0',
\ ' + another_test (AnotherTest):\( {...}\)\?',
\ ],
\ getbufline( winbufnr( g:vimspector_session_windows.watches ),
\ 1,
\ '$' )
\ )
\ } )
call vimspector#test#setup#Reset()
%bwipe!
endfunction

View file

@ -1,5 +1,6 @@
let g:vimspector_test_plugin_path = expand( '<sfile>:p:h:h' )
set mouse=a
set noequalalways
let &rtp = &rtp . ',' . g:vimspector_test_plugin_path