Compare commits

..

329 commits

Author SHA1 Message Date
Joey Yakimowich-Payne
7c12519b9d Modify for mac m1 2021-09-10 10:30:44 -06:00
mergify[bot]
2bb8561eb6
Merge pull request #452 from seezer/readme-gdb-prettyprinter
Readme: pretty printing with vscode-cpptools / gdb
2021-09-09 16:19:52 +00:00
mergify[bot]
a868102b5e
Merge branch 'master' into readme-gdb-prettyprinter 2021-09-09 16:05:28 +00:00
Sebastian Goth
dc862fe565 Readme: pretty printing with vscode-cpptools / gdb 2021-09-09 16:59:01 +02:00
Ben Jackson
b4bcfca932
Merge pull request #450 from puremourning/gha-ubuntu-18.04
Update to ubuntu 18.04 as 16.04 is deprecated
2021-09-08 22:49:22 +01:00
Ben Jackson
3df0602a69
Merge branch 'master' into gha-ubuntu-18.04 2021-09-08 22:30:49 +01:00
mergify[bot]
1c2dda4a6a
Merge pull request #449 from seezer/vscode-cpptools-1.6.0
Update vscode-cpptools from 0.27.0 to 1.6.0
2021-09-08 21:30:08 +00:00
Ben Jackson
db5ed8e802 Update to ubuntu 18.04 as 16.04 is deprecated 2021-09-08 22:20:33 +01:00
Sebastian Goth
17ca1522f8 Use correct spelling of MIMode in tests 2021-09-08 23:16:47 +02:00
Sebastian Goth
561a5b9aa2 Update variables tests to expect register scope
vscode-cpptools 1.6.0 now reports an additional scope 'Registers' after
'Locals'.
2021-09-08 21:58:32 +02:00
Sebastian Goth
46cfdc678d Update vscode-cpptools from 0.27.0 to 1.6.0 2021-09-08 21:58:32 +02:00
Ben Jackson
51d78fce5f
Note on using legacy vscode-dap 2021-09-07 17:00:04 +01:00
mergify[bot]
14f34ea6d1
Merge pull request #442 from roachsinai/master
Fix error: E806: using Float as a String.
2021-08-20 18:09:07 +00:00
roachsinai
a720d0e1d5 Fix error: E806: using Float as a String. 2021-08-21 00:57:27 +08:00
Ben Jackson
7c7e3f9c3f Add config for bash to tests 2021-08-20 11:17:05 +01:00
Ben Jackson
57ce099280 SHow the output in the console, as this is where codelldb puts it 2021-08-03 17:30:42 +01:00
mergify[bot]
27eb464b8e
Merge pull request #436 from puremourning/update-codelldb
Update codelldb
2021-08-02 16:37:04 +00:00
Ben Jackson
f1e2c12e5b Update codelldb
Add a way to checksum downloads and a little guide to updating gadgets
2021-08-02 17:23:32 +01:00
mergify[bot]
26cd7c5c7e
Merge pull request #435 from przepompownia/upgrade-vscode-php-debug-1.17.0
Upgrade vscode-php-debug to 1.17.0
2021-08-02 14:51:01 +00:00
przepompownia
59c9cd10ab Upgrade vscode-php-debug to 1.17.0 2021-08-02 16:11:04 +02:00
mergify[bot]
9c806d2a01
Merge pull request #429 from puremourning/dependabot/bundler/docs/addressable-2.8.0
Bump addressable from 2.7.0 to 2.8.0 in /docs
2021-07-13 15:07:15 +00:00
dependabot[bot]
3af97f1928
Bump addressable from 2.7.0 to 2.8.0 in /docs
Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/sporkmonger/addressable/releases)
- [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.0)

---
updated-dependencies:
- dependency-name: addressable
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-13 05:43:17 +00:00
mergify[bot]
da39c4955c
Merge pull request #422 from przepompownia/upgrade-vscode-php-debug-1.16.1
Upgrade vscode-php-debug to 1.16.1
2021-07-04 21:17:05 +00:00
przepompownia
21ebb22fd4 Upgrade vscode-php-debug to 1.16.1 2021-07-04 23:00:32 +02:00
mergify[bot]
aa0cddc0da
Merge pull request #420 from simondrake/master
Add a runnable Go example
2021-06-24 16:05:30 +00:00
Simon Drake
5075f3a11a Add a runnable Go example 2021-06-24 15:12:20 +01:00
mergify[bot]
bab81953d7
Merge pull request #414 from BaskovicP/patch-1
FIx typo in configuration.md
2021-06-09 18:24:31 +00:00
Paulo
0500e41429
FIx typo in configuration.md
A small typo that wastes time for people that copy and modify the config file
2021-06-09 19:24:37 +02:00
mergify[bot]
1cbb400d42
Merge pull request #413 from przepompownia/vscode-php-debug-1.16.0
Upgrade vscode-php-debug to 1.16.0
2021-06-07 12:27:55 +00:00
przepompownia
5ea1f0d9d4 Upgrade vscode-php-debug to 1.16.0 2021-06-07 14:10:44 +02:00
Ben Jackson
a51b8b23c9 Fix traceback if the current frame isn't set 2021-05-25 14:53:29 +01:00
mergify[bot]
99c0c4f763
Merge pull request #409 from puremourning/dependabot/bundler/docs/nokogiri-1.11.5
Bump nokogiri from 1.11.3 to 1.11.5 in /docs
2021-05-20 11:10:01 +00:00
dependabot[bot]
daa8865fea
Bump nokogiri from 1.11.3 to 1.11.5 in /docs
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.3 to 1.11.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.3...v1.11.5)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-20 10:56:04 +00:00
mergify[bot]
f4d756fe86
Merge pull request #406 from puremourning/debuginfo
Add basic VimspectorDebugInfo command
2021-05-18 19:13:33 +00:00
Ben Jackson
d43904eb57 Add basic VimspectorDebugInfo command 2021-05-15 17:55:01 +01:00
Ben Jackson
aacd62f09f Rename AssertMatchist -> AssertMatchList 2021-05-15 16:06:16 +01:00
Ben Jackson
0e9497ce8f Add cpptools to cpp test proj 2021-05-15 15:55:17 +01:00
mergify[bot]
2708e8e6ec
Merge pull request #398 from przepompownia/php-debug-1.15.1
Upgrade php-debug to v1.15.1
2021-05-11 19:16:29 +00:00
Ben Jackson
adf6163653
Merge branch 'master' into php-debug-1.15.1 2021-05-11 20:05:48 +01:00
mergify[bot]
0af9d70b0d
Merge pull request #394 from puremourning/highlight-current-frame
Add cursorline highlight for current frame
2021-05-11 18:56:14 +00:00
Ben Jackson
9113dbb698 stack_trace: Add cursorline highlight and sign for current frame 2021-05-11 19:44:42 +01:00
przepompownia
08679d1c3e Upgrade php-debug to v1.15.1 2021-05-11 00:55:35 +02:00
Ben Jackson
4e04a862cb Add note about existing github issues 2021-05-03 15:02:50 +01:00
Ben Jackson
a7e8e93920 Allow manual running of locker 2021-05-03 14:09:56 +01:00
Ben Jackson
2b84439413 Lock closed issues after 60 days 2021-05-03 14:09:14 +01:00
Ben Jackson
0c88cc8bad Fix traceback when opening popup in neovim with log visible
* We enter the popup window
* some log data is received, so we update the log buffer and jump to the
  log window to scroll it
* meanwhile, the WinLeave auto command on the popup window fires and
  closes the popup window
* Having scrolled the log window, we try to jump back to the popup
  window, which by now has been closed.

Fixes #390
2021-04-29 10:02:23 +01:00
mergify[bot]
a47d0b921c
Merge pull request #387 from lf-/typos
Fix some typos in the readme
2021-04-22 12:19:58 +00:00
Jade
026ac22280 Fix some typos in the readme 2021-04-22 03:33:02 -07:00
Ben Jackson
297c0bea56 Ensure linux tests pass on PR 2021-04-20 20:52:53 +01:00
Ben Jackson
a9a26a5a60
Merge pull request #386 from puremourning/csharp-test
Add tests for c# using netcoredbg
2021-04-15 23:23:19 +01:00
Ben Jackson
1e25313cb5 Switch to xcode 11 which apparently works with coreclr debugging
https://github.com/dotnet/runtime/issues/42311#issuecomment-700718025
2021-04-15 23:04:31 +01:00
Ben Jackson
bc15c94513 Retire mono debug - never worked and seems abandoned, and vscode-python as it is serious legacy now 2021-04-15 21:39:38 +01:00
Ben Jackson
f389d65a24 Add a test for csharp, run in CI 2021-04-15 21:09:09 +01:00
Ben Jackson
b4195eee93 Upgrade to netcoredbg v1.2.0-782
Also upgrade the test project to LTS 3.1 dotnet framework, as MS is
making it very difficult to get framework 2.2 anymore.

Also remove some object files which apparently were included in the
repo.
2021-04-15 18:02:55 +01:00
Ben Jackson
6ad9101cf2
Add FAQ about json files in each project. 2021-04-15 15:02:46 +01:00
Ben Jackson
a41db89523 Fix get_configurations test 2021-04-13 18:01:10 +01:00
Ben Jackson
dd88e051a4 Attempt to recover from broken messages 2021-04-13 17:35:04 +01:00
Ben Jackson
fa92c2a8d5 Add a mode for debugging the extremely flaky netcoredbg 2021-04-11 19:23:47 +01:00
mergify[bot]
6709b45c77
Merge pull request #382 from aqez/master
Update sha256sum of netcoredbg for macos
2021-04-09 16:45:58 +00:00
Tony Dwire
278fc3cd8c Update sha256sum of netcoredbg 2021-04-09 11:29:17 -05:00
Ben Jackson
13a5a1b947 Fix traceback when +python3 is not availble 2021-04-09 16:54:49 +01:00
Ben Jackson
7d83419a4f Update docs bundles 2021-04-07 22:45:58 +01:00
mergify[bot]
7b3016aa90
Merge pull request #381 from aqez/master
Updated netcoredbg to 1.2.0-761 to enable mac support of async/await
2021-04-07 17:33:27 +00:00
Tony Dwire
d70d51a614 Updated netcoredbg to 1.2.0-761 to enable mac support of async/await 2021-04-07 11:50:26 -05:00
mergify[bot]
caeb6610ed
Merge pull request #379 from puuuuh/master
Update CodeLLDB
2021-03-30 18:13:03 +00:00
puh
0d9e7835a8 Update CodeLLDB 2021-03-30 00:16:58 +03:00
Ben Jackson
054ea35428 Add a way to test with dlv directly. Currrently not ready for the big time 2021-03-22 15:13:58 +00:00
Ben Jackson
244d7d8fdf Add the reference material to the vim doc too 2021-03-22 14:45:21 +00:00
Ben Jackson
35e5b3d56e Add vim doc based on README
Use the following to recrate the doc:

* clone https://github.com/ycm-core/vim-tools
* create a venv and pip install the requierments
* cd to vimspector dir
* /path/to/vim-tools/html2vimdoc.py -f vimspector README.md > doc/vimspector.txt
2021-03-20 15:56:41 +00:00
Ben Jackson
842d9fbc2d Config for pyright language server 2021-03-20 15:56:41 +00:00
mergify[bot]
6a24a17f2e
Merge pull request #371 from aqez/master
Update netcoredbg to 1.2.0-738 to support async/await
2021-03-19 23:33:58 +00:00
Ben Jackson
91e0426e88
Merge branch 'master' into master 2021-03-19 23:20:41 +00:00
mergify[bot]
bf24b37190
Merge pull request #372 from puremourning/hot-code-replace
Hot code replace for java
2021-03-19 23:15:34 +00:00
Ben Jackson
2d589475eb
Merge branch 'master' into master 2021-03-19 23:05:19 +00:00
Ben Jackson
1414f261a1 Documentation for hot code replace 2021-03-19 22:59:27 +00:00
Ben Jackson
a39017dd06 Fix actually sending terminateDebugee, and fix neovim 1-based index reporting 2021-03-19 18:43:45 +00:00
Ben Jackson
c05335c799 Make default option work for terminate debugee 2021-03-19 17:51:59 +00:00
Ben Jackson
efc5c76866 Fix lints 2021-03-19 17:51:59 +00:00
Ben Jackson
154e727b96 Make confirm dialog take arbitrary keys
Confirm now takes the list of options, list of keys to select them and
the default value. Returned values are always a 1-based index into the
list (like SelectFromList) or -1 to mean esc/ctrl-c.

This uses a nice popup dialog in vim and a crappy input on neovim.
2021-03-19 17:51:59 +00:00
Ben Jackson
6b74e584d5 Create a messagebox-like interface in vim 2021-03-19 17:51:59 +00:00
Ben Jackson
85bb8594ab Allow forcing selection from the menu with <leader>F5 2021-03-19 17:51:59 +00:00
Ben Jackson
63fd3165fb Use popup for confirmations (note these have to be async) 2021-03-19 17:51:59 +00:00
Ben Jackson
afb912dd08 Print hotcodereplace messages 2021-03-19 17:51:59 +00:00
Ben Jackson
b92a89f0d4 Add a way to have adapter specific message handlers 2021-03-19 17:51:59 +00:00
Ben Jackson
6f88b400e1 Only disable mappings in the keyboard-version of the popup 2021-03-18 13:51:32 +00:00
mergify[bot]
af2670ef9a
Merge pull request #373 from puremourning/fix-calculus
Fix default variable values having substitutions from the calculus
2021-03-12 22:22:51 +00:00
mergify[bot]
2b24611036
Merge branch 'master' into fix-calculus 2021-03-12 22:08:52 +00:00
mergify[bot]
d84ebdd0ee
Merge pull request #375 from puremourning/up-down-stack
Add commands to navigate up/down the stack in focussed thread.
2021-03-12 22:08:46 +00:00
Ben Jackson
6b67d165b9 Update docs for new mappings 2021-03-12 21:50:37 +00:00
Ben Jackson
a53d68f043 Add up and down frame mappings 2021-03-12 21:27:56 +00:00
Ben Jackson
6d3f3e207b Fix default variable values having substitutions from the calculus 2021-03-12 20:15:45 +00:00
mergify[bot]
5716bbefa9
Merge pull request #369 from puremourning/narrow-mode
Narrow UI mode
2021-03-11 21:38:40 +00:00
Ben Jackson
2615cff97a If there isn't enough vertical space, we get vim errors (not enough room), so don't do that 2021-03-11 21:14:30 +00:00
Ben Jackson
01ea50cb70 use --clean for minimal vimrc 2021-03-11 21:13:58 +00:00
Ben Jackson
7d2770f3c4 Add vertical (i.e. narrow) layout
This puts the 3 utility windows at the top, horizontally split, with the
code view below.  The terminal window is drawn either vertically split
(if there's room) or horizontally split otherwise.  The output window
remains at tht bottom.

We add equivalent sizing options too, setting some defauts that roughly
work on my macbook pro.

We try to guess the best layout to use. In particular we go into
'narrow' mode if there are not enough horizonal columns to fit the
sidebar, code and at least the minimum terminal size. We also try to
move the terminal to be horizontally spit (i.e. vertically stacked) if
we can fit the max number of lines, but only the min number of columns.

This is all a little heuristic, but when testing it myself, it feels
good and tends to pick a good option by default. Users can always
customise the ui mode (g:vimspector_ui_mode and all the various specific
width options)
2021-03-10 23:44:45 +00:00
Tony Dwire
2a635294d0 Fix wrong version number for macos version. 2021-03-09 20:11:58 -06:00
Tony Dwire
38c843219e Updated file name for netcoredbg to reflect new filename. Overrode
version for macos since there is no new build for it yet.
2021-03-09 19:55:38 -06:00
Tony Dwire
c012f9520e Updated netcoredbg to 1.2.0-738 2021-03-09 19:45:27 -06:00
Ben Jackson
943ae6c7c9 Fix error when nothing to expand 2021-03-05 19:05:42 +00:00
Ben Jackson
82db32780b Add example of ssh to remote host 2021-03-04 13:28:04 +00:00
mergify[bot]
4cb4b814a1
Merge pull request #366 from puremourning/fix-stop
Fix crash using Stop function
2021-03-02 11:28:07 +00:00
Ben Jackson
d2b92b7ce5 Fix crash using STop function 2021-03-02 11:12:01 +00:00
Ben Jackson
5bd83d3e37 Add debugging instruction 2021-02-27 21:02:21 +00:00
mergify[bot]
f6517892c1
Merge pull request #357 from puremourning/set-variable-value
Set variable value
2021-02-25 22:39:45 +00:00
Ben Jackson
edcb057ead Add <leader><CR> to docs 2021-02-25 22:23:30 +00:00
Ben Jackson
06f9bfc057 Add basic tests for set variable value 2021-02-25 22:15:09 +00:00
Ben Jackson
804b499286 Allow setting the value via the api 2021-02-25 22:15:09 +00:00
Ben Jackson
49a9a4b367 Allow mappings which aren't special chars 2021-02-25 22:15:09 +00:00
Ben Jackson
f2d407256e Use expression completion for watch and set 2021-02-25 22:15:09 +00:00
Ben Jackson
94242fa532 CustomUI: Make buffers non-modifiable when opened for debugging 2021-02-25 22:15:09 +00:00
Ben Jackson
ba83a59e88 TEst overriding the mappings 2021-02-25 22:15:09 +00:00
Ben Jackson
675a68c601 Make it work in neovim too 2021-02-25 22:15:09 +00:00
Ben Jackson
e1078375fe Also allow <leader><CR> in case modifyOtherKeys mode doesn't work 2021-02-25 22:15:09 +00:00
Ben Jackson
26452289a8 Allow overriding the variables/stack trace mappings in config 2021-02-25 22:15:09 +00:00
Ben Jackson
ec9122284e Add some notes on setting values to the readme 2021-02-25 22:15:09 +00:00
Ben Jackson
131cfcdd33 Don't try and set a value if not supported 2021-02-25 22:15:09 +00:00
Ben Jackson
c2082cffae Support setting from the balloon 2021-02-25 22:15:09 +00:00
Ben Jackson
9e1a1ab4b5 Report failures 2021-02-25 22:15:09 +00:00
Ben Jackson
32f9a6ec43 Use silent for winbar menus 2021-02-25 22:15:09 +00:00
Ben Jackson
d8d6eb2286 Add ability to set a variable value
This works only for things which have known variablesReference, so
particularly currently only for scopes and theoretically for members.

I think this can work for watches too. will need to check.
2021-02-25 22:15:09 +00:00
mergify[bot]
1d38b8198f
Merge pull request #362 from puremourning/expr-completions-startup
Delay launching the python interpreter until needed
2021-02-25 22:14:59 +00:00
Ben Jackson
f40ac5db23 Delay launching the python interpreter until needed 2021-02-25 21:24:40 +00:00
Jake Zimmerman
11edcddd9c
Fix using double-quotes in VimspectorEval
The VimspectorEval command used `-bar` but this prevented the use of double quotes. This seems much more useful than a vim comment in this scenario, so remove the `-bar`.

This is _techncially_ breaking change, but I don't think it's likely anyone will be relying on doing `VimspectorEval x | something else`. If they are, sorry.
2021-02-25 11:04:12 +00:00
mergify[bot]
f9c5a33301
Merge pull request #355 from puremourning/terminate-debugee
Ask the user about terminating the debuggee
2021-02-24 18:27:16 +00:00
mergify[bot]
fdfa8b265b
Merge branch 'master' into terminate-debugee 2021-02-24 18:14:04 +00:00
mergify[bot]
a8651e257b
Merge pull request #356 from puremourning/telemetry-hide
hide the pointless telemetry data;
2021-02-24 18:09:48 +00:00
Ben Jackson
d8eb6a0463 Only prompt in 'interactive' contexts to avoid annoying questions 2021-02-24 18:00:08 +00:00
Ben Jackson
09efcf5e50 hide the controvertial telemetry data; it's not like anyone will ever look at it 2021-02-24 16:49:56 +00:00
Ben Jackson
5201995279 Ask the user about terminating the debuggee
CodeLLDB seems to actually support the terminateDebugee flag, so rather
than just forcefully killing things, ask the user if they want to.
2021-02-24 16:49:03 +00:00
mergify[bot]
fd03e074f3
Merge pull request #354 from YgorSouza/fix-readme-typos
Fix typos in README
2021-02-23 19:57:14 +00:00
Ygor Oliveira
fd0c6e7675 Fix typos in README 2021-02-23 19:51:52 +01:00
Ben Jackson
6fac220ee5 Disable mappings in the popup to ensure navigaion works 2021-02-23 09:42:57 +00:00
Ben Jackson
0810d7154c Fix syntax occasionally not working in popup, and custom vimrc crashing in neovim 2021-02-23 09:03:45 +00:00
Ben Jackson
476300f815 Fix errors resetting in neovim 2021-02-22 13:39:58 +00:00
mergify[bot]
95b900a0a7
Merge pull request #352 from puremourning/fix-restart-socket
Fix restart when using CodeLLDB
2021-02-22 12:29:37 +00:00
Ben Jackson
0e0cc6d4ae Fix restart when using CodeLLDB
Fix restarts always getting stuck "Initializing" when using CodeLLDB.

When using the restart command we re-use the configuration dict as-is,
so always re-use the same TCP port for the lldb socket. Originally it
was thought this was due to a race condition, having the port still
open, but it's not.

When doing a restart, or reset, we shut down the server after we get the
response to the disconnect message. CodeLLDB then also sends a
'terminated' message.

Previously we were forcefully closing the socket before killing the app,
after we get the 'disconnect' response. This meant that the OS buffer
for the socket to localhost:<the port> still contained the terminated
message at the point that we force-closed the socket and killed the
server.

The result was that the firt messages read from the "new" socket to
locahost:<port> were the last messagse written by the previous process,
trikcing vimspector into thinking that the server terminated the process
(before responding to the initialize request).

ANyway, the solution is to ensure that we read all messages from the
previous instance before considering it done. This is done by killing
the server if there is one *first* and then trying to read any messages
from the socket until it closes (reads EOF).

The tricky part is for when we didn't start the server (i.e. in a
multi-session setup). Here we simply _have_ to close the socket because
we can't know when we've received all of the messages, and we shouldn't
expect to receive any 'terminated' events after 'disconnect'.
2021-02-22 12:09:01 +00:00
mergify[bot]
c33fddd150
Merge pull request #351 from puremourning/doautocmd-frame-set
Add User autocommands when jumping to frame and resetting
2021-02-21 21:47:03 +00:00
Ben Jackson
448ee33a6a prevent annoying 'no matching autocmds' message 2021-02-21 21:24:02 +00:00
Ben Jackson
ae289a88c7 Update readme with example 2021-02-21 21:16:54 +00:00
Ben Jackson
3c7311e33a Test that the commands are fired when stepping through and continuing 2021-02-21 20:49:56 +00:00
Ben Jackson
d561c4aea5 Add demo of new commands for local mappings 2021-02-21 19:17:09 +00:00
przepompownia
3c54cd268f Send VimspectorDebugEnded event 2021-02-21 19:17:09 +00:00
przepompownia
bcf4120ba4 Do not send event after leave buffer. 2021-02-21 19:17:09 +00:00
__
50dc55e0e8 Fix errors reported by flake8 2021-02-21 19:17:09 +00:00
__
716181e056 fixup! Send an event before leave buffer in window 2021-02-21 19:17:09 +00:00
__
840ee09242 Send an event before leave buffer in window 2021-02-21 19:17:09 +00:00
__
0bb8416e11 Add test 2021-02-21 19:17:09 +00:00
__
d81bdf30ef Emit User VimspectorFrameWasSet event 2021-02-21 19:17:09 +00:00
mergify[bot]
e70b8f37a3
Merge pull request #350 from puremourning/nvim-float-window
Replace vim balloons with popups
2021-02-21 18:44:21 +00:00
Ben Jackson
5754e96067 FixUp: Change of mapleader 2021-02-21 18:24:26 +00:00
Ben Jackson
4958de92d3 Fix flake8 error 2021-02-21 18:05:59 +00:00
Ben Jackson
6b546cd621 Update TOC 2021-02-21 17:01:41 +00:00
Ben Jackson
323e22b8a9 Update readme 2021-02-21 17:01:41 +00:00
Ben Jackson
5a1eb9250a Fix test now that we're using a mapping 2021-02-21 17:01:41 +00:00
Ben Jackson
cc84e15932 Tidy up, refactor and fix some bugs 2021-02-21 17:01:41 +00:00
dsych
7dcb15f11c cleaning up 2021-02-21 17:01:41 +00:00
dsych
44711899cb moving stuff around 2021-02-21 17:01:41 +00:00
dsych
0313efa06f removing redundant check for array bounds 2021-02-21 17:01:41 +00:00
dsych
51d551fe52 replacing function calls with plug command 2021-02-21 17:01:41 +00:00
dsych
ae137ecdd0 removing old balloon code 2021-02-21 17:01:41 +00:00
dsych
d6c68d691c streamlining the docs 2021-02-21 17:01:41 +00:00
dsych
47680565c4 adding docs 2021-02-21 17:01:41 +00:00
dsych
8c39a861bd hopefully fixing tests on mac 2021-02-21 17:01:41 +00:00
dsych
639e89f5db fixing linting 2021-02-21 17:01:41 +00:00
dsych
5a23ec5beb adding tests for select range, invalid eval and expand/collapse 2021-02-21 17:01:41 +00:00
dsych
e0b0a7f3d2 recording popup win id on the failed evaluation 2021-02-21 17:01:41 +00:00
dsych
0ff9dc5f9e making sure that select marks were set before attempting to extract text 2021-02-21 17:01:41 +00:00
dsych
0c79384529 there is no need to execute feedkeys inside a popup context, since keys are added into the global input buffer 2021-02-21 17:01:41 +00:00
dsych
789377eab4 adding the first test! 2021-02-21 17:01:41 +00:00
dsych
4466fce20b fixing styling inside vim files 2021-02-21 17:01:41 +00:00
dsych
13102dc711 reverting back the highlight group 2021-02-21 17:01:41 +00:00
dsych
91bebc1826 adding a close button for keyboard triggered popup, since drag and resize are also enabled. removing wrap from border. 2021-02-21 17:01:41 +00:00
Ben Jackson
3239963893 Set the correct highlights in both popups in neovim 2021-02-21 17:01:41 +00:00
Ben Jackson
31e44548d3 Tidy up MouseFilter 2021-02-21 17:01:41 +00:00
Ben Jackson
e5e13ffcdd Fix typo: Baloon -> Balloon 2021-02-21 17:01:41 +00:00
Ben Jackson
894ca522d3 Use the popup callback rather than manually trying to do it 2021-02-21 17:01:41 +00:00
Ben Jackson
322b7e0a38 Enable mouse interraction for the both popups in vim 2021-02-21 17:01:41 +00:00
Ben Jackson
bc1146df3b Use normal highlighting for the popup as it's probably more readable (debatable?) 2021-02-21 17:01:41 +00:00
Ben Jackson
d2ed8a828c Use popup_filter_menu for the keyboard-popup rather than 100% our own 2021-02-21 17:01:41 +00:00
Ben Jackson
fccafd6739 FixUp: border characters - indicate that the corner can be dragged 2021-02-21 17:01:41 +00:00
Ben Jackson
672ac78fef Fix flaky syntax highlighting toggling on/off 2021-02-21 17:01:41 +00:00
Ben Jackson
64f2c8eb01 Use a fancy single line border in vim popup when we can 2021-02-21 17:01:41 +00:00
Ben Jackson
cb174c176d Disable wrapping long lines in neovim popup too 2021-02-21 17:01:41 +00:00
Ben Jackson
2d082cc923 Use a more generous maximum size for the popup (TODO: option for this ?) 2021-02-21 17:01:41 +00:00
dsych
0d703779dc evaluating select range 2021-02-21 17:01:41 +00:00
Ben Jackson
f3c39e12ab FixUp: Display in watch window, and indent in popup 2021-02-21 17:01:41 +00:00
Ben Jackson
cfae062da1 Disable cursorLine for the hover-only popup 2021-02-21 17:01:41 +00:00
Ben Jackson
0b4da4c82b Remove more text from the hover popup 2021-02-21 17:01:41 +00:00
Ben Jackson
64e38b57ab Fix crash; enable syntax highlighting in hover popup; use a Watch for the popup and re-use existing drawing code 2021-02-21 17:01:41 +00:00
Ben Jackson
0895c5e829 Add 1 cell of padding to the x direction which makes the popup more readable 2021-02-21 17:01:41 +00:00
Ben Jackson
052d63dee5 Fix mouse interraction with the popup - don't handle events outside the window 2021-02-21 17:01:41 +00:00
dsych
93568ba05d removing test code 2021-02-21 17:01:41 +00:00
dsych
e0b1d6ed81 fixing linting errors in python files 2021-02-21 17:01:41 +00:00
dsych
3c857cebf4 dynamically adjusting window size for nvim's floating window based on the buffer size 2021-02-21 17:01:41 +00:00
dsych
2f1c93a2ac only diplaying relevant info like name and value for nested types and value only for simple types 2021-02-21 17:01:41 +00:00
dsych
cb441be7bc allowing resizing and dragging with a mouse 2021-02-21 17:01:41 +00:00
dsych
b9ed7f34b4 removing redundant name for simple types, shortening variable type to 20 char and variable value to 100 chars to avoid overflowing tooltip window if the wrapped line is longer than the max size of the tooltip 2021-02-21 17:01:41 +00:00
dsych
04a5e889f9 making sure that float window is not modifiable inside nvim 2021-02-21 17:01:41 +00:00
dsych
f60b259dbc adding type information for simple types 2021-02-21 17:01:41 +00:00
dsych
b95ae00054 enabling a close button for popup 2021-02-21 17:01:41 +00:00
dsych
4617250f41 adding border to popup 2021-02-21 17:01:41 +00:00
dsych
0ced5eb1d4 splitting mouse and cursor filtering to avoid trapping keyboard for hover 2021-02-21 17:01:41 +00:00
dsych
747ad9b804 removing literal dictionary syntax, as it is not included in nvim-4.4 2021-02-21 17:01:41 +00:00
dsych
d2990d7bae making sure to open popup relative to cursor 2021-02-21 17:01:41 +00:00
dsych
819d6366ac fully implemented the hover function for vim 2021-02-21 17:01:38 +00:00
dsych
4e994968ff added popup support for vim, still need to figure out how to expand variables 2021-02-21 17:00:47 +00:00
dsych
7432be9532 implemented dynamic float windows for nvim 2021-02-21 17:00:47 +00:00
dsych
07858cc250 adding on the fly eval of inside a floating window 2021-02-21 17:00:47 +00:00
dsych
4c0ba92ac6 working on variables view 2021-02-21 17:00:47 +00:00
dsych
7c4eef9096 finally got float window working with variable evaluation 2021-02-21 17:00:47 +00:00
mergify[bot]
85ca867cc2
Merge pull request #348 from timtyrrell/patch-1
Update README typo
2021-02-16 08:59:33 +00:00
Tim Tyrrell
cb922bdc83
Update README typo 2021-02-14 11:56:27 -07:00
mergify[bot]
e99ac0d658
Merge pull request #345 from markwu/update-vscode-php-debug
Update vscode-php-debug to 1.14.9, it works for both Xdebug 2/3
2021-02-10 16:51:56 +00:00
Mark Wu
0cc4322b18 Update vscode-php-debug to 1.14.9, it works for both Xdebug 2/3 2021-02-10 20:01:18 +08:00
Ben Jackson
7f77842ab8 Make sure that tests fail properly; ensure that empty string is a valid default 2021-02-06 22:08:08 +00:00
mergify[bot]
4454dead0f
Merge pull request #344 from puremourning/multiple-vars
Fix variable substitution for multiple defaulted vars
2021-02-06 21:27:19 +00:00
Ben Jackson
30eec0d93c Fix variable substitution for multiple defaulted vars
The problem was that the python regex engine is strictly left-to-right,
so matching `[^}]|\\}` against \\}} meant that the `\\` was consumed by
the left of the `|`. The solution is to just switch them around.

Also add a way to run python tests from within vim, so we can actually
test this stuff.
2021-02-06 20:55:24 +00:00
Ben Jackson
52eff32651
Telemetry data myth busted. 2021-01-10 12:59:59 +00:00
mergify[bot]
5303de8195
Merge pull request #339 from ailrk/master
fixed some typos in the readme
2021-01-09 15:19:46 +00:00
Jimmy
75e8450cf3 fixed some typos in the readme 2021-01-09 07:47:33 -08:00
Ben Jackson
35f7e08fbb Bit of readme restructuring and improve docs on breakpionts API 2021-01-09 13:14:14 +00:00
Ben Jackson
d38da376c2 There are <plug> mappings 2021-01-09 12:46:13 +00:00
Ben Jackson
1f20115960 Update docs bundle to stfu security warnings 2021-01-09 12:15:55 +00:00
Ben Jackson
442a18f8f2
Merge pull request #338 from puremourning/new-issue
add some links to the new issue page
2021-01-09 12:04:02 +00:00
Ben Jackson
e010d3217c add some links to the new issue page 2021-01-09 12:03:18 +00:00
mergify[bot]
1556e63ef0
Merge pull request #317 from yatli/master
multiple languages per adapter
2021-01-09 11:50:10 +00:00
Ben Jackson
205eb7cdb3
Merge branch 'master' into master 2021-01-09 10:33:38 +00:00
mergify[bot]
44a0f819e2
Merge pull request #336 from puremourning/localhost
Use 127.0.0.1 rather than localhost to avoid issues with ipv6, and lo…
2021-01-08 16:08:12 +00:00
Ben Jackson
4206d0e57c Use 127.0.0.1 rather than localhost to avoid issues with ipv6, and long timeout connecting the socket 2021-01-08 15:54:49 +00:00
mergify[bot]
b180b14ed4
Merge pull request #334 from puremourning/fix-node-thread
Fix node thread
2021-01-08 11:49:20 +00:00
Ben Jackson
d52eb3a6e9 Fix thread state and PC for starting node app
The problem is the sequence of events sent by the debug adapter.
Vimspector requests threads:

* When the initialisation exchange completes (requests all threads)
* Whenever a thread event is received
* whenever a stopped event is received.

If any of those happens while any other request is in progress, we cache
the request and handle it later. The latest request is processed when
the response to the outstanding request is received.

The problem is if the event is a stopped event, it is the handling of
the threads request that actually sets the thread state internally to
stopped. In a sequence where the first event is a stopped event, we end
up discarding the stopped event. like:

1. Stopped event (thread 1 = stopped) (request threads)
2. Initialisation complete (cache request)
3. threads response received (discard response and process cached request)
4. response received (but forgotten about the stopped event).

The solution is to always process the thread response, even if we send
the cached request. To avoid flicker, we don't draw the screen, or
expand any threads/stacks in the case where we're sending a cached
request.
2021-01-08 11:35:01 +00:00
Ben Jackson
b72aa18dec Add a list to tcl tets 2021-01-08 11:06:33 +00:00
mergify[bot]
07ea3880ac
Merge pull request #328 from AllanGuigou/master
Allow a gadget to specify a custom extension path
2021-01-07 08:09:14 +00:00
Ben Jackson
38ed75dda7
Merge branch 'master' into master 2021-01-06 09:56:40 +00:00
Ben Jackson
0ad826704b
Merge branch 'master' into master 2021-01-06 09:54:16 +00:00
mergify[bot]
65708f55e0
Merge pull request #329 from lelutin/debug_py_1.2.1
bump debugpy gadget to version 1.2.1
2021-01-02 22:36:28 +00:00
Gabriel Filion
7bd22d2bbd bump debugpy gadget to version 1.2.1
1.2.1 is, as of this commit, the most recent version of the gadget.

The version currently used, 1.0.0b12 is not compatible with Python 3.9:
the build errors out on missing arguments for _PyEval_EvalFrameDefault.

Python 3.9 is the version of Python that will be shipped with the
upcoming debian release.

Support for 3.9 was merged in before the final 1.0.0 version. So,
upgrading the gadget will bring in python 3.9 support
2021-01-02 15:46:53 -05:00
Allan Guigou
ce8dd9113c Remove gradle wrapper
The gradle wrapper is too large of a dependency to include for every
download of vimspector. Users can use a local installation of gradle to
run the sample kotlin application if necessary.
2020-12-31 10:39:01 -05:00
Allan Guigou
ec68811c8a Add support test for kotlin 2020-12-24 15:10:56 -05:00
Allan Guigou
47c404f823 Allow a gadget to specify a custom extension path
When installing a custom gadget not officially supported by vimspector the
default extension path is 'extension', this works for vscode extensions but
does not support some debug adapters. This commit gives the ability to change
that default extension path by specifying 'extension_path' within the gadget
installer file.

Installing 'cust_adapter' would use the extension path 'adapter' rather
than 'extension' (ie ${gadgetDir}/cust_adapter/${version}/root/adapter)

{
  "cust_adapter": {
    "download": { ... },
    "all": {
      "extension_path": "adapter",
      "adapters": { ... }
    }
  }
}
2020-12-24 14:55:40 -05:00
mergify[bot]
41a98026fa
Merge pull request #327 from AW3i/master
Fix Typo in PHP section
2020-12-23 09:19:49 +00:00
Alex Weigl
523ea29faa
Fix Typo in PHP section 2020-12-22 23:49:25 +02:00
mergify[bot]
d0fc7815b3
Merge pull request #319 from puremourning/docker-test
Fix docker example
2020-12-22 16:04:25 +00:00
Ben Jackson
0942aa4523 Fix docker example for python
The example was was using 'launchCommand' which is not valid according
to the schema; it should be 'runCommand'.

But also, it never really worked. Vimspector would start the "adapter"
(in this case, try and connect to the TCP port) before running the
"prepare" commands, wich in this case would actually start debugpy
listening. So to solve that we run the prepare commands earlier.
Hopefully this won't cause a regression for Java and C++ remote attach,
which we don't really have tests for.

Finally, due to the way docker works, when you forward a port and
nothing is listening on it, docker _accepts_ the connection then
immediately drops it. This is _super_ annoying meaning that it looks to
vimspector liek the server instantly dies if it takes nonzero time for
the remote commands to open the port. So to solve this we add loaunch
and attach delays which can be configured in the adapter config. This
actually solves a prolem where the java debugger just takes agest to
attach on remote launch too.

(Finally, finally...) updated the vimspector schema to represent
the real launch/attach remote configuration, which was incorrectly
spec'd at the adapter level, but it's actually per launch/attach block.
2020-12-22 15:45:26 +00:00
Ben Jackson
f59ba048cb
Merge branch 'master' into master 2020-12-19 18:30:02 +00:00
Yatao Li
f20c4c9725 fix linter errors 2020-12-19 22:35:12 +08:00
Ben Jackson
f8d1e484f9
Update CONTRIBUTING.md
Minor fix and correct CI path
2020-12-18 17:10:29 +00:00
Yatao Li
66130389c5 code format fixes, update docs 2020-12-15 16:25:26 +08:00
Ben Jackson
61179b7670 Update CONTRIBUTING.md for PRs 2020-12-14 20:55:13 +00:00
Ben Jackson
f161ce1e8c Remove redundant comments 2020-12-14 20:55:03 +00:00
mergify[bot]
d04a8400f9
Merge pull request #318 from cposture/feat-update-gadgets-vscode-go
update gadgets vscode-go version
2020-12-14 17:03:34 +00:00
cposture
b65d9536ad update gadgets vscode-go version 2020-12-15 00:22:35 +08:00
Yatao Li
28c5534704 language list 2020-12-14 22:57:32 +08:00
mergify[bot]
2eb32f3153
Merge pull request #315 from puremourning/env-dup-fix
Don't copy the environment to update it
2020-12-05 23:15:43 +00:00
Ben Jackson
8261cde3c9 Don't copy the environment to update it
This causes problems on windows, and is wasteful anyway. The subprocess
will pick up the environment from its parent.
2020-12-05 16:42:07 +00:00
Ben Jackson
573121ee08
Merge pull request #312 from puremourning/watch-errors
Print failure when watch expression errors
2020-12-02 18:19:39 +00:00
Ben Jackson
632e6696ef Add SSH login for failures 2020-12-02 18:06:37 +00:00
Ben Jackson
c531686d39 Use the cask of macvim because apparently the formula requires building gcc from source 2020-12-02 18:06:37 +00:00
Ben Jackson
2eac9ddff8 Print failure when watch expression errors 2020-12-02 15:26:30 +00:00
Ben Jackson
8e2d352eb8 Fix local adapter specs
Somehow we lost the ability to define adapters in the local
.vimspector.json, I think when GetConfigurations was added.

Put that feature back.
2020-11-30 10:19:02 +00:00
mergify[bot]
4ac9785217
Merge pull request #308 from andwilley/docs/update-java-example
Add detail about potential troubleshooting. Recommend jsdls_extension…
2020-11-28 11:51:17 +00:00
Drew Willey
4a45753a4c Add detail about potential troubleshooting. Recommend jsdls_extension_path be set in vimrc. 2020-11-27 21:16:51 -07:00
Ben Jackson
e15c50a4f4 Don't request strack trace if the thread isn't stopped 2020-11-28 00:17:42 +00:00
Ben Jackson
17a9494dbc
Merge pull request #306 from felixfeit/patch-1
Fix typos.
2020-11-26 18:43:04 +00:00
felixfeit
4db4880b6d
Fix typos. 2020-11-26 19:31:46 +01:00
Ben Jackson
4c2b3bd886
Make it clear that the mappings have to be enabled 2020-11-26 12:38:34 +00:00
Ben Jackson
e6500d39d8
Neovim has prompt buffers in nightly 2020-11-26 12:11:23 +00:00
mergify[bot]
ff4acb17d1
Merge pull request #303 from eduardomezencio/lua-fix-configs
Improve lua configuration and test files
2020-11-22 21:55:53 +00:00
Eduardo Mezêncio
4f03e4f65a Improve lua configuration and test files
Change lua test files to call `require 'lldebugger'` only when using
love, because it's not needed with lua or luajit. Also add `stopOnEntry`
key to test `.vimspector.json` because it works correctly with this
change.
2020-11-22 18:38:40 -03:00
mergify[bot]
23130d74ad
Merge pull request #297 from puremourning/threads
[WIP] Improve Threads Handling
2020-11-22 15:07:22 +00:00
Ben Jackson
5ab92a7e67 Breakpont tests too flaky 2020-11-22 14:54:02 +00:00
Ben Jackson
979c1e8779 Reshuffle README 2020-11-22 14:35:30 +00:00
Ben Jackson
a9d0ebde0b Add mapping for Focus, and make focusing a stack frame focus the thread 2020-11-22 14:13:15 +00:00
Ben Jackson
82307ff1ba Correctly handle the 'continue' response when continuing a specific thread 2020-11-22 14:13:15 +00:00
Ben Jackson
7d5ad3ffa1 Another flaky test 2020-11-22 14:13:15 +00:00
Ben Jackson
8801c2dac4 Fix pause/continue of individual threads
work around buggy java server sending invalid threads response.

java server supports this separate threads running/paused as a test
case.
2020-11-22 14:13:14 +00:00
Ben Jackson
e1c1347bdd Fix lint 2020-11-22 14:13:14 +00:00
Ben Jackson
c769e8a479 Fix up the tests to work in linux container too 2020-11-22 14:13:14 +00:00
Ben Jackson
53b1d12447 Allow setting the current thread, use a sign to highlight the line with the current thread 2020-11-22 14:13:14 +00:00
Ben Jackson
8e3a734141 Support continued event properly 2020-11-22 14:13:14 +00:00
Ben Jackson
0f0d684e92 FixUp: comment about why we apply thread state in consume_threads 2020-11-22 14:13:14 +00:00
Ben Jackson
42cdff043a Redraw the screen each 20 retries
This allows us to eyeball why something is failing
2020-11-22 14:13:14 +00:00
Ben Jackson
f0785c11f2 Allow pausing individual threads (in theory) 2020-11-22 14:13:14 +00:00
Ben Jackson
a5d66a7477 Correctly track and now actually report running/paused status
It's quirky, we have to pass the stopped event to LoadThreads so that it
can correctly work out the state of any _newly_ added threads. We now
also correctly apply the allThreadsStopped=False behaviour where you
must not allow expansion of such threads (in theory, that's untested).
2020-11-22 14:13:14 +00:00
Ben Jackson
2399a79cae start to track individual thread state 2020-11-22 14:13:14 +00:00
Ben Jackson
e9e0e9e5b9 Test for new thread creation
- don't clear the stack trace on continue - track running status
  properly (ish)
- mark threads (running) when the app is executing
- indicate the "current" thread with a different icon

TODO:
- allow user to specify current thread?
- track running status of threads individually?
- allow to pause/continue specific threads?
2020-11-22 14:13:14 +00:00
Ben Jackson
e2ca9b5318 Threads tests WIP 2020-11-22 14:13:14 +00:00
mergify[bot]
e5a765409a
Merge pull request #302 from puremourning/updated-go
Update vscode-go to latest version
2020-11-22 13:39:46 +00:00
Ben Jackson
f87aa4aa19 Undo flakiness hack 2020-11-22 13:30:14 +00:00
Ben Jackson
07ec08e664 Fix clearing temp breakpoints - ensure that the isngs are undisplayed 2020-11-22 13:25:10 +00:00
Ben Jackson
3330c704d7 Too many flakes 2020-11-22 12:46:15 +00:00
Ben Jackson
87ce1734ea Update vscode-go to latest version 2020-11-22 12:31:21 +00:00
mergify[bot]
48e075624a
Merge pull request #301 from puremourning/winbar-neovim
Work around neovim WinBar rendering bug
2020-11-19 23:45:01 +00:00
Ben Jackson
b36f9e893a Work around neovim WinBar rendering bug 2020-11-19 23:29:13 +00:00
mergify[bot]
b7de25e3d1
Merge pull request #296 from puremourning/update-servers
Update servers
2020-11-16 22:09:48 +00:00
Ben Jackson
47c2cef2a1 Use a tag for tclpro to avoid installing every time 2020-11-16 21:17:36 +00:00
Ben Jackson
cd3b5f5baa Update mono debug; even though it doesn't work 2020-11-16 21:17:22 +00:00
Ben Jackson
5b88837919 Print the correct version for a git tag 2020-11-16 20:14:39 +00:00
Ben Jackson
888c558aa4
Merge pull request #294 from eduardomezencio/lua-support
Add lua support through local-lua-debugger-vscode
2020-11-16 19:35:13 +00:00
Eduardo Mezêncio
85865e0012 Add regression tests for lua support
Change Dockerfile to install lua, luajit and love and also to install
nodejs 12 needed to build the lua debug adapter. Create the
love-headless test in support/test/lua to test love without an x server.
2020-11-16 15:08:55 -03:00
Eduardo Mezêncio
7be6d852c6
Merge branch 'master' into lua-support 2020-11-16 15:04:26 -03:00
mergify[bot]
96a594e4cf
Merge pull request #295 from TamaMcGlinn/master
Fixed typo 'exisitng' in README
2020-11-16 10:49:58 +00:00
Tama
69bb2737d1 Fixed typo 'exisitng' in README 2020-11-16 11:37:12 +01:00
Eduardo Mezêncio
1eb2bc2199 Add lua to README index. 2020-11-14 20:27:27 -03:00
Eduardo Mezêncio
2819e224e7 Add lua support through local-lua-debugger-vscode
Add the lua adapter to gadgets.py and installer.py, update the README.md
file and create basic tests using lua, luajit and love.
2020-11-14 19:34:15 -03:00
Ben Jackson
2bdb30a45e update docs 2020-11-14 12:34:15 +00:00
mergify[bot]
3f3a001283
Merge pull request #292 from puremourning/codelldb-default
Recommend CodeLLDB
2020-11-13 17:02:14 +00:00
mergify[bot]
5ae3d9f336
Merge branch 'master' into codelldb-default 2020-11-09 22:41:50 +00:00
mergify[bot]
30741f8813
Merge pull request #291 from puremourning/netcoredbg-update
Update netcoredbg
2020-11-09 22:33:09 +00:00
Ben Jackson
2225735b80 Recommend CodeLLDB 2020-11-09 22:23:37 +00:00
Ben Jackson
fb86ef924b Update netcoredbg 2020-11-09 21:57:47 +00:00
mergify[bot]
97bef33660
Merge pull request #289 from sharksforarms/list-configurations
Add a GetConfigurations function
2020-11-06 17:32:59 +00:00
Emmanuel Thompson
d5b9411256 Add a GetConfigurations function 2020-11-06 12:05:14 -05:00
mergify[bot]
7b048367f7
Merge pull request #282 from puremourning/run-to-cursor
Run to cursor
2020-10-23 22:10:55 +00:00
Ben Jackson
80985148e7 Add "run to cursor" support
We add a 'temporary' option to line breakpionts and try and clear any
temporary breakpionts on the line we end up stopping on. This might not
be art, but _probably_ works in almost all cases that matter.

it's a bit hacky the way we have to push the reason around, but we don't
know where we stopped until we actually get the stack trace response and
SetCurrentFrame

Move temporary breakpionts to match server response

Also delete any existing ones when adding a new one and add tests for
run-to-cursor.

Only continue after we successfully set the breakpoints. This makes it
work in go
2020-10-23 22:53:04 +01:00
Ben Jackson
0d112d70a0 Add SetLineBreakpoint and ClaerLineBreakpoint APIs
These are useful for running tests (i.e. ensure there's a breakpiont at
the start of the test) and/or other programmatic usages.

They will also be needed for setting temporary breakpionts.
2020-10-17 22:40:08 +01:00
Ben Jackson
78bec87f4e
Link to wiki for additional language support 2020-10-14 22:33:04 +01:00
mergify[bot]
c76e20cd9b
Merge pull request #280 from camilo-schoeningh-sociomantic/vscode-go-moved
vscode-go: Update plugin and use new repository address.
2020-10-14 21:18:17 +00:00
Camilo Schoeningh
ea36b60a07
vscode-go: Update version and use new repository.
As of June 2020, the vscode-go repository has moved to https://github.com/golang/vscode-go.
2020-10-14 21:21:11 +02:00
Ben Jackson
5057906317
Merge pull request #281 from puremourning/java-cwd
Java: Set cwd by default
2020-10-14 17:02:03 +01:00
Ben Jackson
8d17572538 brew update is failing as some taps have been removed
Per https://github.com/Homebrew/homebrew-core/issues/30917, use brew
update-reset to fix it
2020-10-14 15:50:10 +01:00
Ben Jackson
f3c5944dd2 Java: Set cwd by default 2020-10-14 15:26:54 +01:00
mergify[bot]
1eb9933e2a
Merge pull request #279 from puremourning/breakpoint-event
Fix breakpoint event
2020-10-10 15:29:38 +00:00
Ben Jackson
1b9763a4fc Minor improvements to console usage
Display failures and stop adding random text which makes the (very
useful) CodeLLDB interface look messy
2020-10-10 16:20:55 +01:00
Ben Jackson
16f22b396f Fix breakpoint event
Few problems:
 - we were passing a dict instead of a list of breakpoints
 - if the breakpoint had a source which was {} we crashed
 - we didn't support the 'removed' event
2020-10-10 16:04:46 +01:00
mergify[bot]
f6726de058
Merge pull request #272 from ayberkydn/patch-1
Update README.md
2020-10-01 21:30:12 +00:00
Ayberk Aydın
3d442c978f
Update README.md
fix typo
2020-10-02 00:20:50 +03:00
mergify[bot]
692a0d8d39
Merge pull request #268 from puremourning/breakpoints-file-while-debugging
While debugging, use the correct path for breakpoints
2020-09-27 22:12:33 +00:00
Ben Jackson
bd09206caf While debugging, use the correct path for breakpoints 2020-09-27 22:47:22 +01:00
112 changed files with 10662 additions and 2260 deletions

View file

@ -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_
@ -57,6 +57,12 @@ discussing on Gitter rather than raising an issue.
* Version of Vimspector: (e.g. output of `git rev-parse HEAD` if cloned or the
name of the tarball used to install otherwise)
* Output of `:VimspectorDebugInfo`
```
paste here
```
* Output of `vim --version` or `nvim --version`
```

12
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,12 @@
blank_issues_enabled: false
contact_links:
- name: Questions and support
url: http://gitter.im/vimspector/Lobby
about: Please ask and answer questions here.
- name: Discussions
url: https://github.com/puremourning/vimspector/discussions
about: Please post questions and useful hints here
- name: Support for additional languages
url: https://github.com/puremourning/vimspector/wiki/languages
about: Please see here for information on support for additional languages

View file

@ -13,7 +13,7 @@ defaults:
jobs:
PythonLint:
runs-on: ubuntu-16.04
runs-on: ubuntu-18.04
container: 'puremourning/vimspector:test'
steps:
- uses: actions/checkout@v2
@ -22,7 +22,7 @@ jobs:
- name: 'Run flake8'
run: '$HOME/.local/bin/flake8 python3/ *.py'
VimscriptLint:
runs-on: 'ubuntu-16.04'
runs-on: 'ubuntu-18.04'
container: 'puremourning/vimspector:test'
steps:
- uses: actions/checkout@v2
@ -32,12 +32,13 @@ jobs:
run: $HOME/.local/bin/vint autoload/ compiler/ plugin/ tests/ syntax/
Linux:
runs-on: 'ubuntu-16.04'
runs-on: 'ubuntu-18.04'
container:
image: 'puremourning/vimspector:test'
options: --cap-add=SYS_PTRACE --security-opt seccomp=unconfined
steps:
- uses: actions/checkout@v2
- run: |
eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
go get -u github.com/go-delve/delve/cmd/dlv
@ -79,17 +80,26 @@ jobs:
name: 'package-linux'
path: 'package/linux-${{ github.run_id }}.tar.gz'
# - name: Start SSH session if failed
# uses: luchihoratiu/debug-via-ssh@main
# if: failure()
# with:
# NGROK_AUTH_TOKEN: ${{ secrets.NGROK_AUTH_TOKEN }}
# SSH_PASS: ${{ secrets.SSH_PASS }}
MacOS:
runs-on: 'macos-10.15'
steps:
- uses: actions/checkout@v2
- run: |
brew update
brew update-reset
brew doctor || true
for p in macvim tcl-tk llvm; do
brew install $p
brew outdated $p || brew upgrade $p
for p in python@3.8 tcl-tk llvm lua luajit love; do
brew install $p || brew outdated $p || brew upgrade $p
done
brew install --cask macvim
brew link --overwrite python@3.8
name: 'Install vim and deps'
- run: go get -u github.com/go-delve/delve/cmd/dlv
@ -101,6 +111,16 @@ jobs:
path: gadgets/macos/download
name: Cache gadgets
- name: 'Install .NET Core SDK 3.1'
uses: actions/setup-dotnet@v1.7.2
with:
dotnet-version: 3.1
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ^11
name: "Switch to xcode 11 because of .NET debugging bug"
- run: vim --version
name: 'Print vim version information'
@ -128,8 +148,15 @@ jobs:
name: 'package-macos'
path: 'package/macos-${{ github.run_id }}.tar.gz'
# - name: Start SSH session if failed
# uses: luchihoratiu/debug-via-ssh@main
# if: failure()
# with:
# NGROK_AUTH_TOKEN: ${{ secrets.NGROK_AUTH_TOKEN }}
# SSH_PASS: ${{ secrets.SSH_PASS }} # [V]imspector
PublishRelease:
runs-on: 'ubuntu-16.04'
runs-on: 'ubuntu-18.04'
needs:
- Linux
- MacOS

27
.github/workflows/lock_old_issues.yaml vendored Normal file
View file

@ -0,0 +1,27 @@
name: "Lock Old Issues"
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '60'
# issue-exclude-created-before: ''
# issue-exclude-labels: ''
# issue-lock-labels: ''
# issue-lock-comment: ''
# issue-lock-reason: 'resolved'
# pr-lock-inactive-days: '365'
# pr-exclude-created-before: ''
# pr-exclude-labels: ''
# pr-lock-labels: ''
# pr-lock-comment: ''
# pr-lock-reason: 'resolved'
process-only: 'issues'

2
.gitignore vendored
View file

@ -6,6 +6,7 @@ tests/*.res
tests/messages
tests/debuglog
test.log
*.testlog
gadgets/
package/
*.pyc
@ -19,3 +20,4 @@ support/test/csharp/*.exe*
configurations/
venv/
test-base/
tags

View file

@ -9,9 +9,8 @@ pull_request_rules:
# CI https://doc.mergify.io/conditions.html#github-actions
- status-success=PythonLint
- status-success=VimscriptLint
- status-success=Linux
- status-success=MacOS
actions: &merge-actions
merge:
method: merge

View file

@ -42,7 +42,17 @@ def Settings( **kwargs ):
return {
'sys_path': [
p.join( PATH_TO_THIS_DIR, 'python3' )
]
],
'ls': {
'python': {
'analysis': {
'extraPaths': [
p.join( PATH_TO_THIS_DIR, 'python3' ),
],
'useLibraryCodeForTypes': True
}
}
}
}
if IgnoreExtraConf:

View file

@ -46,6 +46,23 @@ The GitHub issue tracker is for *bug reports* and *features requests* for the
Vimspector project, and on-topic comments and follow-ups to them. It is not for
general discussion, general support or for any other purpose.
Please **search the issue tracker for similar issues** before creating a new
one. There's no point in duplication; if an existing open issue addresses your
problem, please comment there instead of creating a duplicate. However, if the
issue you found is **closed as resolved** (e.g. with a PR or the original user's
problem was resolved), raise a **new issue**, because you've found a new
problem. Reference the original issue if you think that's useful information.
Closed issues which have been inactive for 60 days will be locked, this helps to
keep discussions focussed. If you believe you are still experiencing an issue
which has been closed, please raise a new issue, completing the issue template.
If you do find a similar _open_ issue, **don't just post 'me too' or similar**
responses. This almost never helps resolve the issue, and just causes noise for
the maintainers. Only post if it will aid the maintainers in solving the issue;
if there are existing diagnostics requested in the thread, perform
them and post the results.
Please do not be offended if your Issue or comment is closed or hidden, for any
of the following reasons:
@ -53,6 +70,7 @@ of the following reasons:
* The issue or comment is off-topic
* The issue does not represent a Vimspector bug or feature request
* The issue cannot be reasonably reproduced using the minimal vimrc
* The issue is a duplicate of an existing issue
* etc.
Issue titles are important. It's not usually helpful to write a title like
@ -83,11 +101,47 @@ 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
Vimspector is open to all contributors with ideas great and small! However,
there is a limit to the intended scope of the plugin and the amount of time the
maintainer has to support and... well... maintain features. It's probably well
understood that the contributor's input typically ends when a PR is megred, but
the maintainers have to keep it working forever.
### Small changes
For bug fixes, documentation changes, gadget versin updates, etc. please just
send a PR, I'm super happy to merge these!
If you are unsure, or looking for some pointers, feel free to ask in Gitter, or
mention is in the PR.
### Larger changes
For larger features that might be in any way controvertial, or increase the
complexity of the overall plugin, please come to Gitter and talk to the
maintainer(s) first. This saves a lot of potential back-and-forth and makes sure
that we're "on the same page" about the idea and the ongoing maintenance.
In addition, if you like hacking, feel free to raise a PR tagged with `[RFC]` in
the title and we can discuss the idea. I still prefer to discuss these things on
Gitter rather than back-and-forth on GitHub, though.
Please don't be offended if the maintainer(s) request significant rework for (or
perhaps even dismiss) a PR that's not gone through this process.
Please also don't be offended if the maintainer(s) ask if you're willing to
provide ongoing support for the feature. As an OSS project manned entirely in
what little spare time the maintainer(s) have, we're always looking for
contributions and contributors who will help with support and maintenance of
larger new features.
### PR Guidelines
When contributing pull requests, I ask that:
* You provide a clear and complete summary of the change, the use case and how
@ -95,6 +149,8 @@ When contributing pull requests, I ask that:
* You avoid using APIs that are not available in the versions listed in the
dependencies on README.md
* You add tests for your PR.
* You test your changes in both Vim and Neovim at the supported versions (and
state that in the PR).
* You follow the style of the code as-is; the python code is YCM-stye, it is
*not* PEP8, nor should it be.
@ -129,10 +185,10 @@ Vimspector creator.
### Code Style
The code style of the Python code is "YCM" style, because that's how I like it.
[`flake8`][] is used to check for certain errors and code style.
`flake8` is used to check for certain errors and code style.
The code style of the Vimscript is largely the same, and it is linted by
[`vint`][].
`vint`.
To run them:
@ -144,7 +200,31 @@ To run them:
They're also run by CI, so please check for lint failures. The canonical
definition of the command to run is the command run in CI, i.e. in
`azure-pipelines.yml`.
`.git/workflows/build.yml`.
### Debugging Vimspector
You can debug vimspector's python code using vimspector! We can use debugpy,
from within Vim's embedded python and connect to it. Here's how:
1. In one instance of vim, run the following to get debugpy to start listening
for us to connect: `:py3 __import__( 'vimspector', fromlist=[ 'developer' ]
).developer.SetUpDebugpy()`
2. In another instance of Vim, set a breakpoint in the vimspector python code
you want to debug and launch vimspector (e.g. `<F5>`). Select the `Python:
attach to vim` profile. This will attach to the debugpy running in the other
vim.
3. Back in the first vim (the debuggee), trigger the vimspector code in
question, e.g. by starting to debug something else.
4. You'll see it pause, and the 2nd vim (the debugger), you should be able to
step through and inspect as with any other python remote debugging.
NB. It's also possible to debug the vimscript code using vimspector, but this
requires unreleased vim patches and a fair amount of faff. You can always use
`:debug` (see the help) for this though.
# Code of conduct

1016
README.md

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,9 @@
" See the License for the specific language governing permissions and
" limitations under the License.
if !has( 'python3' )
finish
endif
" Boilerplate {{{
let s:save_cpo = &cpoptions
@ -27,45 +30,62 @@ EOF
endfunction
let s:enabled = vimspector#internal#state#Reset()
let s:enabled = v:null
function! vimspector#Launch() abort
if !s:enabled
function! s:Initialised() abort
return s:enabled != v:null
endfunction
function! s:Enabled() abort
if !s:Initialised()
let s:enabled = vimspector#internal#state#Reset()
endif
return s:enabled
endfunction
function! vimspector#Launch( ... ) abort
if !s:Enabled()
return
endif
py3 _vimspector_session.Start()
py3 _vimspector_session.Start( *vim.eval( 'a:000' ) )
endfunction
function! vimspector#LaunchWithSettings( settings ) abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.Start( launch_variables = vim.eval( 'a:settings' ) )
endfunction
function! vimspector#Reset() abort
if !s:enabled
function! vimspector#Reset( ... ) abort
if !s:Enabled()
return
endif
py3 _vimspector_session.Reset()
if a:0 == 0
let options = {}
else
let options = a:1
endif
py3 _vimspector_session.Reset( **vim.eval( 'options' ) )
endfunction
function! vimspector#Restart() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.Restart()
endfunction
function! vimspector#ClearBreakpoints() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.ClearBreakpoints()
endfunction
function! vimspector#ToggleBreakpoint( ... ) abort
if !s:enabled
if !s:Enabled()
return
endif
if a:0 == 0
@ -76,8 +96,43 @@ function! vimspector#ToggleBreakpoint( ... ) abort
py3 _vimspector_session.ToggleBreakpoint( vim.eval( 'options' ) )
endfunction
function! vimspector#SetLineBreakpoint( file_name, line_num, ... ) abort
if !s:Enabled()
return
endif
if a:0 == 0
let options = {}
else
let options = a:1
endif
py3 _vimspector_session.SetLineBreakpoint(
\ vim.eval( 'a:file_name' ),
\ int( vim.eval( 'a:line_num' ) ),
\ vim.eval( 'options' ) )
endfunction
function! vimspector#ClearLineBreakpoint( file_name, line_num ) abort
if !s:Enabled()
return
endif
py3 _vimspector_session.ClearLineBreakpoint(
\ vim.eval( 'a:file_name' ),
\ int( vim.eval( 'a:line_num' ) ) )
endfunction
function! vimspector#RunToCursor() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.RunTo(
\ vim.eval( "expand( '%' )" ),
\ int( vim.eval( "line( '.' )" ) ) )
endfunction
function! vimspector#AddFunctionBreakpoint( function, ... ) abort
if !s:enabled
if !s:Enabled()
return
endif
if a:0 == 0
@ -90,74 +145,120 @@ function! vimspector#AddFunctionBreakpoint( function, ... ) abort
endfunction
function! vimspector#StepOver() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.StepOver()
endfunction
function! vimspector#StepInto() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.StepInto()
endfunction
function! vimspector#StepOut() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.StepOut()
endfunction
function! vimspector#Continue() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.Continue()
endfunction
function! vimspector#Pause() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.Pause()
endfunction
function! vimspector#Stop() abort
if !s:enabled
function! vimspector#PauseContinueThread() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.Stop()
py3 _vimspector_session.PauseContinueThread()
endfunction
function! vimspector#SetCurrentThread() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.SetCurrentThread()
endfunction
function! vimspector#Stop( ... ) abort
if !s:Enabled()
return
endif
if a:0 == 0
let options = {}
else
let options = a:1
endif
py3 _vimspector_session.Stop( **vim.eval( 'options' ) )
endfunction
function! vimspector#ExpandVariable() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.ExpandVariable()
endfunction
function! vimspector#SetVariableValue( ... ) abort
if !s:Enabled()
return
endif
if a:0 == 0
py3 _vimspector_session.SetVariableValue()
else
py3 _vimspector_session.SetVariableValue( new_value = vim.eval( 'a:1' ) )
endif
endfunction
function! vimspector#DeleteWatch() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.DeleteWatch()
endfunction
function! vimspector#GoToFrame() abort
if !s:enabled
if !s:Enabled()
return
endif
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
if !s:Enabled()
return
endif
if a:0 == 0
let expr = input( 'Enter watch expression: ' )
let expr = input( 'Enter watch expression: ',
\ '',
\ 'custom,vimspector#CompleteExpr' )
else
let expr = a:1
endif
@ -170,7 +271,7 @@ function! vimspector#AddWatch( ... ) abort
endfunction
function! vimspector#AddWatchPrompt( expr ) abort
if !s:enabled
if !s:Enabled()
return
endif
stopinsert
@ -179,24 +280,24 @@ function! vimspector#AddWatchPrompt( expr ) abort
endfunction
function! vimspector#Evaluate( expr ) abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.ShowOutput( 'Console' )
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) )
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ), True )
endfunction
function! vimspector#EvaluateConsole( expr ) abort
if !s:enabled
if !s:Enabled()
return
endif
stopinsert
setlocal nomodified
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) )
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ), False )
endfunction
function! vimspector#ShowOutput( ... ) abort
if !s:enabled
if !s:Enabled()
return
endif
if a:0 == 1
@ -207,7 +308,7 @@ function! vimspector#ShowOutput( ... ) abort
endfunction
function! vimspector#ShowOutputInWindow( win_id, category ) abort
if !s:enabled
if !s:Enabled()
return
endif
py3 __import__( 'vimspector',
@ -217,21 +318,31 @@ function! vimspector#ShowOutputInWindow( win_id, category ) abort
endfunction
function! vimspector#ToggleLog() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.ToggleLog()
endfunction
function! vimspector#ListBreakpoints() abort
if !s:enabled
if !s:Enabled()
return
endif
py3 _vimspector_session.ListBreakpoints()
endfunction
function! vimspector#GetConfigurations() abort
if !s:Enabled()
return
endif
let configurations = py3eval(
\ 'list( _vimspector_session.GetConfigurations( {} )[ 1 ].keys() )'
\ . ' if _vimspector_session else []' )
return configurations
endfunction
function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort
if !s:enabled
if !s:Enabled()
return
endif
let buffers = py3eval( '_vimspector_session.GetOutputBuffers() '
@ -239,37 +350,15 @@ function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort
return join( buffers, "\n" )
endfunction
py3 <<EOF
def _vimspector_GetExprCompletions( ArgLead, prev_non_keyword_char ):
if not _vimspector_session:
return []
items = []
for candidate in _vimspector_session.GetCompletionsSync(
ArgLead,
prev_non_keyword_char ):
label = candidate.get( 'text', candidate[ 'label' ] )
start = prev_non_keyword_char - 1
if 'start' in candidate and 'length' in candidate:
start = candidate[ 'start' ]
items.append( ArgLead[ 0 : start ] + label )
return items
EOF
function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort
if !s:enabled
if !s:Enabled()
return
endif
let col = len( a:ArgLead )
let prev_non_keyword_char = match( a:ArgLead[ 0 : col - 1 ], '\k*$' ) + 1
return join( py3eval( '_vimspector_GetExprCompletions( '
return join( py3eval( '_vimspector_session.GetCommandLineCompletions( '
\ . 'vim.eval( "a:ArgLead" ), '
\ . 'int( vim.eval( "prev_non_keyword_char" ) ) )' ),
\ "\n" )
@ -390,7 +479,7 @@ function! vimspector#OmniFuncConsole( find_start, query ) abort
endfunction
function! vimspector#Install( bang, ... ) abort
if !s:enabled
if !s:Enabled()
return
endif
let prefix = vimspector#internal#state#GetAPIPrefix()
@ -402,7 +491,7 @@ function! vimspector#Install( bang, ... ) abort
endfunction
function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort
if !s:enabled
if !s:Enabled()
return
endif
return py3eval( '"\n".join('
@ -412,7 +501,7 @@ function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort
endfunction
function! vimspector#Update( bang, ... ) abort
if !s:enabled
if !s:Enabled()
return
endif
@ -425,7 +514,7 @@ function! vimspector#Update( bang, ... ) abort
endfunction
function! vimspector#AbortInstall() abort
if !s:enabled
if !s:Enabled()
return
endif
@ -434,6 +523,49 @@ function! vimspector#AbortInstall() abort
endfunction
function! vimspector#OnBufferCreated( file_name ) abort
if len( a:file_name ) == 0
return
endif
" Don't actually load up vimsepctor python in autocommands that trigger
" regularly. We'll only create the session obkect in s:Enabled()
if !s:Initialised()
return
endif
if !s:Enabled()
return
endif
py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) )
endfunction
function! vimspector#ShowEvalBalloon( is_visual ) abort
if a:is_visual
let expr = py3eval( '__import__( "vimspector", fromlist = [ "utils" ] )'
\ . '.utils.GetVisualSelection('
\ . ' int( vim.eval( "winbufnr( winnr() )" ) ) )' )
let expr = join( expr, '\n' )
else
let expr = expand( '<cexpr>' )
endif
return py3eval( '_vimspector_session.ShowEvalBalloon('
\ . ' int( vim.eval( "winnr()" ) ), "'
\ . expr
\ . '", 0 )' )
endfunction
function! vimspector#PrintDebugInfo() abort
if !s:Enabled()
return
endif
py3 _vimspector_session.PrintDebugInfo()
endfunction
" Boilerplate {{{
let &cpoptions=s:save_cpo
unlet s:save_cpo

View file

@ -19,16 +19,323 @@ let s:save_cpo = &cpoptions
set cpoptions&vim
" }}}
" Returns: py.ShowBalloon( winnr, expresssion )
function! vimspector#internal#balloon#BalloonExpr() abort
" winnr + 1 because for *no good reason* winnr is 0 based here unlike
" everywhere else
" int() because for *no good reason* winnr is a string.
return py3eval('_vimspector_session.ShowBalloon('
\ . 'int( vim.eval( "v:beval_winnr" ) ) + 1,'
\ . 'vim.eval( "v:beval_text" ) )' )
scriptencoding utf-8
let s:popup_win_id = 0
let s:nvim_border_win_id = 0
"
" tooltip dimensions
let s:min_width = 1
let s:min_height = 1
let s:max_width = 80
let s:max_height = 20
let s:is_neovim = has( 'nvim' )
" This is used as the balloonexpr in vim to show the Tooltip at the hover
" position
function! vimspector#internal#balloon#HoverTooltip() abort
return py3eval( '_vimspector_session.ShowEvalBalloon('
\ . ' int( vim.eval( "v:beval_winnr" ) ) + 1,'
\ . ' vim.eval( "v:beval_text"),'
\ . ' 1 )' )
endfunction
function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort
let body = []
if a:0 > 0
let body = a:1
endif
if s:popup_win_id != 0
call vimspector#internal#balloon#Close()
endif
if s:is_neovim
call s:CreateNeovimTooltip( body )
else
let config = {
\ 'wrap': 0,
\ 'filtermode': 'n',
\ 'maxwidth': s:max_width,
\ 'maxheight': s:max_height,
\ 'minwidth': s:min_width,
\ 'minheight': s:min_height,
\ 'scrollbar': 1,
\ 'border': [],
\ 'padding': [ 0, 1, 0, 1],
\ 'drag': 1,
\ 'resize': 1,
\ 'close': 'button',
\ 'callback': 'vimspector#internal#balloon#CloseCallback',
\ }
let config = vimspector#internal#popup#SetBorderChars( config )
if a:is_hover
let config[ 'filter' ] = 'vimspector#internal#balloon#MouseFilter'
let config[ 'mousemoved' ] = [ 0, 0, 0 ]
let s:popup_win_id = popup_beval( body, config )
else
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
endif
return s:popup_win_id
endfunction
" Filters for vim {{{
function! vimspector#internal#balloon#MouseFilter( winid, key ) abort
if a:key ==# "\<Esc>"
call vimspector#internal#balloon#Close()
return 0
endif
if index( [ "\<leftmouse>", "\<2-leftmouse>" ], a:key ) < 0
return 0
endif
let handled = 0
let mouse_coords = getmousepos()
" close the popup if mouse is clicked outside the window
if mouse_coords[ 'winid' ] != a:winid
call vimspector#internal#balloon#Close()
return 0
endif
" place the cursor according to the click
call win_execute( a:winid,
\ ':call cursor( '
\ . mouse_coords[ 'line' ]
\ . ', '
\ . mouse_coords[ 'column' ]
\ . ' )' )
" expand the variable if we got double click
if a:key ==? "\<2-leftmouse>"
call py3eval( '_vimspector_session.ExpandVariable('
\ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],'
\ . 'line_num = ' . line( '.', a:winid )
\ . ')' )
let handled = 1
endif
return handled
endfunction
function! s:MatchKey( key, candidates ) abort
for candidate in a:candidates
" If the mapping string looks like a special character, then try and
" expand it. This is... a hack. The whole thing only works if the mapping
" is a single key (anyway), and so we assume any string starting with < is a
" special key (which will be the common case) and try and map it. If it
" fails... it fails.
if candidate[ 0 ] == '<'
try
execute 'let candidate = "\' . candidate . '"'
endtry
endif
if candidate ==# a:key
return v:true
endif
endfor
return v:false
endfunction
function! vimspector#internal#balloon#CursorFilter( winid, key ) abort
let mappings = py3eval(
\ "__import__( 'vimspector',"
\." fromlist = [ 'settings' ] ).settings.Dict("
\." 'mappings' )[ 'variables' ]" )
if index( [ "\<LeftMouse>", "\<2-LeftMouse>" ], a:key ) >= 0
return vimspector#internal#balloon#MouseFilter( a:winid, a:key )
endif
if s:MatchKey( a:key, mappings.expand_collapse )
call py3eval( '_vimspector_session.ExpandVariable('
\ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],'
\ . 'line_num = ' . line( '.', a:winid )
\ . ')' )
return 1
elseif s:MatchKey( a:key, mappings.set_value )
call py3eval( '_vimspector_session.SetVariableValue('
\ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],'
\ . 'line_num = ' . line( '.', a:winid )
\ . ')' )
return 1
endif
return popup_filter_menu( a:winid, a:key )
endfunction
" }}}
" Closing {{{
function! vimspector#internal#balloon#CloseCallback( ... ) abort
let s:popup_win_id = 0
let s:nvim_border_win_id = 0
return py3eval( '_vimspector_session.CleanUpTooltip()' )
endfunction
function! vimspector#internal#balloon#Close() abort
if s:popup_win_id == 0
return
endif
if s:is_neovim
call nvim_win_close( s:popup_win_id, v:true )
call nvim_win_close( s:nvim_border_win_id, v:true )
call vimspector#internal#balloon#CloseCallback()
else
call popup_close(s:popup_win_id)
endif
endfunction
" }}}
" Neovim pollyfill {{{
function! vimspector#internal#balloon#ResizeTooltip() abort
if !s:is_neovim
" Vim does this for us
return
endif
if s:popup_win_id <= 0 || s:nvim_border_win_id <= 0
" nothing to resize
return
endif
noautocmd call win_gotoid( s:popup_win_id )
let buf_lines = getline( 1, '$' )
let width = s:min_width
let height = min( [ max( [ s:min_height, len( buf_lines ) ] ),
\ s:max_height ] )
" calculate the longest line
for l in buf_lines
let width = max( [ width, len( l ) ] )
endfor
let width = min( [ width, s:max_width ] )
let opts = {
\ 'width': width,
\ 'height': height,
\ }
" resize the content window
call nvim_win_set_config( s:popup_win_id, opts )
" resize the border window
let opts[ 'width' ] = width + 4
let opts[ 'height' ] = height + 2
call nvim_win_set_config( s:nvim_border_win_id, opts )
call nvim_buf_set_lines( nvim_win_get_buf( s:nvim_border_win_id ),
\ 0,
\ -1,
\ v:true,
\ s:GenerateBorder( width, height ) )
endfunction
" neovim doesn't have the border support, so we have to make our own.
" FIXME: This will likely break if the user has `ambiwidth=2`
function! s:GenerateBorder( width, height ) abort
let top = '╭' . repeat('─',a:width + 2) . '╮'
let mid = '│' . repeat(' ',a:width + 2) . '│'
let bot = '╰' . repeat('─',a:width + 2) . '╯'
let lines = [ top ] + repeat( [ mid ], a:height ) + [ bot ]
return lines
endfunction
function! s:CreateNeovimTooltip( body ) abort
" generate border for the float window by creating a background buffer and
" overlaying the content buffer
" see https://github.com/neovim/neovim/issues/9718#issuecomment-546603628
let buf_id = nvim_create_buf( v:false, v:true )
call nvim_buf_set_lines( buf_id,
\ 0,
\ -1,
\ v:true,
\ s:GenerateBorder( s:max_width, s:max_height ) )
" default the dimensions initially, then we'll calculate the real size and
" resize it.
let opts = {
\ 'relative': 'cursor',
\ 'width': s:max_width + 2,
\ 'height': s:max_height + 2,
\ 'col': 0,
\ 'row': 1,
\ 'anchor': 'NW',
\ 'style': 'minimal'
\ }
" this is the border window
let s:nvim_border_win_id = nvim_open_win( buf_id, 0, opts )
call nvim_win_set_option( s:nvim_border_win_id, 'signcolumn', 'no' )
call nvim_win_set_option( s:nvim_border_win_id, 'relativenumber', v:false )
call nvim_win_set_option( s:nvim_border_win_id, 'number', v:false )
" when calculating where to display the content window, we need to account
" for the border
let opts.row += 1
let opts.height -= 2
let opts.col += 2
let opts.width -= 4
" create the content window
let buf_id = nvim_create_buf( v:false, v:true )
call nvim_buf_set_lines( buf_id, 0, -1, v:true, a:body )
call nvim_buf_set_option( buf_id, 'modifiable', v:false )
let s:popup_win_id = nvim_open_win( buf_id, v:false, opts )
" Apparently none of these work, when 'style' is 'minimal'
call nvim_win_set_option( s:popup_win_id, 'wrap', v:false )
call nvim_win_set_option( s:popup_win_id, 'cursorline', v:true )
call nvim_win_set_option( s:popup_win_id, 'signcolumn', 'no' )
call nvim_win_set_option( s:popup_win_id, 'relativenumber', v:false )
call nvim_win_set_option( s:popup_win_id, 'number', v:false )
" Move the cursor into the popup window, as this is the only way we can
" interract with the popup in neovim
noautocmd call win_gotoid( s:popup_win_id )
nnoremap <silent> <buffer> <Esc> <cmd>quit<CR>
call py3eval( "__import__( 'vimspector', "
\." fromlist = [ 'variables' ] )."
\.' variables.AddExpandMappings()' )
" Close the popup whenever we leave this window
augroup vimspector#internal#balloon#nvim_float
autocmd!
autocmd WinLeave <buffer>
\ :call vimspector#internal#balloon#Close()
\ | autocmd! vimspector#internal#balloon#nvim_float
augroup END
call vimspector#internal#balloon#ResizeTooltip()
endfunction
" }}}
" Boilerplate {{{
let &cpoptions=s:save_cpo
unlet s:save_cpo

View file

@ -62,7 +62,7 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
\ )
endif
let l:addr = get( a:config, 'host', 'localhost' ) . ':' . a:config[ 'port' ]
let l:addr = get( a:config, 'host', '127.0.0.1' ) . ':' . a:config[ 'port' ]
echo 'Connecting to ' . l:addr . '... (waiting fo up to 10 seconds)'
let s:ch = ch_open( l:addr,
@ -94,34 +94,45 @@ _vimspector_session.OnRequestTimeout( vim.eval( 'a:id' ) )
EOF
endfunction
function! s:KillJob() abort
if exists( 's:job' )
if job_status( s:job ) ==# 'run'
call job_stop( s:job, 'kill' )
endif
unlet s:job
sleep 500m
endif
endfunction
function! vimspector#internal#channel#StopDebugSession() abort
if exists( 's:ch' ) && ch_status( s:ch ) ==# 'open'
if exists( 's:job' )
" We started the job, so we need to kill it and wait to read all the data
" from the socket
if job_status( s:job ) ==# 'run'
call job_stop( s:job, 'term' )
endif
while job_status( s:job ) ==# 'run'
call job_stop( s:job, 'kill' )
endwhile
unlet s:job
if exists( 's:ch' ) && count( [ 'closed', 'fail' ], ch_status( s:ch ) ) == 0
" We're going to block on this channel reading, then manually call the
" close callback, so remove the automatic close callback to avoid tricky
" re-entrancy
call ch_setoptions( s:ch, { 'close_cb': '' } )
endif
elseif exists( 's:ch' ) &&
\ count( [ 'closed', 'fail' ], ch_status( s:ch ) ) == 0
" channel is open, close it and trigger the callback. The callback is _not_
" triggered when manually calling ch_close. if we get here and the channel
" is not open, then we there is a _OnClose callback waiting for us, so do
" nothing.
call ch_close( s:ch )
while ch_status( s:ch ) ==# 'buffered'
let data = ch_read( s:ch, {'timeout': 0} )
if data == ''
continue
endif
call s:_OnServerData( s:ch, data )
endwhile
call s:_OnClose( s:ch )
endif
call s:KillJob()
" block until we've read all data from the socket and handled it.
while count( [ 'open', 'buffered' ], ch_status( s:ch ) ) == 1
let data = ch_read( s:ch, { 'timeout': 10 } )
call s:_OnServerData( s:ch, data )
endwhile
call s:_OnClose( s:ch )
endfunction
function! vimspector#internal#channel#Reset() abort

View file

@ -66,7 +66,7 @@ function! vimspector#internal#neochannel#StartDebugSession( config ) abort
endtry
endif
let l:addr = get( a:config, 'host', 'localhost' ) . ':' . a:config[ 'port' ]
let l:addr = get( a:config, 'host', '127.0.0.1' ) . ':' . a:config[ 'port' ]
let attempt = 1
while attempt <= 10

View file

@ -159,15 +159,16 @@ function! s:_OnCommandEvent( category, id, data, event ) abort
call setbufvar( buffer, '&modified', 0 )
endtry
" if the buffer is visible, scroll it
" if the buffer is visible, scroll it, but don't allow autocommands to fire,
" as this may close the current window!
let w = bufwinnr( buffer )
if w > 0
let cw = winnr()
try
execute w . 'wincmd w'
normal! Gz-
noautocmd execute w . 'wincmd w'
noautocmd normal! Gz-
finally
execute cw . 'wincmd w'
noautocmd execute cw . 'wincmd w'
endtry
endif
elseif a:event ==# 'exit'

View file

@ -80,6 +80,56 @@ function! vimspector#internal#neopopup#HideSplash( id ) abort
unlet s:db[ a:id ]
endfunction
function! vimspector#internal#neopopup#Confirm( confirm_id,
\ text,
\ options,
\ default_value,
\ keys ) abort
" Neovim doesn't have an equivalent of popup_dialog, and it's way too much
" effort to write one, so we just use confirm()...
" Annoyingly we can't use confirm() here because for some reason it doesn't
" render properly in a channel callback. So we use input() and mimic dialog
" behaviour.
let prompt = a:text
for opt in a:options
let prompt .= ' ' . opt
endfor
let prompt .= ': '
try
let result = input( prompt, a:keys[ a:default_value - 1 ] )
catch /.*/
let result = -1
endtry
" Map the results to what the vim popup stuff would return (s:ConfirmCallback
" in popup.vim), i.e.:
" - 1-based index of selected item, or
" - -1 or 0 for cancellation
if result == ''
" User pressed ESC/ctrl-c
let result = -1
else
let index = 1
for k in a:keys
if k ==? result
let result = index
break
endif
let index += 1
endfor
if index > len( a:keys )
let result = -1
endif
endif
py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback(
\ int( vim.eval( 'a:confirm_id' ) ),
\ int( vim.eval( 'result' ) ) )
endfunction
" Boilerplate {{{
let &cpoptions=s:save_cpo
unlet s:save_cpo

View file

@ -12,6 +12,7 @@
" 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.
scriptencoding utf-8
" Boilerplate {{{
@ -32,6 +33,113 @@ function! vimspector#internal#popup#HideSplash( id ) abort
call popup_hide( a:id )
endfunction
let s:current_selection = 0
let s:selections = []
let s:text = []
function! s:UpdatePopup( id ) abort
let buf = copy( s:text )
call extend( buf, s:DrawButtons() )
call popup_settext( a:id, buf )
endfunction
function! s:ConfirmKeyFilter( keys, id, key ) abort
if a:key ==# "\<CR>"
call popup_close( a:id, s:current_selection + 1 )
return 1
elseif index( [ "\<Tab>", "\<Right>" ], a:key ) >= 0
let s:current_selection = ( s:current_selection + 1 ) % len( s:selections )
call s:UpdatePopup( a:id )
return 1
elseif index( [ "\<S-Tab>", "\<Left>" ], a:key ) >= 0
let s:current_selection = s:current_selection == 0
\ ? len( s:selections ) - 1: s:current_selection - 1
call s:UpdatePopup( a:id )
return 1
elseif a:key ==# "\<Esc>" || a:key ==# "\<C-c>"
call popup_close( a:id, -1 )
return 1
endif
let index = 1
for key in a:keys
if a:key ==? key
call popup_close( a:id, index )
return 1
endif
let index += 1
endfor
endfunction
function! s:ConfirmCallback( confirm_id, id, result ) abort
py3 __import__( 'vimspector', fromlist = [ 'utils' ] ).utils.ConfirmCallback(
\ int( vim.eval( 'a:confirm_id' ) ),
\ int( vim.eval( 'a:result' ) ) )
endfunction
function! s:SelectionPosition( idx ) abort
return a:idx == 0 ? 0 : len( join( s:selections[ : a:idx - 1 ], ' ' ) ) + 1
endfunction
function! s:DrawButtons() abort
return [ {
\ 'text': join( s:selections, ' ' ),
\ 'props': [
\ {
\ 'col': s:SelectionPosition( s:current_selection ) + 1,
\ 'length': len( s:selections[ s:current_selection ] ),
\ 'type': 'VimspectorSelectedItem'
\ },
\ ]
\ } ]
endfunction
function! vimspector#internal#popup#Confirm(
\ confirm_id,
\ text,
\ options,
\ default_value,
\ keys ) abort
silent! call prop_type_add( 'VimspectorSelectedItem', {
\ 'highlight': 'PMenuSel'
\ } )
let lines = split( a:text, "\n", v:true )
let buf = []
for line in lines
call add( buf, { 'text': line, 'props': [] } )
endfor
call add( buf, { 'text': '', 'props': [] } )
let s:selections = a:options
let s:current_selection = ( a:default_value - 1 )
let s:text = copy( buf )
call extend( buf, s:DrawButtons() )
let config = {
\ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ),
\ 'filter': function( 's:ConfirmKeyFilter', [ a:keys ] ),
\ 'mapping': v:false,
\ }
let config = vimspector#internal#popup#SetBorderChars( config )
return popup_dialog( buf, config )
endfunction
function! vimspector#internal#popup#SetBorderChars( config ) abort
" When ambiwidth is single, use prettier characters for the border. This
" would look silly when ambiwidth is double.
if &ambiwidth ==# 'single' && &encoding ==? 'utf-8'
let a:config[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ]
endif
return a:config
endfunction
" Boilerplate {{{
let &cpoptions=s:save_cpo
unlet s:save_cpo

View file

@ -34,6 +34,7 @@ function! vimspector#internal#state#Reset() abort
catch /.*/
echohl WarningMsg
echom 'Exception while loading vimspector:' v:exception
echom 'From:' v:throwpoint
echom 'Vimspector unavailable: Requires Vim compiled with Python 3.6'
echohl None
return v:false

1085
doc/vimspector-ref.txt Normal file

File diff suppressed because it is too large Load diff

2394
doc/vimspector.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -28,3 +28,5 @@ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
# Performance-booster for watching directories on Windows
gem "wdm", "~> 0.1.0" if Gem.win_platform?
gem "webrick", "~> 1.7"

View file

@ -1,13 +1,13 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.3.2)
activesupport (6.0.3.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
addressable (2.7.0)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
coffee-script (2.4.1)
coffee-script-source
@ -16,46 +16,49 @@ GEM
colorator (1.1.0)
commonmarker (0.17.13)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.7)
dnsruby (1.61.4)
concurrent-ruby (1.1.8)
dnsruby (1.61.5)
simpleidn (~> 0.1)
em-websocket (0.5.1)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
ethon (0.12.0)
ffi (>= 1.3.0)
eventmachine (1.2.7)
execjs (2.7.0)
faraday (1.0.1)
faraday (1.3.0)
faraday-net_http (~> 1.0)
multipart-post (>= 1.2, < 3)
ffi (1.13.1)
ruby2_keywords
faraday-net_http (1.0.1)
ffi (1.15.0)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (207)
github-pages-health-check (= 1.16.1)
github-pages (214)
github-pages-health-check (= 1.17.0)
jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.13.0)
jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
jekyll-mentions (= 1.5.1)
jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0)
jekyll-redirect-from (= 0.15.0)
jekyll-redirect-from (= 0.16.0)
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.1)
jekyll-remote-theme (= 0.4.3)
jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.6.1)
jekyll-seo-tag (= 2.7.1)
jekyll-sitemap (= 1.4.0)
jekyll-swiss (= 1.0.0)
jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.1)
jekyll-theme-hacker (= 0.1.2)
jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1)
@ -66,20 +69,20 @@ GEM
jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.11.1)
kramdown (= 2.3.0)
jemoji (= 0.12.0)
kramdown (= 2.3.1)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.10.4, < 2.0)
rouge (= 3.19.0)
rouge (= 3.26.0)
terminal-table (~> 1.4)
github-pages-health-check (1.16.1)
github-pages-health-check (1.17.0)
addressable (~> 2.3)
dnsruby (~> 1.60)
octokit (~> 4.0)
public_suffix (~> 3.0)
public_suffix (>= 2.0.2, < 5.0)
typhoeus (~> 1.3)
html-pipeline (2.14.0)
activesupport (>= 2)
@ -114,14 +117,14 @@ GEM
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
jekyll-feed (0.13.0)
jekyll-feed (0.15.1)
jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.5.1)
jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2)
@ -129,18 +132,19 @@ GEM
jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
jekyll-redirect-from (0.15.0)
jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-remote-theme (0.4.1)
jekyll-remote-theme (0.4.3)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
rubyzip (>= 1.3.0)
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
jekyll-seo-tag (2.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-seo-tag (2.7.1)
jekyll (>= 3.8, < 5.0)
jekyll-sitemap (1.4.0)
jekyll (>= 3.7, < 5.0)
jekyll-swiss (1.0.0)
@ -153,8 +157,8 @@ GEM
jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.1)
jekyll (~> 3.5)
jekyll-theme-hacker (0.1.2)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
@ -188,41 +192,44 @@ GEM
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
jemoji (0.11.1)
jemoji (0.12.0)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
kramdown (2.3.0)
kramdown (2.3.1)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.2.1)
listen (3.5.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.4.0)
mini_portile2 (2.5.1)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.1)
minitest (5.14.4)
multipart-post (2.1.1)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
octokit (4.18.0)
nokogiri (1.11.5)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
octokit (4.20.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (3.1.1)
public_suffix (4.0.6)
racc (1.5.2)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.4)
rouge (3.19.0)
ruby-enum (0.8.0)
rexml (3.2.5)
rouge (3.26.0)
ruby-enum (0.9.0)
i18n
ruby2_keywords (0.0.4)
rubyzip (2.3.0)
safe_yaml (1.0.5)
sass (3.7.4)
@ -233,20 +240,21 @@ GEM
sawyer (0.8.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
simpleidn (0.1.1)
simpleidn (0.2.1)
unf (~> 0.1.4)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.7)
tzinfo (1.2.9)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
zeitwerk (2.4.0)
webrick (1.7.0)
zeitwerk (2.4.2)
PLATFORMS
ruby
@ -256,6 +264,7 @@ DEPENDENCIES
jekyll-feed (~> 0.6)
minima (~> 2.0)
tzinfo-data
webrick (~> 1.7)
BUNDLED WITH
2.0.2
2.2.3

View file

@ -1,7 +1,7 @@
To update/install:
gem install bundler
bundle install
bundle install --path vendor/bundle
To run a local server/test the build

View file

@ -12,7 +12,8 @@ for Vimspector.
* [Debug profile configuration](#debug-profile-configuration)
* [Replacements and variables](#replacements-and-variables)
* [The splat operator](#the-splat-operator)
* [Default values](#default-values)
* [Default values](#default-values)
* [Coercing Types](#coercing-types)
* [Configuration Format](#configuration-format)
* [Files and locations](#files-and-locations)
* [Adapter configurations](#adapter-configurations)
@ -20,7 +21,7 @@ for Vimspector.
* [Configuration selection](#configuration-selection)
* [Specifying a default configuration](#specifying-a-default-configuration)
* [Preventing automatic selection](#preventing-automatic-selection)
* [Exception breakpionts](#exception-breakpionts)
* [Exception Breakpoints](#exception-breakpoints)
* [Predefined Variables](#predefined-variables)
* [Remote Debugging Support](#remote-debugging-support)
* [Python (debugpy) Example](#python-debugpy-example)
@ -29,7 +30,7 @@ for Vimspector.
* [Appendix: Configuration file format](#appendix-configuration-file-format)
* [Appendix: Editor configuration](#appendix-editor-configuration)
<!-- Added by: ben, at: Fri 31 Jul 2020 22:13:39 BST -->
<!-- Added by: ben, at: Thu 13 Aug 2020 17:42:11 BST -->
<!--te-->
@ -164,7 +165,7 @@ the following variable substitutions:
the shell command. Note these variables can be supplied by both the debug and
adapter configurations and can be either static strings or shell commands.
### The splat operator
#### The splat operator
Often we want to create a single `.vimspector.json` entry which encompasses many
use cases, as it is tedious to write every use case/start up option in JSON.
@ -205,7 +206,7 @@ You can also combine with static values:
This would yield the intuitive result:
`[ "First", "one", "two three", "four", "Last" ]`
### Default values
#### Default values
You can specify replacements with default values. In this case if the user has
not specified a value, they are prompted but with the default value
@ -236,7 +237,7 @@ the closing `}`. For example, the is a common and useful case:
This will prompt the user to specify `script`, but it will default to the path
to the current file.
### Coercing Types
#### Coercing Types
Sometimes, you want to provide an option for a boolean parameter, or want to
allow the user to specify more than just strings. Vimspector allows you to do
@ -270,7 +271,7 @@ JSON value `true`, and the suffix is stripped fom the key, resulting in the
following:
```json
"stopOnEntry#json": true
"stopOnEntry": true
```
Which is what we need.
@ -282,7 +283,7 @@ can force Vimspector to treat the value as a string by appending `#s`, as in:
"unlikelyKeyName#json#s": "this is a string, not JSON data"
```
#### Advanced usage
***Advanced usage:***
The most common usage for this is for number and bool types, but it works for
objects too. If you want to be able to specify a whole object (e.g. a whole
@ -632,19 +633,26 @@ Vimspector then orchestrates the various tools to set you up.
// Command to launch the debugee and attach the debugger;
// %CMD% replaced with the remote-cmdLine configured in the launch
// configuration. (mandatory)
"launchCommmand": [
"python", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"runCommand": [
"python", "-m", "debugpy",
"--listen", "0.0.0.0:${port}",
"--wait-for-client",
"%CMD%"
]
// Optional alternative to launchCommmand (if you need to run multiple
// Optional alternative to runCommand (if you need to run multiple
// commands)
// "launchCommmands": [
// "runCommands": [
// [ /* first command */ ],
// [ /* second command */ ]
// ]
}
// optional delay to wait after running runCommand(s). This is often
// needed because of the way docker handles TCP, or if you're using some
// wrapper (e.g. to start the JVM)
// "delay": "1000m" // format as per :help sleep
},
"attach": {
"remote": {
@ -684,6 +692,10 @@ Vimspector then orchestrates the various tools to set you up.
// "args": [ "-o", "StrictHostKeyChecking=no" ]
// },
}
// optional delay to wait after running runCommand(s). This is often
// needed because of the way docker handles TCP, or if you're using some
// wrapper (e.g. to start the JVM)
// "delay": "1000m" // format as per :help sleep
}
}
},
@ -710,7 +722,7 @@ Vimspector then orchestrates the various tools to set you up.
"variables": {
// Just an example of how to specify a variable manually rather than
// vimspector asking for input from the user
"ServiceName": "${fileBasenameNoExtention}"
"ServiceName": "${fileBasenameNoExtension}"
},
"adapter": "python-remote",
@ -753,7 +765,7 @@ and have to tell cpptools a few more options.
"remote": {
"host": "${host}",
"account": "${account}",
"launchCommmand": [
"runCommand": [
"gdbserver",
"--once",
"--no-startup-with-shell",
@ -837,19 +849,25 @@ port.
// Command to launch the debugee and attach the debugger;
// %CMD% replaced with the remote-cmdLine configured in the launch
// configuration. (mandatory)
"launchCommmand": [
"python", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"runCommand": [
"python", "-m", "debugpy",
"--listen", "0.0.0.0:${port}",
"--wait-for-client",
"%CMD%"
]
// Optional alternative to launchCommmand (if you need to run multiple
// Optional alternative to runCommand (if you need to run multiple
// commands)
// "launchCommmands": [
// "runCommands": [
// [ /* first command */ ],
// [ /* second command */ ]
// ]
}
// optional delay to wait after running runCommand(s). This is often
// needed because of the way docker handles TCP
"delay": "1000m" // format as per :help sleep
},
"attach": {
"remote": {
@ -885,6 +903,11 @@ port.
// ]
}
// optional delay to wait after running runCommand(s). This is often
// needed because of the way docker handles TCP, or if you're using some
// wrapper (e.g. to start the JVM)
"delay": "1000m" // format as per :help sleep
}
}
},

View file

@ -38,11 +38,144 @@
]
}
},
"adapter-common": {
"adapter-launchattach": {
"properties": {
"launch": {
"allOf": [
{ "$ref": "#/definitions/adapter-remote" },
{
"properties": {
"delay": {
"type": "string",
"description": "A time in the format understood by :help :sleep to wait after running the attachCommand(s)"
}
}
}
]
},
"attach": {
"allOf": [
{ "$ref": "#/definitions/adapter-remote" },
{
"type": "object",
"required": [ "pidSelect" ],
"properties": {
"pidSelect": {
"enum": [ "ask", "none" ]
},
"pidProperty": {
"type": "string",
"description": "The launch config property which the PID should be injected into. Required when 'pidSelect' is 'ask'."
},
"delay": {
"type": "string",
"description": "A time in the format understood by :help :sleep to wait after running the attachCommand(s)"
}
}
}
]
}
}
},
"adapter-remote": {
"type": "object",
"properties": {
"remote": {
"type": "object",
"description": "Configures how Vimspector will marshal remote debugging requests. When remote debugging, Vimspector will either ssh to 'account'@'host' or docker exec -it to 'container' and run 'pidCommand', 'attachCommands', 'runCommands', etc. based on the 'remote-command' option in the debug configuration. If 'remote-command' is 'launch', it runs 'runCommand(s)', otherwise (it's 'attach') vimspector runs 'pidCommand', followed by 'attachCommand(s)'.Then it starts up the debug adapter with the debug configuration as normal. Usually this is configured with an 'attach' request (whether we remotely 'launched' or not). Once the initialization exchange is complete, Vimspector runs the optional 'initCompleteCommand' which can be used to force the application to break, e.g. by sending it SIGINT. This is required on some platforms which have buggy gdbservers (for example)",
"allOf": [
{
"oneOf": [
{ "required": [ "host" ] },
{ "required": [ "container" ] }
]
},
{
"properties": {
"account": {
"type": "string",
"description": "Remote account name used when ssh'ing. Defaults to the current user account."
},
"host": {
"type": "string",
"description": "Name of the remote host to connect to (via passwordless SSH)."
},
"container": {
"type": "string",
"description": "Name or container id of the docker run container to connect to (via docker exec). Note the container must already be running (Vimspector will not start it) and it must have the port forwarded to the host if subsequently connecting via a port (for example <tt>docker run -p 8765:8765 -it simple_python</tt>)."
}
}
},
{
"oneOf": [
{
"allOf": [
{
"oneOf": [
{ "required": [ "attachCommand" ] },
{ "required": [ "attachCommands" ] }
]
},
{
"properties": {
"initCompleteCommand": {
"type": "array",
"items": { "type": "string" },
"description": "For remote-attach. Remote command to execute after initialization of the debug adapter. Can be used to work around buggy attach behaviour on certain platforms (advanced usage). Can contain the special token %PID% which is replaced with the PID returned by 'pidCommand'"
},
"pidCommand": {
"type": "array",
"items": { "type": "string" },
"description": "Required for remote-attach. Remote command to execute to return the PID to attach to."
},
"attachCommands": {
"type": [ "array" ],
"items": { "type": "array", "items": { "type": "string" } },
"description": "For remote-attach. List of commands to execute remotely to set up the attach. Can contain the special token %PID% which is replaced with the PID returned by the remote 'pidCommand'."
},
"attachCommand": {
"type": "array",
"items": { "type": "string" },
"description": "A single command to execute for remote-attach. Like attachCommands but for a single command. If attachCommands is supplied, this is not used."
}
}
}
]
},
{
"allOf": [
{
"oneOf": [
{ "required": [ "runCommand" ] },
{ "required": [ "runCommands" ] }
]
},
{
"properties": {
"runCommands": {
"type": [ "array" ],
"items": { "type": "array", "items": { "type": "string" } },
"description": "For remote-launch. List of commands to execute remotely to set up the launch. An entry in the array can be the special token '%CMD%' which is replaced with the evaluated 'remote-cmdLine' value in the debug configuration. This is useful to parameterize launcging remotely under something like gdbserver."
},
"runCommand": {
"type": "array",
"items": { "type": "string" },
"description": "A single command to execute for remote-launch. Like runCommands but for a single command."
}
}
}
]
}
]
}
]
}
}
},
"adapter": {
"allOf": [
{ "type": "object" },
{ "$ref": "#/definitions/variables" },
{ "$ref": "#/definitions/adapter-remote" },
{ "$ref": "#/definitions/adapter-attach" },
{
"properties": {
"name": {
@ -54,136 +187,30 @@
"description": "Base debug configuration. Can be used to set default values for all debug configurations. When reading individual debug configurations from 'configurations', those configurations are merged with this object. Definitions in the debug configuration override anything in this object. Typical usage for this is to set the 'type' parameter, which some debug adapters are very picky about, or to set e.g. the path to an underlying debugger."
}
}
}
]
},
"adapter-attach": {
"properties": {
"attach": {
"type": "object",
"required": [ "pidSelect" ],
"properties": {
"pidSelect": {
"enum": [ "ask", "none" ]
},
"pidProperty": {
"type": "string",
"description": "The launch config property which the PID should be injected into. Required when 'pidSelect' is 'ask'."
}
}
}
}
},
"adapter-remote": {
"properties": {
"remote": {
"type": "object",
"oneOf": [
{
"required": [
"host"
]
},
{
"required": [
"container"
]
}
],
"description": "Configures how Vimspector will marshal remote debugging requests. When remote debugging, Vimspector will either ssh to 'account'@'host' or docker exec -it to 'container' and run 'pidCommand', 'attachCommands', 'runCommands', etc. based on the 'remote-command' option in the debug configuration. If 'remote-command' is 'launch', it runs 'runCommand(s)', otherwise (it's 'attach') vimspector runs 'pidCommand', followed by 'attachCommand(s)'.Then it starts up the debug adapter with the debug configuration as normal. Usually this is configured with an 'attach' request (whether we remotely 'launched' or not). Once the initialization exchange is complete, Vimspector runs the optional 'initCompleteCommand' which can be used to force the application to break, e.g. by sending it SIGINT. This is required on some platforms which have buggy gdbservers (for example)",
"properties": {
"account": {
"type": "string",
"description": "Remote account name used when ssh'ing. Defaults to the current user account."
},
"host": {
"type": "string",
"description": "Name of the remote host to connect to (via passwordless SSH)."
},
"container": {
"type": "string",
"description": "Name or container id of the docker run container to connect to (via docker exec -it)."
},
"pidCommand": {
"type": "array",
"items": { "type": "string" },
"description": "Required for remote-attach. Remote command to execute to return the PID to attach to."
},
"initCompleteCommand": {
"type": "array",
"items": { "type": "string" },
"description": "For remote-attach. Remote command to execute after initialization of the debug adapter. Can be used to work around buggy attach behaviour on certain platforms (advanced usage). Can contain the special token %PID% which is replaced with the PID returned by 'pidCommand'"
},
"attachCommands": {
"type": [ "array" ],
"items": { "type": "array", "items": { "type": "string" } },
"description": "For remote-attach. List of commands to execute remotely to set up the attach. Can contain the special token %PID% which is replaced with the PID returned by the remote 'pidCommand'."
},
"attachCommand": {
"type": "array",
"items": { "type": "string" },
"description": "A single command to execute for remote-attach. Like attachCommands but for a single command. If attachCommands is supplied, this is not used."
},
"runCommands": {
"type": [ "array" ],
"items": { "type": "array", "items": { "type": "string" } },
"description": "For remote-launch. List of commands to execute remotely to set up the launch. An entry in the array can be the special token '%CMD%' which is replaced with the evaluated 'remote-cmdLine' value in the debug configuration. This is useful to parameterize launcging remotely under something like gdbserver."
},
"runCommand": {
"type": "array",
"items": { "type": "string" },
"description": "A single command to execute for remote-launch. Like runCommands but for a single command."
}
}
}
}
},
"adapter": {
"oneOf": [
},
{ "$ref": "#/definitions/adapter-launchattach" },
{
"allOf": [
{ "$ref": "#/definitions/adapter-common" },
{
"required": [ "port" ],
"properties": {
"port": {
"oneOf": [
{
"type": "string",
"enum": [ "ask" ]
},
{
"type": "integer"
}
],
"description": "If supplied, indicates that a socket connection should be made to this port on 'localhost'. If the value is 'ask', then the user is asked to enter the port number to connect to."
}
}
}
"anyOf": [
{ "required": [ "command" ] },
{ "required": [ "port" ] },
{ "required": [ "command", "port" ] }
]
},
{
"allOf": [
{ "$ref": "#/definitions/adapter-common" },
{
"required": [ "command" ],
"properties": {
"command": {
"type": [ "string", "array" ],
"description": "Command line to execute the debug adapter.",
"items": { "type": "string" }
},
"env": {
"type": "object",
"description": "Name/value pairs to set in the environment when starting the adapter."
},
"cwd": {
"type": "string",
"description": "Directory from which to start the adapter. Defaults to the working directory of the window on launch"
}
}
"properties": {
"host": {
"type": "string",
"default": "127.0.0.1",
"description": "Connect to this host in multi-session mode"
},
"port": {
"oneOf": [
{ "type": "string" },
{ "type": "integer" }
],
"description": "If supplied, indicates that a socket connection should be made to this port on 'host'. If the value is 'ask', then the user is asked to enter the port number to connect to."
}
]
}
}
]
}

View file

@ -114,32 +114,35 @@ parser.add_argument( '--sudo',
done_languages = set()
for name, gadget in gadgets.GADGETS.items():
lang = gadget[ 'language' ]
if lang in done_languages:
continue
langs = gadget[ 'language' ]
if not isinstance( langs, list ):
langs = [ langs ]
for lang in langs:
if lang in done_languages:
continue
done_languages.add( lang )
if not gadget.get( 'enabled', True ):
parser.add_argument(
'--force-enable-' + lang,
action = 'store_true',
help = 'Install the unsupported {} debug adapter for {} support'.format(
name,
lang ) )
continue
done_languages.add( lang )
if not gadget.get( 'enabled', True ):
parser.add_argument(
'--force-enable-' + lang,
'--enable-' + lang,
action = 'store_true',
help = 'Install the unsupported {} debug adapter for {} support'.format(
help = 'Install the {} debug adapter for {} support'.format(
name,
lang ) )
continue
parser.add_argument(
'--enable-' + lang,
action = 'store_true',
help = 'Install the {} debug adapter for {} support'.format(
name,
lang ) )
parser.add_argument(
'--disable-' + lang,
action = 'store_true',
help = "Don't install the {} debug adapter for {} support "
'(when supplying --all)'.format( name, lang ) )
parser.add_argument(
'--disable-' + lang,
action = 'store_true',
help = "Don't install the {} debug adapter for {} support "
'(when supplying --all)'.format( name, lang ) )
parser.add_argument(
"--no-check-certificate",
@ -182,15 +185,25 @@ all_adapters = installer.ReadAdapters(
manifest = installer.Manifest()
for name, gadget in gadgets.GADGETS.items():
if not gadget.get( 'enabled', True ):
if ( not args.force_all
and not getattr( args, 'force_enable_' + gadget[ 'language' ] ) ):
continue
else:
if not args.all and not getattr( args, 'enable_' + gadget[ 'language' ] ):
continue
if getattr( args, 'disable_' + gadget[ 'language' ] ):
continue
langs = gadget[ 'language' ]
if not isinstance( langs, list ):
langs = [ langs ]
skip = 0
for lang in langs:
if not gadget.get( 'enabled', True ):
if ( not args.force_all
and not getattr( args, 'force_enable_' + lang ) ):
skip = skip + 1
continue
else:
if not args.all and not getattr( args, 'enable_' + lang ):
skip = skip + 1
continue
if getattr( args, 'disable_' + lang ):
skip = skip + 1
continue
if skip == len( langs ):
continue
if not args.upgrade:
manifest.Clear( name )

View file

@ -13,6 +13,13 @@
" See the License for the specific language governing permissions and
" limitations under the License.
if !has( 'python3' )
echohl WarningMsg
echom 'Vimspector unavailable: Requires Vim compiled with +python3'
echohl None
finish
endif
" Boilerplate {{{
let s:save_cpo = &cpoptions
set cpoptions&vim
@ -28,11 +35,6 @@ if exists( 'g:loaded_vimpector' )
endif
"}}}
" TODO:
" - Check Vim version (for jobs)
" - Check python support
" - Add commands/mappings/menus?
let g:loaded_vimpector = 1
let g:vimspector_home = expand( '<sfile>:p:h:h' )
@ -40,6 +42,8 @@ let s:mappings = get( g:, 'vimspector_enable_mappings', '' )
nnoremap <silent> <Plug>VimspectorContinue
\ :<c-u>call vimspector#Continue()<CR>
nnoremap <silent> <Plug>VimspectorLaunch
\ :<c-u>call vimspector#Launch( v:true )<CR>
nnoremap <silent> <Plug>VimspectorStop
\ :<c-u>call vimspector#Stop()<CR>
nnoremap <silent> <Plug>VimspectorRestart
@ -62,6 +66,21 @@ nnoremap <silent> <Plug>VimspectorStepInto
nnoremap <silent> <Plug>VimspectorStepOut
\ :<c-u>call vimspector#StepOut()<CR>
nnoremap <silent> <Plug>VimspectorRunToCursor
\ :<c-u>call vimspector#RunToCursor()<CR>
" Eval for normal mode
nnoremap <silent> <Plug>VimspectorBalloonEval
\ :<c-u>call vimspector#ShowEvalBalloon( 0 )<CR>
" And for visual modes
xnoremap <silent> <Plug>VimspectorBalloonEval
\ :<c-u>call vimspector#ShowEvalBalloon( 1 )<CR>
nnoremap <silent> <Plug>VimspectorUpFrame
\ :<c-u>call vimspector#UpFrame()<CR>
nnoremap <silent> <Plug>VimspectorDownFrame
\ :<c-u>call vimspector#DownFrame()<CR>
if s:mappings ==# 'VISUAL_STUDIO'
nmap <F5> <Plug>VimspectorContinue
nmap <S-F5> <Plug>VimspectorStop
@ -74,12 +93,14 @@ if s:mappings ==# 'VISUAL_STUDIO'
nmap <S-F11> <Plug>VimspectorStepOut
elseif s:mappings ==# 'HUMAN'
nmap <F5> <Plug>VimspectorContinue
nmap <leader><F5> <Plug>VimspectorLaunch
nmap <F3> <Plug>VimspectorStop
nmap <F4> <Plug>VimspectorRestart
nmap <F6> <Plug>VimspectorPause
nmap <F9> <Plug>VimspectorToggleBreakpoint
nmap <leader><F9> <Plug>VimspectorToggleConditionalBreakpoint
nmap <F8> <Plug>VimspectorAddFunctionBreakpoint
nmap <leader><F8> <Plug>VimspectorRunToCursor
nmap <F10> <Plug>VimspectorStepOver
nmap <F11> <Plug>VimspectorStepInto
nmap <F12> <Plug>VimspectorStepOut
@ -94,12 +115,15 @@ command! -bar -nargs=? -complete=custom,vimspector#CompleteOutput
command! -bar
\ VimspectorToggleLog
\ call vimspector#ToggleLog()
command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr
command! -bar
\ VimspectorDebugInfo
\ call vimspector#PrintDebugInfo()
command! -nargs=1 -complete=custom,vimspector#CompleteExpr
\ VimspectorEval
\ call vimspector#Evaluate( <f-args> )
command! -bar
\ VimspectorReset
\ call vimspector#Reset()
\ call vimspector#Reset( { 'interactive': v:true } )
" Installer commands
command! -bar -bang -nargs=* -complete=custom,vimspector#CompleteInstall
@ -116,9 +140,17 @@ command! -bar -nargs=0
" Dummy autocommands so that we can call this whenever
augroup VimspectorUserAutoCmds
au!
au User VimspectorUICreated silent
au User VimspectorTerminalOpened silent
autocmd!
autocmd User VimspectorUICreated silent
autocmd User VimspectorTerminalOpened silent
autocmd user VimspectorJumpedToFrame silent
autocmd user VimspectorDebugEnded silent
augroup END
" FIXME: Only register this _while_ debugging is active
augroup Vimspector
autocmd!
autocmd BufNew * call vimspector#OnBufferCreated( expand( '<afile>' ) )
augroup END
" boilerplate {{{

View file

@ -141,50 +141,123 @@ class ProjectBreakpoints( object ):
self.UpdateUI()
def _FindLineBreakpoint( self, file_name, line ):
file_name = os.path.abspath( file_name )
for index, bp in enumerate( self._line_breakpoints[ file_name ] ):
self._SignToLine( file_name, bp )
if bp[ 'line' ] == line:
return bp, index
return None, None
def _PutLineBreakpoint( self, file_name, line, options ):
self._line_breakpoints[ os.path.abspath( file_name ) ].append( {
'state': 'ENABLED',
'line': line,
'options': options,
# 'sign_id': <filled in when placed>,
#
# Used by other breakpoint types (specified in options):
# 'condition': ...,
# 'hitCondition': ...,
# 'logMessage': ...
} )
def _DeleteLineBreakpoint( self, bp, file_name, index ):
if 'sign_id' in bp:
signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
del self._line_breakpoints[ os.path.abspath( file_name ) ][ index ]
def ToggleBreakpoint( self, options ):
line, column = vim.current.window.cursor
line, _ = vim.current.window.cursor
file_name = vim.current.buffer.name
if not file_name:
return
found_bp = False
action = 'New'
for index, bp in enumerate( self._line_breakpoints[ file_name ] ):
self._SignToLine( file_name, bp )
if bp[ 'line' ] == line:
found_bp = True
if bp[ 'state' ] == 'ENABLED' and not self._connection:
bp[ 'state' ] = 'DISABLED'
action = 'Disable'
else:
if 'sign_id' in bp:
signs.UnplaceSign( bp[ 'sign_id' ], 'VimspectorBP' )
del self._line_breakpoints[ file_name ][ index ]
action = 'Delete'
break
self._logger.debug( "Toggle found bp at {}:{} ? {} ({})".format(
file_name,
line,
found_bp,
action ) )
if not found_bp:
self._line_breakpoints[ file_name ].append( {
'state': 'ENABLED',
'line': line,
'options': options,
# 'sign_id': <filled in when placed>,
#
# Used by other breakpoint types (specified in options):
# 'condition': ...,
# 'hitCondition': ...,
# 'logMessage': ...
} )
bp, index = self._FindLineBreakpoint( file_name, line )
if bp is None:
# ADD
self._PutLineBreakpoint( file_name, line, options )
elif bp[ 'state' ] == 'ENABLED' and not self._connection:
# DISABLE
bp[ 'state' ] = 'DISABLED'
else:
# DELETE
self._DeleteLineBreakpoint( bp, file_name, index )
self.UpdateUI()
def SetLineBreakpoint( self, file_name, line_num, options, then = None ):
bp, _ = self._FindLineBreakpoint( file_name, line_num )
if bp is not None:
bp[ 'options' ] = options
return
self._PutLineBreakpoint( file_name, line_num, options )
self.UpdateUI( then )
def ClearLineBreakpoint( self, file_name, line_num ):
bp, index = self._FindLineBreakpoint( file_name, line_num )
if bp is None:
return
self._DeleteLineBreakpoint( bp, file_name, index )
self.UpdateUI()
def ClearTemporaryBreakpoint( self, file_name, line_num ):
bp, index = self._FindLineBreakpoint( file_name, line_num )
if bp is None:
return
if bp[ 'options' ].get( 'temporary' ):
self._DeleteLineBreakpoint( bp, file_name, index )
self.UpdateUI()
def ClearTemporaryBreakpoints( self ):
to_delete = []
for file_name, breakpoints in self._line_breakpoints.items():
for index, bp in enumerate( breakpoints ):
if bp[ 'options' ].get( 'temporary' ):
to_delete.append( ( bp, file_name, index ) )
for entry in to_delete:
self._DeleteLineBreakpoint( *entry )
def _UpdateTemporaryBreakpoints( self, breakpoints, temp_idxs ):
# adjust any temporary breakpoints to match the server result
# TODO: Maybe now is the time to ditch the split breakpoints nonesense
for temp_idx, user_bp in temp_idxs:
if temp_idx >= len( breakpoints ):
# Just can't trust servers ?
self._logger.debug( "Server Error - invalid breakpoints list did not "
"contain entry for temporary breakpoint at index "
f"{ temp_idx } i.e. { user_bp }" )
continue
bp = breakpoints[ temp_idx ]
if 'line' not in bp or not bp[ 'verified' ]:
utils.UserMessage(
"Unable to set temporary breakpoint at line "
f"{ user_bp[ 'line' ] } execution will continue...",
persist = True,
error = True )
self._logger.debug( f"Updating temporary breakpoint { user_bp } line "
f"{ user_bp[ 'line' ] } to { bp[ 'line' ] }" )
# if it was moved, update the user-breakpoint so that we unset it
# again properly
user_bp[ 'line' ] = bp[ 'line' ]
def AddFunctionBreakpoint( self, function, options ):
self._func_breakpoints.append( {
'state': 'ENABLED',
@ -200,11 +273,13 @@ class ProjectBreakpoints( object ):
self.UpdateUI()
def UpdateUI( self ):
def UpdateUI( self, then = None ):
if self._connection:
self.SendBreakpoints()
self.SendBreakpoints( then )
else:
self._ShowBreakpoints()
if then:
then()
def SetBreakpointsHandler( self, handler ):
@ -224,15 +299,25 @@ class ProjectBreakpoints( object ):
awaiting = 0
def response_received():
def response_received( *failure_args ):
nonlocal awaiting
awaiting = awaiting - 1
if failure_args and self._connection:
reason, msg = failure_args
utils.UserMessage( 'Unable to set breakpoint: {0}'.format( reason ),
persist = True,
error = True )
if awaiting == 0 and doneHandler:
doneHandler()
def response_handler( source, msg ):
def response_handler( source, msg, temp_idxs = [] ):
if msg:
self._breakpoints_handler.AddBreakpoints( source, msg )
breakpoints = ( msg.get( 'body' ) or {} ).get( 'breakpoints' ) or []
self._UpdateTemporaryBreakpoints( breakpoints, temp_idxs )
response_received()
@ -243,9 +328,9 @@ class ProjectBreakpoints( object ):
# TODO: add the _configured_breakpoints to line_breakpoints
# TODO: the line numbers might have changed since pressing the F9 key!
for file_name, line_breakpoints in self._line_breakpoints.items():
temp_idxs = []
breakpoints = []
for bp in line_breakpoints:
self._SignToLine( file_name, bp )
@ -259,8 +344,15 @@ class ProjectBreakpoints( object ):
dap_bp = {}
dap_bp.update( bp[ 'options' ] )
dap_bp.update( { 'line': bp[ 'line' ] } )
dap_bp.pop( 'temporary', None )
if bp[ 'options' ].get( 'temporary' ):
temp_idxs.append( [ len( breakpoints ), bp ] )
breakpoints.append( dap_bp )
source = {
'name': os.path.basename( file_name ),
'path': file_name,
@ -268,7 +360,13 @@ class ProjectBreakpoints( object ):
awaiting = awaiting + 1
self._connection.DoRequest(
lambda msg: response_handler( source, msg ),
# The source=source here is critical to ensure that we capture each
# source in the iteration, rather than ending up passing the same source
# to each callback.
lambda msg, source=source, temp_idxs=temp_idxs: response_handler(
source,
msg,
temp_idxs = temp_idxs ),
{
'command': 'setBreakpoints',
'arguments': {
@ -277,7 +375,7 @@ class ProjectBreakpoints( object ):
},
'sourceModified': False, # TODO: We can actually check this
},
failure_handler = lambda *_: response_received()
failure_handler = response_received
)
# TODO: Add the _configured_breakpoints to function breakpoints
@ -301,7 +399,7 @@ class ProjectBreakpoints( object ):
'breakpoints': breakpoints,
}
},
failure_handler = lambda *_: response_received()
failure_handler = response_received
)
if self._exception_breakpoints:
@ -312,7 +410,7 @@ class ProjectBreakpoints( object ):
'command': 'setExceptionBreakpoints',
'arguments': self._exception_breakpoints
},
failure_handler = lambda *_: response_received()
failure_handler = response_received
)
if awaiting == 0 and doneHandler:
@ -369,6 +467,12 @@ class ProjectBreakpoints( object ):
# pay any attention to them anyway.
self._exception_breakpoints[ 'exceptionOptions' ] = []
def Refresh( self, file_name ):
# TODO: Just this file ?
self._ShowBreakpoints()
def _ShowBreakpoints( self ):
for file_name, line_breakpoints in self._line_breakpoints.items():
for bp in line_breakpoints:
@ -383,17 +487,21 @@ class ProjectBreakpoints( object ):
else 'vimspectorBPCond' if 'condition' in bp[ 'options' ]
else 'vimspectorBP' )
signs.PlaceSign( bp[ 'sign_id' ],
'VimspectorBP',
sign,
file_name,
bp[ 'line' ] )
if utils.BufferExists( file_name ):
signs.PlaceSign( bp[ 'sign_id' ],
'VimspectorBP',
sign,
file_name,
bp[ 'line' ] )
def _SignToLine( self, file_name, bp ):
if 'sign_id' not in bp:
return bp[ 'line' ]
if not utils.BufferExists( file_name ):
return bp[ 'line' ]
signs = vim.eval( "sign_getplaced( '{}', {} )".format(
utils.Escape( file_name ),
json.dumps( { 'id': bp[ 'sign_id' ], 'group': 'VimspectorBP', } ) ) )

View file

@ -32,6 +32,7 @@ class CodeView( object ):
self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger )
# FIXME: This ID is by group, so should be module scope
self._next_sign_id = 1
self._breakpoints = defaultdict( list )
self._signs = {
@ -41,14 +42,25 @@ class CodeView( object ):
self._current_frame = None
with utils.LetCurrentWindow( self._window ):
vim.command( 'nnoremenu WinBar.■\\ Stop :call vimspector#Stop()<CR>' )
vim.command( 'nnoremenu WinBar.▶\\ Cont :call vimspector#Continue()<CR>' )
vim.command( 'nnoremenu WinBar.▷\\ Pause :call vimspector#Pause()<CR>' )
vim.command( 'nnoremenu WinBar.↷\\ Next :call vimspector#StepOver()<CR>' )
vim.command( 'nnoremenu WinBar.→\\ Step :call vimspector#StepInto()<CR>' )
vim.command( 'nnoremenu WinBar.←\\ Out :call vimspector#StepOut()<CR>' )
vim.command( 'nnoremenu WinBar.⟲: :call vimspector#Restart()<CR>' )
vim.command( 'nnoremenu WinBar.✕ :call vimspector#Reset()<CR>' )
if utils.UseWinBar():
# Buggy neovim doesn't render correctly when the WinBar is defined:
# https://github.com/neovim/neovim/issues/12689
vim.command( 'nnoremenu WinBar.■\\ Stop '
':call vimspector#Stop()<CR>' )
vim.command( 'nnoremenu WinBar.▶\\ Cont '
':call vimspector#Continue()<CR>' )
vim.command( 'nnoremenu WinBar.▷\\ Pause '
':call vimspector#Pause()<CR>' )
vim.command( 'nnoremenu WinBar.↷\\ Next '
':call vimspector#StepOver()<CR>' )
vim.command( 'nnoremenu WinBar.→\\ Step '
':call vimspector#StepInto()<CR>' )
vim.command( 'nnoremenu WinBar.←\\ Out '
':call vimspector#StepOut()<CR>' )
vim.command( 'nnoremenu WinBar.⟲: '
':call vimspector#Restart()<CR>' )
vim.command( 'nnoremenu WinBar.✕ '
':call vimspector#Reset()<CR>' )
if not signs.SignDefined( 'vimspectorPC' ):
signs.DefineSign( 'vimspectorPC',
@ -93,16 +105,12 @@ class CodeView( object ):
sign = 'vimspectorPCBP'
break
try:
if utils.BufferExists( frame[ 'source' ][ 'path' ] ):
signs.PlaceSign( self._signs[ 'vimspectorPC' ],
'VimspectorCode',
sign,
frame[ 'source' ][ 'path' ],
frame[ 'line' ] )
except vim.error as e:
# Ignore 'invalid buffer name'
if 'E158' not in str( e ):
raise
def SetCurrentFrame( self, frame ):
@ -119,7 +127,6 @@ class CodeView( object ):
return False
self._current_frame = frame
self._DisplayPC()
if not self._window.valid:
return False
@ -127,6 +134,7 @@ class CodeView( object ):
utils.JumpToWindow( self._window )
try:
utils.OpenFileInCurrentWindow( frame[ 'source' ][ 'path' ] )
vim.command( 'doautocmd <nomodeline> User VimspectorJumpedToFrame' )
except vim.error:
self._logger.exception( 'Unexpected vim error opening file {}'.format(
frame[ 'source' ][ 'path' ] ) )
@ -148,6 +156,8 @@ class CodeView( object ):
self.current_syntax = utils.ToUnicode(
vim.current.buffer.options[ 'syntax' ] )
self.ShowBreakpoints()
return True
def Clear( self ):
@ -165,25 +175,29 @@ class CodeView( object ):
def AddBreakpoints( self, source, breakpoints ):
for breakpoint in breakpoints:
if 'source' not in breakpoint:
if source:
breakpoint[ 'source' ] = source
else:
self._logger.warn( 'missing source in breakpoint {0}'.format(
json.dumps( breakpoint ) ) )
continue
source = breakpoint.get( 'source' ) or source
if not source or 'path' not in source:
self._logger.warn( 'missing source/path in breakpoint {0}'.format(
json.dumps( breakpoint ) ) )
continue
self._breakpoints[ breakpoint[ 'source' ][ 'path' ] ].append(
breakpoint )
breakpoint[ 'source' ] = source
self._breakpoints[ source[ 'path' ] ].append( breakpoint )
self._logger.debug( 'Breakpoints at this point: {0}'.format(
json.dumps( self._breakpoints, indent = 2 ) ) )
self.ShowBreakpoints()
def AddBreakpoint( self, breakpoint ):
self.AddBreakpoints( None, [ breakpoint ] )
def UpdateBreakpoint( self, bp ):
if 'id' not in bp:
self.AddBreakpoints( None, [ bp ] )
self.AddBreakpoint( bp )
return
for _, breakpoint_list in self._breakpoints.items():
for index, breakpoint in enumerate( breakpoint_list ):
@ -193,7 +207,27 @@ class CodeView( object ):
return
# Not found. Assume new
self.AddBreakpoints( None, [ bp ] )
self.AddBreakpoint( bp )
def RemoveBreakpoint( self, bp ):
for _, breakpoint_list in self._breakpoints.items():
found_index = None
for index, breakpoint in enumerate( breakpoint_list ):
if 'id' in breakpoint and breakpoint[ 'id' ] == bp[ 'id' ]:
found_index = index
break
if found_index is not None:
del breakpoint_list[ found_index ]
self.ShowBreakpoints()
return
def Refresh( self, file_name ):
# TODO: jsut the file ?
self.ShowBreakpoints()
def _UndisplaySigns( self ):
for sign_id in self._signs[ 'breakpoints' ]:
@ -216,12 +250,13 @@ class CodeView( object ):
sign_id = self._next_sign_id
self._next_sign_id += 1
self._signs[ 'breakpoints' ].append( sign_id )
signs.PlaceSign( sign_id,
'VimspectorCode',
'vimspectorBP' if breakpoint[ 'verified' ]
else 'vimspectorBPDisabled',
file_name,
breakpoint[ 'line' ] )
if utils.BufferExists( file_name ):
signs.PlaceSign( sign_id,
'VimspectorCode',
'vimspectorBP' if breakpoint[ 'verified' ]
else 'vimspectorBPDisabled',
file_name,
breakpoint[ 'line' ] )
# We need to also check if there's a breakpoint on this PC line and chnge
# the PC

View file

@ -0,0 +1,51 @@
# vimspector - A multi-language debugging system for Vim
# Copyright 2021 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.
from vimspector.debug_session import DebugSession
from vimspector import utils, settings
class JavaDebugAdapter( object ):
def __init__( self, debug_session: DebugSession ):
self.debug_session = debug_session
def OnEvent_hotcodereplace( self, message ):
# Hack for java debug server hot-code-replace
body = message.get( 'body' ) or {}
if body.get( 'type' ) != 'hotcodereplace':
return
if body.get( 'changeType' ) == 'BUILD_COMPLETE':
def handler( result ):
if result == 1:
self.debug_session._connection.DoRequest( None, {
'command': 'redefineClasses',
'arguments': {},
} )
mode = settings.Get( 'java_hotcodereplace_mode' )
if mode == 'ask':
utils.Confirm( self.debug_session._api_prefix,
'Code has changed, hot reload?',
handler,
default_value = 1 )
elif mode == 'always':
self.debug_session._connection.DoRequest( None, {
'command': 'redefineClasses',
'arguments': {},
} )
elif body.get( 'message' ):
utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] )

View file

@ -29,14 +29,14 @@ class PendingRequest( object ):
class DebugAdapterConnection( object ):
def __init__( self, handler, send_func ):
def __init__( self, handlers, send_func ):
self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger )
self._Write = send_func
self._SetState( 'READ_HEADER' )
self._buffer = bytes()
self._handler = handler
self._handlers = handlers
self._next_message_id = 0
self._outstanding_requests = {}
@ -124,7 +124,7 @@ class DebugAdapterConnection( object ):
def Reset( self ):
self._Write = None
self._handler = None
self._handlers = None
while self._outstanding_requests:
_, request = self._outstanding_requests.popitem()
@ -169,6 +169,10 @@ class DebugAdapterConnection( object ):
self._headers = {}
def _SendMessage( self, msg ):
if not self._Write:
# Connection was destroyed
return False
msg = json.dumps( msg )
self._logger.debug( 'Sending Message: {0}'.format( msg ) )
@ -222,7 +226,12 @@ class DebugAdapterConnection( object ):
# self._logger.debug( 'Message received (raw): %s', payload )
message = json.loads( payload )
try:
message = json.loads( payload, strict = False )
except Exception:
self._logger.exception( "Invalid message received: %s", payload )
self._SetState( 'READ_HEADER' )
raise
self._logger.debug( 'Message received: {0}'.format( message ) )
@ -233,7 +242,7 @@ class DebugAdapterConnection( object ):
def _OnMessageReceived( self, message ):
if not self._handler:
if not self._handlers:
return
if message[ 'type' ] == 'response':
@ -266,25 +275,21 @@ class DebugAdapterConnection( object ):
self._logger.error( 'Request failed: {0}'.format( reason ) )
if request.failure_handler:
request.failure_handler( reason, message )
elif 'OnFailure' in dir( self._handler ):
self._handler.OnFailure( reason, request.msg, message )
else:
utils.UserMessage( 'Request failed: {0}'.format( reason ) )
for h in self._handlers:
if 'OnFailure' in dir( h ):
h.OnFailure( reason, request.msg, message )
elif message[ 'type' ] == 'event':
method = 'OnEvent_' + message[ 'event' ]
if method in dir( self._handler ):
getattr( self._handler, method )( message )
else:
utils.UserMessage( 'Unhandled event: {0}'.format( message[ 'event' ] ),
persist = True )
for h in self._handlers:
if method in dir( h ):
getattr( h, method )( message )
elif message[ 'type' ] == 'request':
method = 'OnRequest_' + message[ 'command' ]
if method in dir( self._handler ):
getattr( self._handler, method )( message )
else:
utils.UserMessage(
'Unhandled request: {0}'.format( message[ 'command' ] ),
persist = True )
for h in self._handlers:
if method in dir( h ):
getattr( h, method )( message )
def _KillTimer( request ):

View file

@ -21,6 +21,7 @@ import shlex
import subprocess
import functools
import vim
import importlib
from vimspector import ( breakpoints,
code,
@ -68,6 +69,7 @@ class DebugSession( object ):
self._configuration = None
self._adapter = None
self._launch_config = None
self._ResetServerState()
@ -77,8 +79,28 @@ class DebugSession( object ):
self._launch_complete = False
self._on_init_complete_handlers = []
self._server_capabilities = {}
self.ClearTemporaryBreakpoints()
def Start( self, launch_variables = None ):
def GetConfigurations( self, adapters ):
current_file = utils.GetBufferFilepath( vim.current.buffer )
filetypes = utils.GetBufferFiletypes( vim.current.buffer )
configurations = {}
for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME,
current_file,
filetypes ):
self._logger.debug( f'Reading configurations from: {launch_config_file}' )
if not launch_config_file or not os.path.exists( launch_config_file ):
continue
with open( launch_config_file, 'r' ) as f:
database = json.loads( minify( f.read() ) )
configurations.update( database.get( 'configurations' ) or {} )
adapters.update( database.get( 'adapters' ) or {} )
return launch_config_file, configurations
def Start( self, force_choose=False, launch_variables = None ):
# We mutate launch_variables, so don't mutate the default argument.
# https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
if launch_variables is None:
@ -88,11 +110,17 @@ class DebugSession( object ):
launch_variables )
self._configuration = None
self._adapter = None
self._launch_config = None
current_file = utils.GetBufferFilepath( vim.current.buffer )
filetypes = utils.GetBufferFiletypes( vim.current.buffer )
configurations = {}
adapters = {}
launch_config_file, configurations = self.GetConfigurations( adapters )
if not configurations:
utils.UserMessage( 'Unable to find any debug configurations. '
'You need to tell vimspector how to launch your '
'application.' )
return
glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME ) )
for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME,
@ -105,26 +133,13 @@ class DebugSession( object ):
a = json.loads( minify( f.read() ) ).get( 'adapters' ) or {}
adapters.update( a )
for launch_config_file in PathsToAllConfigFiles( VIMSPECTOR_HOME,
current_file,
filetypes ):
self._logger.debug( f'Reading configurations from: {launch_config_file}' )
if not launch_config_file or not os.path.exists( launch_config_file ):
continue
with open( launch_config_file, 'r' ) as f:
database = json.loads( minify( f.read() ) )
adapters.update( database.get( 'adapters' ) or {} )
configurations.update( database.get( 'configurations' or {} ) )
if not configurations:
utils.UserMessage( 'Unable to find any debug configurations. '
'You need to tell vimspector how to launch your '
'application.' )
return
if 'configuration' in launch_variables:
configuration_name = launch_variables.pop( 'configuration' )
elif force_choose:
# Always display the menu
configuration_name = utils.SelectFromList(
'Which launch configuration?',
sorted( configurations.keys() ) )
elif ( len( configurations ) == 1 and
next( iter( configurations.values() ) ).get( "autoselect", True ) ):
configuration_name = next( iter( configurations.keys() ) )
@ -273,6 +288,7 @@ class DebugSession( object ):
def start():
self._configuration = configuration
self._adapter = adapter
self._launch_config = None
self._logger.info( 'Configuration: %s',
json.dumps( self._configuration ) )
@ -284,6 +300,7 @@ class DebugSession( object ):
else:
vim.current.tabpage = self._uiTab
self._Prepare()
self._StartDebugAdapter()
self._Initialise()
@ -309,7 +326,7 @@ class DebugSession( object ):
if self._connection:
self._logger.debug( "_StopDebugAdapter with callback: start" )
self._StopDebugAdapter( start )
self._StopDebugAdapter( interactive = False, callback = start )
return
start()
@ -374,14 +391,15 @@ class DebugSession( object ):
self._connection = None
@IfConnected()
def Stop( self ):
def Stop( self, interactive = False ):
self._logger.debug( "Stop debug adapter with no callback" )
self._StopDebugAdapter()
self._StopDebugAdapter( interactive = interactive )
def Reset( self ):
def Reset( self, interactive = False ):
if self._connection:
self._logger.debug( "Stop debug adapter with callback : self._Reset()" )
self._StopDebugAdapter( lambda: self._Reset() )
self._StopDebugAdapter( interactive = interactive,
callback = lambda: self._Reset() )
else:
self._Reset()
@ -401,6 +419,7 @@ class DebugSession( object ):
self._outputView.Reset()
self._codeView.Reset()
vim.command( 'tabclose!' )
vim.command( 'doautocmd <nomodeline> User VimspectorDebugEnded' )
self._stackTraceView = None
self._variablesView = None
self._outputView = None
@ -423,43 +442,98 @@ class DebugSession( object ):
},
} )
self._stackTraceView.OnContinued()
self._codeView.SetCurrentFrame( None )
@IfConnected()
def StepInto( self ):
if self._stackTraceView.GetCurrentThreadId() is None:
threadId = self._stackTraceView.GetCurrentThreadId()
if threadId is None:
return
self._connection.DoRequest( None, {
def handler( *_ ):
self._stackTraceView.OnContinued( { 'threadId': threadId } )
self._codeView.SetCurrentFrame( None )
self._connection.DoRequest( handler, {
'command': 'stepIn',
'arguments': {
'threadId': self._stackTraceView.GetCurrentThreadId()
'threadId': threadId
},
} )
@IfConnected()
def StepOut( self ):
if self._stackTraceView.GetCurrentThreadId() is None:
threadId = self._stackTraceView.GetCurrentThreadId()
if threadId is None:
return
self._connection.DoRequest( None, {
def handler( *_ ):
self._stackTraceView.OnContinued( { 'threadId': threadId } )
self._codeView.SetCurrentFrame( None )
self._connection.DoRequest( handler, {
'command': 'stepOut',
'arguments': {
'threadId': self._stackTraceView.GetCurrentThreadId()
'threadId': threadId
},
} )
def Continue( self ):
if self._connection:
self._stackTraceView.Continue()
else:
if not self._connection:
self.Start()
return
threadId = self._stackTraceView.GetCurrentThreadId()
if threadId is None:
utils.UserMessage( 'No current thread', persist = True )
return
def handler( msg ):
self._stackTraceView.OnContinued( {
'threadId': threadId,
'allThreadsContinued': ( msg.get( 'body' ) or {} ).get(
'allThreadsContinued',
True )
} )
self._codeView.SetCurrentFrame( None )
self._connection.DoRequest( handler, {
'command': 'continue',
'arguments': {
'threadId': threadId,
},
} )
@IfConnected()
def Pause( self ):
self._stackTraceView.Pause()
if self._stackTraceView.GetCurrentThreadId() is None:
utils.UserMessage( 'No current thread', persist = True )
return
self._connection.DoRequest( None, {
'command': 'pause',
'arguments': {
'threadId': self._stackTraceView.GetCurrentThreadId(),
},
} )
@IfConnected()
def ExpandVariable( self ):
self._variablesView.ExpandVariable()
def PauseContinueThread( self ):
self._stackTraceView.PauseContinueThread()
@IfConnected()
def SetCurrentThread( self ):
self._stackTraceView.SetCurrentThread()
@IfConnected()
def ExpandVariable( self, buf = None, line_num = None ):
self._variablesView.ExpandVariable( buf, line_num )
@IfConnected()
def SetVariableValue( self, new_value = None, buf = None, line_num = None ):
self._variablesView.SetVariableValue( new_value, buf, line_num )
@IfConnected()
def AddWatch( self, expression ):
@ -467,21 +541,22 @@ class DebugSession( object ):
expression )
@IfConnected()
def EvaluateConsole( self, expression ):
def EvaluateConsole( self, expression, verbose ):
self._outputView.Evaluate( self._stackTraceView.GetCurrentFrame(),
expression )
expression,
verbose )
@IfConnected()
def DeleteWatch( self ):
self._variablesView.DeleteWatch()
@IfConnected()
def ShowBalloon( self, winnr, expression ):
"""Proxy: ballonexpr -> variables.ShowBallon"""
def ShowEvalBalloon( self, winnr, expression, is_hover ):
frame = self._stackTraceView.GetCurrentFrame()
# Check if RIP is in a frame
if frame is None:
self._logger.debug( 'Balloon: Not in a stack frame' )
self._logger.debug( 'Tooltip: Not in a stack frame' )
return ''
# Check if cursor in code window
@ -492,12 +567,24 @@ class DebugSession( object ):
return ''
# Return variable aware function
return self._variablesView.ShowBalloon( frame, expression )
return self._variablesView.VariableEval( frame, expression, is_hover )
def CleanUpTooltip( self ):
return self._variablesView.CleanUpTooltip()
@IfConnected()
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' )
@ -559,10 +646,68 @@ class DebugSession( object ):
return response[ 'body' ][ 'targets' ]
@IfConnected( otherwise=[] )
def GetCommandLineCompletions( self, ArgLead, prev_non_keyword_char ):
items = []
for candidate in self.GetCompletionsSync( ArgLead, prev_non_keyword_char ):
label = candidate.get( 'text', candidate[ 'label' ] )
start = prev_non_keyword_char - 1
if 'start' in candidate and 'length' in candidate:
start = candidate[ 'start' ]
items.append( ArgLead[ 0 : start ] + label )
return items
def RefreshSigns( self, file_name ):
if self._connection:
self._codeView.Refresh( file_name )
else:
self._breakpoints.Refresh( file_name )
def _SetUpUI( self ):
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 )
@ -603,12 +748,73 @@ 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 ),
'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():
@ -621,7 +827,7 @@ class DebugSession( object ):
self.SetCurrentFrame( None )
@RequiresUI()
def SetCurrentFrame( self, frame ):
def SetCurrentFrame( self, frame, reason = '' ):
if not frame:
self._stackTraceView.Clear()
self._variablesView.Clear()
@ -629,11 +835,16 @@ class DebugSession( object ):
if not self._codeView.SetCurrentFrame( frame ):
return False
if frame:
self._variablesView.SetSyntax( self._codeView.current_syntax )
self._stackTraceView.SetSyntax( self._codeView.current_syntax )
self._variablesView.LoadScopes( frame )
self._variablesView.EvaluateWatches()
# the codeView.SetCurrentFrame already checked the frame was valid and
# countained a valid source
self._variablesView.SetSyntax( self._codeView.current_syntax )
self._stackTraceView.SetSyntax( self._codeView.current_syntax )
self._variablesView.LoadScopes( frame )
self._variablesView.EvaluateWatches()
if reason == 'stopped':
self._breakpoints.ClearTemporaryBreakpoint( frame[ 'source' ][ 'path' ],
frame[ 'line' ] )
return True
@ -652,7 +863,6 @@ class DebugSession( object ):
json.dumps( self._adapter ) )
self._init_complete = False
self._on_init_complete_handlers = []
self._launch_complete = False
self._run_on_server_exit = None
@ -668,12 +878,9 @@ class DebugSession( object ):
self._adapter[ 'port' ] = port
self._connection_type = self._api_prefix + self._connection_type
self._logger.debug( f"Connection Type: { self._connection_type }" )
# TODO: Do we actually need to copy and update or does Vim do that?
env = os.environ.copy()
if 'env' in self._adapter:
env.update( self._adapter[ 'env' ] )
self._adapter[ 'env' ] = env
self._adapter[ 'env' ] = self._adapter.get( 'env', {} )
if 'cwd' not in self._adapter:
self._adapter[ 'cwd' ] = os.getcwd()
@ -687,56 +894,93 @@ class DebugSession( object ):
self._splash_screen,
"Unable to start adapter" )
else:
if 'custom_handler' in self._adapter:
spec = self._adapter[ 'custom_handler' ]
if isinstance( spec, dict ):
module = spec[ 'module' ]
cls = spec[ 'class' ]
else:
module, cls = spec.rsplit( '.', 1 )
CustomHandler = getattr( importlib.import_module( module ), cls )
handlers = [ CustomHandler( self ), self ]
else:
handlers = [ self ]
self._connection = debug_adapter_connection.DebugAdapterConnection(
self,
handlers,
lambda msg: utils.Call(
"vimspector#internal#{}#Send".format( self._connection_type ),
msg ) )
self._logger.info( 'Debug Adapter Started' )
def _StopDebugAdapter( self, callback = None ):
self._splash_screen = utils.DisplaySplash(
self._api_prefix,
self._splash_screen,
"Shutting down debug adapter..." )
def handler( *args ):
self._splash_screen = utils.HideSplash( self._api_prefix,
self._splash_screen )
if callback:
self._logger.debug( "Setting server exit handler before disconnect" )
assert not self._run_on_server_exit
self._run_on_server_exit = callback
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
self._connection_type ) )
def _StopDebugAdapter( self, interactive = False, callback = None ):
arguments = {}
if self._server_capabilities.get( 'supportTerminateDebuggee' ):
# If we attached, we should _not_ terminate the debuggee
arguments[ 'terminateDebuggee' ] = False
self._connection.DoRequest( handler, {
'command': 'disconnect',
'arguments': arguments,
}, failure_handler = handler, timeout = 5000 )
def disconnect():
self._splash_screen = utils.DisplaySplash(
self._api_prefix,
self._splash_screen,
"Shutting down debug adapter..." )
# TODO: Use the 'tarminate' request if supportsTerminateRequest set
def handler( *args ):
self._splash_screen = utils.HideSplash( self._api_prefix,
self._splash_screen )
if callback:
self._logger.debug( "Setting server exit handler before disconnect" )
assert not self._run_on_server_exit
self._run_on_server_exit = callback
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
self._connection_type ) )
self._connection.DoRequest( handler, {
'command': 'disconnect',
'arguments': arguments,
}, failure_handler = handler, timeout = 5000 )
if not interactive:
disconnect()
elif not self._server_capabilities.get( 'supportTerminateDebuggee' ):
disconnect()
elif not self._stackTraceView.AnyThreadsRunning():
disconnect()
else:
def handle_choice( choice ):
if choice == 1:
# yes
arguments[ 'terminateDebuggee' ] = True
elif choice == 2:
# no
arguments[ 'terminateDebuggee' ] = False
elif choice <= 0:
# Abort
return
# Else, use server default
disconnect()
utils.Confirm( self._api_prefix,
"Terminate debuggee?",
handle_choice,
default_value = 3,
options = [ '(Y)es', '(N)o', '(D)efault' ],
keys = [ 'y', 'n', 'd' ] )
def _PrepareAttach( self, adapter_config, launch_config ):
atttach_config = adapter_config.get( 'attach' )
attach_config = adapter_config.get( 'attach' )
if not atttach_config:
if not attach_config:
return
if 'remote' in atttach_config:
if 'remote' in attach_config:
# FIXME: We almost want this to feed-back variables to be expanded later,
# e.g. expand variables when we use them, not all at once. This would
# remove the whole %PID% hack.
remote = atttach_config[ 'remote' ]
remote = attach_config[ 'remote' ]
remote_exec_cmd = self._GetRemoteExecCommand( remote )
# FIXME: Why does this not use self._GetCommands ?
@ -777,20 +1021,23 @@ class DebugSession( object ):
self._codeView._window,
self._remote_term )
else:
if atttach_config[ 'pidSelect' ] == 'ask':
prop = atttach_config[ 'pidProperty' ]
if attach_config[ 'pidSelect' ] == 'ask':
prop = attach_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':
elif attach_config[ 'pidSelect' ] == 'none':
return
raise ValueError( 'Unrecognised pidSelect {0}'.format(
atttach_config[ 'pidSelect' ] ) )
attach_config[ 'pidSelect' ] ) )
if 'delay' in attach_config:
utils.UserMessage( f"Waiting ( { attach_config[ 'delay' ] } )..." )
vim.command( f'sleep { attach_config[ "delay" ] }' )
def _PrepareLaunch( self, command_line, adapter_config, launch_config ):
@ -823,6 +1070,11 @@ class DebugSession( object ):
self._codeView._window,
self._remote_term )
if 'delay' in run_config:
utils.UserMessage( f"Waiting ( {run_config[ 'delay' ]} )..." )
vim.command( f'sleep { run_config[ "delay" ] }' )
def _GetSSHCommand( self, remote ):
ssh = [ 'ssh' ] + remote.get( 'ssh', {} ).get( 'args', [] )
@ -896,6 +1148,7 @@ class DebugSession( object ):
def handle_initialize_response( msg ):
self._server_capabilities = msg.get( 'body' ) or {}
self._breakpoints.SetServerCapabilities( self._server_capabilities )
self._variablesView.SetServerCapabilities( self._server_capabilities )
self._Launch()
self._connection.DoRequest( handle_initialize_response, {
@ -921,40 +1174,44 @@ class DebugSession( object ):
message )
self._outputView.Print( 'server', msg )
def _Launch( self ):
def _Prepare( self ):
self._on_init_complete_handlers = []
self._logger.debug( "LAUNCH!" )
adapter_config = self._adapter
launch_config = {}
launch_config.update( self._adapter.get( 'configuration', {} ) )
launch_config.update( self._configuration[ 'configuration' ] )
self._launch_config = {}
self._launch_config.update( self._adapter.get( 'configuration', {} ) )
self._launch_config.update( self._configuration[ 'configuration' ] )
request = self._configuration.get(
'remote-request',
launch_config.get( 'request', 'launch' ) )
self._launch_config.get( 'request', 'launch' ) )
if request == "attach":
self._splash_screen = utils.DisplaySplash(
self._api_prefix,
self._splash_screen,
"Attaching to debugee..." )
"Attaching to debuggee..." )
self._PrepareAttach( adapter_config, launch_config )
self._PrepareAttach( self._adapter, self._launch_config )
elif request == "launch":
self._splash_screen = utils.DisplaySplash(
self._api_prefix,
self._splash_screen,
"Launching debugee..." )
"Launching debuggee..." )
# FIXME: This cmdLine hack is not fun.
self._PrepareLaunch( self._configuration.get( 'remote-cmdLine', [] ),
adapter_config,
launch_config )
self._adapter,
self._launch_config )
# FIXME: name is mandatory. Forcefully add it (we should really use the
# _actual_ name, but that isn't actually remembered at this point)
if 'name' not in launch_config:
launch_config[ 'name' ] = 'test'
if 'name' not in self._launch_config:
self._launch_config[ 'name' ] = 'test'
def _Launch( self ):
def failure_handler( reason, msg ):
text = [
'Launch Failed',
@ -967,12 +1224,11 @@ class DebugSession( object ):
self._splash_screen,
text )
self._connection.DoRequest(
lambda msg: self._OnLaunchComplete(),
{
'command': launch_config[ 'request' ],
'arguments': launch_config
'command': self._launch_config[ 'request' ],
'arguments': self._launch_config
},
failure_handler )
@ -1014,6 +1270,37 @@ class DebugSession( object ):
self._stackTraceView.LoadThreads( True )
@IfConnected()
@RequiresUI()
def PrintDebugInfo( self ):
def Line():
return ( "--------------------------------------------------------------"
"------------------" )
def Pretty( obj ):
if obj is None:
return [ "None" ]
return [ Line() ] + json.dumps( obj, indent=2 ).splitlines() + [ Line() ]
debugInfo = [
"Vimspector Debug Info",
Line(),
f"ConnectionType: { self._connection_type }",
"Adapter: " ] + Pretty( self._adapter ) + [
"Configuration: " ] + Pretty( self._configuration ) + [
f"API Prefix: { self._api_prefix }",
f"Launch/Init: { self._launch_complete } / { self._init_complete }",
f"Workspace Root: { self._workspace_root }",
"Launch Config: " ] + Pretty( self._launch_config ) + [
"Server Capabilities: " ] + Pretty( self._server_capabilities ) + [
]
self._outputView.ClearCategory( 'DebugInfo' )
self._outputView.Print( "DebugInfo", debugInfo )
self.ShowOutput( "DebugInfo" )
def OnEvent_loadedSource( self, msg ):
pass
@ -1050,7 +1337,9 @@ class DebugSession( object ):
if reason == 'changed':
self._codeView.UpdateBreakpoint( bp )
elif reason == 'new':
self._codeView.AddBreakpoints( None, bp )
self._codeView.AddBreakpoint( bp )
elif reason == 'removed':
self._codeView.RemoveBreakpoint( bp )
else:
utils.UserMessage(
'Unrecognised breakpoint event (undocumented): {0}'.format( reason ),
@ -1074,19 +1363,33 @@ class DebugSession( object ):
self._connection.DoResponse( message, None, response )
def OnEvent_terminated( self, message ):
# The debugging _session_ has terminated. This does not mean that the
# debuggee has terminated (that's the exited event).
#
# We will handle this when the server actually exists.
#
# FIXME we should always wait for this event before disconnecting closing
# any socket connection
self.SetCurrentFrame( None )
def OnEvent_exited( self, message ):
utils.UserMessage( 'The debugee exited with status code: {}'.format(
utils.UserMessage( 'The debuggee exited with status code: {}'.format(
message[ 'body' ][ 'exitCode' ] ) )
self._stackTraceView.OnExited( message )
self._codeView.SetCurrentFrame( None )
def OnEvent_process( self, message ):
utils.UserMessage( 'The debugee was started: {}'.format(
utils.UserMessage( 'The debuggee was started: {}'.format(
message[ 'body' ][ 'name' ] ) )
def OnEvent_module( self, message ):
pass
def OnEvent_continued( self, message ):
pass
self._stackTraceView.OnContinued( message[ 'body' ] )
self._codeView.SetCurrentFrame( None )
def Clear( self ):
self._codeView.Clear()
@ -1118,10 +1421,6 @@ class DebugSession( object ):
else:
self._logger.debug( "No server exit handler" )
def OnEvent_terminated( self, message ):
# We will handle this when the server actually exists
utils.UserMessage( "Debugging was terminated by the server." )
def OnEvent_output( self, message ):
if self._outputView:
self._outputView.OnOutput( message[ 'body' ] )
@ -1162,6 +1461,26 @@ class DebugSession( object ):
def ToggleBreakpoint( self, options ):
return self._breakpoints.ToggleBreakpoint( options )
def RunTo( self, file_name, line ):
self.ClearTemporaryBreakpoints()
self.SetLineBreakpoint( file_name,
line,
{ 'temporary': True },
lambda: self.Continue() )
def ClearTemporaryBreakpoints( self ):
return self._breakpoints.ClearTemporaryBreakpoints()
def SetLineBreakpoint( self, file_name, line_num, options, then = None ):
return self._breakpoints.SetLineBreakpoint( file_name,
line_num,
options,
then )
def ClearLineBreakpoint( self, file_name, line_num ):
return self._breakpoints.ClearLineBreakpoint( file_name, line_num )
def ClearBreakpoints( self ):
if self._connection:
self._codeView.ClearBreakpoints()

View file

@ -21,7 +21,7 @@ import os
GADGETS = {
'vscode-cpptools': {
'language': 'c',
'language': [ 'c', 'cpp', 'rust' ],
'download': {
'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/'
'${version}/${file_name}',
@ -30,12 +30,12 @@ GADGETS = {
root,
gadget ),
'all': {
'version': '0.27.0',
'version': '1.6.0',
"adapters": {
"vscode-cpptools": {
"name": "cppdbg",
"command": [
"${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7"
"${gadgetDir}/vscode-cpptools/debugAdapters/bin/OpenDebugAD7"
],
"attach": {
"pidProperty": "processId",
@ -53,17 +53,17 @@ GADGETS = {
'linux': {
'file_name': 'cpptools-linux.vsix',
'checksum':
'3695202e1e75a03de18049323b66d868165123f26151f8c974a480eaf0205435',
'c25299bcfb46b22d41aa3f125df7184e6282a35ff9fb69c47def744cb4778f55',
},
'macos': {
'file_name': 'cpptools-osx.vsix',
'file_name': 'cpptools-osx-arm64.vsix',
'checksum':
'cb061e3acd7559a539e5586f8d3f535101c4ec4e8a48195856d1d39380b5cf3c',
'ceb3e8cdaa2b5bb45af50913ddd8402089969748af8d70f5d46480408287ba6f',
},
'windows': {
'file_name': 'cpptools-win32.vsix',
'checksum':
'aa294368ed16d48c59e49c8000e146eae5a19ad07b654efed5db8ec93b24229e',
'ef7ac5831874a3c7dbf0feb826bfda2be579aff9b6d990622fff1d0d4ede00d1',
"adapters": {
"vscode-cpptools": {
"name": "cppdbg",
@ -86,39 +86,16 @@ GADGETS = {
},
},
},
'vscode-python': {
'language': 'python.legacy',
'enabled': False,
'download': {
'url': 'https://github.com/Microsoft/vscode-python/releases/download/'
'${version}/${file_name}',
},
'all': {
'version': '2019.11.50794',
'file_name': 'ms-python-release.vsix',
'checksum':
'6a9edf9ecabed14aac424e6007858068204a3638bf3bb4f235bd6035d823acc6',
},
'adapters': {
"vscode-python": {
"name": "vscode-python",
"command": [
"node",
"${gadgetDir}/vscode-python/out/client/debugger/debugAdapter/main.js",
],
}
},
},
'debugpy': {
'language': 'python',
'download': {
'url': 'https://github.com/microsoft/debugpy/archive/${file_name}'
},
'all': {
'version': '1.0.0b12',
'file_name': 'v1.0.0b12.zip',
'version': '1.2.1',
'file_name': 'v1.2.1.zip',
'checksum':
'210632bba2221fbb841c9785a615258819ceec401d1abdbeb5f2326f12cc72a1'
'29a6c5d1053d2b6f3b1a63e1a8ecff93f951d3cc0b7548431592e9e3007239e6'
},
'do': lambda name, root, gadget: installer.InstallDebugpy( name,
root,
@ -157,6 +134,10 @@ GADGETS = {
"vscode-java": {
"name": "vscode-java",
"port": "${DAPPort}",
"configuration": {
"cwd": "${workspaceRoot}"
},
'custom_handler': 'vimspector.custom.java.JavaDebugAdapter'
}
},
},
@ -193,7 +174,7 @@ GADGETS = {
'language': 'tcl',
'repo': {
'url': 'https://github.com/puremourning/TclProDebug',
'ref': 'master'
'ref': 'v1.0.0'
},
'do': lambda name, root, gadget: installer.InstallTclProDebug( name,
root,
@ -222,26 +203,27 @@ GADGETS = {
},
},
'netcoredbg': {
'language': 'csharp',
'language': [ 'csharp', 'fsharp', 'vbnet' ],
'enabled': False,
'download': {
'url': 'https://github.com/Samsung/netcoredbg/releases/download/latest/'
'${file_name}',
'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/'
'${version}/${file_name}' ),
'format': 'tar',
},
'all': {
'version': 'master'
'version': '1.2.0-782'
},
'macos': {
'file_name': 'netcoredbg-osx-master.tar.gz',
'checksum': '',
'file_name': 'netcoredbg-osx.tar.gz',
'checksum':
'',
},
'linux': {
'file_name': 'netcoredbg-linux-master.tar.gz',
'file_name': 'netcoredbg-linux-bionic-amd64.tar.gz',
'checksum': '',
},
'windows': {
'file_name': 'netcoredbg-win64-master.zip',
'file_name': 'netcoredbg-win64.zip',
'checksum': '',
},
'do': lambda name, root, gadget: installer.MakeSymlink(
@ -258,35 +240,9 @@ GADGETS = {
"pidProperty": "processId",
"pidSelect": "ask"
},
},
}
},
'vscode-mono-debug': {
'language': 'csharp',
'enabled': False,
'download': {
'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/'
'publishers/ms-vscode/vsextensions/mono-debug/${version}/'
'vspackage',
'target': 'vscode-mono-debug.vsix.gz',
'format': 'zip.gz',
},
'all': {
'file_name': 'vscode-mono-debug.vsix',
'version': '0.15.8',
'checksum':
'723eb2b621b99d65a24f215cb64b45f5fe694105613a900a03c859a62a810470',
},
'adapters': {
'vscode-mono-debug': {
"name": "mono-debug",
"command": [
"mono",
"${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe"
],
"attach": {
"pidSelect": "none"
},
"configuration": {
"cwd": "${workspaceRoot}"
}
},
}
},
@ -336,22 +292,25 @@ GADGETS = {
'vscode-go': {
'language': 'go',
'download': {
'url': 'https://github.com/microsoft/vscode-go/releases/download/'
'${version}/${file_name}'
'url': 'https://github.com/golang/vscode-go/releases/download/'
'v${version}/${file_name}'
},
'all': {
'version': '0.11.4',
'file_name': 'Go-0.11.4.vsix',
'version': '0.19.1',
'file_name': 'go-0.19.1.vsix',
'checksum':
'ff7d7b944da5448974cb3a0086f4a2fd48e2086742d9c013d6964283d416027e'
'7f9dc014245b030d9f562b28f3ea9b1fd6e2708fac996c53ff6a707f8204ec64',
},
'adapters': {
'vscode-go': {
'name': 'delve',
'command': [
'node',
'${gadgetDir}/vscode-go/out/src/debugAdapter/goDebug.js'
'${gadgetDir}/vscode-go/dist/debugAdapter.js'
],
"configuration": {
"cwd": "${workspaceRoot}",
}
},
},
},
@ -360,14 +319,14 @@ GADGETS = {
'enabled': False,
'download': {
'url':
'https://github.com/felixfbecker/vscode-php-debug/releases/download/'
'https://github.com/xdebug/vscode-php-debug/releases/download/'
'${version}/${file_name}',
},
'all': {
'version': 'v1.13.0',
'file_name': 'php-debug.vsix',
'version': 'v1.17.0',
'file_name': 'php-debug-1.17.0.vsix',
'checksum':
'8a51e593458fd14623c1c89ebab87347b087d67087717f18bcf77bb788052718',
'd0fff272503414b6696cc737bc2e18e060fdd5e5dc4bcaf38ae7373afd8d8bc9',
},
'adapters': {
'vscode-php-debug': {
@ -429,18 +388,18 @@ GADGETS = {
},
'CodeLLDB': {
'language': 'rust',
'enabled': False,
'enabled': True,
'download': {
'url': 'https://github.com/vadimcn/vscode-lldb/releases/download/'
'${version}/${file_name}',
},
'all': {
'version': 'v1.5.3',
'version': 'v1.6.6',
},
'macos': {
'file_name': 'codelldb-x86_64-darwin.vsix',
'file_name': 'codelldb-aarch64-darwin.vsix',
'checksum':
'7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a',
'5adc3b9139eabdafd825bd5efc55df4424a203fb2b6087b425cd434956e7ec58',
'make_executable': [
'adapter/codelldb',
'lldb/bin/debugserver',
@ -451,7 +410,7 @@ GADGETS = {
'linux': {
'file_name': 'codelldb-x86_64-linux.vsix',
'checksum':
'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139',
'eda2cd9b3089dcc0524c273e91ffb5875fe08c930bf643739a2cd1846e1f98d6',
'make_executable': [
'adapter/codelldb',
'lldb/bin/lldb',
@ -462,7 +421,7 @@ GADGETS = {
'windows': {
'file_name': 'codelldb-x86_64-windows.vsix',
'checksum':
'',
'8ddebe8381a3d22dc3d95139c3797fda06b5cc34aadf300e13b1c516b9da95fe',
'make_executable': []
},
'adapters': {
@ -486,4 +445,31 @@ GADGETS = {
},
},
},
'local-lua-debugger-vscode': {
'language': 'lua',
'enabled': True,
'repo': {
'url': 'https://github.com/tomblind/local-lua-debugger-vscode.git',
'ref': 'release-${version}'
},
'all': {
'version': '0.2.0',
},
'do': lambda name, root, gadget: installer.InstallLuaLocal( name,
root,
gadget ),
'adapters': {
'lua-local': {
'command': [
'node',
'${gadgetDir}/local-lua-debugger-vscode/extension/debugAdapter.js'
],
'name': 'lua-local',
'configuration': {
'interpreter': 'lua',
'extensionPath': '${gadgetDir}/local-lua-debugger-vscode'
}
}
},
},
}

View file

@ -229,10 +229,14 @@ def GadgetListToInstallerArgs( *gadget_list ):
except KeyError:
continue
lang = gadget[ "language" ]
if isinstance( lang, list ):
lang = lang[ 0 ]
if not gadget.get( 'enabled', True ):
installer_args.append( f'--force-enable-{ gadget[ "language" ] }' )
installer_args.append( f'--force-enable-{lang}' )
else:
installer_args.append( f'--enable-{ gadget[ "language" ] }' )
installer_args.append( f'--enable-{lang}' )
return installer_args
@ -340,11 +344,12 @@ def WriteAdapters( all_adapters, to_file=None ):
def InstallGeneric( name, root, gadget ):
extension = os.path.join( root, 'extension' )
extension_path = gadget.get( 'extension_path', 'extension' )
extension = os.path.join( root, extension_path )
for f in gadget.get( 'make_executable', [] ):
MakeExecutable( os.path.join( extension, f ) )
MakeExtensionSymlink( name, root )
MakeExtensionSymlink( name, root, extension_path )
def InstallCppTools( name, root, gadget ):
@ -353,7 +358,8 @@ def InstallCppTools( name, root, gadget ):
# It's hilarious, but the execute bits aren't set in the vsix. So they
# actually have javascript code which does this. It's just a horrible horrible
# hack that really is not funny.
MakeExecutable( os.path.join( extension, 'debugAdapters', 'OpenDebugAD7' ) )
MakeExecutable(
os.path.join( extension, 'debugAdapters', 'bin', 'OpenDebugAD7' ) )
with open( os.path.join( extension, 'package.json' ) ) as f:
package = json.load( f )
runtime_dependencies = package[ 'runtimeDependencies' ]
@ -425,6 +431,13 @@ def InstallNodeDebug( name, root, gadget ):
MakeSymlink( name, root )
def InstallLuaLocal( name, root, gadget ):
with CurrentWorkingDir( root ):
CheckCall( [ 'npm', 'install' ] )
CheckCall( [ 'npm', 'run', 'build' ] )
MakeSymlink( name, root )
def InstallGagdet( name: str,
gadget: dict,
manifest: Manifest,
@ -481,7 +494,7 @@ def InstallGagdet( name: str,
url = string.Template( gadget[ 'repo' ][ 'url' ] ).substitute( spec )
ref = string.Template( gadget[ 'repo' ][ 'ref' ] ).substitute( spec )
print( f"Installing {name}@{gadget[ 'repo' ][ 'ref' ]}..." )
print( f"Installing {name}@{ref}..." )
spec[ 'repo' ] = gadget[ 'repo' ]
if not manifest.RequiresUpdate( name, spec ):
save_adapters()
@ -692,8 +705,8 @@ def ExtractZipTo( file_path, destination, format ):
CheckCall( [ 'tar', 'zxvf', file_path ] )
def MakeExtensionSymlink( name, root ):
MakeSymlink( name, os.path.join( root, 'extension' ) ),
def MakeExtensionSymlink( name, root, extension_path = 'extension' ):
MakeSymlink( name, os.path.join( root, extension_path ) ),
def MakeSymlink( link, pointing_to, in_folder = None ):

View file

@ -32,8 +32,9 @@ class TabBuffer( object ):
BUFFER_MAP = {
'console': 'Console',
'stdout': 'Console',
'output': 'Console',
'stderr': 'stderr',
'telemetry': 'Telemetry',
'telemetry': None,
}
@ -64,8 +65,11 @@ class OutputView( object ):
self._api_prefix = api_prefix
VIEWS.add( self )
def Print( self, categroy, text ):
self._Print( 'server', text.splitlines() )
def Print( self, category, text: typing.Union[ str, list ] ):
if not isinstance( text, list ):
text = text.splitlines()
self._Print( category, text )
def OnOutput( self, event ):
category = CategoryToBuffer( event.get( 'category' ) or 'output' )
@ -77,6 +81,10 @@ class OutputView( object ):
self._Print( category, text_lines )
def _Print( self, category, text_lines ):
if category is None:
# This category is supressed
return
if category not in self._buffers:
self._CreateBuffer( category )
@ -100,13 +108,26 @@ class OutputView( object ):
def Clear( self ):
for category, tab_buffer in self._buffers.items():
if tab_buffer.is_job:
utils.CleanUpCommand( category, self._api_prefix )
utils.CleanUpHiddenBuffer( tab_buffer.buf )
self._CleanUpBuffer( category, tab_buffer )
# FIXME: nunmenu the WinBar ?
self._buffers = {}
def ClearCategory( self, category: str ):
if category not in self._buffers:
return
self._CleanUpBuffer( category, self._buffers[ category ] )
def _CleanUpBuffer( self, category: str, tab_buffer: TabBuffer ):
if tab_buffer.is_job:
utils.CleanUpCommand( category, self._api_prefix )
utils.CleanUpHiddenBuffer( tab_buffer.buf )
def WindowIsValid( self ):
return self._window.valid
@ -210,6 +231,9 @@ class OutputView( object ):
utils.CleanUpHiddenBuffer( buf_to_delete )
def _RenderWinBar( self, category ):
if not utils.UseWinBar():
return
if not self._window.valid:
return
@ -227,7 +251,7 @@ class OutputView( object ):
raise
vim.command(
"nnoremenu 1.{0} WinBar.{1}{2} "
"nnoremenu <silent> 1.{0} WinBar.{1}{2} "
":call vimspector#ShowOutputInWindow( {3}, '{1}' )<CR>".format(
tab_buffer.index,
utils.Escape( category ),
@ -248,7 +272,8 @@ class DAPOutputView( OutputView ):
self._connection = None
for b in set( BUFFER_MAP.values() ):
self._CreateBuffer( b )
if b is not None:
self._CreateBuffer( b )
self.AddLogFileView()
self._ShowOutput( 'Console' )
@ -260,14 +285,18 @@ class DAPOutputView( OutputView ):
# Don't clear because output is probably still useful
self._connection = None
def Evaluate( self, frame, expression ):
self._Print( 'Console', [ 'Evaluating: ' + expression ] )
def Evaluate( self, frame, expression, verbose ):
if verbose:
self._Print( 'Console', f"Evaluating: { expression }" )
def print_result( message ):
result = message[ 'body' ][ 'result' ]
if result is None:
result = '<no result>'
self._Print( 'Console', f' Result: { result }' )
self._Print( 'Console', result.splitlines() )
def print_failure( reason, msg ):
self._Print( 'Console', reason.splitlines() )
request = {
'command': 'evaluate',
@ -280,4 +309,6 @@ class DAPOutputView( OutputView ):
if frame:
request[ 'arguments' ][ 'frameId' ] = frame[ 'id' ]
self._connection.DoRequest( print_result, request )
self._connection.DoRequest( print_result,
request,
print_failure )

View file

@ -20,23 +20,50 @@ 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': {
'vimspectorPC': 200,
'vimspectorPCBP': 200,
'vimspectorBP': 9,
'vimspectorBPCond': 9,
'vimspectorBPDisabled': 9,
'vimspectorPC': 200,
'vimspectorPCBP': 200,
'vimspectorBP': 9,
'vimspectorBPCond': 9,
'vimspectorBPDisabled': 9,
'vimspectorCurrentThread': 200,
'vimspectorCurrentFrame': 200,
},
# Installer
'install_gadgets': [],
# Mappings
'mappings': {
'variables': {
'expand_collapse': [ '<CR>', '<2-LeftMouse>' ],
'delete': [ '<Del>' ],
'set_value': [ '<C-CR>', '<leader><CR>' ]
},
'stack_trace': {
'expand_or_jump': [ '<CR>', '<2-LeftMouse>' ],
'focus_thread': [ '<leader><CR>' ],
}
},
# Custom
'java_hotcodereplace_mode': 'ask',
}
@ -68,9 +95,44 @@ if hasattr( vim, 'Dictionary' ):
DICT_TYPE = vim.Dictionary
def Dict( option: str ):
d = DICT_TYPE( DEFAULTS.get( option, {} ) )
d.update( utils.GetVimValue( vim.vars,
f'vimspector_{ option }',
{} ) )
return d
def Dict( option ):
return _UpdateDict( DICT_TYPE( DEFAULTS.get( option, {} ) ),
vim.vars.get( f'vimspector_{ option }', DICT_TYPE() ) )
def _UpdateDict( target, override ):
"""Apply the updates in |override| to the dict |target|. This is like
dict.update, but recursive. i.e. if the existing element is a dict, then
override elements of the sub-dict rather than wholesale replacing.
e.g.
UpdateDict(
{
'outer': { 'inner': { 'key': 'oldValue', 'existingKey': True } }
},
{
'outer': { 'inner': { 'key': 'newValue' } },
'newKey': { 'newDict': True },
}
)
yields:
{
'outer': {
'inner': {
'key': 'newValue',
'existingKey': True
}
},
'newKey': { newDict: True }
}
"""
for key, value in override.items():
current_value = target.get( key )
if not isinstance( current_value, DICT_TYPE ):
target[ key ] = value
elif isinstance( value, DICT_TYPE ):
target[ key ] = _UpdateDict( current_value, value )
else:
target[ key ] = value
return target

View file

@ -29,7 +29,7 @@ def DefineSign( name, text, double_text, texthl, col = 'right', **kwargs ):
vim.command( cmd )
def PlaceSign( sign_id, group, name, file, line ):
def PlaceSign( sign_id, group, name, file_name, line ):
priority = settings.Dict( 'sign_priority' )[ name ]
cmd = ( f'sign place { sign_id } '
@ -37,7 +37,7 @@ def PlaceSign( sign_id, group, name, file, line ):
f'name={ name } '
f'priority={ priority } '
f'line={ line } '
f'file={ file }' )
f'file={ file_name }' )
vim.command( cmd )

View file

@ -16,11 +16,75 @@
import vim
import os
import logging
import typing
from vimspector import utils
from vimspector import utils, signs, settings
class Thread:
"""The state of a single thread."""
PAUSED = 0
RUNNING = 1
TERMINATED = 3
state = RUNNING
stopped_event: typing.Dict
thread: typing.Dict
stacktrace: typing.List[ typing.Dict ]
id: str
def __init__( self, thread ):
self.id = thread[ 'id' ]
self.stopped_event = None
self.Update( thread )
def Update( self, thread ):
self.thread = thread
self.stacktrace = None
def Paused( self, event ):
self.state = Thread.PAUSED
self.stopped_event = event
def Continued( self ):
self.state = Thread.RUNNING
self.stopped_event = None
self.Collapse()
def Exited( self ):
self.state = Thread.TERMINATED
self.stopped_event = None
def State( self ):
if self.state == Thread.PAUSED:
return self.stopped_event.get( 'description' ) or 'paused'
elif self.state == Thread.RUNNING:
return 'running'
return 'terminated'
def Expand( self, stack_trace ):
self.stacktrace = stack_trace
def Collapse( self ):
self.stacktrace = None
def IsExpanded( self ):
return self.stacktrace is not None
def CanExpand( self ):
return self.state == Thread.PAUSED
class StackTraceView( object ):
class ThreadRequestState:
NO = 0
REQUESTING = 1
PENDING = 2
# FIXME: Make into a dict by id ?
_threads: typing.List[ Thread ]
_line_to_thread = typing.Dict[ int, Thread ]
def __init__( self, session, win ):
self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger )
@ -37,25 +101,55 @@ class StackTraceView( object ):
self._sources = {}
self._scratch_buffers = []
# FIXME: This ID is by group, so should be module scope
self._current_thread_sign_id = 0 # 1 when used
self._current_frame_sign_id = 0 # 2 when used
utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' )
utils.SetUpUIWindow( win )
vim.command( 'nnoremap <silent> <buffer> <CR> '
':<C-U>call vimspector#GoToFrame()<CR>' )
vim.command( 'nnoremap <silent> <buffer> <2-LeftMouse> '
':<C-U>call vimspector#GoToFrame()<CR>' )
mappings = settings.Dict( 'mappings' )[ 'stack_trace' ]
with utils.LetCurrentWindow( win ):
for mapping in utils.GetVimList( mappings, 'expand_or_jump' ):
vim.command( f'nnoremap <silent> <buffer> { mapping } '
':<C-U>call vimspector#GoToFrame()<CR>' )
for mapping in utils.GetVimList( mappings, 'focus_thread' ):
vim.command( f'nnoremap <silent> <buffer> { mapping } '
':<C-U>call vimspector#SetCurrentThread()<CR>' )
if utils.UseWinBar():
vim.command( 'nnoremenu <silent> 1.1 WinBar.Pause/Continue '
':call vimspector#PauseContinueThread()<CR>' )
vim.command( 'nnoremenu <silent> 1.2 WinBar.Expand/Collapse '
':call vimspector#GoToFrame()<CR>' )
vim.command( 'nnoremenu <silent> 1.3 WinBar.Focus '
':call vimspector#SetCurrentThread()<CR>' )
win.options[ 'cursorline' ] = False
win.options[ 'signcolumn' ] = 'auto'
if not signs.SignDefined( 'vimspectorCurrentThread' ):
signs.DefineSign( 'vimspectorCurrentThread',
text = '',
double_text = '',
texthl = 'MatchParen',
linehl = 'CursorLine' )
if not signs.SignDefined( 'vimspectorCurrentFrame' ):
signs.DefineSign( 'vimspectorCurrentFrame',
text = '',
double_text = '',
texthl = 'Special',
linehl = 'CursorLine' )
self._line_to_frame = {}
self._line_to_thread = {}
# TODO: We really need a proper state model
#
# AWAIT_CONNECTION -- OnServerReady / RequestThreads --> REQUESTING_THREADS
# REQUESTING -- OnGotThreads / RequestScopes --> REQUESTING_SCOPES
#
# When we attach using gdbserver, this whole thing breaks because we request
# the threads over and over and get duff data back on later threads.
self._requesting_threads = False
self._requesting_threads = StackTraceView.ThreadRequestState.NO
self._pending_thread_request = None
def GetCurrentThreadId( self ):
@ -68,14 +162,22 @@ class StackTraceView( object ):
self._current_frame = None
self._current_thread = None
self._current_syntax = ""
self._threads = []
self._threads.clear()
self._sources = {}
self._requesting_threads = StackTraceView.ThreadRequestState.NO
self._pending_thread_request = None
if self._current_thread_sign_id:
signs.UnplaceSign( self._current_thread_sign_id, 'VimspectorStackTrace' )
self._current_thread_sign_id = 0
if self._current_frame_sign_id:
signs.UnplaceSign( self._current_frame_sign_id, 'VimspectorStackTrace' )
self._current_frame_sign_id = 0
with utils.ModifiableScratchBuffer( self._buf ):
utils.ClearBuffer( self._buf )
def ConnectionUp( self, connection ):
self._connection = connection
self._requesting_threads = False
def ConnectionClosed( self ):
self.Clear()
@ -86,47 +188,95 @@ class StackTraceView( object ):
utils.CleanUpHiddenBuffer( self._buf )
for b in self._scratch_buffers:
utils.CleanUpHiddenBuffer( b )
self._scratch_buffers = []
self._buf = None
def LoadThreads( self, infer_current_frame ):
pending_request = False
if self._requesting_threads:
pending_request = True
def LoadThreads( self,
infer_current_frame,
reason = '',
stopEvent = None ):
if self._requesting_threads != StackTraceView.ThreadRequestState.NO:
self._requesting_threads = StackTraceView.ThreadRequestState.PENDING
self._pending_thread_request = ( infer_current_frame,
reason,
stopEvent )
return
def consume_threads( message ):
self._requesting_threads = False
requesting = False
if self._requesting_threads == StackTraceView.ThreadRequestState.PENDING:
# We may have hit a thread event, so try again.
self._requesting_threads = StackTraceView.ThreadRequestState.NO
self.LoadThreads( *self._pending_thread_request )
requesting = True
if not message[ 'body' ][ 'threads' ]:
if pending_request:
# We may have hit a thread event, so try again.
self.LoadThreads( infer_current_frame )
return
else:
# This is a protocol error. It is required to return at least one!
utils.UserMessage( 'Server returned no threads. Is it running?',
persist = True )
self._requesting_threads = StackTraceView.ThreadRequestState.NO
self._pending_thread_request = None
if not ( message.get( 'body' ) or {} ).get( 'threads' ):
# This is a protocol error. It is required to return at least one!
utils.UserMessage( 'Protocol error: Server returned no threads',
persist = False,
error = True )
return
existing_threads = self._threads[ : ]
self._threads.clear()
for thread in message[ 'body' ][ 'threads' ]:
if stopEvent is not None:
stoppedThreadId = stopEvent.get( 'threadId' )
allThreadsStopped = stopEvent.get( 'allThreadsStopped', False )
# FIXME: This is horribly inefficient
for t in message[ 'body' ][ 'threads' ]:
thread = None
for existing_thread in existing_threads:
if existing_thread.id == t[ 'id' ]:
thread = existing_thread
thread.Update( t )
break
if not thread:
thread = Thread( t )
self._threads.append( thread )
if infer_current_frame and thread[ 'id' ] == self._current_thread:
self._LoadStackTrace( thread, True )
elif infer_current_frame and self._current_thread is None:
self._current_thread = thread[ 'id' ]
self._LoadStackTrace( thread, True )
# If the threads were requested due to a stopped event, update any
# stopped thread state. Note we have to do this here (rather than in the
# stopped event handler) because we must apply this event to any new
# threads that are received here.
if stopEvent:
if allThreadsStopped:
thread.Paused( stopEvent )
elif stoppedThreadId is not None and thread.id == stoppedThreadId:
thread.Paused( stopEvent )
self._DrawThreads()
# If this is a stopped event, load the stack trace for the "current"
# thread. Don't do this on other thrads requests because some servers
# just break when that happens.
#
# Don't do this if we're also satisfying a cached request already (we'll
# do it then)
if infer_current_frame and not requesting:
if thread.id == self._current_thread:
if thread.CanExpand():
self._LoadStackTrace( thread, True, reason )
requesting = True
elif self._current_thread is None:
self._current_thread = thread.id
if thread.CanExpand():
self._LoadStackTrace( thread, True, reason )
requesting = True
if not requesting:
self._DrawThreads()
def failure_handler( reason, msg ):
# Make sure we request them again if the request fails
self._requesting_threads = False
self._requesting_threads = StackTraceView.ThreadRequestState.NO
self._pending_thread_request = None
self._requesting_threads = True
self._requesting_threads = StackTraceView.ThreadRequestState.REQUESTING
self._connection.DoRequest( consume_threads, {
'command': 'threads',
}, failure_handler )
@ -135,26 +285,42 @@ class StackTraceView( object ):
self._line_to_frame.clear()
self._line_to_thread.clear()
if self._current_thread_sign_id:
signs.UnplaceSign( self._current_thread_sign_id, 'VimspectorStackTrace' )
else:
self._current_thread_sign_id = 1
with utils.ModifiableScratchBuffer( self._buf ):
utils.ClearBuffer( self._buf )
with utils.RestoreCursorPosition():
utils.ClearBuffer( self._buf )
for thread in self._threads:
icon = '+' if '_frames' not in thread else '-'
for thread in self._threads:
icon = '+' if not thread.IsExpanded() else '-'
line = utils.AppendToBuffer(
self._buf,
f'{icon} Thread {thread.id}: {thread.thread["name"]} '
f'({thread.State()})' )
line = utils.AppendToBuffer(
self._buf,
'{0} Thread: {1}'.format( icon, thread[ 'name' ] ) )
if self._current_thread == thread.id:
signs.PlaceSign( self._current_thread_sign_id,
'VimspectorStackTrace',
'vimspectorCurrentThread',
self._buf.name,
line )
self._line_to_thread[ line ] = thread
self._line_to_thread[ line ] = thread
self._DrawStackTrace( thread )
self._DrawStackTrace( thread )
def _LoadStackTrace( self,
thread: Thread,
infer_current_frame,
reason = '' ):
def _LoadStackTrace( self, thread, infer_current_frame ):
def consume_stacktrace( message ):
thread[ '_frames' ] = message[ 'body' ][ 'stackFrames' ]
thread.Expand( message[ 'body' ][ 'stackFrames' ] )
if infer_current_frame:
for frame in thread[ '_frames' ]:
if self._JumpToFrame( frame ):
for frame in thread.stacktrace:
if self._JumpToFrame( frame, reason ):
break
self._DrawThreads()
@ -162,32 +328,113 @@ class StackTraceView( object ):
self._connection.DoRequest( consume_stacktrace, {
'command': 'stackTrace',
'arguments': {
'threadId': thread[ 'id' ],
'threadId': thread.id,
}
} )
def ExpandFrameOrThread( self ):
def _GetSelectedThread( self ) -> Thread:
if vim.current.buffer != self._buf:
return None
return self._line_to_thread.get( vim.current.window.cursor[ 0 ] )
def GetSelectedThreadId( self ):
thread = self._GetSelectedThread()
return thread.id if thread else thread
def _SetCurrentThread( self, thread: Thread ):
self._current_thread = thread.id
self._DrawThreads()
def SetCurrentThread( self ):
thread = self._GetSelectedThread()
if thread:
self._SetCurrentThread( thread )
elif vim.current.buffer != self._buf:
return
elif vim.current.window.cursor[ 0 ] in self._line_to_frame:
thread, frame = self._line_to_frame[ vim.current.window.cursor[ 0 ] ]
self._SetCurrentThread( thread )
self._JumpToFrame( frame )
else:
utils.UserMessage( "No thread selected" )
current_line = vim.current.window.cursor[ 0 ]
def ExpandFrameOrThread( self ):
thread = self._GetSelectedThread()
if current_line in self._line_to_frame:
self._JumpToFrame( self._line_to_frame[ current_line ] )
elif current_line in self._line_to_thread:
thread = self._line_to_thread[ current_line ]
if '_frames' in thread:
del thread[ '_frames' ]
with utils.RestoreCursorPosition():
self._DrawThreads()
else:
if thread:
if thread.IsExpanded():
thread.Collapse()
self._DrawThreads()
elif thread.CanExpand():
self._LoadStackTrace( thread, False )
else:
utils.UserMessage( "Thread is not stopped" )
elif vim.current.buffer != self._buf:
return
elif vim.current.window.cursor[ 0 ] in self._line_to_frame:
thread, frame = self._line_to_frame[ vim.current.window.cursor[ 0 ] ]
self._JumpToFrame( frame )
def _JumpToFrame( self, 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:
return True
return False
def _JumpToFrame( self, frame, reason = '' ):
def do_jump():
if 'line' in frame and frame[ 'line' ] > 0:
# Should this set the current _Thread_ too ? If i jump to a frame in
# Thread 2, should that become the focussed thread ?
self._current_frame = frame
return self._session.SetCurrentFrame( self._current_frame )
self._DrawThreads()
return self._session.SetCurrentFrame( self._current_frame, reason )
return False
source = frame.get( 'source' ) or {}
@ -202,59 +449,94 @@ class StackTraceView( object ):
else:
return do_jump()
def PauseContinueThread( self ):
thread = self._GetSelectedThread()
if thread is None:
utils.UserMessage( 'No thread selected' )
elif thread.state == Thread.PAUSED:
self._session._connection.DoRequest(
lambda msg: self.OnContinued( {
'threadId': thread.id,
'allThreadsContinued': ( msg.get( 'body' ) or {} ).get(
'allThreadsContinued',
True )
} ),
{
'command': 'continue',
'arguments': {
'threadId': thread.id,
},
} )
elif thread.state == Thread.RUNNING:
self._session._connection.DoRequest( None, {
'command': 'pause',
'arguments': {
'threadId': thread.id,
},
} )
else:
utils.UserMessage(
f'Thread cannot be modified in state {thread.State()}' )
def OnContinued( self, event = None ):
threadId = None
allThreadsContinued = True
if event is not None:
threadId = event[ 'threadId' ]
allThreadsContinued = event.get( 'allThreadsContinued', False )
for thread in self._threads:
if allThreadsContinued:
thread.Continued()
elif thread.id == threadId:
thread.Continued()
break
self._DrawThreads()
def OnStopped( self, event ):
if 'threadId' in event:
self._current_thread = event[ 'threadId' ]
elif event.get( 'allThreadsStopped', False ) and self._threads:
self._current_thread = self._threads[ 0 ][ 'id' ]
threadId = event.get( 'threadId' )
allThreadsStopped = event.get( 'allThreadsStopped', False )
if self._current_thread is not None:
for thread in self._threads:
if thread[ 'id' ] == self._current_thread:
self._LoadStackTrace( thread, True )
return
# Work out if we should change the current thread
if threadId is not None:
self._current_thread = threadId
elif self._current_thread is None and allThreadsStopped and self._threads:
self._current_thread = self._threads[ 0 ].id
self.LoadThreads( True )
self.LoadThreads( True, 'stopped', event )
def OnThreadEvent( self, event ):
infer_current_frame = False
if event[ 'reason' ] == 'started' and self._current_thread is None:
self._current_thread = event[ 'threadId' ]
self.LoadThreads( True )
infer_current_frame = True
def Continue( self ):
if self._current_thread is None:
utils.UserMessage( 'No current thread', persist = True )
if event[ 'reason' ] == 'exited':
for thread in self._threads:
if thread.id == event[ 'threadId' ]:
thread.Exited()
break
self.LoadThreads( infer_current_frame )
def OnExited( self, event ):
for thread in self._threads:
thread.Exited()
def _DrawStackTrace( self, thread: Thread ):
if not thread.IsExpanded():
return
self._session._connection.DoRequest( None, {
'command': 'continue',
'arguments': {
'threadId': self._current_thread,
},
} )
if self._current_frame_sign_id:
signs.UnplaceSign( self._current_frame_sign_id, 'VimspectorStackTrace' )
else:
self._current_frame_sign_id = 2
self._session.ClearCurrentFrame()
self.LoadThreads( True )
def Pause( self ):
if self._current_thread is None:
utils.UserMessage( 'No current thread', persist = True )
return
self._session._connection.DoRequest( None, {
'command': 'pause',
'arguments': {
'threadId': self._current_thread,
},
} )
def _DrawStackTrace( self, thread ):
if '_frames' not in thread:
return
stackFrames = thread[ '_frames' ]
for frame in stackFrames:
for frame in thread.stacktrace:
if frame.get( 'source' ):
source = frame[ 'source' ]
else:
@ -278,7 +560,15 @@ class StackTraceView( object ):
source[ 'name' ],
frame[ 'line' ] ) )
self._line_to_frame[ line ] = frame
if ( self._current_frame is not None and
self._current_frame[ 'id' ] == frame[ 'id' ] ):
signs.PlaceSign( self._current_frame_sign_id,
'VimspectorStackTrace',
'vimspectorCurrentFrame',
self._buf.name,
line )
self._line_to_frame[ line ] = ( thread, frame )
def _ResolveSource( self, source, and_then ):
source_reference = int( source[ 'sourceReference' ] )

View file

@ -1,5 +1,6 @@
from vimspector import utils, settings
import os
import vim
@ -17,17 +18,58 @@ def LaunchTerminal( api_prefix,
else:
term = existing_term
cwd = params[ 'cwd' ]
args = params[ 'args' ]
env = params.get( 'env', {} )
cwd = params[ 'cwd' ] or os.getcwd()
args = params[ 'args' ] or []
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
@ -49,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(

View file

@ -45,14 +45,20 @@ _logger = logging.getLogger( __name__ )
SetUpLogging( _logger )
def BufferNumberForFile( file_name ):
return int( vim.eval( "bufnr( '{0}', 1 )".format( Escape( file_name ) ) ) )
def BufferNumberForFile( file_name, create = True ):
return int( vim.eval( "bufnr( '{0}', {1} )".format(
Escape( file_name ),
int( create ) ) ) )
def BufferForFile( file_name ):
return vim.buffers[ BufferNumberForFile( file_name ) ]
def BufferExists( file_name ):
return bool( int ( vim.eval( f"bufexists( '{ Escape( file_name ) }' )" ) ) )
def NewEmptyBuffer():
bufnr = int( vim.eval( 'bufadd("")' ) )
Call( 'bufload', bufnr )
@ -350,20 +356,63 @@ def SelectFromList( prompt, options ):
return None
def AskForInput( prompt, default_value = None ):
def AskForInput( prompt, default_value = None, completion = None ):
if default_value is None:
default_option = ''
else:
default_option = ", '{}'".format( Escape( default_value ) )
default_value = ''
args = [ prompt, default_value ]
if completion is not None:
if completion == 'expr':
args.append( 'custom,vimspector#CompleteExpr' )
else:
args.append( completion )
with InputSave():
try:
return vim.eval( "input( '{}' {} )".format( Escape( prompt ),
default_option ) )
return Call( 'input', *args )
except ( KeyboardInterrupt, vim.error ):
return None
CONFIRM = {}
CONFIRM_ID = 0
def ConfirmCallback( confirm_id, result ):
try:
handler = CONFIRM.pop( confirm_id )
except KeyError:
UserMessage( f"Internal error: unexpected callback id { confirm_id }",
persist = True,
error = True )
return
handler( result )
def Confirm( api_prefix,
prompt,
handler,
default_value = 2,
options: list = None,
keys: list = None ):
if not options:
options = [ '(Y)es', '(N)o' ]
if not keys:
keys = [ 'y', 'n' ]
global CONFIRM_ID
CONFIRM_ID += 1
CONFIRM[ CONFIRM_ID ] = handler
Call( f'vimspector#internal#{ api_prefix }popup#Confirm',
CONFIRM_ID,
prompt,
options,
default_value,
keys )
def AppendToBuffer( buf, line_or_lines, modified=False ):
line = 1
try:
@ -392,8 +441,10 @@ def AppendToBuffer( buf, line_or_lines, modified=False ):
def ClearBuffer( buf ):
def ClearBuffer( buf, modified = False ):
buf[ : ] = None
if not modified:
buf.options[ 'modified' ] = False
def SetBufferContents( buf, lines, modified=False ):
@ -454,8 +505,8 @@ VAR_MATCH = re.compile(
{(?P<braceddefault> # or An {id:default} - default param, as
(?P<defname>[_a-z][_a-z0-9]*) # an ID
: # then a colon
(?P<default>(?:[^}]|\})*) # then anything up to }, or a \}
)} | #
(?P<default>(?:\\}|[^}])*) # then anything up to }, or a \}
)} | # then a }
(?P<invalid>) # or Something else - invalid
)
""",
@ -483,7 +534,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( '\\}', '}' ) )
@ -525,8 +575,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 )
@ -628,15 +681,19 @@ def ParseVariables( variables_list,
return new_variables
def DisplayBaloon( is_term, display ):
def DisplayBalloon( is_term, display, is_hover = False ):
if not is_term:
display = '\n'.join( display )
# To enable the Windows GUI to display the balloon correctly
# Refer https://github.com/vim/vim/issues/1512#issuecomment-492070685
vim.eval( "balloon_show( '' )" )
display = '\n'.join( display )
vim.eval( "balloon_show( {0} )".format(
json.dumps( display ) ) )
created_win_id = int( vim.eval(
"vimspector#internal#balloon#CreateTooltip({}, {})".format(
int( is_hover ), json.dumps( display )
)
) )
return created_win_id
def GetBufferFilepath( buf ):
@ -697,7 +754,7 @@ def SetSyntax( current_syntax, syntax, *args ):
syntax = ''
if current_syntax == syntax:
return
return syntax
# We use set syn= because just setting vim.Buffer.options[ 'syntax' ]
# doesn't actually trigger the Syntax autocommand, and i'm not sure that
@ -713,6 +770,28 @@ def GetBufferFiletypes( buf ):
return ft.split( '.' )
def GetVisualSelection( bufnr ):
start_line, start_col = vim.current.buffer.mark( "<" )
end_line, end_col = vim.current.buffer.mark( ">" )
# lines are 1 based, but columns are 0 based
# don't ask me why...
start_line -= 1
end_line -= 1
lines = vim.buffers[ bufnr ][ start_line : end_line + 1 ]
# Do end first, in case it's on the same line as start (as doing start first
# would change the offset)
lines[ -1 ] = lines[ -1 ][ : end_col + 1 ]
lines[ 0 ] = lines[ 0 ][ start_col : ]
_logger.debug( f'Visual selection: { lines } from '
f'{ start_line }/{ start_col } -> { end_line }/{ end_col }' )
return lines
def DisplaySplash( api_prefix, splash, text ):
if splash:
return Call( f'vimspector#internal#{api_prefix}popup#UpdateSplash',
@ -779,3 +858,9 @@ def WindowID( window, tab=None ):
if tab is None:
tab = window.tabpage
return int( Call( 'win_getid', window.number, tab.number ) )
def UseWinBar():
# Buggy neovim doesn't render correctly when the WinBar is defined:
# https://github.com/neovim/neovim/issues/12689
return not int( Call( 'has', 'nvim' ) )

View file

@ -19,7 +19,7 @@ import logging
from functools import partial
import typing
from vimspector import utils
from vimspector import utils, settings
class Expandable:
@ -32,8 +32,9 @@ class Expandable:
a 'variablesReference' to be resolved by the 'variables' request. Records the
current state expanded/collapsed. Implementations just implement
VariablesReference to get the variables."""
def __init__( self ):
def __init__( self, container: 'Expandable' = None ):
self.variables: typing.List[ 'Variable' ] = None
self.container: Expandable = container
# None is Falsy and represents collapsed _by default_. WHen set to False,
# this means the user explicitly collapsed it. When True, the user expanded
# it (or we expanded it by default).
@ -48,6 +49,9 @@ class Expandable:
def IsExpandable( self ):
return self.VariablesReference() > 0
def IsContained( self ):
return self.container is not None
@abc.abstractmethod
def VariablesReference( self ):
assert False
@ -84,10 +88,16 @@ class WatchResult( Expandable ):
self.result = result
class WatchFailure( WatchResult ):
def __init__( self, reason ):
super().__init__( { 'result': reason } )
self.changed = True
class Variable( Expandable ):
"""Holds one level of an expanded value tree. Also itself expandable."""
def __init__( self, variable: dict ):
super().__init__()
def __init__( self, container: Expandable, variable: dict ):
super().__init__( container = container )
self.variable = variable
# A new variable appearing is marked as changed
self.changed = True
@ -111,17 +121,48 @@ class Watch:
self.expression = expression
self.result = None
@staticmethod
def New( frame, expression, context ):
watch = {
'expression': expression,
'context': context,
}
if frame:
watch[ 'frameId' ] = frame[ 'id' ]
return Watch( watch )
class View:
lines: typing.Dict[ int, Expandable ]
draw: typing.Callable
syntax: str
def __init__( self, win, lines, draw ):
self.lines = lines
self.draw = draw
self.buf = win.buffer
self.syntax = None
if win is not None:
self.buf = win.buffer
utils.SetUpUIWindow( win )
utils.SetUpUIWindow( win )
class BufView( View ):
def __init__( self, buf, lines, draw ):
super().__init__( None, lines, draw )
self.buf = buf
def AddExpandMappings( mappings = None ):
if mappings is None:
mappings = settings.Dict( 'mappings' )[ 'variables' ]
for mapping in utils.GetVimList( mappings, 'expand_collapse' ):
vim.command( f'nnoremap <silent> <buffer> { mapping } '
':<C-u>call vimspector#ExpandVariable()<CR>' )
for mapping in utils.GetVimList( mappings, 'set_value' ):
vim.command( f'nnoremap <silent> <buffer> { mapping } '
':<C-u>call vimspector#SetVariableValue()<CR>' )
class VariablesView( object ):
@ -131,19 +172,22 @@ class VariablesView( object ):
self._connection = None
self._current_syntax = ''
self._server_capabilities = None
def AddExpandMappings():
vim.command( 'nnoremap <silent> <buffer> <CR> '
':<C-u>call vimspector#ExpandVariable()<CR>' )
vim.command( 'nnoremap <silent> <buffer> <2-LeftMouse> '
':<C-u>call vimspector#ExpandVariable()<CR>' )
self._variable_eval: Scope = None
self._variable_eval_view: View = None
mappings = settings.Dict( 'mappings' )[ 'variables' ]
# Set up the "Variables" buffer in the variables_win
self._scopes: typing.List[ Scope ] = []
self._vars = View( variables_win, {}, self._DrawScopes )
utils.SetUpHiddenBuffer( self._vars.buf, 'vimspector.Variables' )
with utils.LetCurrentWindow( variables_win ):
AddExpandMappings()
if utils.UseWinBar():
vim.command( 'nnoremenu <silent> 1.1 WinBar.Set '
':call vimspector#SetVariableValue()<CR>' )
AddExpandMappings( mappings )
# Set up the "Watches" buffer in the watches_win (and create a WinBar in
# there)
@ -155,16 +199,20 @@ class VariablesView( object ):
'vimspector#AddWatchPrompt',
'vimspector#OmniFuncWatch' )
with utils.LetCurrentWindow( watches_win ):
AddExpandMappings()
vim.command(
'nnoremap <buffer> <DEL> :call vimspector#DeleteWatch()<CR>' )
AddExpandMappings( mappings )
for mapping in utils.GetVimList( mappings, 'delete' ):
vim.command(
f'nnoremap <buffer> { mapping } :call vimspector#DeleteWatch()<CR>' )
vim.command( 'nnoremenu 1.1 WinBar.New '
':call vimspector#AddWatch()<CR>' )
vim.command( 'nnoremenu 1.2 WinBar.Expand/Collapse '
':call vimspector#ExpandVariable()<CR>' )
vim.command( 'nnoremenu 1.3 WinBar.Delete '
':call vimspector#DeleteWatch()<CR>' )
if utils.UseWinBar():
vim.command( 'nnoremenu <silent> 1.1 WinBar.New '
':call vimspector#AddWatch()<CR>' )
vim.command( 'nnoremenu <silent> 1.2 WinBar.Expand/Collapse '
':call vimspector#ExpandVariable()<CR>' )
vim.command( 'nnoremenu <silent> 1.3 WinBar.Delete '
':call vimspector#DeleteWatch()<CR>' )
vim.command( 'nnoremenu <silent> 1.1 WinBar.Set '
':call vimspector#SetVariableValue()<CR>' )
# Set the (global!) balloon expr if supported
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
@ -176,7 +224,9 @@ class VariablesView( object ):
'balloonexpr': vim.options[ 'balloonexpr' ],
'balloondelay': vim.options[ 'balloondelay' ],
}
vim.options[ 'balloonexpr' ] = 'vimspector#internal#balloon#BalloonExpr()'
vim.options[ 'balloonexpr' ] = ( "vimspector#internal#"
"balloon#HoverTooltip()" )
vim.options[ 'balloondelay' ] = 250
if has_balloon:
@ -194,21 +244,30 @@ class VariablesView( object ):
utils.ClearBuffer( self._vars.buf )
with utils.ModifiableScratchBuffer( self._watch.buf ):
utils.ClearBuffer( self._watch.buf )
self.ClearTooltip()
self._current_syntax = ''
def ConnectionUp( self, connection ):
self._connection = connection
def SetServerCapabilities( self, capabilities ):
self._server_capabilities = capabilities
def ConnectionClosed( self ):
self.Clear()
self._connection = None
self._server_capabilities = None
def Reset( self ):
self._server_capabilities = None
for k, v in self._oldoptions.items():
vim.options[ k ] = v
utils.CleanUpHiddenBuffer( self._vars.buf )
utils.CleanUpHiddenBuffer( self._watch.buf )
self.ClearTooltip()
def LoadScopes( self, frame ):
def scopes_consumer( message ):
@ -260,15 +319,97 @@ class VariablesView( object ):
},
} )
def AddWatch( self, frame, expression ):
watch = {
'expression': expression,
'context': 'watch',
}
if frame:
watch[ 'frameId' ] = frame[ 'id' ]
def _DrawBalloonEval( self ):
watch = self._variable_eval
view = self._variable_eval_view
self._watches.append( Watch( watch ) )
with utils.RestoreCursorPosition():
with utils.ModifiableScratchBuffer( view.buf ):
utils.ClearBuffer( view.buf )
view.syntax = utils.SetSyntax( view.syntax,
self._current_syntax,
view.buf )
self._DrawWatchResult( view,
0,
watch,
is_short = True )
vim.eval( "vimspector#internal#balloon#ResizeTooltip()" )
def ClearTooltip( self ):
# This will actually end up calling CleanUpTooltip via the popup close
# callback
vim.eval( 'vimspector#internal#balloon#Close()' )
def CleanUpTooltip( self ) :
# remove reference to old tooltip window
self._variable_eval_view = None
vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = None
def VariableEval( self, frame, expression, is_hover ):
"""Callback to display variable under cursor `:h ballonexpr`"""
if not self._connection:
return ''
def handler( message ):
watch = self._variable_eval
if watch.result is None:
watch.result = WatchResult( message[ 'body' ] )
else:
watch.result.Update( message[ 'body' ] )
popup_win_id = utils.DisplayBalloon( self._is_term, [], is_hover )
# record the global eval window id
vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = int( popup_win_id )
popup_bufnr = int( vim.eval( "winbufnr({})".format( popup_win_id ) ) )
# We don't need to do any UI window setup here, as it's already done as
# part of the popup creation, so just pass the buffer to the View instance
self._variable_eval_view = BufView(
vim.buffers[ popup_bufnr ],
{},
self._DrawBalloonEval
)
if watch.result.IsExpandable():
# Always expand the first level
watch.result.expanded = Expandable.EXPANDED_BY_US
if watch.result.IsExpanded():
self._connection.DoRequest( partial( self._ConsumeVariables,
self._variable_eval_view.draw,
watch.result ), {
'command': 'variables',
'arguments': {
'variablesReference': watch.result.VariablesReference(),
},
} )
self._DrawBalloonEval()
def failure_handler( reason, message ):
display = [ reason ]
float_win_id = utils.DisplayBalloon( self._is_term, display, is_hover )
# record the global eval window id
vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = int( float_win_id )
self._variable_eval = Watch.New( frame,
expression,
'hover' )
# Send async request
self._connection.DoRequest( handler, {
'command': 'evaluate',
'arguments': self._variable_eval.expression,
}, failure_handler )
# Return working (meanwhile)
return ''
def AddWatch( self, frame, expression ):
self._watches.append( Watch.New( frame, expression, 'watch' ) )
self.EvaluateWatches()
def DeleteWatch( self ):
@ -295,11 +436,14 @@ class VariablesView( object ):
def EvaluateWatches( self ):
for watch in self._watches:
self._connection.DoRequest( partial( self._UpdateWatchExpression,
watch ), {
'command': 'evaluate',
'arguments': watch.expression,
} )
self._connection.DoRequest(
partial( self._UpdateWatchExpression, watch ),
{
'command': 'evaluate',
'arguments': watch.expression,
},
failure_handler = lambda reason, msg, watch=watch:
self._WatchExpressionFailed( reason, watch ) )
def _UpdateWatchExpression( self, watch: Watch, message: dict ):
if watch.result is not None:
@ -320,19 +464,42 @@ class VariablesView( object ):
self._DrawWatches()
def ExpandVariable( self ):
if vim.current.buffer == self._vars.buf:
def _WatchExpressionFailed( self, reason: str, watch: Watch ):
if watch.result is not None:
# We already have a result for this watch. Wut ?
return
watch.result = WatchFailure( reason )
self._DrawWatches()
def _GetVariable( self, buf = None, line_num = None ):
none = ( None, None )
if buf is None:
buf = vim.current.buffer
if line_num is None:
line_num = vim.current.window.cursor[ 0 ]
if buf == self._vars.buf:
view = self._vars
elif vim.current.buffer == self._watch.buf:
elif buf == self._watch.buf:
view = self._watch
elif ( self._variable_eval_view is not None
and buf == self._variable_eval_view.buf ):
view = self._variable_eval_view
else:
return
return none
current_line = vim.current.window.cursor[ 0 ]
if current_line not in view.lines:
return
if line_num not in view.lines:
return none
variable = view.lines[ current_line ]
return view.lines[ line_num ], view
def ExpandVariable( self, buf = None, line_num = None ):
variable, view = self._GetVariable( buf, line_num )
if variable is None:
return
if variable.IsExpanded():
# Collapse
@ -353,25 +520,101 @@ class VariablesView( object ):
},
} )
def _DrawVariables( self, view, variables, indent ):
def SetVariableValue( self, new_value = None, buf = None, line_num = None ):
variable: Variable
view: View
if not self._server_capabilities.get( 'supportsSetVariable' ):
return
variable, view = self._GetVariable( buf, line_num )
if variable is None:
return
if not variable.IsContained():
return
if new_value is None:
new_value = utils.AskForInput( 'New Value: ',
variable.variable.get( 'value', '' ),
completion = 'expr' )
if new_value is None:
return
def handler( message ):
# Annoyingly the response to setVariable request doesn't return a
# Variable, but some part of it, so take a copy of the existing Variable
# dict and update it, then call its update method with the updated copy.
new_variable = dict( variable.variable )
new_variable.update( message[ 'body' ] )
# Clear any existing known children (FIXME: Is this the right thing to do)
variable.variables = None
# If the variable is expanded, re-request its children
if variable.IsExpanded():
self._connection.DoRequest( partial( self._ConsumeVariables,
view.draw,
variable ), {
'command': 'variables',
'arguments': {
'variablesReference': variable.VariablesReference()
},
} )
variable.Update( new_variable )
view.draw()
def failure_handler( reason, message ):
utils.UserMessage( f'Cannot set value: { reason }', error = True )
self._connection.DoRequest( handler, {
'command': 'setVariable',
'arguments': {
'variablesReference': variable.container.VariablesReference(),
'name': variable.variable[ 'name' ],
'value': new_value
},
}, failure_handler = failure_handler )
def _DrawVariables( self, view, variables, indent, is_short = False ):
assert indent > 0
for variable in variables:
line = utils.AppendToBuffer(
view.buf,
'{indent}{marker}{icon} {name} ({type_}): {value}'.format(
text = ''
if is_short:
text = '{indent}{icon} {name}: {value}'.format(
# We borrow 1 space of indent to draw the change marker
indent = ' ' * ( indent - 1 ),
icon = '+' if ( variable.IsExpandable()
and not variable.IsExpanded() ) else '-',
name = variable.variable.get( 'name', '' ),
value = variable.variable.get( 'value', '<unknown>' )
)
else:
text = '{indent}{marker}{icon} {name} ({type_}): {value}'.format(
# We borrow 1 space of indent to draw the change marker
indent = ' ' * ( indent - 1 ),
marker = '*' if variable.changed else ' ',
icon = '+' if ( variable.IsExpandable()
and not variable.IsExpanded() ) else '-',
name = variable.variable[ 'name' ],
name = variable.variable.get( 'name', '' ),
type_ = variable.variable.get( 'type', '' ),
value = variable.variable.get( 'value',
'<unknown>' ) ).split( '\n' ) )
value = variable.variable.get( 'value', '<unknown>' )
)
line = utils.AppendToBuffer(
view.buf,
text.split( '\n' )
)
view.lines[ line ] = variable
if variable.ShouldDrawDrillDown():
self._DrawVariables( view, variable.variables, indent + 2 )
self._DrawVariables( view, variable.variables, indent + 2, is_short )
def _DrawScopes( self ):
# FIXME: The drawing is dumb and draws from scratch every time. This is
@ -398,7 +641,7 @@ class VariablesView( object ):
'Expression: '
+ watch.expression[ 'expression' ] )
watch.line = line
self._DrawWatchResult( 2, watch )
self._DrawWatchResult( self._watch, 2, watch )
def _DrawScope( self, indent, scope ):
icon = '+' if scope.IsExpandable() and not scope.IsExpanded() else '-'
@ -414,27 +657,36 @@ class VariablesView( object ):
indent += 2
self._DrawVariables( self._vars, scope.variables, indent )
def _DrawWatchResult( self, indent, watch ):
def _DrawWatchResult( self, view, indent, watch, is_short = False ):
if not watch.result:
return
assert indent > 0
icon = '+' if ( watch.result.IsExpandable() and
not watch.result.IsExpanded() ) else '-'
assert is_short or indent > 0
line = '{indent}{marker}{icon} Result: {result}'.format(
if is_short:
# The first result is always expanded in a hover (short format)
icon = ''
marker = ''
leader = ''
else:
icon = '+' if ( watch.result.IsExpandable() and
not watch.result.IsExpanded() ) else '-'
marker = '*' if watch.result.changed else ' '
leader = ' Result: '
line = '{indent}{marker}{icon}{leader}{result}'.format(
# We borrow 1 space of indent to draw the change marker
indent = ' ' * ( indent - 1 ),
marker = '*' if watch.result.changed else ' ',
marker = marker,
icon = icon,
leader = leader,
result = watch.result.result.get( 'result', '<unknown>' ) )
line = utils.AppendToBuffer( self._watch.buf, line.split( '\n' ) )
self._watch.lines[ line ] = watch.result
line = utils.AppendToBuffer( view.buf, line.split( '\n' ) )
view.lines[ line ] = watch.result
if watch.result.ShouldDrawDrillDown():
indent = 4
self._DrawVariables( self._watch, watch.result.variables, indent )
self._DrawVariables( view, watch.result.variables, indent + 2, is_short )
def _ConsumeVariables( self, draw, parent, message ):
new_variables = []
@ -449,9 +701,8 @@ class VariablesView( object ):
variable = v
found = True
break
if not found:
variable = Variable( variable_body )
variable = Variable( parent, variable_body )
else:
variable.Update( variable_body )
@ -471,47 +722,10 @@ class VariablesView( object ):
draw()
def ShowBalloon( self, frame, expression ):
"""Callback to display variable under cursor `:h ballonexpr`"""
if not self._connection:
return ''
def handler( message ):
# TODO: this result count be expandable, but we have no way to allow the
# user to interact with the balloon to expand it, unless we use a popup
# instead, but even then we don't really want to trap the cursor.
body = message[ 'body' ]
result = body[ 'result' ]
if result is None:
result = 'null'
display = [
'Type: ' + body.get( 'type', '<unknown>' ),
'Value: ' + result
]
utils.DisplayBaloon( self._is_term, display )
def failure_handler( reason, message ):
display = [ reason ]
utils.DisplayBaloon( self._is_term, display )
# Send async request
self._connection.DoRequest( handler, {
'command': 'evaluate',
'arguments': {
'expression': expression,
'frameId': frame[ 'id' ],
'context': 'hover',
}
}, failure_handler )
# Return working (meanwhile)
return '...'
def SetSyntax( self, syntax ):
# TODO: Switch to View.syntax
self._current_syntax = utils.SetSyntax( self._current_syntax,
syntax,
self._vars.buf,
self._watch.buf )
# vim: sw=2

View file

@ -21,7 +21,7 @@ out_fd=1
while [ -n "$1" ]; do
case "$1" in
"--basedir")
"--basedir"|"--base-dir"|"--test-base")
shift
SetBaseDir $1
shift
@ -36,7 +36,7 @@ while [ -n "$1" ]; do
INSTALL=$1
shift
;;
"--update")
"--update"|"--upgrade")
UPDATE=1
shift
;;
@ -91,7 +91,8 @@ if [ "$INSTALL" = "1" ] || [ "$INSTALL" = "script" ]; then
if ! python3 $(dirname $0)/install_gadget.py \
--basedir ${BASEDIR} \
${INSTALLER_ARGS} \
--all; then
--all \
--force-enable-csharp; then
echo "Script installation reported errors" >&2
exit 1
fi
@ -102,7 +103,7 @@ if [ "$INSTALL" = "1" ] || [ "$INSTALL" = "vim" ]; then
--cmd "${BASEDIR_CMD}" \
-c 'autocmd User VimspectorInstallSuccess qa!' \
-c 'autocmd User VimspectorInstallFailed cquit!' \
-c "VimspectorInstall --all"; then
-c "VimspectorInstall --all netcoredbg"; then
echo "Vim installation reported errors" >&2
exit 1
fi
@ -144,6 +145,9 @@ set -e
pushd tests/testdata/cpp/simple
make clean all
popd
pushd support/test/csharp
dotnet build
popd
set +e
echo "%DONE - built test programs"

View file

@ -1,5 +1,12 @@
" setup boilerplate to make this file usable with vim -Nu <tihs file> {{{
scriptencoding utf-8
execute 'source' expand( '<sfile>:p:h' ) . '/minimal_vimrc'
set noequalalways
let mapleader = ','
let maplocalleader = "\<Space>"
" }}}
" Custom Layout {{{
function! s:CustomiseUI()
let wins = g:vimspector_session_windows
@ -31,6 +38,10 @@ function! s:CustomiseUI()
endfunction
function s:SetUpTerminal()
if !has_key( g:vimspector_session_windows, 'terminal' )
" There's a neovim bug which means that this doesn't work in neovim
return
endif
let terminal_win = g:vimspector_session_windows.terminal
" Make the terminal window at most 80 columns wide, ensuring there is enough
@ -43,7 +54,7 @@ function s:SetUpTerminal()
let padding = 4
let cols = max( [ min( [ &columns - left_bar - code - padding, 80 ] ), 10 ] )
call win_gotoid( terminal_win )
execute cols . 'wincmd |'
execute string(cols) . 'wincmd |'
endfunction
function! s:CustomiseWinBar()
@ -66,9 +77,85 @@ augroup TestUICustomistaion
autocmd User VimspectorUICreated call s:CustomiseWinBar()
augroup END
" }}}
" Custom sign priority {{{
let g:vimspector_sign_priority = {
\ 'vimspectorBP': 3,
\ 'vimspectorBPCond': 2,
\ 'vimspectorBPDisabled': 1,
\ 'vimspectorPC': 999,
\ }
" }}}
" Custom mappings while debuggins {{{
let s:mapped = {}
function! s:OnJumpToFrame() abort
if has_key( s:mapped, string( bufnr() ) )
return
endif
nmap <silent> <buffer> <LocalLeader>dn <Plug>VimspectorStepOver
nmap <silent> <buffer> <LocalLeader>ds <Plug>VimspectorStepInto
nmap <silent> <buffer> <LocalLeader>df <Plug>VimspectorStepOut
nmap <silent> <buffer> <LocalLeader>dc <Plug>VimspectorContinue
nmap <silent> <buffer> <LocalLeader>di <Plug>VimspectorBalloonEval
xmap <silent> <buffer> <LocalLeader>di <Plug>VimspectorBalloonEval
let s:mapped[ string( bufnr() ) ] = { 'modifiable': &modifiable }
setlocal nomodifiable
endfunction
function! s:OnDebugEnd() abort
let original_buf = bufnr()
let hidden = &hidden
try
set hidden
for bufnr in keys( s:mapped )
try
execute 'noautocmd buffer' bufnr
silent! nunmap <buffer> <LocalLeader>dn
silent! nunmap <buffer> <LocalLeader>ds
silent! nunmap <buffer> <LocalLeader>df
silent! nunmap <buffer> <LocalLeader>dc
silent! nunmap <buffer> <LocalLeader>di
silent! xunmap <buffer> <LocalLeader>di
let &l:modifiable = s:mapped[ bufnr ][ 'modifiable' ]
endtry
endfor
finally
execute 'noautocmd buffer' original_buf
let &hidden = hidden
endtry
let s:mapped = {}
endfunction
augroup TestCustomMappings
au!
autocmd User VimspectorJumpedToFrame call s:OnJumpToFrame()
autocmd User VimspectorDebugEnded call s:OnDebugEnd()
augroup END
" }}}
" Custom mappings for special buffers {{{
let g:vimspector_mappings = {
\ 'stack_trace': {},
\ 'variables': {
\ 'set_value': [ '<Tab>', '<C-CR>', 'C' ],
\ }
\ }
" }}}
" vim: foldmethod=marker

View file

@ -0,0 +1,8 @@
# Manually updating shipped gadgets
Download the gadget files manuall from their official source into this dir.
Run `./checksum.py <list of files>` to get the checksums.
Update ../../python3/vimspector/gadgets.py with the new version and the
checksums.

View file

@ -0,0 +1,13 @@
#!/usr/bin/env python3
import hashlib
import sys
def GetChecksumSHA254( file_path ):
with open( file_path, 'rb' ) as existing_file:
return hashlib.sha256( existing_file.read() ).hexdigest()
for arg in sys.argv[ 1: ]:
print( f"{ arg } = { GetChecksumSHA254( arg ) }" )

View file

@ -0,0 +1,15 @@
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json",
"configurations": {
"Run Current Script": {
"adapter": "vscode-bash",
"autoselect": false,
"configuration": {
"request": "launch",
"program": "${file}",
"cwd": "${fileDirname}",
"args": [ "*${args}" ]
}
}
}
}

View file

@ -1,12 +1,29 @@
{
"configurations": {
"simple_c_program - Launch": {
"adapter": "vscode-cpptools",
"CodeLLDB": {
"adapter": "CodeLLDB",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/test",
"stopAtEntry": true
}
},
"lldb-vscode": {
"adapter": "lldb-vscode",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/test",
"stopAtEntry": true
}
},
"cpptools": {
"adapter": "vscode-cpptools",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/test",
"stopOnEntry": true,
"MIMode": "lldb"
}
}
}
}

View file

@ -1,4 +1,4 @@
def Settings( **kwargs ):
return {
'flags': [ '-x', 'c++', '-Wall', '-Wextra' ]
'flags': [ '-x', 'c++', '-Wall', '-Wextra', '-std=c++17' ]
}

View file

@ -1,3 +1,5 @@
#include <cstdio>
#include <cstdlib>
#include <iostream>
namespace Test
@ -33,6 +35,8 @@ int main ( int argc, char ** argv )
{
int x{ 10 };
printf( "HOME: %s\n", getenv( "HOME" ) );
Test::TestStruct t{ true, {99} };
foo( t );
}

View file

@ -1,2 +1,3 @@
bin/
obj/Debug
obj/

View file

@ -1,21 +1,57 @@
{
"configurations": {
"launch - netcoredbg": {
"adapter": "netcoredbg",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll",
"args": [],
"stopAtEntry": true
}
"adapters": {
"netcoredbg-debuglog": {
"attach": {
"pidProperty": "processId",
"pidSelect": "ask"
},
"launch - mono": {
"adapter": "vscode-mono-debug",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/Program.exe"
}
"command": [
"${gadgetDir}/netcoredbg/netcoredbg",
"--interpreter=vscode",
"--engineLogging=${workspaceRoot}/netcoredbg.engine.log",
"--log=${workspaceRoot}/netcoredbg.log"
],
"configuration": {
"cwd": "${workspaceRoot}"
},
"name": "netcoredbg"
}
},
"configurations": {
//
// NOTE:
// If you add to this, you must update tests/get_configurations.test.vim
//
"launch - netcoredbg": {
"adapter": "netcoredbg",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/netcoreapp3.1/csharp.dll",
"args": [],
"stopAtEntry": false
}
},
"launch - netcoredbg - with debug log": {
"adapter": "netcoredbg-debuglog",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/netcoreapp3.1/csharp.dll",
"args": [],
"stopAtEntry": false
}
},
"launch - mono": {
"adapter": "vscode-mono-debug",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/Program.exe",
"console": "integratedTerminal",
"cwd": "${workspaceRoot}",
"args": [],
"env": {}
}
}
}
}

View file

@ -2,11 +2,36 @@
namespace csharp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
class Program
{
string toaster = "Making round of toast";
static int max_bread = 100;
int bread = max_bread;
void PrintToast( int r ) {
int this_round = ( max_bread - bread - r);
Console.WriteLine( this.toaster + ": " + this_round );
}
void MakeToast( int rounds ) {
if (this.bread - rounds < 0) {
throw new Exception( "No moar bread!" );
}
this.bread -= rounds;
for (int r = 0; r < rounds; ++r) {
this.PrintToast( r );
}
Console.WriteLine( "Got only " + this.bread + " left" );
}
static void Main(string[] args)
{
Program p = new Program();
for (int x = 1; x < 10; ++ x) {
p.MakeToast( x );
}
}
}
}

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>

View file

@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp", "csharp.csproj", "{91DB205F-E422-430B-BBB8-955110C7B3B6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,4 +17,18 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Debug|x64.ActiveCfg = Debug|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Debug|x64.Build.0 = Debug|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Debug|x86.ActiveCfg = Debug|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Debug|x86.Build.0 = Debug|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Release|Any CPU.Build.0 = Release|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Release|x64.ActiveCfg = Release|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Release|x64.Build.0 = Release|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Release|x86.ActiveCfg = Release|Any CPU
{91DB205F-E422-430B-BBB8-955110C7B3B6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -1,5 +0,0 @@
{
"version": 1,
"dgSpecHash": "6/vdr7YprlSIoQecv/nNuLNflFpO0X7eN7jHUinZTsgian9nYpmHMWirsDWMi5l+29TH+Qy8O/QfaB/48QtjRQ==",
"success": true
}

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">/Users/ben/.vim/bundle/vimspector/support/test/csharp/obj/project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/Users/ben/.nuget/packages/</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/Users/ben/.nuget/packages/;/usr/local/share/dotnet/sdk/NuGetFallbackFolder</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">4.9.4</NuGetToolVersion>
</PropertyGroup>
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="/usr/local/share/dotnet/sdk/NuGetFallbackFolder/microsoft.netcore.app/2.2.0/build/netcoreapp2.2/Microsoft.NETCore.App.props" Condition="Exists('/usr/local/share/dotnet/sdk/NuGetFallbackFolder/microsoft.netcore.app/2.2.0/build/netcoreapp2.2/Microsoft.NETCore.App.props')" />
</ImportGroup>
</Project>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="/usr/local/share/dotnet/sdk/NuGetFallbackFolder/netstandard.library/2.0.3/build/netstandard2.0/NETStandard.Library.targets" Condition="Exists('/usr/local/share/dotnet/sdk/NuGetFallbackFolder/netstandard.library/2.0.3/build/netstandard2.0/NETStandard.Library.targets')" />
<Import Project="/usr/local/share/dotnet/sdk/NuGetFallbackFolder/microsoft.netcore.app/2.2.0/build/netcoreapp2.2/Microsoft.NETCore.App.targets" Condition="Exists('/usr/local/share/dotnet/sdk/NuGetFallbackFolder/microsoft.netcore.app/2.2.0/build/netcoreapp2.2/Microsoft.NETCore.App.targets')" />
</ImportGroup>
</Project>

View file

@ -1,742 +0,0 @@
{
"version": 3,
"targets": {
".NETCoreApp,Version=v2.2": {
"Microsoft.NETCore.App/2.2.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.DotNetHostPolicy": "2.2.0",
"Microsoft.NETCore.Platforms": "2.2.0",
"Microsoft.NETCore.Targets": "2.0.0",
"NETStandard.Library": "2.0.3"
},
"compile": {
"ref/netcoreapp2.2/Microsoft.CSharp.dll": {},
"ref/netcoreapp2.2/Microsoft.VisualBasic.dll": {},
"ref/netcoreapp2.2/Microsoft.Win32.Primitives.dll": {},
"ref/netcoreapp2.2/System.AppContext.dll": {},
"ref/netcoreapp2.2/System.Buffers.dll": {},
"ref/netcoreapp2.2/System.Collections.Concurrent.dll": {},
"ref/netcoreapp2.2/System.Collections.Immutable.dll": {},
"ref/netcoreapp2.2/System.Collections.NonGeneric.dll": {},
"ref/netcoreapp2.2/System.Collections.Specialized.dll": {},
"ref/netcoreapp2.2/System.Collections.dll": {},
"ref/netcoreapp2.2/System.ComponentModel.Annotations.dll": {},
"ref/netcoreapp2.2/System.ComponentModel.DataAnnotations.dll": {},
"ref/netcoreapp2.2/System.ComponentModel.EventBasedAsync.dll": {},
"ref/netcoreapp2.2/System.ComponentModel.Primitives.dll": {},
"ref/netcoreapp2.2/System.ComponentModel.TypeConverter.dll": {},
"ref/netcoreapp2.2/System.ComponentModel.dll": {},
"ref/netcoreapp2.2/System.Configuration.dll": {},
"ref/netcoreapp2.2/System.Console.dll": {},
"ref/netcoreapp2.2/System.Core.dll": {},
"ref/netcoreapp2.2/System.Data.Common.dll": {},
"ref/netcoreapp2.2/System.Data.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.Contracts.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.Debug.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.DiagnosticSource.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.FileVersionInfo.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.Process.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.StackTrace.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.TextWriterTraceListener.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.Tools.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.TraceSource.dll": {},
"ref/netcoreapp2.2/System.Diagnostics.Tracing.dll": {},
"ref/netcoreapp2.2/System.Drawing.Primitives.dll": {},
"ref/netcoreapp2.2/System.Drawing.dll": {},
"ref/netcoreapp2.2/System.Dynamic.Runtime.dll": {},
"ref/netcoreapp2.2/System.Globalization.Calendars.dll": {},
"ref/netcoreapp2.2/System.Globalization.Extensions.dll": {},
"ref/netcoreapp2.2/System.Globalization.dll": {},
"ref/netcoreapp2.2/System.IO.Compression.Brotli.dll": {},
"ref/netcoreapp2.2/System.IO.Compression.FileSystem.dll": {},
"ref/netcoreapp2.2/System.IO.Compression.ZipFile.dll": {},
"ref/netcoreapp2.2/System.IO.Compression.dll": {},
"ref/netcoreapp2.2/System.IO.FileSystem.DriveInfo.dll": {},
"ref/netcoreapp2.2/System.IO.FileSystem.Primitives.dll": {},
"ref/netcoreapp2.2/System.IO.FileSystem.Watcher.dll": {},
"ref/netcoreapp2.2/System.IO.FileSystem.dll": {},
"ref/netcoreapp2.2/System.IO.IsolatedStorage.dll": {},
"ref/netcoreapp2.2/System.IO.MemoryMappedFiles.dll": {},
"ref/netcoreapp2.2/System.IO.Pipes.dll": {},
"ref/netcoreapp2.2/System.IO.UnmanagedMemoryStream.dll": {},
"ref/netcoreapp2.2/System.IO.dll": {},
"ref/netcoreapp2.2/System.Linq.Expressions.dll": {},
"ref/netcoreapp2.2/System.Linq.Parallel.dll": {},
"ref/netcoreapp2.2/System.Linq.Queryable.dll": {},
"ref/netcoreapp2.2/System.Linq.dll": {},
"ref/netcoreapp2.2/System.Memory.dll": {},
"ref/netcoreapp2.2/System.Net.Http.dll": {},
"ref/netcoreapp2.2/System.Net.HttpListener.dll": {},
"ref/netcoreapp2.2/System.Net.Mail.dll": {},
"ref/netcoreapp2.2/System.Net.NameResolution.dll": {},
"ref/netcoreapp2.2/System.Net.NetworkInformation.dll": {},
"ref/netcoreapp2.2/System.Net.Ping.dll": {},
"ref/netcoreapp2.2/System.Net.Primitives.dll": {},
"ref/netcoreapp2.2/System.Net.Requests.dll": {},
"ref/netcoreapp2.2/System.Net.Security.dll": {},
"ref/netcoreapp2.2/System.Net.ServicePoint.dll": {},
"ref/netcoreapp2.2/System.Net.Sockets.dll": {},
"ref/netcoreapp2.2/System.Net.WebClient.dll": {},
"ref/netcoreapp2.2/System.Net.WebHeaderCollection.dll": {},
"ref/netcoreapp2.2/System.Net.WebProxy.dll": {},
"ref/netcoreapp2.2/System.Net.WebSockets.Client.dll": {},
"ref/netcoreapp2.2/System.Net.WebSockets.dll": {},
"ref/netcoreapp2.2/System.Net.dll": {},
"ref/netcoreapp2.2/System.Numerics.Vectors.dll": {},
"ref/netcoreapp2.2/System.Numerics.dll": {},
"ref/netcoreapp2.2/System.ObjectModel.dll": {},
"ref/netcoreapp2.2/System.Reflection.DispatchProxy.dll": {},
"ref/netcoreapp2.2/System.Reflection.Emit.ILGeneration.dll": {},
"ref/netcoreapp2.2/System.Reflection.Emit.Lightweight.dll": {},
"ref/netcoreapp2.2/System.Reflection.Emit.dll": {},
"ref/netcoreapp2.2/System.Reflection.Extensions.dll": {},
"ref/netcoreapp2.2/System.Reflection.Metadata.dll": {},
"ref/netcoreapp2.2/System.Reflection.Primitives.dll": {},
"ref/netcoreapp2.2/System.Reflection.TypeExtensions.dll": {},
"ref/netcoreapp2.2/System.Reflection.dll": {},
"ref/netcoreapp2.2/System.Resources.Reader.dll": {},
"ref/netcoreapp2.2/System.Resources.ResourceManager.dll": {},
"ref/netcoreapp2.2/System.Resources.Writer.dll": {},
"ref/netcoreapp2.2/System.Runtime.CompilerServices.VisualC.dll": {},
"ref/netcoreapp2.2/System.Runtime.Extensions.dll": {},
"ref/netcoreapp2.2/System.Runtime.Handles.dll": {},
"ref/netcoreapp2.2/System.Runtime.InteropServices.RuntimeInformation.dll": {},
"ref/netcoreapp2.2/System.Runtime.InteropServices.WindowsRuntime.dll": {},
"ref/netcoreapp2.2/System.Runtime.InteropServices.dll": {},
"ref/netcoreapp2.2/System.Runtime.Loader.dll": {},
"ref/netcoreapp2.2/System.Runtime.Numerics.dll": {},
"ref/netcoreapp2.2/System.Runtime.Serialization.Formatters.dll": {},
"ref/netcoreapp2.2/System.Runtime.Serialization.Json.dll": {},
"ref/netcoreapp2.2/System.Runtime.Serialization.Primitives.dll": {},
"ref/netcoreapp2.2/System.Runtime.Serialization.Xml.dll": {},
"ref/netcoreapp2.2/System.Runtime.Serialization.dll": {},
"ref/netcoreapp2.2/System.Runtime.dll": {},
"ref/netcoreapp2.2/System.Security.Claims.dll": {},
"ref/netcoreapp2.2/System.Security.Cryptography.Algorithms.dll": {},
"ref/netcoreapp2.2/System.Security.Cryptography.Csp.dll": {},
"ref/netcoreapp2.2/System.Security.Cryptography.Encoding.dll": {},
"ref/netcoreapp2.2/System.Security.Cryptography.Primitives.dll": {},
"ref/netcoreapp2.2/System.Security.Cryptography.X509Certificates.dll": {},
"ref/netcoreapp2.2/System.Security.Principal.dll": {},
"ref/netcoreapp2.2/System.Security.SecureString.dll": {},
"ref/netcoreapp2.2/System.Security.dll": {},
"ref/netcoreapp2.2/System.ServiceModel.Web.dll": {},
"ref/netcoreapp2.2/System.ServiceProcess.dll": {},
"ref/netcoreapp2.2/System.Text.Encoding.Extensions.dll": {},
"ref/netcoreapp2.2/System.Text.Encoding.dll": {},
"ref/netcoreapp2.2/System.Text.RegularExpressions.dll": {},
"ref/netcoreapp2.2/System.Threading.Overlapped.dll": {},
"ref/netcoreapp2.2/System.Threading.Tasks.Dataflow.dll": {},
"ref/netcoreapp2.2/System.Threading.Tasks.Extensions.dll": {},
"ref/netcoreapp2.2/System.Threading.Tasks.Parallel.dll": {},
"ref/netcoreapp2.2/System.Threading.Tasks.dll": {},
"ref/netcoreapp2.2/System.Threading.Thread.dll": {},
"ref/netcoreapp2.2/System.Threading.ThreadPool.dll": {},
"ref/netcoreapp2.2/System.Threading.Timer.dll": {},
"ref/netcoreapp2.2/System.Threading.dll": {},
"ref/netcoreapp2.2/System.Transactions.Local.dll": {},
"ref/netcoreapp2.2/System.Transactions.dll": {},
"ref/netcoreapp2.2/System.ValueTuple.dll": {},
"ref/netcoreapp2.2/System.Web.HttpUtility.dll": {},
"ref/netcoreapp2.2/System.Web.dll": {},
"ref/netcoreapp2.2/System.Windows.dll": {},
"ref/netcoreapp2.2/System.Xml.Linq.dll": {},
"ref/netcoreapp2.2/System.Xml.ReaderWriter.dll": {},
"ref/netcoreapp2.2/System.Xml.Serialization.dll": {},
"ref/netcoreapp2.2/System.Xml.XDocument.dll": {},
"ref/netcoreapp2.2/System.Xml.XPath.XDocument.dll": {},
"ref/netcoreapp2.2/System.Xml.XPath.dll": {},
"ref/netcoreapp2.2/System.Xml.XmlDocument.dll": {},
"ref/netcoreapp2.2/System.Xml.XmlSerializer.dll": {},
"ref/netcoreapp2.2/System.Xml.dll": {},
"ref/netcoreapp2.2/System.dll": {},
"ref/netcoreapp2.2/WindowsBase.dll": {},
"ref/netcoreapp2.2/mscorlib.dll": {},
"ref/netcoreapp2.2/netstandard.dll": {}
},
"build": {
"build/netcoreapp2.2/Microsoft.NETCore.App.props": {},
"build/netcoreapp2.2/Microsoft.NETCore.App.targets": {}
}
},
"Microsoft.NETCore.DotNetAppHost/2.2.0": {
"type": "package"
},
"Microsoft.NETCore.DotNetHostPolicy/2.2.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.DotNetHostResolver": "2.2.0"
}
},
"Microsoft.NETCore.DotNetHostResolver/2.2.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.DotNetAppHost": "2.2.0"
}
},
"Microsoft.NETCore.Platforms/2.2.0": {
"type": "package",
"compile": {
"lib/netstandard1.0/_._": {}
},
"runtime": {
"lib/netstandard1.0/_._": {}
}
},
"Microsoft.NETCore.Targets/2.0.0": {
"type": "package",
"compile": {
"lib/netstandard1.0/_._": {}
},
"runtime": {
"lib/netstandard1.0/_._": {}
}
},
"NETStandard.Library/2.0.3": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0"
},
"compile": {
"lib/netstandard1.0/_._": {}
},
"runtime": {
"lib/netstandard1.0/_._": {}
},
"build": {
"build/netstandard2.0/NETStandard.Library.targets": {}
}
}
}
},
"libraries": {
"Microsoft.NETCore.App/2.2.0": {
"sha512": "7z5l8Jp324S8bU8+yyWeYHXUFYvKyiI5lqS1dXgTzOx1H69Qbf6df12kCKlNX45LpMfCMd4U3M6p7Rl5Zk7SLA==",
"type": "package",
"path": "microsoft.netcore.app/2.2.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.TXT",
"Microsoft.NETCore.App.versions.txt",
"THIRD-PARTY-NOTICES.TXT",
"build/netcoreapp2.2/Microsoft.NETCore.App.PlatformManifest.txt",
"build/netcoreapp2.2/Microsoft.NETCore.App.props",
"build/netcoreapp2.2/Microsoft.NETCore.App.targets",
"microsoft.netcore.app.2.2.0.nupkg.sha512",
"microsoft.netcore.app.nuspec",
"ref/netcoreapp2.2/Microsoft.CSharp.dll",
"ref/netcoreapp2.2/Microsoft.CSharp.xml",
"ref/netcoreapp2.2/Microsoft.VisualBasic.dll",
"ref/netcoreapp2.2/Microsoft.VisualBasic.xml",
"ref/netcoreapp2.2/Microsoft.Win32.Primitives.dll",
"ref/netcoreapp2.2/Microsoft.Win32.Primitives.xml",
"ref/netcoreapp2.2/System.AppContext.dll",
"ref/netcoreapp2.2/System.Buffers.dll",
"ref/netcoreapp2.2/System.Buffers.xml",
"ref/netcoreapp2.2/System.Collections.Concurrent.dll",
"ref/netcoreapp2.2/System.Collections.Concurrent.xml",
"ref/netcoreapp2.2/System.Collections.Immutable.dll",
"ref/netcoreapp2.2/System.Collections.Immutable.xml",
"ref/netcoreapp2.2/System.Collections.NonGeneric.dll",
"ref/netcoreapp2.2/System.Collections.NonGeneric.xml",
"ref/netcoreapp2.2/System.Collections.Specialized.dll",
"ref/netcoreapp2.2/System.Collections.Specialized.xml",
"ref/netcoreapp2.2/System.Collections.dll",
"ref/netcoreapp2.2/System.Collections.xml",
"ref/netcoreapp2.2/System.ComponentModel.Annotations.dll",
"ref/netcoreapp2.2/System.ComponentModel.Annotations.xml",
"ref/netcoreapp2.2/System.ComponentModel.DataAnnotations.dll",
"ref/netcoreapp2.2/System.ComponentModel.EventBasedAsync.dll",
"ref/netcoreapp2.2/System.ComponentModel.EventBasedAsync.xml",
"ref/netcoreapp2.2/System.ComponentModel.Primitives.dll",
"ref/netcoreapp2.2/System.ComponentModel.Primitives.xml",
"ref/netcoreapp2.2/System.ComponentModel.TypeConverter.dll",
"ref/netcoreapp2.2/System.ComponentModel.TypeConverter.xml",
"ref/netcoreapp2.2/System.ComponentModel.dll",
"ref/netcoreapp2.2/System.ComponentModel.xml",
"ref/netcoreapp2.2/System.Configuration.dll",
"ref/netcoreapp2.2/System.Console.dll",
"ref/netcoreapp2.2/System.Console.xml",
"ref/netcoreapp2.2/System.Core.dll",
"ref/netcoreapp2.2/System.Data.Common.dll",
"ref/netcoreapp2.2/System.Data.Common.xml",
"ref/netcoreapp2.2/System.Data.dll",
"ref/netcoreapp2.2/System.Diagnostics.Contracts.dll",
"ref/netcoreapp2.2/System.Diagnostics.Contracts.xml",
"ref/netcoreapp2.2/System.Diagnostics.Debug.dll",
"ref/netcoreapp2.2/System.Diagnostics.Debug.xml",
"ref/netcoreapp2.2/System.Diagnostics.DiagnosticSource.dll",
"ref/netcoreapp2.2/System.Diagnostics.DiagnosticSource.xml",
"ref/netcoreapp2.2/System.Diagnostics.FileVersionInfo.dll",
"ref/netcoreapp2.2/System.Diagnostics.FileVersionInfo.xml",
"ref/netcoreapp2.2/System.Diagnostics.Process.dll",
"ref/netcoreapp2.2/System.Diagnostics.Process.xml",
"ref/netcoreapp2.2/System.Diagnostics.StackTrace.dll",
"ref/netcoreapp2.2/System.Diagnostics.StackTrace.xml",
"ref/netcoreapp2.2/System.Diagnostics.TextWriterTraceListener.dll",
"ref/netcoreapp2.2/System.Diagnostics.TextWriterTraceListener.xml",
"ref/netcoreapp2.2/System.Diagnostics.Tools.dll",
"ref/netcoreapp2.2/System.Diagnostics.Tools.xml",
"ref/netcoreapp2.2/System.Diagnostics.TraceSource.dll",
"ref/netcoreapp2.2/System.Diagnostics.TraceSource.xml",
"ref/netcoreapp2.2/System.Diagnostics.Tracing.dll",
"ref/netcoreapp2.2/System.Diagnostics.Tracing.xml",
"ref/netcoreapp2.2/System.Drawing.Primitives.dll",
"ref/netcoreapp2.2/System.Drawing.Primitives.xml",
"ref/netcoreapp2.2/System.Drawing.dll",
"ref/netcoreapp2.2/System.Dynamic.Runtime.dll",
"ref/netcoreapp2.2/System.Globalization.Calendars.dll",
"ref/netcoreapp2.2/System.Globalization.Extensions.dll",
"ref/netcoreapp2.2/System.Globalization.dll",
"ref/netcoreapp2.2/System.IO.Compression.Brotli.dll",
"ref/netcoreapp2.2/System.IO.Compression.FileSystem.dll",
"ref/netcoreapp2.2/System.IO.Compression.ZipFile.dll",
"ref/netcoreapp2.2/System.IO.Compression.ZipFile.xml",
"ref/netcoreapp2.2/System.IO.Compression.dll",
"ref/netcoreapp2.2/System.IO.Compression.xml",
"ref/netcoreapp2.2/System.IO.FileSystem.DriveInfo.dll",
"ref/netcoreapp2.2/System.IO.FileSystem.DriveInfo.xml",
"ref/netcoreapp2.2/System.IO.FileSystem.Primitives.dll",
"ref/netcoreapp2.2/System.IO.FileSystem.Watcher.dll",
"ref/netcoreapp2.2/System.IO.FileSystem.Watcher.xml",
"ref/netcoreapp2.2/System.IO.FileSystem.dll",
"ref/netcoreapp2.2/System.IO.FileSystem.xml",
"ref/netcoreapp2.2/System.IO.IsolatedStorage.dll",
"ref/netcoreapp2.2/System.IO.IsolatedStorage.xml",
"ref/netcoreapp2.2/System.IO.MemoryMappedFiles.dll",
"ref/netcoreapp2.2/System.IO.MemoryMappedFiles.xml",
"ref/netcoreapp2.2/System.IO.Pipes.dll",
"ref/netcoreapp2.2/System.IO.Pipes.xml",
"ref/netcoreapp2.2/System.IO.UnmanagedMemoryStream.dll",
"ref/netcoreapp2.2/System.IO.dll",
"ref/netcoreapp2.2/System.Linq.Expressions.dll",
"ref/netcoreapp2.2/System.Linq.Expressions.xml",
"ref/netcoreapp2.2/System.Linq.Parallel.dll",
"ref/netcoreapp2.2/System.Linq.Parallel.xml",
"ref/netcoreapp2.2/System.Linq.Queryable.dll",
"ref/netcoreapp2.2/System.Linq.Queryable.xml",
"ref/netcoreapp2.2/System.Linq.dll",
"ref/netcoreapp2.2/System.Linq.xml",
"ref/netcoreapp2.2/System.Memory.dll",
"ref/netcoreapp2.2/System.Memory.xml",
"ref/netcoreapp2.2/System.Net.Http.dll",
"ref/netcoreapp2.2/System.Net.Http.xml",
"ref/netcoreapp2.2/System.Net.HttpListener.dll",
"ref/netcoreapp2.2/System.Net.HttpListener.xml",
"ref/netcoreapp2.2/System.Net.Mail.dll",
"ref/netcoreapp2.2/System.Net.Mail.xml",
"ref/netcoreapp2.2/System.Net.NameResolution.dll",
"ref/netcoreapp2.2/System.Net.NameResolution.xml",
"ref/netcoreapp2.2/System.Net.NetworkInformation.dll",
"ref/netcoreapp2.2/System.Net.NetworkInformation.xml",
"ref/netcoreapp2.2/System.Net.Ping.dll",
"ref/netcoreapp2.2/System.Net.Ping.xml",
"ref/netcoreapp2.2/System.Net.Primitives.dll",
"ref/netcoreapp2.2/System.Net.Primitives.xml",
"ref/netcoreapp2.2/System.Net.Requests.dll",
"ref/netcoreapp2.2/System.Net.Requests.xml",
"ref/netcoreapp2.2/System.Net.Security.dll",
"ref/netcoreapp2.2/System.Net.Security.xml",
"ref/netcoreapp2.2/System.Net.ServicePoint.dll",
"ref/netcoreapp2.2/System.Net.ServicePoint.xml",
"ref/netcoreapp2.2/System.Net.Sockets.dll",
"ref/netcoreapp2.2/System.Net.Sockets.xml",
"ref/netcoreapp2.2/System.Net.WebClient.dll",
"ref/netcoreapp2.2/System.Net.WebClient.xml",
"ref/netcoreapp2.2/System.Net.WebHeaderCollection.dll",
"ref/netcoreapp2.2/System.Net.WebHeaderCollection.xml",
"ref/netcoreapp2.2/System.Net.WebProxy.dll",
"ref/netcoreapp2.2/System.Net.WebProxy.xml",
"ref/netcoreapp2.2/System.Net.WebSockets.Client.dll",
"ref/netcoreapp2.2/System.Net.WebSockets.Client.xml",
"ref/netcoreapp2.2/System.Net.WebSockets.dll",
"ref/netcoreapp2.2/System.Net.WebSockets.xml",
"ref/netcoreapp2.2/System.Net.dll",
"ref/netcoreapp2.2/System.Numerics.Vectors.dll",
"ref/netcoreapp2.2/System.Numerics.Vectors.xml",
"ref/netcoreapp2.2/System.Numerics.dll",
"ref/netcoreapp2.2/System.ObjectModel.dll",
"ref/netcoreapp2.2/System.ObjectModel.xml",
"ref/netcoreapp2.2/System.Reflection.DispatchProxy.dll",
"ref/netcoreapp2.2/System.Reflection.DispatchProxy.xml",
"ref/netcoreapp2.2/System.Reflection.Emit.ILGeneration.dll",
"ref/netcoreapp2.2/System.Reflection.Emit.ILGeneration.xml",
"ref/netcoreapp2.2/System.Reflection.Emit.Lightweight.dll",
"ref/netcoreapp2.2/System.Reflection.Emit.Lightweight.xml",
"ref/netcoreapp2.2/System.Reflection.Emit.dll",
"ref/netcoreapp2.2/System.Reflection.Emit.xml",
"ref/netcoreapp2.2/System.Reflection.Extensions.dll",
"ref/netcoreapp2.2/System.Reflection.Metadata.dll",
"ref/netcoreapp2.2/System.Reflection.Metadata.xml",
"ref/netcoreapp2.2/System.Reflection.Primitives.dll",
"ref/netcoreapp2.2/System.Reflection.Primitives.xml",
"ref/netcoreapp2.2/System.Reflection.TypeExtensions.dll",
"ref/netcoreapp2.2/System.Reflection.TypeExtensions.xml",
"ref/netcoreapp2.2/System.Reflection.dll",
"ref/netcoreapp2.2/System.Resources.Reader.dll",
"ref/netcoreapp2.2/System.Resources.ResourceManager.dll",
"ref/netcoreapp2.2/System.Resources.ResourceManager.xml",
"ref/netcoreapp2.2/System.Resources.Writer.dll",
"ref/netcoreapp2.2/System.Resources.Writer.xml",
"ref/netcoreapp2.2/System.Runtime.CompilerServices.VisualC.dll",
"ref/netcoreapp2.2/System.Runtime.CompilerServices.VisualC.xml",
"ref/netcoreapp2.2/System.Runtime.Extensions.dll",
"ref/netcoreapp2.2/System.Runtime.Extensions.xml",
"ref/netcoreapp2.2/System.Runtime.Handles.dll",
"ref/netcoreapp2.2/System.Runtime.InteropServices.RuntimeInformation.dll",
"ref/netcoreapp2.2/System.Runtime.InteropServices.RuntimeInformation.xml",
"ref/netcoreapp2.2/System.Runtime.InteropServices.WindowsRuntime.dll",
"ref/netcoreapp2.2/System.Runtime.InteropServices.WindowsRuntime.xml",
"ref/netcoreapp2.2/System.Runtime.InteropServices.dll",
"ref/netcoreapp2.2/System.Runtime.InteropServices.xml",
"ref/netcoreapp2.2/System.Runtime.Loader.dll",
"ref/netcoreapp2.2/System.Runtime.Loader.xml",
"ref/netcoreapp2.2/System.Runtime.Numerics.dll",
"ref/netcoreapp2.2/System.Runtime.Numerics.xml",
"ref/netcoreapp2.2/System.Runtime.Serialization.Formatters.dll",
"ref/netcoreapp2.2/System.Runtime.Serialization.Formatters.xml",
"ref/netcoreapp2.2/System.Runtime.Serialization.Json.dll",
"ref/netcoreapp2.2/System.Runtime.Serialization.Json.xml",
"ref/netcoreapp2.2/System.Runtime.Serialization.Primitives.dll",
"ref/netcoreapp2.2/System.Runtime.Serialization.Primitives.xml",
"ref/netcoreapp2.2/System.Runtime.Serialization.Xml.dll",
"ref/netcoreapp2.2/System.Runtime.Serialization.Xml.xml",
"ref/netcoreapp2.2/System.Runtime.Serialization.dll",
"ref/netcoreapp2.2/System.Runtime.dll",
"ref/netcoreapp2.2/System.Runtime.xml",
"ref/netcoreapp2.2/System.Security.Claims.dll",
"ref/netcoreapp2.2/System.Security.Claims.xml",
"ref/netcoreapp2.2/System.Security.Cryptography.Algorithms.dll",
"ref/netcoreapp2.2/System.Security.Cryptography.Algorithms.xml",
"ref/netcoreapp2.2/System.Security.Cryptography.Csp.dll",
"ref/netcoreapp2.2/System.Security.Cryptography.Csp.xml",
"ref/netcoreapp2.2/System.Security.Cryptography.Encoding.dll",
"ref/netcoreapp2.2/System.Security.Cryptography.Encoding.xml",
"ref/netcoreapp2.2/System.Security.Cryptography.Primitives.dll",
"ref/netcoreapp2.2/System.Security.Cryptography.Primitives.xml",
"ref/netcoreapp2.2/System.Security.Cryptography.X509Certificates.dll",
"ref/netcoreapp2.2/System.Security.Cryptography.X509Certificates.xml",
"ref/netcoreapp2.2/System.Security.Principal.dll",
"ref/netcoreapp2.2/System.Security.Principal.xml",
"ref/netcoreapp2.2/System.Security.SecureString.dll",
"ref/netcoreapp2.2/System.Security.dll",
"ref/netcoreapp2.2/System.ServiceModel.Web.dll",
"ref/netcoreapp2.2/System.ServiceProcess.dll",
"ref/netcoreapp2.2/System.Text.Encoding.Extensions.dll",
"ref/netcoreapp2.2/System.Text.Encoding.Extensions.xml",
"ref/netcoreapp2.2/System.Text.Encoding.dll",
"ref/netcoreapp2.2/System.Text.RegularExpressions.dll",
"ref/netcoreapp2.2/System.Text.RegularExpressions.xml",
"ref/netcoreapp2.2/System.Threading.Overlapped.dll",
"ref/netcoreapp2.2/System.Threading.Overlapped.xml",
"ref/netcoreapp2.2/System.Threading.Tasks.Dataflow.dll",
"ref/netcoreapp2.2/System.Threading.Tasks.Dataflow.xml",
"ref/netcoreapp2.2/System.Threading.Tasks.Extensions.dll",
"ref/netcoreapp2.2/System.Threading.Tasks.Extensions.xml",
"ref/netcoreapp2.2/System.Threading.Tasks.Parallel.dll",
"ref/netcoreapp2.2/System.Threading.Tasks.Parallel.xml",
"ref/netcoreapp2.2/System.Threading.Tasks.dll",
"ref/netcoreapp2.2/System.Threading.Tasks.xml",
"ref/netcoreapp2.2/System.Threading.Thread.dll",
"ref/netcoreapp2.2/System.Threading.Thread.xml",
"ref/netcoreapp2.2/System.Threading.ThreadPool.dll",
"ref/netcoreapp2.2/System.Threading.ThreadPool.xml",
"ref/netcoreapp2.2/System.Threading.Timer.dll",
"ref/netcoreapp2.2/System.Threading.Timer.xml",
"ref/netcoreapp2.2/System.Threading.dll",
"ref/netcoreapp2.2/System.Threading.xml",
"ref/netcoreapp2.2/System.Transactions.Local.dll",
"ref/netcoreapp2.2/System.Transactions.Local.xml",
"ref/netcoreapp2.2/System.Transactions.dll",
"ref/netcoreapp2.2/System.ValueTuple.dll",
"ref/netcoreapp2.2/System.Web.HttpUtility.dll",
"ref/netcoreapp2.2/System.Web.HttpUtility.xml",
"ref/netcoreapp2.2/System.Web.dll",
"ref/netcoreapp2.2/System.Windows.dll",
"ref/netcoreapp2.2/System.Xml.Linq.dll",
"ref/netcoreapp2.2/System.Xml.ReaderWriter.dll",
"ref/netcoreapp2.2/System.Xml.ReaderWriter.xml",
"ref/netcoreapp2.2/System.Xml.Serialization.dll",
"ref/netcoreapp2.2/System.Xml.XDocument.dll",
"ref/netcoreapp2.2/System.Xml.XDocument.xml",
"ref/netcoreapp2.2/System.Xml.XPath.XDocument.dll",
"ref/netcoreapp2.2/System.Xml.XPath.XDocument.xml",
"ref/netcoreapp2.2/System.Xml.XPath.dll",
"ref/netcoreapp2.2/System.Xml.XPath.xml",
"ref/netcoreapp2.2/System.Xml.XmlDocument.dll",
"ref/netcoreapp2.2/System.Xml.XmlSerializer.dll",
"ref/netcoreapp2.2/System.Xml.XmlSerializer.xml",
"ref/netcoreapp2.2/System.Xml.dll",
"ref/netcoreapp2.2/System.dll",
"ref/netcoreapp2.2/WindowsBase.dll",
"ref/netcoreapp2.2/mscorlib.dll",
"ref/netcoreapp2.2/netstandard.dll",
"runtime.json"
]
},
"Microsoft.NETCore.DotNetAppHost/2.2.0": {
"sha512": "DrhaKInRKKvN6Ns2VNIlC7ZffLOp9THf8cO6X4fytPRJovJUbF49/zzx4WfgX9E44FMsw9hT8hrKiIqDSHvGvA==",
"type": "package",
"path": "microsoft.netcore.dotnetapphost/2.2.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"microsoft.netcore.dotnetapphost.2.2.0.nupkg.sha512",
"microsoft.netcore.dotnetapphost.nuspec",
"runtime.json"
]
},
"Microsoft.NETCore.DotNetHostPolicy/2.2.0": {
"sha512": "FJie7IoPZFaPgNDxhZGmDBQP/Bs5vPdfca/G2Wf9gd6LIvMYkZcibtmJwB4tcf4KXkaOYfIOo4Cl9sEPMsSzkw==",
"type": "package",
"path": "microsoft.netcore.dotnethostpolicy/2.2.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"microsoft.netcore.dotnethostpolicy.2.2.0.nupkg.sha512",
"microsoft.netcore.dotnethostpolicy.nuspec",
"runtime.json"
]
},
"Microsoft.NETCore.DotNetHostResolver/2.2.0": {
"sha512": "spDm3AJYmebthDNhzY17YLPtvbc+Y1lCLVeiIH1uLJ/hZaM+40pBiPefFR8J1u66Ndkqi8ipR2tEbqPnYnjRhw==",
"type": "package",
"path": "microsoft.netcore.dotnethostresolver/2.2.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"microsoft.netcore.dotnethostresolver.2.2.0.nupkg.sha512",
"microsoft.netcore.dotnethostresolver.nuspec",
"runtime.json"
]
},
"Microsoft.NETCore.Platforms/2.2.0": {
"sha512": "T/J+XZo+YheFTJh8/4uoeJDdz5qOmOMkjg6/VL8mHJ9AnP8+fmV/kcbxeXsob0irRNiChf+V0ig1MCRLp/+Kog==",
"type": "package",
"path": "microsoft.netcore.platforms/2.2.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"lib/netstandard1.0/_._",
"microsoft.netcore.platforms.2.2.0.nupkg.sha512",
"microsoft.netcore.platforms.nuspec",
"runtime.json",
"useSharedDesignerContext.txt",
"version.txt"
]
},
"Microsoft.NETCore.Targets/2.0.0": {
"sha512": "odP/tJj1z6GylFpNo7pMtbd/xQgTC3Ex2If63dRTL38bBNMwsBnJ+RceUIyHdRBC0oik/3NehYT+oECwBhIM3Q==",
"type": "package",
"path": "microsoft.netcore.targets/2.0.0",
"files": [
".nupkg.metadata",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"lib/netstandard1.0/_._",
"microsoft.netcore.targets.2.0.0.nupkg.sha512",
"microsoft.netcore.targets.nuspec",
"runtime.json",
"useSharedDesignerContext.txt",
"version.txt"
]
},
"NETStandard.Library/2.0.3": {
"sha512": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
"type": "package",
"path": "netstandard.library/2.0.3",
"files": [
".nupkg.metadata",
"LICENSE.TXT",
"THIRD-PARTY-NOTICES.TXT",
"build/netstandard2.0/NETStandard.Library.targets",
"build/netstandard2.0/ref/Microsoft.Win32.Primitives.dll",
"build/netstandard2.0/ref/System.AppContext.dll",
"build/netstandard2.0/ref/System.Collections.Concurrent.dll",
"build/netstandard2.0/ref/System.Collections.NonGeneric.dll",
"build/netstandard2.0/ref/System.Collections.Specialized.dll",
"build/netstandard2.0/ref/System.Collections.dll",
"build/netstandard2.0/ref/System.ComponentModel.Composition.dll",
"build/netstandard2.0/ref/System.ComponentModel.EventBasedAsync.dll",
"build/netstandard2.0/ref/System.ComponentModel.Primitives.dll",
"build/netstandard2.0/ref/System.ComponentModel.TypeConverter.dll",
"build/netstandard2.0/ref/System.ComponentModel.dll",
"build/netstandard2.0/ref/System.Console.dll",
"build/netstandard2.0/ref/System.Core.dll",
"build/netstandard2.0/ref/System.Data.Common.dll",
"build/netstandard2.0/ref/System.Data.dll",
"build/netstandard2.0/ref/System.Diagnostics.Contracts.dll",
"build/netstandard2.0/ref/System.Diagnostics.Debug.dll",
"build/netstandard2.0/ref/System.Diagnostics.FileVersionInfo.dll",
"build/netstandard2.0/ref/System.Diagnostics.Process.dll",
"build/netstandard2.0/ref/System.Diagnostics.StackTrace.dll",
"build/netstandard2.0/ref/System.Diagnostics.TextWriterTraceListener.dll",
"build/netstandard2.0/ref/System.Diagnostics.Tools.dll",
"build/netstandard2.0/ref/System.Diagnostics.TraceSource.dll",
"build/netstandard2.0/ref/System.Diagnostics.Tracing.dll",
"build/netstandard2.0/ref/System.Drawing.Primitives.dll",
"build/netstandard2.0/ref/System.Drawing.dll",
"build/netstandard2.0/ref/System.Dynamic.Runtime.dll",
"build/netstandard2.0/ref/System.Globalization.Calendars.dll",
"build/netstandard2.0/ref/System.Globalization.Extensions.dll",
"build/netstandard2.0/ref/System.Globalization.dll",
"build/netstandard2.0/ref/System.IO.Compression.FileSystem.dll",
"build/netstandard2.0/ref/System.IO.Compression.ZipFile.dll",
"build/netstandard2.0/ref/System.IO.Compression.dll",
"build/netstandard2.0/ref/System.IO.FileSystem.DriveInfo.dll",
"build/netstandard2.0/ref/System.IO.FileSystem.Primitives.dll",
"build/netstandard2.0/ref/System.IO.FileSystem.Watcher.dll",
"build/netstandard2.0/ref/System.IO.FileSystem.dll",
"build/netstandard2.0/ref/System.IO.IsolatedStorage.dll",
"build/netstandard2.0/ref/System.IO.MemoryMappedFiles.dll",
"build/netstandard2.0/ref/System.IO.Pipes.dll",
"build/netstandard2.0/ref/System.IO.UnmanagedMemoryStream.dll",
"build/netstandard2.0/ref/System.IO.dll",
"build/netstandard2.0/ref/System.Linq.Expressions.dll",
"build/netstandard2.0/ref/System.Linq.Parallel.dll",
"build/netstandard2.0/ref/System.Linq.Queryable.dll",
"build/netstandard2.0/ref/System.Linq.dll",
"build/netstandard2.0/ref/System.Net.Http.dll",
"build/netstandard2.0/ref/System.Net.NameResolution.dll",
"build/netstandard2.0/ref/System.Net.NetworkInformation.dll",
"build/netstandard2.0/ref/System.Net.Ping.dll",
"build/netstandard2.0/ref/System.Net.Primitives.dll",
"build/netstandard2.0/ref/System.Net.Requests.dll",
"build/netstandard2.0/ref/System.Net.Security.dll",
"build/netstandard2.0/ref/System.Net.Sockets.dll",
"build/netstandard2.0/ref/System.Net.WebHeaderCollection.dll",
"build/netstandard2.0/ref/System.Net.WebSockets.Client.dll",
"build/netstandard2.0/ref/System.Net.WebSockets.dll",
"build/netstandard2.0/ref/System.Net.dll",
"build/netstandard2.0/ref/System.Numerics.dll",
"build/netstandard2.0/ref/System.ObjectModel.dll",
"build/netstandard2.0/ref/System.Reflection.Extensions.dll",
"build/netstandard2.0/ref/System.Reflection.Primitives.dll",
"build/netstandard2.0/ref/System.Reflection.dll",
"build/netstandard2.0/ref/System.Resources.Reader.dll",
"build/netstandard2.0/ref/System.Resources.ResourceManager.dll",
"build/netstandard2.0/ref/System.Resources.Writer.dll",
"build/netstandard2.0/ref/System.Runtime.CompilerServices.VisualC.dll",
"build/netstandard2.0/ref/System.Runtime.Extensions.dll",
"build/netstandard2.0/ref/System.Runtime.Handles.dll",
"build/netstandard2.0/ref/System.Runtime.InteropServices.RuntimeInformation.dll",
"build/netstandard2.0/ref/System.Runtime.InteropServices.dll",
"build/netstandard2.0/ref/System.Runtime.Numerics.dll",
"build/netstandard2.0/ref/System.Runtime.Serialization.Formatters.dll",
"build/netstandard2.0/ref/System.Runtime.Serialization.Json.dll",
"build/netstandard2.0/ref/System.Runtime.Serialization.Primitives.dll",
"build/netstandard2.0/ref/System.Runtime.Serialization.Xml.dll",
"build/netstandard2.0/ref/System.Runtime.Serialization.dll",
"build/netstandard2.0/ref/System.Runtime.dll",
"build/netstandard2.0/ref/System.Security.Claims.dll",
"build/netstandard2.0/ref/System.Security.Cryptography.Algorithms.dll",
"build/netstandard2.0/ref/System.Security.Cryptography.Csp.dll",
"build/netstandard2.0/ref/System.Security.Cryptography.Encoding.dll",
"build/netstandard2.0/ref/System.Security.Cryptography.Primitives.dll",
"build/netstandard2.0/ref/System.Security.Cryptography.X509Certificates.dll",
"build/netstandard2.0/ref/System.Security.Principal.dll",
"build/netstandard2.0/ref/System.Security.SecureString.dll",
"build/netstandard2.0/ref/System.ServiceModel.Web.dll",
"build/netstandard2.0/ref/System.Text.Encoding.Extensions.dll",
"build/netstandard2.0/ref/System.Text.Encoding.dll",
"build/netstandard2.0/ref/System.Text.RegularExpressions.dll",
"build/netstandard2.0/ref/System.Threading.Overlapped.dll",
"build/netstandard2.0/ref/System.Threading.Tasks.Parallel.dll",
"build/netstandard2.0/ref/System.Threading.Tasks.dll",
"build/netstandard2.0/ref/System.Threading.Thread.dll",
"build/netstandard2.0/ref/System.Threading.ThreadPool.dll",
"build/netstandard2.0/ref/System.Threading.Timer.dll",
"build/netstandard2.0/ref/System.Threading.dll",
"build/netstandard2.0/ref/System.Transactions.dll",
"build/netstandard2.0/ref/System.ValueTuple.dll",
"build/netstandard2.0/ref/System.Web.dll",
"build/netstandard2.0/ref/System.Windows.dll",
"build/netstandard2.0/ref/System.Xml.Linq.dll",
"build/netstandard2.0/ref/System.Xml.ReaderWriter.dll",
"build/netstandard2.0/ref/System.Xml.Serialization.dll",
"build/netstandard2.0/ref/System.Xml.XDocument.dll",
"build/netstandard2.0/ref/System.Xml.XPath.XDocument.dll",
"build/netstandard2.0/ref/System.Xml.XPath.dll",
"build/netstandard2.0/ref/System.Xml.XmlDocument.dll",
"build/netstandard2.0/ref/System.Xml.XmlSerializer.dll",
"build/netstandard2.0/ref/System.Xml.dll",
"build/netstandard2.0/ref/System.dll",
"build/netstandard2.0/ref/mscorlib.dll",
"build/netstandard2.0/ref/netstandard.dll",
"build/netstandard2.0/ref/netstandard.xml",
"lib/netstandard1.0/_._",
"netstandard.library.2.0.3.nupkg.sha512",
"netstandard.library.nuspec"
]
}
},
"projectFileDependencyGroups": {
".NETCoreApp,Version=v2.2": [
"Microsoft.NETCore.App >= 2.2.0"
]
},
"packageFolders": {
"/Users/ben/.nuget/packages/": {},
"/usr/local/share/dotnet/sdk/NuGetFallbackFolder": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/Users/ben/.vim/bundle/vimspector/support/test/csharp/csharp.csproj",
"projectName": "csharp",
"projectPath": "/Users/ben/.vim/bundle/vimspector/support/test/csharp/csharp.csproj",
"packagesPath": "/Users/ben/.nuget/packages/",
"outputPath": "/Users/ben/.vim/bundle/vimspector/support/test/csharp/obj/",
"projectStyle": "PackageReference",
"fallbackFolders": [
"/usr/local/share/dotnet/sdk/NuGetFallbackFolder"
],
"configFilePaths": [
"/Users/ben/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"netcoreapp2.2"
],
"sources": {
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"netcoreapp2.2": {
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
}
},
"frameworks": {
"netcoreapp2.2": {
"dependencies": {
"Microsoft.NETCore.App": {
"suppressParent": "All",
"target": "Package",
"version": "[2.2.0, )",
"autoReferenced": true
}
},
"imports": [
"net461"
],
"assetTargetFallback": true,
"warn": true
}
}
}
}

View file

@ -1,7 +1,22 @@
{
"adapters": {
"dlv-dap": {
"variables": {
"port": "${unusedLocalPort}"
},
"command": [
"$HOME/go/bin/dlv",
"dap",
"--listen",
"127.0.0.1:${port}"
],
"port": "${port}"
}
},
"configurations": {
"run": {
"adapter": "vscode-go",
"default": true,
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/hello-world.go",
@ -10,6 +25,35 @@
"trace": true,
"env": { "GO111MODULE": "off" }
}
},
"run-dap": {
"adapter": "dlv-dap",
"configuration": {
"request": "launch",
"env": { "GO111MODULE": "off" },
"mode": "debug", // debug|test
"program": "${workspaceRoot}/hello-world.go"
// "args": [],
// "buildFlags": ...
// "stackTraceDepth": ...,
// "showGlobalVariables": true,
}
},
"run-exec": {
// NOTE: To use this you _must_ disable optimistaion:
// go build -o hello_world -gcflags="all=-N -l"
// https://github.com/golang/vscode-go/blob/master/docs/debugging.md#troubleshooting
"adapter": "vscode-go",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/hello-world",
"mode": "exec",
"dlvToolPath": "$HOME/go/bin/dlv",
"trace": true,
"env": { "GO111MODULE": "off" }
}
}
}
}

View file

@ -0,0 +1,29 @@
{
"configurations": {
"run-cmd": {
"adapter": "vscode-go",
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/cmd/namestartswithvowel/main.go",
"mode": "debug",
"dlvToolPath": "$HOME/go/bin/dlv",
"dlvLoadConfig": {
"maxArrayValues": 1000,
"maxStringLen": 1000
}
}
},
"test-current-file": {
"adapter": "vscode-go",
"configuration": {
"request": "launch",
"mode": "test",
"program": "${fileDirname}",
"cwd": "${fileDirname}",
"dlvToolPath": "$GOPATH/bin/dlv",
"env": {},
"args": []
}
}
}
}

View file

@ -0,0 +1,33 @@
# Purpose
This example comes with two example vimspector configs for the Go programming language.
1) `run-cmd` will launch the main programme under `cmd/namestartswithvowel`.
1) `test-current-file` will run the tests in the current file in debug mode.
## Example use-cases
### run-cmd
* Open `cmd/namestartswithvowel/main.go`
* Add a breakpoint somewhere within the programme
* Start the debugger (`:call vimspector#Continue()` or your relevant keymapping)
* Select the first launch configuration (`1: run-cmd`)
### test-current-file
* Open `internal/vowels/vowels_test.go`
* Add a breakpoint somewhere within the test
* Start the debugger (`:call vimspector#Continue()` or your relevant keymapping)
* Select the second launch configuration (`2: test-current-file`)
## Additional Configuration
There are two additional configuration options specified under `run-cmd`; these parameters configure the maximum string/array size to be shown while debugging.
```
"dlvLoadConfig": {
"maxArrayValues": 1000,
"maxStringLen": 1000
}
```

View file

@ -0,0 +1,20 @@
package main
import (
"fmt"
"example.com/internal/vowels"
)
func main() {
names := []string{"Simon", "Bob", "Jennifer", "Amy", "Duke", "Elizabeth"}
for _, n := range names {
if vowels.NameStartsWithVowel(n) {
fmt.Printf("%s starts with a vowel!\n", n)
continue
}
fmt.Printf("%s does not start with a vowel!\n", n)
}
}

View file

@ -0,0 +1,3 @@
module example.com
go 1.16

View file

@ -0,0 +1,9 @@
package vowels
import "strings"
func NameStartsWithVowel(name string) bool {
s := strings.Split(strings.ToLower(name), "")
return s[0] == "a" || s[0] == "e" || s[0] == "i" || s[0] == "o" || s[0] == "u"
}

View file

@ -0,0 +1,30 @@
package vowels
import (
"fmt"
"testing"
)
func TestNameStartsWithVowel(t *testing.T) {
testCases := []struct {
input string
expectedOutput bool
}{
{
input: "Simon",
expectedOutput: false,
},
{
input: "Andy",
expectedOutput: true,
},
}
for _, tt := range testCases {
t.Run(fmt.Sprintf("%s should product %t", tt.input, tt.expectedOutput), func(t *testing.T) {
out := NameStartsWithVowel(tt.input)
if out != tt.expectedOutput {
t.Errorf("%s produced %t, when %t was expected", tt.input, out, tt.expectedOutput)
}
})
}
}

View file

@ -4,7 +4,7 @@
<artifactId>TestApplication</artifactId>
<version>1</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>

2
support/test/kotlin/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.gradle
build

View file

@ -0,0 +1,21 @@
{
"configurations": {
"kotlin-debug-adapter launch": {
"adapter": "cust_kotlin-debug-adapter",
"configuration": {
"request": "launch",
"projectRoot": "${workspaceFolder}",
"mainClass": "vimspector/test/ApplicationKt"
}
},
"kotlin-debug-adapter attach": {
"adapter": "cust_kotlin-debug-adapter",
"configuration": {
"request": "attach",
"projectRoot": "${workspaceFolder}",
"hostName": "${hostName}",
"port": "${port}"
}
}
}
}

View file

@ -0,0 +1,25 @@
plugins {
kotlin("jvm") version "1.4.0"
application
}
repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
dependencies {
// Align versions of all Kotlin components
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
// Use the Kotlin JDK 8 standard library.
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
}
application {
// Define the main class for the application.
mainClassName = "vimspector.test.ApplicationKt"
}

View file

@ -0,0 +1 @@
rootProject.name = "vimspector-test"

View file

@ -0,0 +1,5 @@
package vimspector.test
fun main(args: Array<String>) {
println("Hello World!")
}

View file

@ -0,0 +1,18 @@
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json#",
"configurations": {
"love": {
"adapter": "lua-local",
"configuration": {
"request": "launch",
"type": "lua-local",
"cwd": "${workspaceFolder}",
"program": {
"command": "love"
},
"args": ["${workspaceFolder}"],
"stopOnEntry": false
}
}
}
}

View file

@ -0,0 +1,12 @@
function love.conf(t)
t.modules.audio = false
t.modules.font = false
t.modules.graphics = false
t.modules.image = false
t.modules.mouse = false
t.modules.physics = false
t.modules.sound = false
t.modules.touch = false
t.modules.video = false
t.modules.window = false
end

View file

@ -0,0 +1,10 @@
if pcall(require, 'lldebugger') then
require('lldebugger').start()
end
local time = 0
function love.update(dt)
time = time + dt
love.event.quit()
end

View file

@ -0,0 +1,18 @@
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json#",
"configurations": {
"love": {
"adapter": "lua-local",
"configuration": {
"request": "launch",
"type": "lua-local",
"cwd": "${workspaceFolder}",
"program": {
"command": "love"
},
"args": ["${workspaceFolder}"],
"stopOnEntry": false
}
}
}
}

View file

@ -0,0 +1,21 @@
if pcall(require, 'lldebugger') then
require('lldebugger').start()
end
local rect = {0, 0, 64, 64}
function love.update(dt)
rect[1] = rect[1] + 10 * dt
rect[2] = rect[2] + 10 * dt
end
function love.draw()
love.graphics.rectangle('fill', rect[1], rect[2], rect[3], rect[4])
end
function love.keypressed()
love.event.quit()
end

View file

@ -0,0 +1,31 @@
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json#",
"configurations": {
"lua": {
"adapter": "lua-local",
"configuration": {
"request": "launch",
"type": "lua-local",
"cwd": "${workspaceFolder}",
"program": {
"lua": "lua",
"file": "simple.lua",
"stopOnEntry": false
}
}
},
"luajit": {
"adapter": "lua-local",
"configuration": {
"request": "launch",
"type": "lua-local",
"cwd": "${workspaceFolder}",
"program": {
"lua": "luajit",
"file": "simple.lua",
"stopOnEntry": false
}
}
}
}
}

View file

@ -0,0 +1,21 @@
local separator = ' '
local function createMessage()
local words = {}
table.insert(words, 'Hello')
table.insert(words, 'world')
return table.concat(words, separator)
end
local function withEmphasis(func)
return function()
return func() .. '!'
end
end
createMessage = withEmphasis(createMessage)
print(createMessage())

View file

@ -3,7 +3,7 @@ var msg = 'Hello, world!'
var obj = {
test: 'testing',
toast: function() {
return 'toasty' . this.test;
return 'toasty' + this.test;
}
}

View file

@ -0,0 +1,21 @@
{
"configurations": {
"run": {
"adapter": "debugpy",
"default": true,
"configuration": {
"request": "launch",
"program": "${workspaceRoot}/moo.py",
"cwd": "${workspaceRoot}",
"stopOnEntry": true
},
"breakpoints": {
"exception": {
"raised": "N",
"uncaught": "",
"userUnhandled": ""
}
}
}
}
}

View file

@ -0,0 +1,15 @@
def Say( *args, **kwargs ):
print( *args, **kwargs )
def Quiet():
pass

View file

@ -0,0 +1,13 @@
import cow
def Moo():
for i in range( 1, 100 ):
cow.Say( 'Moo' )
for i in range( 1, 100 ):
cow.Say( 'Ooom' )
if __name__ == '__main__':
Moo()

View file

@ -1,5 +1,56 @@
{
"$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json",
"adapters": {
"run_with_debugpy": {
"command": [ "${workspaceRoot}/run_with_debugpy" ],
"port": 9876,
"env": {
"DEBUG_PORT": "9876"
}
},
"python-remote-docker": {
"variables": {
"port": "8765"
},
"port": "${port}",
"launch": {
"remote": {
"container": "${ContainerID}",
"runCommand": [
"python3", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"--wait-for-client",
"%CMD%"
]
},
"delay": "5000m"
}
},
"python-remote-ssh": {
"variables": {
"port": "8765"
},
"port": "${port}",
"host": "${host}",
"launch": {
"remote": {
"host": "${host}",
"account": "${account}",
"runCommand": [
"python3", "-m", "debugpy", "--listen", "0.0.0.0:${port}",
"--wait-for-client",
"%CMD%"
]
}
}
}
},
"configurations": {
"Use custom gadget": {
"adapter": "test_custom",
"configuration": {
"request": "launch"
}
},
// This is a comment.
"run legacy vscode-python": {
"adapter": "vscode-python", /* coment goes here too */
@ -32,6 +83,33 @@
}
}
},
"attach-run": {
"adapter": "run_with_debugpy",
"configuration": {
"request": "attach"
},
"breakpoints": {
"exception": {
"raised": "N",
"uncaught": "",
"userUnhandled": ""
}
}
},
"docker-attach": {
"adapter": "python-remote-docker",
"remote-cmdLine": [ "/root/main.py" ],
"remote-request": "launch",
"configuration": {
"request": "attach",
"pathMappings": [
{
"localRoot": "${workspaceRoot}",
"remoteRoot": "/root"
}
]
}
},
"run": {
"adapter": "debugpy",
"configuration": {
@ -52,6 +130,11 @@
},
"run - default": {
"adapter": "debugpy",
"variables": {
"MAKE_ENV_OUTPUT": {
"shell": "${workspaceRoot}/make_env.sh"
}
},
"configuration": {
"request": "launch",
"type": "python",
@ -60,8 +143,8 @@
"stopOnEntry#json": "${StopOnEntry:true}",
"console": "integratedTerminal",
"args#json": "${args:[]}",
"env#json": "${env:{\\}}",
"igored#json#s": "string not json"
"igored#json#s": "string not json",
"env#json": "${MAKE_ENV_OUTPUT}"
},
"breakpoints": {
"exception": {
@ -99,6 +182,23 @@
"stopOnEntry": false,
"console": "integratedTerminal"
}
},
"run - remote host": {
"adapter": "python-remote-ssh",
"remote-cmdLine": [
"${remoteRoot}/main.py"
],
"remote-request": "launch",
"configuration": {
"request": "attach",
"redirectOutput": true,
"pathMappings": [
{
"localRoot": "${workspaceRoot}",
"remoteRoot": "${remoteRoot}"
}
]
}
}
}
}

View file

@ -0,0 +1,22 @@
FROM ubuntu:18.04
RUN apt-get update && \
apt-get -y dist-upgrade && \
apt-get -y install sudo \
lsb-release \
ca-certificates \
python3-dev \
python3-pip \
ca-cacert \
locales \
language-pack-en \
libncurses5-dev libncursesw5-dev \
git && \
apt-get -y autoremove
## cleanup of files from setup
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN pip3 install debugpy
ADD main.py /root/main.py

View file

@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -e
if [ "$1" = "--continue" ]; then
OPTS=""
else
OPTS="--no-cache"
fi
docker build ${OPTS} -t puremourning/vimspector:simple_python .

View file

@ -0,0 +1,9 @@
#!/usr/bin/env bash
cat <<"EOF"
{
"Something": "Value1",
"SomethingElse": "Value2"
}
EOF

View file

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
def Main():
print( os.environ.get( 'Something', 'ERROR' ) )
print( os.environ.get( 'SomethingElse', 'ERROR' ) )
for k, v in os.environ:
print( f'{ k } = "{ v }"' )
Main()

View file

@ -1,9 +1,7 @@
#!/usr/bin/env bash
PYTHON=python3
if [ -n "$1" ]; then
PYTHON=$1
if [ -z "$DEBUG_PORT" ]; then
DEBUG_PORT=5678
fi
pushd $(dirname $0)
@ -11,10 +9,11 @@ pushd $(dirname $0)
rm -rf env
fi
$PYTHON -m venv env
python3 -m venv env
. env/bin/activate
python -m pip install -r requirements.txt
echo "using port $DEBUG_PORT"
echo "*** Launching ***"
python -m debugpy --wait-for-client --listen 0.0.0.0:5678 main.py
python -m debugpy --wait-for-client --listen 0.0.0.0:${DEBUG_PORT} main.py
popd

View file

@ -3,6 +3,8 @@
set SCALAR g
array set ARRAY {key1 value1 key2 value2}
set LIST [list a b c {def} {g h i j} k l m]
proc Wrap { body } {
uplevel 1 $body
}

View file

@ -1,43 +1,12 @@
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( v:none )
call ThisTestIsFlaky()
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Mappings_Are_Added_HUMAN()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Mappings_Are_Added_VISUAL_STUDIO()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
function! Test_Mappings_Are_Added_VISUAL_STUDIO()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Signs_Placed_Using_API_Are_Shown()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
@ -78,68 +47,6 @@ function! Test_Signs_Placed_Using_API_Are_Shown()
%bwipeout!
endfunction
function! SetUp_Test_Use_Mappings_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Use_Mappings_HUMAN()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 15, 1 ] )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Disable the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBPDisabled',
\ 9 )
" Delete the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add it again
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Here we go. Start Debugging
call feedkeys( "\<F5>", 'xt' )
call assert_equal( 2, len( gettabinfo() ) )
let cur_tabnr = tabpagenr()
call assert_equal( 5, len( gettabinfo( cur_tabnr )[ 0 ].windows ) )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" Step
call feedkeys( "\<F10>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cp', 16 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_StopAtEntry()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
@ -200,8 +107,8 @@ function Test_DisableBreakpointWhileDebugging()
\ 16 )
\ } )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call setpos( '.', [ 0, 1, 1 ] )
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
@ -211,7 +118,6 @@ function Test_DisableBreakpointWhileDebugging()
\ } )
" Run to breakpoint
call setpos( '.', [ 0, 15, 1 ] )
call feedkeys( "\<F5>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
@ -258,6 +164,58 @@ function Test_DisableBreakpointWhileDebugging()
%bwipeout!
endfunction
function! Test_Add_Breakpoints_In_File_Then_Open()
lcd testdata/cpp/simple
" Set and clear without file open
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
call vimspector#ClearLineBreakpoint( 'simple.cpp', 16 )
" Clear non-set breakpoint
call vimspector#ClearLineBreakpoint( 'simple.cpp', 1 )
" Re-add
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
" Open and expect sign to be added
edit simple.cpp
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 16,
\ 'vimspectorBP',
\ 9 )
call vimspector#LaunchWithSettings( { 'configuration': 'run-to-breakpoint' } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! Test_Add_Breakpoints_In_NonOpenedFile_RunToBreak()
lcd testdata/cpp/simple
" add
call vimspector#SetLineBreakpoint( 'simple.cpp', 16 )
call vimspector#LaunchWithSettings( {
\ 'configuration': 'run-to-breakpoint-specify-file',
\ 'prog': 'simple'
\ } )
call WaitFor( {-> bufexists( 'simple.cpp' ) } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 16,
\ 'vimspectorPCBP',
\ 200 )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_Insert_Code_Above_Breakpoint()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
@ -308,7 +266,6 @@ function! Test_Insert_Code_Above_Breakpoint()
" Delete it
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 26 )
endfunction
function! SetUp_Test_Conditional_Line_Breakpoint()
@ -323,8 +280,8 @@ function! Test_Conditional_Line_Breakpoint()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
" Add the conditional breakpoint
call feedkeys( "\\\<F9>argc==0\<CR>\<CR>", 'xt' )
" Add the conditional breakpoint (note , is the mapleader)
call feedkeys( ",\<F9>argc==0\<CR>\<CR>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 16,
\ 'vimspectorBPCond',
@ -360,8 +317,11 @@ function! Test_Conditional_Line_Breakpoint()
\ 'vimspectorBP',
\ 9 )
call setpos( '.', [ 0, 17, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': 'argc == 1' } )
call setpos( '.', [ 0, 1, 1 ] )
call vimspector#SetLineBreakpoint(
\ 'simple.cpp',
\ 17,
\ { 'condition': 'argc == 1' } )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 17,
@ -400,8 +360,8 @@ function! Test_Conditional_Line_Breakpoint_Hit()
exe 'edit' fn
call setpos( '.', [ 0, 14, 1 ] )
" Add the conditional breakpoint (3 times)
call feedkeys( "\\\<F9>\<CR>3\<CR>", 'xt' )
" Add the conditional breakpoint (3 times) (note , is the mapleader)
call feedkeys( ",\<F9>\<CR>3\<CR>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 14,
@ -576,7 +536,7 @@ function! Test_Custom_Breakpoint_Priority()
\ 'vimspectorBPDisabled',
\ 4 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
call setpos( '.', [ 0, 17, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': '1' } )
@ -663,7 +623,7 @@ function! Test_Custom_Breakpoint_Priority_Partial()
\ 'vimspectorBPDisabled',
\ 4 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
call setpos( '.', [ 0, 17, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': '1' } )
@ -723,3 +683,72 @@ function! Test_Custom_Breakpoint_Priority_Partial()
%bwipeout!
unlet! g:vimspector_sign_priority
endfunction
function! Test_Add_Line_BP_In_Other_File_While_Debugging()
call ThisTestIsFlaky()
let moo = 'moo.py'
let cow = 'cow.py'
lcd ../support/test/python/multiple_files
exe 'edit' moo
call vimspector#Launch()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( moo, 1, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( moo, 1 )
call cursor( 6, 3 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertPCIsAtLineInBuffer( moo, 1 )
call WaitForAssert( {->
\vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorBP',
\ 9 ) } )
exe 'edit' cow
call cursor( 2, 1 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 6 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 2,
\ 'vimspectorBP',
\ 9 ) } )
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( moo, 6, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( moo, 6 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 2 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorBP',
\ 9 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorPCBP',
\ 200 )
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( cow, 2, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( cow, 2 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 6 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 2,
\ 'vimspectorBP',
\ 9 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 2,
\ 'vimspectorPCBP',
\ 200 )
lcd -
call vimspector#test#setup#Reset()
%bwipe!
endfunction

View file

@ -1,44 +1,13 @@
function! SetUp()
set ambiwidth=double
call vimspector#test#setup#SetUpWithMappings( v:none )
call ThisTestIsFlaky()
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Mappings_Are_Added_HUMAN()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Mappings_Are_Added_VISUAL_STUDIO()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
function! Test_Mappings_Are_Added_VISUAL_STUDIO()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Signs_Placed_Using_API_Are_Shown()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
@ -132,7 +101,7 @@ function! Test_Use_Mappings_HUMAN()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cp', 16 )
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
\ } )
call vimspector#test#setup#Reset()
@ -324,8 +293,8 @@ function! Test_Conditional_Line_Breakpoint()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
" Add the conditional breakpoint
call feedkeys( "\\\<F9>argc==0\<CR>\<CR>", 'xt' )
" Add the conditional breakpoint (, is mapleader)
call feedkeys( ",\<F9>argc==0\<CR>\<CR>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 16,
\ 'vimspectorBPCond',
@ -401,8 +370,8 @@ function! Test_Conditional_Line_Breakpoint_Hit()
exe 'edit' fn
call setpos( '.', [ 0, 14, 1 ] )
" Add the conditional breakpoint (3 times)
call feedkeys( "\\\<F9>\<CR>3\<CR>", 'xt' )
" Add the conditional breakpoint (3 times) (, is mapleader)
call feedkeys( ",\<F9>\<CR>3\<CR>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 14,
@ -577,7 +546,7 @@ function! Test_Custom_Breakpoint_Priority()
\ 'vimspectorBPDisabled',
\ 4 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
call setpos( '.', [ 0, 17, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': '1' } )
@ -664,7 +633,7 @@ function! Test_Custom_Breakpoint_Priority_Partial()
\ 'vimspectorBPDisabled',
\ 4 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 16 )
call setpos( '.', [ 0, 17, 1 ] )
call vimspector#ToggleBreakpoint( { 'condition': '1' } )
@ -724,3 +693,73 @@ function! Test_Custom_Breakpoint_Priority_Partial()
%bwipeout!
unlet! g:vimspector_sign_priority
endfunction
function! Test_Add_Line_BP_In_Other_File_While_Debugging()
call ThisTestIsFlaky()
let moo = 'moo.py'
let cow = 'cow.py'
lcd ../support/test/python/multiple_files
exe 'edit' moo
call vimspector#Launch()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( moo, 1, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( moo, 1 )
call cursor( 6, 3 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertPCIsAtLineInBuffer( moo, 1 )
call WaitForAssert( {->
\vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorBP',
\ 9 ) } )
exe 'edit' cow
call cursor( 2, 1 )
call vimspector#ToggleBreakpoint()
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 6 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 2,
\ 'vimspectorBP',
\ 9 ) } )
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( moo, 6, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( moo, 6 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 2 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorBP',
\ 9 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 6,
\ 'vimspectorPCBP',
\ 200 )
call vimspector#Continue()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( cow, 2, 1 )
call vimspector#test#signs#AssertPCIsAtLineInBuffer( cow, 2 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode', 6 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 2,
\ 'vimspectorBP',
\ 9 )
call vimspector#test#signs#AssertSignAtLine(
\ 'VimspectorCode',
\ 2,
\ 'vimspectorPCBP',
\ 200 )
lcd -
call vimspector#test#setup#Reset()
%bwipe!
endfunction

View file

@ -4,8 +4,19 @@ ENV DEBIAN_FRONTEND=noninteractive
ENV LC_ALL C.UTF-8
RUN apt-get update && \
apt-get install -y curl \
dirmngr \
apt-transport-https \
lsb-release \
ca-certificates \
software-properties-common && \
curl -sL https://deb.nodesource.com/setup_12.x | bash - && \
add-apt-repository ppa:bartbes/love-stable -y && \
apt-get update && \
apt-get -y dist-upgrade && \
apt-get -y install python3-dev \
apt-get -y install gcc-8 \
g++-8 \
python3-dev \
python3-pip \
python3-venv \
ca-cacert \
@ -17,14 +28,18 @@ RUN apt-get update && \
tcllib \
gdb \
lldb \
curl \
nodejs \
npm && \
lua5.1 \
luajit \
love && \
apt-get -y autoremove
RUN ln -fs /usr/share/zoneinfo/Europe/London /etc/localtime && \
dpkg-reconfigure --frontend noninteractive tzdata
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 1 \
--slave /usr/bin/g++ g++ /usr/bin/g++-8
## cleanup of files from setup
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@ -55,6 +70,12 @@ RUN mkdir -p /home/linuxbrew/.linuxbrew &&\
RUN /home/linuxbrew/.linuxbrew/bin/brew install golang
# dotnet
RUN curl -sSL https://dot.net/v1/dotnet-install.sh \
| bash /dev/stdin --channel LTS --install-dir /usr/share/dotnet && \
update-alternatives --install /usr/bin/dotnet dotnet \
/usr/share/dotnet/dotnet 1
# clean up
RUN /home/linuxbrew/.linuxbrew/bin/brew cleanup && \
rm -rf ~/.cache && \

View file

@ -0,0 +1,22 @@
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function Test_Get_Configurations()
lcd ../support/test/csharp/
let configs = vimspector#GetConfigurations()
call assert_equal([
\ 'launch - netcoredbg',
\ 'launch - netcoredbg - with debug log',
\ 'launch - mono',
\ ], configs)
lcd -
%bwipe!
endfunction

View file

@ -0,0 +1,65 @@
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! SetUp_Test_Go_Simple()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_CSharp_Simple()
let fn='Program.cs'
lcd ../support/test/csharp
exe 'edit ' . fn
call vimspector#SetLineBreakpoint( fn, 31 )
call vimspector#LaunchWithSettings( {
\ 'configuration': 'launch - netcoredbg'
\ } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 31, 7 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 31 )
\ } )
call vimspector#StepOver()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 32, 12 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 32 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! Test_Run_To_Cursor()
let fn='Program.cs'
lcd ../support/test/csharp
exe 'edit ' . fn
call vimspector#SetLineBreakpoint( fn, 31 )
call vimspector#LaunchWithSettings( {
\ 'configuration': 'launch - netcoredbg'
\ } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 31, 7 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 31 )
\ } )
call cursor( 33, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 33, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 33 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction

View file

@ -45,3 +45,28 @@ function! Test_Go_Simple()
lcd -
%bwipeout!
endfunction
function! Test_Run_To_Cursor()
let fn='hello-world.go'
lcd ../support/test/go/hello_world
exe 'edit ' . fn
call vimspector#SetLineBreakpoint( fn, 4 )
call vimspector#Launch()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 4, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 4 )
\ } )
call cursor( 5, 1 )
call vimspector#RunToCursor()
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 5, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 5 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction

View file

@ -0,0 +1,74 @@
function! SetUp()
let g:vimspector_enable_mappings = 'HUMAN'
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! BaseTest( configuration )
let fn='simple.lua'
lcd ../support/test/lua/simple
exe 'edit ' . fn
call vimspector#SetLineBreakpoint( fn, 5 )
call vimspector#LaunchWithSettings( { 'configuration': a:configuration } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 5, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 5 )
\ } )
" Step
call feedkeys( "\<F10>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 6, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 6 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! Test_Lua_Simple()
call BaseTest( 'lua' )
endfunction
function! Test_Lua_Luajit()
call BaseTest( 'luajit' )
endfunction
function! Test_Lua_Love()
let fn='main.lua'
lcd ../support/test/lua/love-headless
exe 'edit ' . fn
call vimspector#SetLineBreakpoint( fn, 8 )
call vimspector#LaunchWithSettings( { 'configuration': 'love' } )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 8 )
\ } )
" Step
call feedkeys( "\<F10>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 9, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( fn, 9 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction

View file

@ -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

View file

@ -1,6 +1,7 @@
function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer,
\ line,
\ column ) abort
call WaitFor( {-> bufexists( a:buffer ) } )
call WaitForAssert( {->
\ assert_equal( fnamemodify( a:buffer, ':p' ),
\ fnamemodify( bufname( '%' ), ':p' ),
@ -15,6 +16,7 @@ function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer,
endfunction
function! vimspector#test#signs#AssertPCIsAtLineInBuffer( buffer, line ) abort
call WaitFor( {-> bufexists( a:buffer ) } )
let signs = sign_getplaced( a:buffer, {
\ 'group': 'VimspectorCode',
\ } )
@ -70,7 +72,11 @@ function! vimspector#test#signs#AssertSignGroupSingletonAtLine( group,
endfunction
function! vimspector#test#signs#AssertSignAtLine( group, line, sign_name, priority ) abort
function! vimspector#test#signs#AssertSignAtLine(
\ group,
\ line,
\ sign_name,
\ priority ) abort
let signs = sign_getplaced( '%', {
\ 'group': a:group,
@ -106,7 +112,7 @@ endfunction
function! vimspector#test#signs#AssertSignGroupEmptyAtLine( group, line ) abort
let signs = sign_getplaced( '%', {
\ 'group': a:group,
\ 'lnum': line( '.' )
\ 'lnum': a:line,
\ } )
return assert_equal( 1,

View file

@ -51,7 +51,10 @@ func s:WaitForCommon(expr, assert, timeout)
let start = reltime()
endif
let iters = 0
while 1
let iters += 1
let errors_before = len( v:errors )
if type(a:expr) == v:t_func
let success = a:expr()
@ -65,6 +68,10 @@ func s:WaitForCommon(expr, assert, timeout)
return slept
endif
if iters % 20 == 0
redraw!
endif
if slept >= a:timeout
break
endif
@ -91,3 +98,31 @@ endfunc
function! ThisTestIsFlaky()
let g:test_is_flaky = v:true
endfunction
function! AssertMatchList( 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! GetBufLine( buf, start, end = '$' )
if type( a:start ) != v:t_string && a:start < 0
let start = getbufinfo( a:buf )[ 0 ].linecount + a:start
else
let start = a:start
endif
if type( a:end ) != v:t_string && a:end < 0
let end = getbufinfo( a:buf )[ 0 ].linecount + a:end
else
let end = a:end
endif
return getbufline( a:buf, start, end )
endfunction

View file

@ -82,6 +82,16 @@ func! Abort( timer_id )
qa!
endfunc
func! TestLog( msg )
if type( a:msg ) == v:t_string
let msg = [ a:msg ]
else
let msg = a:msg
endif
call extend( s:messages, msg )
endfunc
func RunTheTest(test)
echo 'Executing ' . a:test
@ -152,8 +162,6 @@ func RunTheTest(test)
augroup END
exe 'call ' . a:test
au! EarlyExit
catch /^\cskipped/
call add(s:messages, ' Skipped')
call add(s:skipped,
@ -193,6 +201,8 @@ func RunTheTest(test)
call s:TestFailed()
endtry
au! EarlyExit
call timer_stop( timer )
" In case 'insertmode' was set and something went wrong, make sure it is
@ -371,7 +381,7 @@ for s:test in sort(s:tests)
if len(v:errors) > 0
\ && $TEST_NO_RETRY == ''
\ && g:test_is_flaky
for retry in range( 5 )
for retry in range( 10 )
call add( s:messages, 'Found errors in ' . s:test . '. Retrying.' )
call extend( s:messages, v:errors )

143
tests/mappings.test.vim Normal file
View file

@ -0,0 +1,143 @@
function! SetUp()
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Mappings_Are_Added_HUMAN()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
call assert_true( hasmapto( 'vimspector#RunToCursor()' ) )
endfunction
function! SetUp_Test_Mappings_Are_Added_VISUAL_STUDIO()
let g:vimspector_enable_mappings = 'VISUAL_STUDIO'
endfunction
function! Test_Mappings_Are_Added_VISUAL_STUDIO()
call assert_true( hasmapto( 'vimspector#Continue()' ) )
call assert_false( hasmapto( 'vimspector#Launch()' ) )
call assert_true( hasmapto( 'vimspector#Stop()' ) )
call assert_true( hasmapto( 'vimspector#Restart()' ) )
call assert_true( hasmapto( 'vimspector#ToggleBreakpoint()' ) )
call assert_true( hasmapto( 'vimspector#AddFunctionBreakpoint' ) )
call assert_true( hasmapto( 'vimspector#StepOver()' ) )
call assert_true( hasmapto( 'vimspector#StepInto()' ) )
call assert_true( hasmapto( 'vimspector#StepOut()' ) )
endfunction
function! SetUp_Test_Use_Mappings_HUMAN()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function! Test_Use_Mappings_HUMAN()
call ThisTestIsFlaky()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 15, 1 ] )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Disable the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBPDisabled',
\ 9 )
" Delete the breakpoint
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add and clear using API
call vimspector#SetLineBreakpoint( 'simple.cpp', 15 )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
call vimspector#ClearLineBreakpoint( 'simple.cpp', 15 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add it again
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBP',
\ 9 )
" Here we go. Start Debugging
call feedkeys( "\<F5>", 'xt' )
call assert_equal( 2, len( gettabinfo() ) )
let cur_tabnr = tabpagenr()
call assert_equal( 5, len( gettabinfo( cur_tabnr )[ 0 ].windows ) )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" Step
call feedkeys( "\<F10>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
\ } )
" Run to cursor (note , is the mapleader)
call cursor( 9, 1 )
call feedkeys( ",\<F8>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 9, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 9 )
\ } )
" Stop
call feedkeys( "\<F3>", 'xt' )
call WaitForAssert( {->
\ assert_equal( [],
\ getbufline( g:vimspector_session_windows.variables,
\ 1,
\ '$' ) )
\ } )
call WaitForAssert( {->
\ assert_equal( [],
\ getbufline( g:vimspector_session_windows.stack_trace,
\ 1,
\ '$' ) )
\ } )
call WaitForAssert( {->
\ assert_equal( [],
\ getbufline( g:vimspector_session_windows.watches,
\ 1,
\ '$' ) )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction

Some files were not shown because too many files have changed in this diff Show more