Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f05a7f66a | ||
|
|
0cdab6be4e | ||
|
|
099431ba55 | ||
|
|
fb2bad216f |
60 changed files with 1795 additions and 1028 deletions
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -57,12 +57,6 @@ 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`
|
||||
|
||||
```
|
||||
|
|
|
|||
20
.github/workflows/build.yaml
vendored
20
.github/workflows/build.yaml
vendored
|
|
@ -13,7 +13,7 @@ defaults:
|
|||
|
||||
jobs:
|
||||
PythonLint:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-16.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-18.04'
|
||||
runs-on: 'ubuntu-16.04'
|
||||
container: 'puremourning/vimspector:test'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
@ -32,7 +32,7 @@ jobs:
|
|||
run: $HOME/.local/bin/vint autoload/ compiler/ plugin/ tests/ syntax/
|
||||
|
||||
Linux:
|
||||
runs-on: 'ubuntu-18.04'
|
||||
runs-on: 'ubuntu-16.04'
|
||||
container:
|
||||
image: 'puremourning/vimspector:test'
|
||||
options: --cap-add=SYS_PTRACE --security-opt seccomp=unconfined
|
||||
|
|
@ -111,16 +111,6 @@ 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'
|
||||
|
||||
|
|
@ -153,10 +143,10 @@ jobs:
|
|||
# if: failure()
|
||||
# with:
|
||||
# NGROK_AUTH_TOKEN: ${{ secrets.NGROK_AUTH_TOKEN }}
|
||||
# SSH_PASS: ${{ secrets.SSH_PASS }} # [V]imspector
|
||||
# SSH_PASS: ${{ secrets.SSH_PASS }}
|
||||
|
||||
PublishRelease:
|
||||
runs-on: 'ubuntu-18.04'
|
||||
runs-on: 'ubuntu-16.04'
|
||||
needs:
|
||||
- Linux
|
||||
- MacOS
|
||||
|
|
|
|||
27
.github/workflows/lock_old_issues.yaml
vendored
27
.github/workflows/lock_old_issues.yaml
vendored
|
|
@ -1,27 +0,0 @@
|
|||
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'
|
||||
|
|
@ -9,8 +9,9 @@ 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
|
||||
|
|
|
|||
|
|
@ -46,23 +46,6 @@ 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:
|
||||
|
||||
|
|
@ -70,7 +53,6 @@ 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
|
||||
|
|
|
|||
199
README.md
199
README.md
|
|
@ -3,7 +3,7 @@
|
|||
For a tutorial and usage overview, take a look at the
|
||||
[Vimspector website][website].
|
||||
|
||||
For detailed explanation of the `.vimspector.json` format, see the
|
||||
For detailed explanatin of the `.vimspector.json` format, see the
|
||||
[reference guide][vimspector-ref].
|
||||
|
||||
 [](https://gitter.im/vimspector/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
|
@ -61,14 +61,14 @@ For detailed explanation of the `.vimspector.json` format, see the
|
|||
* [Closing debugger](#closing-debugger)
|
||||
* [Terminate debuggee](#terminate-debuggee)
|
||||
* [Debug profile configuration](#debug-profile-configuration)
|
||||
* [C, C++, Rust, etc.](#c-c-rust-etc)
|
||||
* [Data visualization / pretty printing](#data-visualization--pretty-printing)
|
||||
* [C++ Remote debugging](#c-remote-debugging)
|
||||
* [C++ Remote launch and attach](#c-remote-launch-and-attach)
|
||||
* [C, C , Rust, etc.](#c-c-rust-etc)
|
||||
* [C Remote debugging](#c-remote-debugging)
|
||||
* [C Remote launch and attach](#c-remote-launch-and-attach)
|
||||
* [Rust](#rust)
|
||||
* [Python](#python)
|
||||
* [Python Remote Debugging](#python-remote-debugging)
|
||||
* [Python Remote launch and attach](#python-remote-launch-and-attach)
|
||||
* [Legacy: vscode-python](#legacy-vscode-python)
|
||||
* [TCL](#tcl)
|
||||
* [C♯](#c)
|
||||
* [Go](#go)
|
||||
|
|
@ -100,7 +100,7 @@ For detailed explanation of the `.vimspector.json` format, see the
|
|||
# Features and Usage
|
||||
|
||||
The plugin is a capable Vim graphical debugger for multiple languages.
|
||||
It's mostly tested for C++, Python and TCL, but in theory supports any
|
||||
It's mostly tested for c++, python and TCL, but in theory supports any
|
||||
language that Visual Studio Code supports (but see caveats).
|
||||
|
||||
The [Vimspector website][website] has an overview of the UI, along with basic
|
||||
|
|
@ -145,24 +145,23 @@ runtime dependencies). They are categorised by their level of support:
|
|||
* `Supported` : Fully supported, frequently used and manually tested
|
||||
* `Experimental`: Working, but not frequently used and rarely tested
|
||||
* `Legacy`: No longer supported, please migrate your config
|
||||
* `Retired`: No longer included or supported.
|
||||
|
||||
| Language | Status | Switch (for `install_gadget.py`) | Adapter (for `:VimspectorInstall`) | Dependencies |
|
||||
|--------------------|-----------|----------------------------------|------------------------------------|--------------------------------------------|
|
||||
| C, C++, Rust etc. | Tested | `--all` or `--enable-c` (or cpp) | vscode-cpptools | mono-core |
|
||||
| Rust, C, C++, etc. | Supported | `--force-enable-rust` | CodeLLDB | Python 3 |
|
||||
| Python | Tested | `--all` or `--enable-python` | debugpy | Python 2.7 or Python 3 |
|
||||
| Go | Tested | `--enable-go` | vscode-go | Node, Go, [Delve][] |
|
||||
| TCL | Supported | `--all` or `--enable-tcl` | tclpro | TCL 8.5 |
|
||||
| Bourne Shell | Supported | `--all` or `--enable-bash` | vscode-bash-debug | Bash v?? |
|
||||
| Lua | Supported | `--all` or `--enable-lua` | local-lua-debugger-vscode | Node >=12.13.0, Npm, Lua interpreter |
|
||||
| Node.js | Supported | `--force-enable-node` | vscode-node-debug2 | 6 < Node < 12, Npm |
|
||||
| Javascript | Supported | `--force-enable-chrome` | debugger-for-chrome | Chrome |
|
||||
| Java | Supported | `--force-enable-java ` | vscode-java-debug | Compatible LSP plugin (see [later](#java)) |
|
||||
| C# (dotnet core) | Tested | `--force-enable-csharp` | netcoredbg | DotNet core |
|
||||
| F#, VB, etc. | Supported | `--force-enable-[fsharp,vbnet]` | `, `--force-enable-vbnet` | netcoredbg | DotNet core |
|
||||
| C# (mono) | _Retired_ | N/A | N/A | N/A |
|
||||
| Python.legacy | _Retired_ | N/A | N/A | N/A |
|
||||
| Language | Status | Switch (for `install_gadget.py`) | Adapter (for `:VimspectorInstall`) | Dependencies |
|
||||
|--------------------|--------------|------------------------------------|------------------------------------|--------------------------------------------|
|
||||
| C, C++, Rust etc. | Tested | `--all` or `--enable-c` (or cpp) | vscode-cpptools | mono-core |
|
||||
| Rust, C, C++, etc. | Supported | `--force-enable-rust` | CodeLLDB | Python 3 |
|
||||
| Python | Tested | `--all` or `--enable-python` | debugpy | Python 2.7 or Python 3 |
|
||||
| Go | Tested | `--enable-go` | vscode-go | Node, Go, [Delve][] |
|
||||
| TCL | Supported | `--all` or `--enable-tcl` | tclpro | TCL 8.5 |
|
||||
| Bourne Shell | Supported | `--all` or `--enable-bash` | vscode-bash-debug | Bash v?? |
|
||||
| Lua | Supported | `--all` or `--enable-lua` | local-lua-debugger-vscode | Node >=12.13.0, Npm, Lua interpreter |
|
||||
| Node.js | Supported | `--force-enable-node` | vscode-node-debug2 | 6 < Node < 12, Npm |
|
||||
| Javascript | Supported | `--force-enable-chrome` | debugger-for-chrome | Chrome |
|
||||
| Java | Supported | `--force-enable-java ` | vscode-java-debug | Compatible LSP plugin (see [later](#java)) |
|
||||
| C# (dotnet core) | Experimental | `--force-enable-csharp` | netcoredbg | DotNet core |
|
||||
| C# (mono) | Experimental | `--force-enable-csharp` | vscode-mono-debug | Mono |
|
||||
| F#, VB, etc. | Experimental | `--force-enable-fsharp` (or vbnet) | netcoredbg | DotNet core |
|
||||
| Python.legacy | Legacy | `--force-enable-python.legacy` | vscode-python | Node 10, Python 2.7 or Python 3 |
|
||||
|
||||
## Other languages
|
||||
|
||||
|
|
@ -291,7 +290,7 @@ If you just want to try out vimspector without changing your vim config, there
|
|||
are example projects for a number of languages in `support/test`, including:
|
||||
|
||||
* Python (`support/test/python/simple_python`)
|
||||
* Go (`support/test/go/hello_world` and `support/test/go/name-starts-with-vowel`)
|
||||
* Go (`support/test/go/hello_world`)
|
||||
* Nodejs (`support/test/node/simple`)
|
||||
* Chrome (`support/test/chrome/`)
|
||||
* etc.
|
||||
|
|
@ -527,6 +526,13 @@ Example:
|
|||
"${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7"
|
||||
],
|
||||
"name": "cppdbg"
|
||||
},
|
||||
"vscode-python": {
|
||||
"command": [
|
||||
"node",
|
||||
"${gadgetDir}/vscode-python/out/client/debugger/debugAdapter/main.js"
|
||||
],
|
||||
"name": "vscode-python"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1008,8 +1014,6 @@ be changed manually to "switch to" that thread.
|
|||
to set the "focussed" thread to the currently selected one. If the selected
|
||||
line is a stack frame, set the focussed thread to the thread of that frame and
|
||||
jump to that frame in the code window.
|
||||
* The current frame when a breakpoint is hit or if manuall jumping is also
|
||||
highlighted.
|
||||
|
||||

|
||||
|
||||
|
|
@ -1071,8 +1075,6 @@ information when something goes wrong that's not a Vim traceback.
|
|||
If you just want to see the Vimspector log file, use `:VimspectorToggleLog`,
|
||||
which will tail it in a little window (doesn't work on Windows).
|
||||
|
||||
You can see some debugging info with `:VimspectorDebugInfo`
|
||||
|
||||
## Closing debugger
|
||||
|
||||
To close the debugger, use:
|
||||
|
|
@ -1177,38 +1179,6 @@ licensing.
|
|||
}
|
||||
```
|
||||
|
||||
### Data visualization / pretty printing
|
||||
|
||||
Depending on the backend you need to enable pretty printing of complex types manually.
|
||||
|
||||
* LLDB: Pretty printing is enabled by default
|
||||
|
||||
* GDB: To enable gdb pretty printers, consider the snippet below.
|
||||
It is not enough to have `set print pretty on` in your .gdbinit!
|
||||
|
||||
```
|
||||
{
|
||||
"configurations": {
|
||||
"Launch": {
|
||||
"adapter": "vscode-cpptools",
|
||||
"configuration": {
|
||||
"request": "launch",
|
||||
"program": "<path to binary>",
|
||||
...
|
||||
"MIMode": "gdb"
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### C++ Remote debugging
|
||||
|
||||
The cpptools documentation describes how to attach cpptools to gdbserver using
|
||||
|
|
@ -1294,6 +1264,10 @@ Rust is supported with any gdb/lldb-based debugger. So it works fine with
|
|||
headers/libs to build a C python extension for performance.
|
||||
* Full options: https://github.com/microsoft/debugpy/wiki/Debug-configuration-settings
|
||||
|
||||
|
||||
**Migrating from `vscode-python`**: change `"adapter": "vscode-python"` to
|
||||
`"adapter": "debugpy"`.
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": {
|
||||
|
|
@ -1360,6 +1334,34 @@ debugpy](https://github.com/microsoft/debugpy/wiki/Debugging-over-SSH).
|
|||
If you're feeling fancy, checkout the [reference guide][remote-debugging] for
|
||||
an example of getting Vimspector to remotely launch and attach.
|
||||
|
||||
### Legacy: vscode-python
|
||||
|
||||
* No longer installed by default - please pass `--force-enable-python.legacy` if
|
||||
you just want to continue using your working setup.
|
||||
* [vscode-python](https://github.com/Microsoft/vscode-python)
|
||||
* NOTE: You must be running `node` 10. See [this issue](https://github.com/puremourning/vimspector/issues/105)
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": {
|
||||
"<name>: Launch": {
|
||||
"adapter": "vscode-python",
|
||||
"configuration": {
|
||||
"name": "<name>: Launch",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"cwd": "<working directory>",
|
||||
"stopOnEntry": true,
|
||||
"console": "externalTerminal",
|
||||
"debugOptions": [],
|
||||
"program": "<path to main python file>"
|
||||
}
|
||||
}
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## TCL
|
||||
|
||||
* TCL (TclProDebug)
|
||||
|
|
@ -1383,8 +1385,35 @@ netcoredbg`
|
|||
"program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll",
|
||||
"args": [],
|
||||
"stopAtEntry": true,
|
||||
"cwd": "${workspaceRoot}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* C# - mono
|
||||
|
||||
Install with `install_gadget.py --force-enable-csharp` or `:VimspectorInstall
|
||||
vscode-mono-debug`.
|
||||
|
||||
***Known not to work.***
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": {
|
||||
"launch - mono": {
|
||||
"adapter": "vscode-mono-debug",
|
||||
"configuration": {
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {}
|
||||
"runtimeExecutable": "mono",
|
||||
"runtimeArgs": [],
|
||||
"env": [],
|
||||
"externalConsole": false,
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1401,8 +1430,6 @@ Requires:
|
|||
* [Delve][delve-install] installed, e.g. `go get -u github.com/go-delve/delve/cmd/dlv`
|
||||
* Delve to be in your PATH, or specify the `dlvToolPath` launch option
|
||||
|
||||
NOTE: Vimspector uses the ["legacy" vscode-go debug adapter](https://github.com/golang/vscode-go/blob/master/docs/debugging-legacy.md) rather than the "built-in" DAP support in Delve. You can track https://github.com/puremourning/vimspector/issues/186 for that.
|
||||
|
||||
```json
|
||||
{
|
||||
"configurations": {
|
||||
|
|
@ -1420,7 +1447,7 @@ NOTE: Vimspector uses the ["legacy" vscode-go debug adapter](https://github.com/
|
|||
```
|
||||
|
||||
See the vscode-go docs for
|
||||
[troubleshooting information](https://github.com/golang/vscode-go/blob/master/docs/debugging-legacy.md#troubleshooting)
|
||||
[troubleshooting information](https://github.com/golang/vscode-go/blob/master/docs/debugging.md#troubleshooting)
|
||||
|
||||
## PHP
|
||||
|
||||
|
|
@ -1739,26 +1766,22 @@ Vimsector uses them, they will not be replaced. So to customise the signs,
|
|||
define them in your `vimrc`.
|
||||
|
||||
|
||||
| Sign | Description | Priority |
|
||||
|---------------------------|-----------------------------------------|----------|
|
||||
| `vimspectorBP` | Line breakpoint | 9 |
|
||||
| `vimspectorBPCond` | Conditional line breakpoint | 9 |
|
||||
| `vimspectorBPDisabled` | Disabled breakpoint | 9 |
|
||||
| `vimspectorPC` | Program counter (i.e. current line) | 200 |
|
||||
| `vimspectorPCBP` | Program counter and breakpoint | 200 |
|
||||
| `vimspectorCurrentThread` | Focussed thread in stack trace view | 200 |
|
||||
| `vimspectorCurrentFrame` | Current stack frame in stack trace view | 200 |
|
||||
| Sign | Description | Priority |
|
||||
|------------------------|-------------------------------------|----------|
|
||||
| `vimspectorBP` | Line breakpoint | 9 |
|
||||
| `vimspectorBPCond` | Conditional line breakpoint | 9 |
|
||||
| `vimspectorBPDisabled` | Disabled breakpoint | 9 |
|
||||
| `vimspectorPC` | Program counter (i.e. current line) | 200 |
|
||||
| `vimspectorPCBP` | Program counter and breakpoint | 200 |
|
||||
|
||||
The default symbols are the equivalent of something like the following:
|
||||
|
||||
```viml
|
||||
sign define vimspectorBP text=\ ● texthl=WarningMsg
|
||||
sign define vimspectorBPCond text=\ ◆ texthl=WarningMsg
|
||||
sign define vimspectorBPDisabled text=\ ● texthl=LineNr
|
||||
sign define vimspectorPC text=\ ▶ texthl=MatchParen linehl=CursorLine
|
||||
sign define vimspectorPCBP text=●▶ texthl=MatchParen linehl=CursorLine
|
||||
sign define vimspectorCurrentThread text=▶ texthl=MatchParen linehl=CursorLine
|
||||
sign define vimspectorCurrentFrame text=▶ texthl=Special linehl=CursorLine
|
||||
sign define vimspectorBP text=\ ● texthl=WarningMsg
|
||||
sign define vimspectorBPCond text=\ ◆ texthl=WarningMsg
|
||||
sign define vimspectorBPDisabled text=\ ● texthl=LineNr
|
||||
sign define vimspectorPC text=\ ▶ texthl=MatchParen linehl=CursorLine
|
||||
sign define vimspectorPCBP text=●▶ texthl=MatchParen linehl=CursorLine
|
||||
```
|
||||
|
||||
If the signs don't display properly, your font probably doesn't contain these
|
||||
|
|
@ -1766,13 +1789,11 @@ glyphs. You can easily change them by defining the sign in your vimrc. For
|
|||
example, you could put this in your `vimrc` to use some simple ASCII symbols:
|
||||
|
||||
```viml
|
||||
sign define vimspectorBP text=o texthl=WarningMsg
|
||||
sign define vimspectorBPCond text=o? texthl=WarningMsg
|
||||
sign define vimspectorBPDisabled text=o! texthl=LineNr
|
||||
sign define vimspectorPC text=\ > texthl=MatchParen
|
||||
sign define vimspectorPCBP text=o> texthl=MatchParen
|
||||
sign define vimspectorCurrentThread text=> texthl=MatchParen
|
||||
sign define vimspectorCurrentFrame text=> texthl=Special
|
||||
sign define vimspectorBP text=o texthl=WarningMsg
|
||||
sign define vimspectorBPCond text=o? texthl=WarningMsg
|
||||
sign define vimspectorBPDisabled text=o! texthl=LineNr
|
||||
sign define vimspectorPC text=\ > texthl=MatchParen
|
||||
sign define vimspectorPCBP text=o> texthl=MatchParen
|
||||
```
|
||||
|
||||
## Sign priority
|
||||
|
|
@ -2049,10 +2070,6 @@ hi link jsonComment Comment
|
|||
Debug adapters (for some reason) send telemetry data to clients. Vimspector simply
|
||||
displays this information in the output window. It *does not* and *will not ever*
|
||||
collect, use, forward or otherwise share any data with any third parties.
|
||||
10. Do I _have_ to put a `.vimspector.json` in the root of every project? No, you
|
||||
can put all of your adapter and debug configs in a [single directory](https://puremourning.github.io/vimspector/configuration.html#debug-configurations) if you want to, but note
|
||||
the caveat that `${workspaceRoot}` won't be calculated correctly in that case.
|
||||
The vimsepctor author uses this [a lot](https://github.com/puremourning/.vim-mac/tree/master/vimspector-conf).
|
||||
|
||||
|
||||
[ycmd]: https://github.com/Valloric/ycmd
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@
|
|||
" 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
|
||||
|
|
@ -557,14 +554,6 @@ function! vimspector#ShowEvalBalloon( is_visual ) abort
|
|||
\ . '", 0 )' )
|
||||
endfunction
|
||||
|
||||
function! vimspector#PrintDebugInfo() abort
|
||||
if !s:Enabled()
|
||||
return
|
||||
endif
|
||||
|
||||
py3 _vimspector_session.PrintDebugInfo()
|
||||
endfunction
|
||||
|
||||
|
||||
" Boilerplate {{{
|
||||
let &cpoptions=s:save_cpo
|
||||
|
|
|
|||
|
|
@ -19,30 +19,36 @@ let s:save_cpo = &cpoptions
|
|||
set cpoptions&vim
|
||||
" }}}
|
||||
|
||||
function! s:_OnServerData( channel, data ) abort
|
||||
if !exists( 's:ch' ) || s:ch isnot a:channel
|
||||
let s:channels = {}
|
||||
let s:jobs = {}
|
||||
|
||||
function! s:_OnServerData( session_id, channel, data ) abort
|
||||
if !has_key( s:channels, a:session_id ) ||
|
||||
\ s:channels[ a:session_id ] isnot a:channel
|
||||
return
|
||||
endif
|
||||
|
||||
py3 << EOF
|
||||
_vimspector_session.OnChannelData( vim.eval( 'a:data' ) )
|
||||
EOF
|
||||
py3 _VimspectorSession( vim.eval( 'a:session_id' ) ).OnChannelData(
|
||||
\ vim.eval( 'a:data' ) )
|
||||
endfunction
|
||||
|
||||
function! s:_OnClose( channel ) abort
|
||||
if !exists( 's:ch' ) || s:ch isnot a:channel
|
||||
function! s:_OnClose( session_id, channel ) abort
|
||||
if !has_key( s:channels, a:session_id ) ||
|
||||
\ s:channels[ a:session_id ] isnot a:channel
|
||||
return
|
||||
endif
|
||||
|
||||
echom 'Channel closed'
|
||||
redraw
|
||||
unlet s:ch
|
||||
py3 _vimspector_session.OnServerExit( 0 )
|
||||
unlet s:channels[ a:session_id ]
|
||||
py3 _VimspectorSession( vim.eval( 'a:session_id' ) ).OnServerExit( 0 )
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#StartDebugSession( config ) abort
|
||||
function! vimspector#internal#channel#StartDebugSession(
|
||||
\ session_id,
|
||||
\ config ) abort
|
||||
|
||||
if exists( 's:ch' )
|
||||
if has_key( s:channels, a:session_id )
|
||||
echo 'Channel is already running'
|
||||
return v:false
|
||||
endif
|
||||
|
|
@ -50,7 +56,7 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
|
|||
" If we _also_ have a command line, then start the actual job. This allows for
|
||||
" servers which start up and listen on some port
|
||||
if has_key( a:config, 'command' )
|
||||
let s:job = job_start( a:config[ 'command' ],
|
||||
let s:jobs[ a:session_id ] = job_start( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'in_mode': 'raw',
|
||||
\ 'out_mode': 'raw',
|
||||
|
|
@ -65,16 +71,19 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
|
|||
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,
|
||||
" FIXME: This _always_ waits 10s; the neochannel version is quicker
|
||||
let s:channels[ a:session_id ] = ch_open( l:addr,
|
||||
\ {
|
||||
\ 'mode': 'raw',
|
||||
\ 'callback': funcref( 's:_OnServerData' ),
|
||||
\ 'close_cb': funcref( 's:_OnClose' ),
|
||||
\ 'callback': funcref( 's:_OnServerData',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'close_cb': funcref( 's:_OnClose',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'waittime': 10000,
|
||||
\ }
|
||||
\ )
|
||||
|
||||
if ch_status( s:ch ) !=# 'open'
|
||||
if ch_status( s:channels[ a:session_id ] ) !=# 'open'
|
||||
echom 'Unable to connect to' l:addr
|
||||
redraw
|
||||
return v:false
|
||||
|
|
@ -83,62 +92,67 @@ function! vimspector#internal#channel#StartDebugSession( config ) abort
|
|||
return v:true
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#Send( msg ) abort
|
||||
call ch_sendraw( s:ch, a:msg )
|
||||
function! vimspector#internal#channel#Send( session_id, msg ) abort
|
||||
call ch_sendraw( s:channels[ a:session_id ], a:msg )
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#Timeout( id ) abort
|
||||
py3 << EOF
|
||||
_vimspector_session.OnRequestTimeout( vim.eval( 'a:id' ) )
|
||||
EOF
|
||||
function! vimspector#internal#channel#Timeout( session_id, id ) abort
|
||||
py3 _VimspectorSession( vim.eval( 'a:session_id' ) ).OnRequestTimeout(
|
||||
\ vim.eval( 'a:id' ) )
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#StopDebugSession() abort
|
||||
function! s:_ChannelExists( session_id ) abort
|
||||
return has_key( s:channels, a:session_id ) &&
|
||||
\ count( [ 'closed', 'fail' ],
|
||||
\ ch_status( s:channels[ a:session_id ] ) ) == 0
|
||||
endfunction
|
||||
|
||||
if exists( 's:job' )
|
||||
function! vimspector#internal#channel#StopDebugSession( session_id ) abort
|
||||
|
||||
if has_key( s:jobs, a:session_id )
|
||||
" 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' )
|
||||
let job = s:jobs[ a:session_id ]
|
||||
if job_status( job ) ==# 'run'
|
||||
call job_stop( job, 'term' )
|
||||
endif
|
||||
|
||||
while job_status( s:job ) ==# 'run'
|
||||
call job_stop( s:job, 'kill' )
|
||||
while job_status( job ) ==# 'run'
|
||||
call job_stop( job, 'kill' )
|
||||
endwhile
|
||||
|
||||
unlet s:job
|
||||
call remove( s:jobs, a:session_id )
|
||||
|
||||
if exists( 's:ch' ) && count( [ 'closed', 'fail' ], ch_status( s:ch ) ) == 0
|
||||
if s:_ChannelExists( a:session_id )
|
||||
" 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': '' } )
|
||||
call ch_setoptions( s:channels[ a:session_id ], { 'close_cb': '' } )
|
||||
endif
|
||||
|
||||
elseif exists( 's:ch' ) &&
|
||||
\ count( [ 'closed', 'fail' ], ch_status( s:ch ) ) == 0
|
||||
|
||||
elseif s:_ChannelExists( a:session_id )
|
||||
" 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 )
|
||||
call ch_close( s:channels[ a:session_id ] )
|
||||
endif
|
||||
|
||||
" 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 )
|
||||
while has_key( s:channels, a:session_id ) &&
|
||||
\ count( [ 'open', 'buffered' ],
|
||||
\ ch_status( s:channels[ a:session_id ] ) ) == 1
|
||||
let data = ch_read( s:channels[ a:session_id ], { 'timeout': 10 } )
|
||||
call s:_OnServerData( s:channels[ a:session_id ], data )
|
||||
endwhile
|
||||
call s:_OnClose( s:ch )
|
||||
if has_key( s:channels, a:session_id )
|
||||
call s:_OnClose( a:session_id, s:channels[ a:session_id ] )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#channel#Reset() abort
|
||||
if exists( 's:ch' ) || exists( 's:job' )
|
||||
call vimspector#internal#channel#StopDebugSession()
|
||||
endif
|
||||
function! vimspector#internal#channel#Reset( session_id ) abort
|
||||
call vimspector#internal#channel#StopDebugSession( a:session_id )
|
||||
endfunction
|
||||
|
||||
" Boilerplate {{{
|
||||
|
|
|
|||
|
|
@ -19,44 +19,54 @@ let s:save_cpo = &cpoptions
|
|||
set cpoptions&vim
|
||||
" }}}
|
||||
|
||||
function! s:_OnServerData( channel, data ) abort
|
||||
if !exists( 's:job' ) || ch_getjob( a:channel ) isnot s:job
|
||||
let s:jobs = {}
|
||||
let s:commands = {}
|
||||
|
||||
function! s:_OnServerData( session_id, channel, data ) abort
|
||||
if !has_key( s:jobs, a:session_id ) ||
|
||||
\ ch_getjob( a:channel ) isnot s:jobs[ a:session_id ]
|
||||
call ch_log( 'Get data after process exit' )
|
||||
return
|
||||
endif
|
||||
|
||||
py3 _vimspector_session.OnChannelData( vim.eval( 'a:data' ) )
|
||||
py3 _VimspectorSession( vim.eval( 'a:session_id' ) ).OnChannelData(
|
||||
\ vim.eval( 'a:data' ) )
|
||||
endfunction
|
||||
|
||||
function! s:_OnServerError( channel, data ) abort
|
||||
if !exists( 's:job' ) || ch_getjob( a:channel ) isnot s:job
|
||||
function! s:_OnServerError( session_id, channel, data ) abort
|
||||
if !has_key( s:jobs, a:session_id ) ||
|
||||
\ ch_getjob( a:channel ) isnot s:jobs[ a:session_id ]
|
||||
call ch_log( 'Get data after process exit' )
|
||||
return
|
||||
endif
|
||||
|
||||
py3 _vimspector_session.OnServerStderr( vim.eval( 'a:data' ) )
|
||||
py3 _VimspectorSession( vim.eval( 'a:session_id' ) ).OnServerStderr(
|
||||
\ vim.eval( 'a:data' ) )
|
||||
endfunction
|
||||
|
||||
|
||||
" FIXME: We should wait until both the exit_cb _and_ the channel closed callback
|
||||
" have been received before OnServerExit?
|
||||
|
||||
function! s:_OnExit( channel, status ) abort
|
||||
if !exists( 's:job' ) || ch_getjob( a:channel ) isnot s:job
|
||||
function! s:_OnExit( session_id, channel, status ) abort
|
||||
if !has_key( s:jobs, a:session_id ) ||
|
||||
\ ch_getjob( a:channel ) isnot s:jobs[ a:session_id ]
|
||||
call ch_log( 'Unexpected exit callback' )
|
||||
return
|
||||
endif
|
||||
|
||||
echom 'Channel exit with status ' . a:status
|
||||
redraw
|
||||
if exists( 's:job' )
|
||||
unlet s:job
|
||||
if has_key( s:jobs, a:session_id )
|
||||
unlet s:jobs[ a:session_id ]
|
||||
endif
|
||||
py3 _vimspector_session.OnServerExit( vim.eval( 'a:status' ) )
|
||||
py3 _VimspectorSession( vim.eval( 'a:session_id' ) ).OnServerExit(
|
||||
\ vim.eval( 'a:status' ) )
|
||||
endfunction
|
||||
|
||||
function! s:_OnClose( channel ) abort
|
||||
if !exists( 's:job' ) || job_getchannel( s:job ) != a:channel
|
||||
function! s:_OnClose( session_id, channel ) abort
|
||||
if !has_key( s:jobs, a:session_id ) ||
|
||||
\ ch_getjob( a:channel ) isnot s:jobs[ a:session_id ]
|
||||
call ch_log( 'Channel closed after exit' )
|
||||
return
|
||||
endif
|
||||
|
|
@ -65,34 +75,38 @@ function! s:_OnClose( channel ) abort
|
|||
redraw
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#job#StartDebugSession( config ) abort
|
||||
if exists( 's:job' )
|
||||
function! vimspector#internal#job#StartDebugSession( session_id, config ) abort
|
||||
if has_key( s:jobs, a:session_id )
|
||||
echom 'Not starting: Job is already running'
|
||||
redraw
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let s:job = job_start( a:config[ 'command' ],
|
||||
let s:jobs[ a:session_id ] = job_start( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'in_mode': 'raw',
|
||||
\ 'out_mode': 'raw',
|
||||
\ 'err_mode': 'raw',
|
||||
\ 'exit_cb': funcref( 's:_OnExit' ),
|
||||
\ 'close_cb': funcref( 's:_OnClose' ),
|
||||
\ 'out_cb': funcref( 's:_OnServerData' ),
|
||||
\ 'err_cb': funcref( 's:_OnServerError' ),
|
||||
\ 'exit_cb': funcref( 's:_OnExit',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'close_cb': funcref( 's:_OnClose',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'out_cb': funcref( 's:_OnServerData',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'err_cb': funcref( 's:_OnServerError',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'stoponexit': 'term',
|
||||
\ 'env': a:config[ 'env' ],
|
||||
\ 'cwd': a:config[ 'cwd' ],
|
||||
\ }
|
||||
\ )
|
||||
|
||||
if !exists( 's:job' )
|
||||
if !has_key( s:jobs, a:session_id )
|
||||
" The job died immediately after starting and we cleaned up
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let status = job_status( s:job )
|
||||
let status = job_status( s:jobs[ a:session_id ] )
|
||||
|
||||
echom 'Started job, status is: ' . status
|
||||
redraw
|
||||
|
|
@ -104,20 +118,22 @@ function! vimspector#internal#job#StartDebugSession( config ) abort
|
|||
return v:true
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#job#Send( msg ) abort
|
||||
if ! exists( 's:job' )
|
||||
function! vimspector#internal#job#Send( session_id, msg ) abort
|
||||
if ! has_key( s:jobs, a:session_id )
|
||||
echom "Can't send message: Job was not initialised correctly"
|
||||
redraw
|
||||
return 0
|
||||
endif
|
||||
|
||||
if job_status( s:job ) !=# 'run'
|
||||
let job = s:jobs[ a:session_id ]
|
||||
|
||||
if job_status( job ) !=# 'run'
|
||||
echom "Can't send message: Job is not running"
|
||||
redraw
|
||||
return 0
|
||||
endif
|
||||
|
||||
let ch = job_getchannel( s:job )
|
||||
let ch = job_getchannel( job )
|
||||
if ch ==# 'channel fail'
|
||||
echom 'Channel was closed unexpectedly!'
|
||||
redraw
|
||||
|
|
@ -128,45 +144,55 @@ function! vimspector#internal#job#Send( msg ) abort
|
|||
return 1
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#job#StopDebugSession() abort
|
||||
if !exists( 's:job' )
|
||||
function! vimspector#internal#job#StopDebugSession( session_id ) abort
|
||||
if ! has_key( s:jobs, a:session_id )
|
||||
echom "Not stopping session: Job doesn't exist"
|
||||
redraw
|
||||
return
|
||||
endif
|
||||
|
||||
if job_status( s:job ) ==# 'run'
|
||||
let job = s:jobs[ a:session_id ]
|
||||
|
||||
if job_status( job ) ==# 'run'
|
||||
echom 'Terminating job'
|
||||
redraw
|
||||
call job_stop( s:job, 'kill' )
|
||||
call job_stop( job, 'kill' )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#job#Reset() abort
|
||||
call vimspector#internal#job#StopDebugSession()
|
||||
function! vimspector#internal#job#Reset( session_id ) abort
|
||||
call vimspector#internal#job#StopDebugSession( a:session_id )
|
||||
endfunction
|
||||
|
||||
function! s:_OnCommandExit( category, ch, code ) abort
|
||||
function! s:_OnCommandExit( session_id, category, ch, code ) abort
|
||||
py3 __import__( "vimspector",
|
||||
\ fromlist = [ "utils" ] ).utils.OnCommandWithLogComplete(
|
||||
\ vim.eval( 'a:session_id' ),
|
||||
\ vim.eval( 'a:category' ),
|
||||
\ int( vim.eval( 'a:code' ) ) )
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort
|
||||
function! vimspector#internal#job#StartCommandWithLog(
|
||||
\ session_id,
|
||||
\ cmd,
|
||||
\ category ) abort
|
||||
if ! exists( 's:commands' )
|
||||
let s:commands = {}
|
||||
endif
|
||||
|
||||
if ! has_key( s:commands, a:category )
|
||||
let s:commands[ a:category ] = []
|
||||
if ! has_key( s:commands, a:session_id )
|
||||
let s:commands[ a:session_id ] = {}
|
||||
endif
|
||||
|
||||
let l:index = len( s:commands[ a:category ] )
|
||||
if ! has_key( s:commands[ a:session_id ], a:category )
|
||||
let s:commands[ a:session_id ][ a:category ] = []
|
||||
endif
|
||||
|
||||
let buf = '_vimspector_log_' . a:category
|
||||
let l:index = len( s:commands[ a:session_id ][ a:category ] )
|
||||
|
||||
call add( s:commands[ a:category ], job_start(
|
||||
let buf = '_vimspector_log_' . a:session_id . '_' . a:category
|
||||
|
||||
call add( s:commands[ a:session_id ][ a:category ], job_start(
|
||||
\ a:cmd,
|
||||
\ {
|
||||
\ 'out_io': 'buffer',
|
||||
|
|
@ -175,13 +201,14 @@ function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort
|
|||
\ 'err_msg': 0,
|
||||
\ 'out_name': buf,
|
||||
\ 'err_name': buf,
|
||||
\ 'exit_cb': funcref( 's:_OnCommandExit', [ a:category ] ),
|
||||
\ 'exit_cb': funcref( 's:_OnCommandExit',
|
||||
\ [ a:session_id, a:category ] ),
|
||||
\ 'out_modifiable': 0,
|
||||
\ 'err_modifiable': 0,
|
||||
\ 'stoponexit': 'kill'
|
||||
\ } ) )
|
||||
|
||||
if job_status( s:commands[ a:category ][ index ] ) !=# 'run'
|
||||
if job_status( s:commands[ a:session_id ][ a:category ][ index ] ) !=# 'run'
|
||||
echom 'Unable to start job for ' . string( a:cmd )
|
||||
redraw
|
||||
return v:none
|
||||
|
|
@ -191,19 +218,27 @@ function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort
|
|||
endfunction
|
||||
|
||||
|
||||
function! vimspector#internal#job#CleanUpCommand( category ) abort
|
||||
function! vimspector#internal#job#CleanUpCommand( session_id, category ) abort
|
||||
if ! exists( 's:commands' )
|
||||
let s:commands = {}
|
||||
endif
|
||||
|
||||
if ! has_key( s:commands, a:category )
|
||||
if ! has_key( s:commands, a:session_id )
|
||||
let s:commands[ a:session_id ] = {}
|
||||
endif
|
||||
|
||||
if ! has_key( s:commands[ a:session_id ], a:category )
|
||||
return
|
||||
endif
|
||||
for j in s:commands[ a:category ]
|
||||
for j in s:commands[ a:session_id ][ a:category ]
|
||||
call job_stop( j, 'kill' )
|
||||
endfor
|
||||
|
||||
unlet s:commands[ a:category ]
|
||||
unlet s:commands[ a:session_id ][ a:category ]
|
||||
|
||||
if len( s:commands[ a:session_id ] ) == 0
|
||||
unlet s:commands[ a:session_id ]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Boilerplate {{{
|
||||
|
|
|
|||
|
|
@ -20,28 +20,34 @@ set cpoptions&vim
|
|||
" }}}
|
||||
|
||||
|
||||
let s:channels = {}
|
||||
let s:jobs = {}
|
||||
|
||||
function! s:_OnEvent( chan_id, data, event ) abort
|
||||
|
||||
function! s:_OnEvent( session_id, chan_id, data, event ) abort
|
||||
if v:exiting isnot# v:null
|
||||
return
|
||||
endif
|
||||
|
||||
if !exists( 's:ch' ) || a:chan_id != s:ch
|
||||
if !has_key( s:channels, a:session_id ) ||
|
||||
\ a:chan_id != s:channels[ a:session_id ]
|
||||
return
|
||||
endif
|
||||
|
||||
if a:data == ['']
|
||||
echom 'Channel closed'
|
||||
redraw
|
||||
unlet s:ch
|
||||
unlet s:channels[ a:session_id ]
|
||||
py3 _vimspector_session.OnServerExit( 0 )
|
||||
else
|
||||
py3 _vimspector_session.OnChannelData( '\n'.join( vim.eval( 'a:data' ) ) )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neochannel#StartDebugSession( config ) abort
|
||||
if exists( 's:ch' )
|
||||
function! vimspector#internal#neochannel#StartDebugSession(
|
||||
\ session_id,
|
||||
\ config ) abort
|
||||
if has_key( s:channels, a:session_id )
|
||||
echom 'Not starting: Channel is already running'
|
||||
redraw
|
||||
return v:false
|
||||
|
|
@ -54,12 +60,12 @@ function! vimspector#internal#neochannel#StartDebugSession( config ) abort
|
|||
try
|
||||
let old_env = vimspector#internal#neoterm#PrepareEnvironment(
|
||||
\ a:config[ 'env' ] )
|
||||
let s:job = jobstart( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'cwd': a:config[ 'cwd' ],
|
||||
\ 'env': a:config[ 'env' ],
|
||||
\ }
|
||||
\ )
|
||||
let s:jobs[ a:session_id ] = jobstart( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'cwd': a:config[ 'cwd' ],
|
||||
\ 'env': a:config[ 'env' ],
|
||||
\ }
|
||||
\ )
|
||||
finally
|
||||
call vimspector#internal#neoterm#ResetEnvironment( a:config[ 'env' ],
|
||||
\ old_env )
|
||||
|
|
@ -72,9 +78,10 @@ function! vimspector#internal#neochannel#StartDebugSession( config ) abort
|
|||
while attempt <= 10
|
||||
echo 'Connecting to ' . l:addr . '... (attempt' attempt 'of 10)'
|
||||
try
|
||||
let s:ch = sockconnect( 'tcp',
|
||||
\ addr,
|
||||
\ { 'on_data': funcref( 's:_OnEvent' ) } )
|
||||
let s:channels[ a:session_id ] = sockconnect(
|
||||
\ 'tcp',
|
||||
\ addr,
|
||||
\ { 'on_data': funcref( 's:_OnEvent', [ a:session_id ] ) } )
|
||||
redraw
|
||||
return v:true
|
||||
catch /connection refused/
|
||||
|
|
@ -88,30 +95,30 @@ function! vimspector#internal#neochannel#StartDebugSession( config ) abort
|
|||
return v:false
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neochannel#Send( msg ) abort
|
||||
if ! exists( 's:ch' )
|
||||
function! vimspector#internal#neochannel#Send( session_id, msg ) abort
|
||||
if ! has_key( s:channels, a:session_id )
|
||||
echom "Can't send message: Channel was not initialised correctly"
|
||||
redraw
|
||||
return 0
|
||||
endif
|
||||
|
||||
call chansend( s:ch, a:msg )
|
||||
call chansend( s:channels[ a:session_id ], a:msg )
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neochannel#StopDebugSession() abort
|
||||
if exists( 's:ch' )
|
||||
call chanclose( s:ch )
|
||||
function! vimspector#internal#neochannel#StopDebugSession( session_id ) abort
|
||||
if has_key( s:channels, a:session_id )
|
||||
call chanclose( s:channels[ a:session_id ] )
|
||||
" It doesn't look like we get a callback after chanclos. Who knows if we
|
||||
" will subsequently receive data callbacks.
|
||||
call s:_OnEvent( s:ch, [ '' ], 'data' )
|
||||
call s:_OnEvent( a:session_id, s:channels[ a:session_id ], [ '' ], 'data' )
|
||||
endif
|
||||
|
||||
if exists( 's:job' )
|
||||
if vimspector#internal#neojob#JobIsRunning( s:job )
|
||||
call jobstop( s:job )
|
||||
if has_key( s:jobs, a:session_id )
|
||||
if vimspector#internal#neojob#JobIsRunning( s:jobs[ a:session_id ] )
|
||||
call jobstop( s:jobs[ a:session_id ] )
|
||||
endif
|
||||
unlet s:job
|
||||
unlet s:jobs[ a:session_id ]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,17 @@ let s:save_cpo = &cpoptions
|
|||
set cpoptions&vim
|
||||
" }}}
|
||||
|
||||
let s:jobs = {}
|
||||
let s:commands = {}
|
||||
|
||||
|
||||
function! s:_OnEvent( chan_id, data, event ) abort
|
||||
|
||||
function! s:_OnEvent( session_id, chan_id, data, event ) abort
|
||||
if v:exiting isnot# v:null
|
||||
return
|
||||
endif
|
||||
|
||||
if !exists( 's:job' ) || a:chan_id != s:job
|
||||
if !has_key( s:jobs, a:session_id ) || a:chan_id != s:jobs[ a:session_id ]
|
||||
return
|
||||
endif
|
||||
|
||||
|
|
@ -38,13 +41,15 @@ function! s:_OnEvent( chan_id, data, event ) abort
|
|||
elseif a:event ==# 'exit'
|
||||
echom 'Channel exit with status ' . a:data
|
||||
redraw
|
||||
unlet s:job
|
||||
unlet s:jobs[ a:session_id ]
|
||||
py3 _vimspector_session.OnServerExit( vim.eval( 'a:data' ) )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neojob#StartDebugSession( config ) abort
|
||||
if exists( 's:job' )
|
||||
function! vimspector#internal#neojob#StartDebugSession(
|
||||
\ session_id,
|
||||
\ config ) abort
|
||||
if has_key( s:jobs, a:session_id )
|
||||
echom 'Not starging: Job is already running'
|
||||
redraw
|
||||
return v:false
|
||||
|
|
@ -57,11 +62,14 @@ function! vimspector#internal#neojob#StartDebugSession( config ) abort
|
|||
try
|
||||
let old_env = vimspector#internal#neoterm#PrepareEnvironment(
|
||||
\ a:config[ 'env' ] )
|
||||
let s:job = jobstart( a:config[ 'command' ],
|
||||
let s:jobs[ a:session_id ] = jobstart( a:config[ 'command' ],
|
||||
\ {
|
||||
\ 'on_stdout': funcref( 's:_OnEvent' ),
|
||||
\ 'on_stderr': funcref( 's:_OnEvent' ),
|
||||
\ 'on_exit': funcref( 's:_OnEvent' ),
|
||||
\ 'on_stdout': funcref( 's:_OnEvent',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'on_stderr': funcref( 's:_OnEvent',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'on_exit': funcref( 's:_OnEvent',
|
||||
\ [ a:session_id ] ),
|
||||
\ 'cwd': a:config[ 'cwd' ],
|
||||
\ 'env': a:config[ 'env' ],
|
||||
\ }
|
||||
|
|
@ -78,40 +86,40 @@ function! vimspector#internal#neojob#JobIsRunning( job ) abort
|
|||
return jobwait( [ a:job ], 0 )[ 0 ] == -1
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neojob#Send( msg ) abort
|
||||
if ! exists( 's:job' )
|
||||
function! vimspector#internal#neojob#Send( session_id, msg ) abort
|
||||
if ! has_key( s:jobs, a:session_id )
|
||||
echom "Can't send message: Job was not initialised correctly"
|
||||
redraw
|
||||
return 0
|
||||
endif
|
||||
|
||||
if !vimspector#internal#neojob#JobIsRunning( s:job )
|
||||
if !vimspector#internal#neojob#JobIsRunning( s:jobs[ a:session_id ] )
|
||||
echom "Can't send message: Job is not running"
|
||||
redraw
|
||||
return 0
|
||||
endif
|
||||
|
||||
call chansend( s:job, a:msg )
|
||||
call chansend( s:jobs[ a:session_id ], a:msg )
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neojob#StopDebugSession() abort
|
||||
if !exists( 's:job' )
|
||||
function! vimspector#internal#neojob#StopDebugSession( session_id ) abort
|
||||
if !has_key( s:jobs, a:session_id )
|
||||
return
|
||||
endif
|
||||
|
||||
if vimspector#internal#neojob#JobIsRunning( s:job )
|
||||
if vimspector#internal#neojob#JobIsRunning( s:jobs[ a:session_id ] )
|
||||
echom 'Terminating job'
|
||||
redraw
|
||||
call jobstop( s:job )
|
||||
call jobstop( s:jobs[ a:session_id ] )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neojob#Reset() abort
|
||||
call vimspector#internal#neojob#StopDebugSession()
|
||||
function! vimspector#internal#neojob#Reset( session_id ) abort
|
||||
call vimspector#internal#neojob#StopDebugSession( a:session_id )
|
||||
endfunction
|
||||
|
||||
function! s:_OnCommandEvent( category, id, data, event ) abort
|
||||
function! s:_OnCommandEvent( session_id, category, id, data, event ) abort
|
||||
if v:exiting isnot# v:null
|
||||
return
|
||||
endif
|
||||
|
|
@ -121,18 +129,22 @@ function! s:_OnCommandEvent( category, id, data, event ) abort
|
|||
return
|
||||
endif
|
||||
|
||||
if !has_key( s:commands, a:category )
|
||||
if ! has_key( s:commands, a:session_id )
|
||||
return
|
||||
endif
|
||||
|
||||
if !has_key( s:commands[ a:category ], a:id )
|
||||
if !has_key( s:commands[ a:session_id ], a:category )
|
||||
return
|
||||
endif
|
||||
|
||||
if !has_key( s:commands[ a:session_id ][ a:category ], a:id )
|
||||
return
|
||||
endif
|
||||
|
||||
if a:event ==# 'stdout'
|
||||
let buffer = s:commands[ a:category ][ a:id ].stdout
|
||||
let buffer = s:commands[ a:session_id ][ a:category ][ a:id ].stdout
|
||||
elseif a:event ==# 'stderr'
|
||||
let buffer = s:commands[ a:category ][ a:id ].stderr
|
||||
let buffer = s:commands[ a:session_id ][ a:category ][ a:id ].stderr
|
||||
endif
|
||||
|
||||
try
|
||||
|
|
@ -159,21 +171,21 @@ function! s:_OnCommandEvent( category, id, data, event ) abort
|
|||
call setbufvar( buffer, '&modified', 0 )
|
||||
endtry
|
||||
|
||||
" if the buffer is visible, scroll it, but don't allow autocommands to fire,
|
||||
" as this may close the current window!
|
||||
" if the buffer is visible, scroll it
|
||||
let w = bufwinnr( buffer )
|
||||
if w > 0
|
||||
let cw = winnr()
|
||||
try
|
||||
noautocmd execute w . 'wincmd w'
|
||||
noautocmd normal! Gz-
|
||||
execute w . 'wincmd w'
|
||||
normal! Gz-
|
||||
finally
|
||||
noautocmd execute cw . 'wincmd w'
|
||||
execute cw . 'wincmd w'
|
||||
endtry
|
||||
endif
|
||||
elseif a:event ==# 'exit'
|
||||
py3 __import__( "vimspector",
|
||||
\ fromlist = [ "utils" ] ).utils.OnCommandWithLogComplete(
|
||||
\ vim.eval( 'a:session_id' ),
|
||||
\ vim.eval( 'a:category' ),
|
||||
\ int( vim.eval( 'a:data' ) ) )
|
||||
endif
|
||||
|
|
@ -199,11 +211,16 @@ function! s:MakeBufferWritable( buffer ) abort
|
|||
endfunction
|
||||
|
||||
|
||||
let s:commands = {}
|
||||
function! vimspector#internal#neojob#StartCommandWithLog(
|
||||
\ session_id,
|
||||
\ cmd,
|
||||
\ category ) abort
|
||||
if ! has_key( s:commands, a:session_id )
|
||||
let s:commands[ a:session_id ] = {}
|
||||
endif
|
||||
|
||||
function! vimspector#internal#neojob#StartCommandWithLog( cmd, category ) abort
|
||||
if ! has_key( s:commands, a:category )
|
||||
let s:commands[ a:category ] = {}
|
||||
if ! has_key( s:commands[ a:session_id ], a:category )
|
||||
let s:commands[ a:session_id ][ a:category ] = {}
|
||||
endif
|
||||
|
||||
let buf = bufnr( '_vimspector_log_' . a:category, v:true )
|
||||
|
|
@ -216,14 +233,14 @@ function! vimspector#internal#neojob#StartCommandWithLog( cmd, category ) abort
|
|||
let id = jobstart(a:cmd,
|
||||
\ {
|
||||
\ 'on_stdout': funcref( 's:_OnCommandEvent',
|
||||
\ [ a:category ] ),
|
||||
\ [ a:session_id, a:category ] ),
|
||||
\ 'on_stderr': funcref( 's:_OnCommandEvent',
|
||||
\ [ a:category ] ),
|
||||
\ [ a:session_id, a:category ] ),
|
||||
\ 'on_exit': funcref( 's:_OnCommandEvent',
|
||||
\ [ a:category ] ),
|
||||
\ [ a:session_id, a:category ] ),
|
||||
\ } )
|
||||
|
||||
let s:commands[ a:category ][ id ] = {
|
||||
let s:commands[ a:session_id ][ a:category ][ id ] = {
|
||||
\ 'stdout': buf,
|
||||
\ 'stderr': buf
|
||||
\ }
|
||||
|
|
@ -231,19 +248,25 @@ function! vimspector#internal#neojob#StartCommandWithLog( cmd, category ) abort
|
|||
return buf
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#neojob#CleanUpCommand( category ) abort
|
||||
if ! has_key( s:commands, a:category )
|
||||
function! vimspector#internal#neojob#CleanUpCommand(
|
||||
\ session_id,
|
||||
\ category ) abort
|
||||
if ! has_key( s:commands, a:session_id )
|
||||
return
|
||||
endif
|
||||
|
||||
for id in keys( s:commands[ a:category ] )
|
||||
if ! has_key( s:commands[ a:session_id ], a:category )
|
||||
return
|
||||
endif
|
||||
|
||||
for id in keys( s:commands[ a:session_id ][ a:category ] )
|
||||
let id = str2nr( id )
|
||||
if jobwait( [ id ], 0 )[ 0 ] == -1
|
||||
call jobstop( id )
|
||||
endif
|
||||
call jobwait( [ id ], -1 )
|
||||
endfor
|
||||
unlet! s:commands[ a:category ]
|
||||
unlet! s:commands[ a:session_id ][ a:category ]
|
||||
endfunction
|
||||
|
||||
" Boilerplate {{{
|
||||
|
|
|
|||
|
|
@ -26,11 +26,22 @@ endif
|
|||
|
||||
function! vimspector#internal#state#Reset() abort
|
||||
try
|
||||
py3 import vim
|
||||
py3 _vimspector_session = __import__(
|
||||
\ "vimspector",
|
||||
\ fromlist=[ "debug_session" ] ).debug_session.DebugSession(
|
||||
\ vim.eval( 's:prefix' ) )
|
||||
py3 <<EOF
|
||||
|
||||
import vim
|
||||
|
||||
_vimspector_session_man = __import__(
|
||||
"vimspector",
|
||||
fromlist=[ "session_manager" ] ).session_manager.Get()
|
||||
|
||||
# Deprecated
|
||||
_vimspector_session = _vimspector_session_man.NewSession(
|
||||
vim.eval( 's:prefix' ) )
|
||||
|
||||
def _VimspectorSession( session_id ):
|
||||
return _vimspector_session_man.GetSession( int( session_id ) )
|
||||
|
||||
EOF
|
||||
catch /.*/
|
||||
echohl WarningMsg
|
||||
echom 'Exception while loading vimspector:' v:exception
|
||||
|
|
@ -47,6 +58,22 @@ function! vimspector#internal#state#GetAPIPrefix() abort
|
|||
return s:prefix
|
||||
endfunction
|
||||
|
||||
function! vimspector#internal#state#SwitchToSession( id ) abort
|
||||
py3 _vimspector_session = _VimspectorSession( vim.eval( 'a:id' ) )
|
||||
endfunction
|
||||
|
||||
|
||||
function! vimspector#internal#state#OnTabEnter() abort
|
||||
py3 <<EOF
|
||||
session = _vimspector_session_man.SessionForTab(
|
||||
int( vim.eval( 'tabpagenr()' ) ) )
|
||||
|
||||
if session is not None:
|
||||
_vimspector_session = session
|
||||
EOF
|
||||
endfunction
|
||||
|
||||
|
||||
" Boilerplate {{{
|
||||
let &cpoptions=s:save_cpo
|
||||
unlet s:save_cpo
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (6.0.3.6)
|
||||
activesupport (6.0.3.4)
|
||||
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.8.0)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
|
|
@ -16,7 +16,7 @@ GEM
|
|||
colorator (1.1.0)
|
||||
commonmarker (0.17.13)
|
||||
ruby-enum (~> 0.5)
|
||||
concurrent-ruby (1.1.8)
|
||||
concurrent-ruby (1.1.7)
|
||||
dnsruby (1.61.5)
|
||||
simpleidn (~> 0.1)
|
||||
em-websocket (0.5.2)
|
||||
|
|
@ -30,12 +30,12 @@ GEM
|
|||
faraday-net_http (~> 1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
faraday-net_http (1.0.1)
|
||||
ffi (1.15.0)
|
||||
faraday-net_http (1.0.0)
|
||||
ffi (1.14.2)
|
||||
forwardable-extended (2.6.0)
|
||||
gemoji (3.0.1)
|
||||
github-pages (214)
|
||||
github-pages-health-check (= 1.17.0)
|
||||
github-pages (209)
|
||||
github-pages-health-check (= 1.16.1)
|
||||
jekyll (= 3.9.0)
|
||||
jekyll-avatar (= 0.7.0)
|
||||
jekyll-coffeescript (= 1.1.1)
|
||||
|
|
@ -50,9 +50,9 @@ GEM
|
|||
jekyll-readme-index (= 0.3.0)
|
||||
jekyll-redirect-from (= 0.16.0)
|
||||
jekyll-relative-links (= 0.6.1)
|
||||
jekyll-remote-theme (= 0.4.3)
|
||||
jekyll-remote-theme (= 0.4.2)
|
||||
jekyll-sass-converter (= 1.5.2)
|
||||
jekyll-seo-tag (= 2.7.1)
|
||||
jekyll-seo-tag (= 2.6.1)
|
||||
jekyll-sitemap (= 1.4.0)
|
||||
jekyll-swiss (= 1.0.0)
|
||||
jekyll-theme-architect (= 0.1.1)
|
||||
|
|
@ -70,19 +70,19 @@ GEM
|
|||
jekyll-theme-time-machine (= 0.1.1)
|
||||
jekyll-titles-from-headings (= 0.5.3)
|
||||
jemoji (= 0.12.0)
|
||||
kramdown (= 2.3.1)
|
||||
kramdown (= 2.3.0)
|
||||
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.26.0)
|
||||
rouge (= 3.23.0)
|
||||
terminal-table (~> 1.4)
|
||||
github-pages-health-check (1.17.0)
|
||||
github-pages-health-check (1.16.1)
|
||||
addressable (~> 2.3)
|
||||
dnsruby (~> 1.60)
|
||||
octokit (~> 4.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
public_suffix (~> 3.0)
|
||||
typhoeus (~> 1.3)
|
||||
html-pipeline (2.14.0)
|
||||
activesupport (>= 2)
|
||||
|
|
@ -136,15 +136,15 @@ GEM
|
|||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-relative-links (0.6.1)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-remote-theme (0.4.3)
|
||||
jekyll-remote-theme (0.4.2)
|
||||
addressable (~> 2.0)
|
||||
jekyll (>= 3.5, < 5.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.7.1)
|
||||
jekyll (>= 3.8, < 5.0)
|
||||
jekyll-seo-tag (2.6.1)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-sitemap (1.4.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-swiss (1.0.0)
|
||||
|
|
@ -196,23 +196,23 @@ GEM
|
|||
gemoji (~> 3.0)
|
||||
html-pipeline (~> 2.2)
|
||||
jekyll (>= 3.0, < 5.0)
|
||||
kramdown (2.3.1)
|
||||
kramdown (2.3.0)
|
||||
rexml
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
kramdown (~> 2.0)
|
||||
liquid (4.0.3)
|
||||
listen (3.5.1)
|
||||
listen (3.4.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.5.1)
|
||||
mini_portile2 (2.5.0)
|
||||
minima (2.5.1)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-feed (~> 0.9)
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.14.4)
|
||||
minitest (5.14.3)
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.11.5)
|
||||
nokogiri (1.11.1)
|
||||
mini_portile2 (~> 2.5.0)
|
||||
racc (~> 1.4)
|
||||
octokit (4.20.0)
|
||||
|
|
@ -220,16 +220,16 @@ GEM
|
|||
sawyer (~> 0.8.0, >= 0.5.3)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
public_suffix (4.0.6)
|
||||
public_suffix (3.1.1)
|
||||
racc (1.5.2)
|
||||
rb-fsevent (0.10.4)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.2.5)
|
||||
rouge (3.26.0)
|
||||
ruby-enum (0.9.0)
|
||||
rexml (3.2.4)
|
||||
rouge (3.23.0)
|
||||
ruby-enum (0.8.0)
|
||||
i18n
|
||||
ruby2_keywords (0.0.4)
|
||||
ruby2_keywords (0.0.2)
|
||||
rubyzip (2.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sass (3.7.4)
|
||||
|
|
@ -240,7 +240,7 @@ GEM
|
|||
sawyer (0.8.2)
|
||||
addressable (>= 2.3.5)
|
||||
faraday (> 0.8, < 2.0)
|
||||
simpleidn (0.2.1)
|
||||
simpleidn (0.1.1)
|
||||
unf (~> 0.1.4)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ JSON value `true`, and the suffix is stripped fom the key, resulting in the
|
|||
following:
|
||||
|
||||
```json
|
||||
"stopOnEntry": true
|
||||
"stopOnEntry#json": true
|
||||
```
|
||||
|
||||
Which is what we need.
|
||||
|
|
@ -722,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": "${fileBasenameNoExtension}"
|
||||
"ServiceName": "${fileBasenameNoExtention}"
|
||||
},
|
||||
|
||||
"adapter": "python-remote",
|
||||
|
|
|
|||
|
|
@ -13,13 +13,6 @@
|
|||
" 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
|
||||
|
|
@ -115,9 +108,6 @@ command! -bar -nargs=? -complete=custom,vimspector#CompleteOutput
|
|||
command! -bar
|
||||
\ VimspectorToggleLog
|
||||
\ call vimspector#ToggleLog()
|
||||
command! -bar
|
||||
\ VimspectorDebugInfo
|
||||
\ call vimspector#PrintDebugInfo()
|
||||
command! -nargs=1 -complete=custom,vimspector#CompleteExpr
|
||||
\ VimspectorEval
|
||||
\ call vimspector#Evaluate( <f-args> )
|
||||
|
|
@ -151,6 +141,7 @@ augroup END
|
|||
augroup Vimspector
|
||||
autocmd!
|
||||
autocmd BufNew * call vimspector#OnBufferCreated( expand( '<afile>' ) )
|
||||
autocmd TabEnter * call vimspector#internal#state#OnTabEnter()
|
||||
augroup END
|
||||
|
||||
" boilerplate {{{
|
||||
|
|
|
|||
|
|
@ -34,13 +34,24 @@ class ServerBreakpointHandler( object ):
|
|||
pass
|
||||
|
||||
|
||||
# FIXME: THis really should be project scope and not associated with a debug
|
||||
# session. Breakpoints set by the user should be independent and breakpoints for
|
||||
# the current active session should be associated with the session when they are
|
||||
# in use.
|
||||
#
|
||||
# Questions include:
|
||||
# 1. what happens if we set/chnage a breakpiont in session #2 while session #1
|
||||
# is active ? Maybe we re-send the breakpoints to _all_ active sessions?
|
||||
#
|
||||
# More...
|
||||
class ProjectBreakpoints( object ):
|
||||
def __init__( self ):
|
||||
def __init__( self, session_id ):
|
||||
self._connection = None
|
||||
self._logger = logging.getLogger( __name__ )
|
||||
utils.SetUpLogging( self._logger )
|
||||
self._logger = logging.getLogger( __name__ + '.' + str( session_id ) )
|
||||
utils.SetUpLogging( self._logger, session_id )
|
||||
|
||||
# These are the user-entered breakpoints.
|
||||
# These are the user-entered breakpoints. NOTE: if updating this, also
|
||||
# update Copy()
|
||||
self._line_breakpoints = defaultdict( list )
|
||||
self._func_breakpoints = []
|
||||
self._exception_breakpoints = None
|
||||
|
|
@ -91,6 +102,12 @@ class ProjectBreakpoints( object ):
|
|||
# FIXME: If the adapter type changes, we should probably forget this ?
|
||||
|
||||
|
||||
def Copy( self, other: 'ProjectBreakpoints' ):
|
||||
self._line_breakpoints = dict( other._line_breakpoints )
|
||||
self._func_breakpoints = list( other._func_breakpoints )
|
||||
if other._exception_breakpoints is not None:
|
||||
self._exception_breakpoints = dict( other._exception_breakpoints )
|
||||
|
||||
def BreakpointsAsQuickFix( self ):
|
||||
# FIXME: Handling of breakpoints is a mess, split between _codeView and this
|
||||
# object. This makes no sense and should be centralised so that we don't
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@ from collections import defaultdict
|
|||
|
||||
from vimspector import utils, terminal, signs
|
||||
|
||||
NEXT_SIGN_ID = 1
|
||||
|
||||
|
||||
class CodeView( object ):
|
||||
def __init__( self, window, api_prefix ):
|
||||
def __init__( self, session_id, window, api_prefix ):
|
||||
self._window = window
|
||||
self._api_prefix = api_prefix
|
||||
|
||||
self._terminal = None
|
||||
self.current_syntax = None
|
||||
|
||||
self._logger = logging.getLogger( __name__ )
|
||||
self._logger = logging.getLogger( __name__ + '.' + str( session_id ) )
|
||||
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 = {
|
||||
'vimspectorPC': None,
|
||||
|
|
@ -92,8 +92,9 @@ class CodeView( object ):
|
|||
self._UndisplayPC( clear_pc = False )
|
||||
|
||||
# FIXME: Do we relly need to keep using up IDs ?
|
||||
self._signs[ 'vimspectorPC' ] = self._next_sign_id
|
||||
self._next_sign_id += 1
|
||||
global NEXT_SIGN_ID
|
||||
self._signs[ 'vimspectorPC' ] = NEXT_SIGN_ID
|
||||
NEXT_SIGN_ID += 1
|
||||
|
||||
sign = 'vimspectorPC'
|
||||
# If there's also a breakpoint on this line, use vimspectorPCBP
|
||||
|
|
@ -247,8 +248,9 @@ class CodeView( object ):
|
|||
if 'line' not in breakpoint:
|
||||
continue
|
||||
|
||||
sign_id = self._next_sign_id
|
||||
self._next_sign_id += 1
|
||||
global NEXT_SIGN_ID
|
||||
sign_id = NEXT_SIGN_ID
|
||||
NEXT_SIGN_ID += 1
|
||||
self._signs[ 'breakpoints' ].append( sign_id )
|
||||
if utils.BufferExists( file_name ):
|
||||
signs.PlaceSign( sign_id,
|
||||
|
|
|
|||
77
python3/vimspector/custom/python.py
Normal file
77
python3/vimspector/custom/python.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# 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 session_manager, gadgets, utils
|
||||
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
class Debugpy( object ):
|
||||
parent: DebugSession
|
||||
sessions: Sequence[ DebugSession ]
|
||||
|
||||
def __init__( self, debug_session: DebugSession ):
|
||||
self.parent = debug_session
|
||||
self.queue = []
|
||||
|
||||
def LaunchSubprocessDebugSession( self, result ):
|
||||
launch_arguments = self.queue.pop( 0 )
|
||||
|
||||
if result == 1:
|
||||
session = session_manager.Get().NewSession( self.parent._api_prefix )
|
||||
|
||||
# Inject the launch config (HACK!). This will actually mean that the
|
||||
# configuration passed below is ignored.
|
||||
session._launch_config = launch_arguments
|
||||
|
||||
# FIXME: We probably do need to add a StartWithLauncArguments and somehow
|
||||
# tell the new session that it shoud not support "Restart" requests ?
|
||||
#
|
||||
# In fact, what even would Reset do... ?
|
||||
session._breakpoints.Copy( self.parent._breakpoints )
|
||||
session._StartWithConfiguration( { 'configuration': launch_arguments },
|
||||
launch_arguments[ 'connect' ] )
|
||||
|
||||
self.HandleNext()
|
||||
|
||||
|
||||
def OnEvent_debugpyAttach( self, message ):
|
||||
# Debugpy sends us the contents of a launch request that we should use. We
|
||||
# probaly just jave to guess the rest
|
||||
launch_arguments = message[ 'body' ]
|
||||
self.queue.append( launch_arguments )
|
||||
|
||||
# We use a queue because the confirm mechanism is quasi-modal and we can't
|
||||
# do multiple 'confirm' dialogs at once. It's not uncommon for
|
||||
# multiprocessing to create multiple subprocesses all at the same time.
|
||||
if len( self.queue ) == 1:
|
||||
self.HandleNext()
|
||||
|
||||
def HandleNext( self ):
|
||||
if not self.queue:
|
||||
return
|
||||
|
||||
launch_argyments = self.queue[ 0 ]
|
||||
pid = launch_argyments[ 'subProcessId' ]
|
||||
|
||||
utils.Confirm(
|
||||
self.parent._api_prefix,
|
||||
f"Subprocess {pid} was launched.\nAttach to it in a new tab?",
|
||||
self.LaunchSubprocessDebugSession,
|
||||
default_value = 1,
|
||||
options = [ 'Yes', 'No' ],
|
||||
keys = [ 'y', 'n' ] )
|
||||
|
||||
|
|
@ -29,14 +29,15 @@ class PendingRequest( object ):
|
|||
|
||||
|
||||
class DebugAdapterConnection( object ):
|
||||
def __init__( self, handlers, send_func ):
|
||||
self._logger = logging.getLogger( __name__ )
|
||||
utils.SetUpLogging( self._logger )
|
||||
def __init__( self, handlers, session_id, send_func ):
|
||||
self._logger = logging.getLogger( __name__ + '.' + str( session_id ) )
|
||||
utils.SetUpLogging( self._logger, session_id )
|
||||
|
||||
self._Write = send_func
|
||||
self._SetState( 'READ_HEADER' )
|
||||
self._buffer = bytes()
|
||||
self._handlers = handlers
|
||||
self._session_id = session_id
|
||||
self._next_message_id = 0
|
||||
self._outstanding_requests = {}
|
||||
|
||||
|
|
@ -51,10 +52,12 @@ class DebugAdapterConnection( object ):
|
|||
msg[ 'seq' ] = this_id
|
||||
msg[ 'type' ] = 'request'
|
||||
|
||||
# TODO/FIXME: This is so messy
|
||||
expiry_id = vim.eval(
|
||||
'timer_start( {}, "vimspector#internal#channel#Timeout" )'.format(
|
||||
timeout ) )
|
||||
'timer_start( {}, '
|
||||
' function( "vimspector#internal#channel#Timeout", '
|
||||
' [ {} ] ) )'.format(
|
||||
timeout,
|
||||
self._session_id ) )
|
||||
|
||||
request = PendingRequest( msg,
|
||||
handler,
|
||||
|
|
@ -226,12 +229,7 @@ class DebugAdapterConnection( object ):
|
|||
|
||||
# self._logger.debug( 'Message received (raw): %s', payload )
|
||||
|
||||
try:
|
||||
message = json.loads( payload, strict = False )
|
||||
except Exception:
|
||||
self._logger.exception( "Invalid message received: %s", payload )
|
||||
self._SetState( 'READ_HEADER' )
|
||||
raise
|
||||
message = json.loads( payload )
|
||||
|
||||
self._logger.debug( 'Message received: {0}'.format( message ) )
|
||||
|
||||
|
|
|
|||
|
|
@ -42,15 +42,17 @@ VIMSPECTOR_HOME = utils.GetVimspectorBase()
|
|||
# cache of what the user entered for any option we ask them
|
||||
USER_CHOICES = {}
|
||||
|
||||
|
||||
class DebugSession( object ):
|
||||
def __init__( self, api_prefix ):
|
||||
self._logger = logging.getLogger( __name__ )
|
||||
utils.SetUpLogging( self._logger )
|
||||
def __init__( self, session_id, session_manager, api_prefix ):
|
||||
self.session_id = session_id
|
||||
self.manager = session_manager
|
||||
self._logger = logging.getLogger( __name__ + '.' + str( session_id ) )
|
||||
utils.SetUpLogging( self._logger, session_id )
|
||||
|
||||
self._api_prefix = api_prefix
|
||||
|
||||
self._logger.info( "**** INITIALISING NEW VIMSPECTOR SESSION ****" )
|
||||
self._logger.info( "**** INITIALISING NEW VIMSPECTOR SESSION FOR ID "
|
||||
f"{session_id } ****" )
|
||||
self._logger.info( "API is: {}".format( api_prefix ) )
|
||||
self._logger.info( 'VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME )
|
||||
self._logger.info( 'gadgetDir = %s',
|
||||
|
|
@ -61,7 +63,7 @@ class DebugSession( object ):
|
|||
self._stackTraceView = None
|
||||
self._variablesView = None
|
||||
self._outputView = None
|
||||
self._breakpoints = breakpoints.ProjectBreakpoints()
|
||||
self._breakpoints = breakpoints.ProjectBreakpoints( session_id )
|
||||
self._splash_screen = None
|
||||
self._remote_term = None
|
||||
|
||||
|
|
@ -73,6 +75,11 @@ class DebugSession( object ):
|
|||
|
||||
self._ResetServerState()
|
||||
|
||||
|
||||
def __del__( self ):
|
||||
self.manager.DestroySession( self )
|
||||
|
||||
|
||||
def _ResetServerState( self ):
|
||||
self._connection = None
|
||||
self._init_complete = False
|
||||
|
|
@ -408,7 +415,13 @@ class DebugSession( object ):
|
|||
if self._uiTab:
|
||||
self._logger.debug( "Clearing down UI" )
|
||||
|
||||
del vim.vars[ 'vimspector_session_windows' ]
|
||||
try:
|
||||
# FIXME: vimspector_session_windows is totally buseted with multiple
|
||||
# sessions
|
||||
del vim.vars[ 'vimspector_session_windows' ]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
vim.current.tabpage = self._uiTab
|
||||
|
||||
self._splash_screen = utils.HideSplash( self._api_prefix,
|
||||
|
|
@ -667,6 +680,15 @@ class DebugSession( object ):
|
|||
|
||||
def _SetUpUI( self ):
|
||||
vim.command( 'tab split' )
|
||||
|
||||
# Switch to this session now that we've made it visible. Note that the
|
||||
# TabEnter autocmd does trigger when the above is run, but that's before the
|
||||
# following line assigns the tab to this session, so when we try to find
|
||||
# this session by tab number, it's not found. So we have to manually switch
|
||||
# to it when creating a new tab.
|
||||
utils.Call( 'vimspector#internal#state#SwitchToSession',
|
||||
self.session_id )
|
||||
|
||||
self._uiTab = vim.current.tabpage
|
||||
|
||||
mode = settings.Get( 'ui_mode' )
|
||||
|
|
@ -710,7 +732,9 @@ class DebugSession( object ):
|
|||
def _SetUpUIHorizontal( self ):
|
||||
# Code window
|
||||
code_window = vim.current.window
|
||||
self._codeView = code.CodeView( code_window, self._api_prefix )
|
||||
self._codeView = code.CodeView( self.session_id,
|
||||
code_window,
|
||||
self._api_prefix )
|
||||
|
||||
# Call stack
|
||||
vim.command(
|
||||
|
|
@ -735,7 +759,8 @@ class DebugSession( object ):
|
|||
with utils.LetCurrentWindow( stack_trace_window ):
|
||||
vim.command( f'{ one_third }wincmd _' )
|
||||
|
||||
self._variablesView = variables.VariablesView( vars_window,
|
||||
self._variablesView = variables.VariablesView( self,
|
||||
vars_window,
|
||||
watch_window )
|
||||
|
||||
# Output/logging
|
||||
|
|
@ -743,7 +768,8 @@ class DebugSession( object ):
|
|||
vim.command( f'rightbelow { settings.Int( "bottombar_height" ) }new' )
|
||||
output_window = vim.current.window
|
||||
self._outputView = output.DAPOutputView( output_window,
|
||||
self._api_prefix )
|
||||
self._api_prefix,
|
||||
session_id = self.session_id )
|
||||
|
||||
# TODO: If/when we support multiple sessions, we'll need some way to
|
||||
# indicate which tab was created and store all the tabs
|
||||
|
|
@ -766,7 +792,9 @@ class DebugSession( object ):
|
|||
def _SetUpUIVertical( self ):
|
||||
# Code window
|
||||
code_window = vim.current.window
|
||||
self._codeView = code.CodeView( code_window, self._api_prefix )
|
||||
self._codeView = code.CodeView( self.session_id,
|
||||
code_window,
|
||||
self._api_prefix )
|
||||
|
||||
# Call stack
|
||||
vim.command(
|
||||
|
|
@ -793,7 +821,8 @@ class DebugSession( object ):
|
|||
with utils.LetCurrentWindow( stack_trace_window ):
|
||||
vim.command( f'{ one_third }wincmd |' )
|
||||
|
||||
self._variablesView = variables.VariablesView( vars_window,
|
||||
self._variablesView = variables.VariablesView( self,
|
||||
vars_window,
|
||||
watch_window )
|
||||
|
||||
|
||||
|
|
@ -802,7 +831,8 @@ class DebugSession( object ):
|
|||
vim.command( f'rightbelow { settings.Int( "bottombar_height" ) }new' )
|
||||
output_window = vim.current.window
|
||||
self._outputView = output.DAPOutputView( output_window,
|
||||
self._api_prefix )
|
||||
self._api_prefix,
|
||||
session_id = self.session_id )
|
||||
|
||||
# TODO: If/when we support multiple sessions, we'll need some way to
|
||||
# indicate which tab was created and store all the tabs
|
||||
|
|
@ -887,8 +917,10 @@ class DebugSession( object ):
|
|||
|
||||
vim.vars[ '_vimspector_adapter_spec' ] = self._adapter
|
||||
if not vim.eval( "vimspector#internal#{}#StartDebugSession( "
|
||||
" {},"
|
||||
" g:_vimspector_adapter_spec "
|
||||
")".format( self._connection_type ) ):
|
||||
")".format( self._connection_type,
|
||||
self.session_id ) ):
|
||||
self._logger.error( "Unable to start debug server" )
|
||||
self._splash_screen = utils.DisplaySplash( self._api_prefix,
|
||||
self._splash_screen,
|
||||
|
|
@ -908,9 +940,11 @@ class DebugSession( object ):
|
|||
handlers = [ self ]
|
||||
|
||||
self._connection = debug_adapter_connection.DebugAdapterConnection(
|
||||
handlers,
|
||||
lambda msg: utils.Call(
|
||||
handlers = handlers,
|
||||
session_id = self.session_id,
|
||||
send_func = lambda msg: utils.Call(
|
||||
"vimspector#internal#{}#Send".format( self._connection_type ),
|
||||
self.session_id,
|
||||
msg ) )
|
||||
|
||||
self._logger.info( 'Debug Adapter Started' )
|
||||
|
|
@ -933,8 +967,9 @@ class DebugSession( object ):
|
|||
assert not self._run_on_server_exit
|
||||
self._run_on_server_exit = callback
|
||||
|
||||
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
|
||||
self._connection_type ) )
|
||||
vim.eval( 'vimspector#internal#{}#StopDebugSession( {} )'.format(
|
||||
self._connection_type,
|
||||
self.session_id ) )
|
||||
|
||||
self._connection.DoRequest( handler, {
|
||||
'command': 'disconnect',
|
||||
|
|
@ -1179,9 +1214,10 @@ class DebugSession( object ):
|
|||
self._on_init_complete_handlers = []
|
||||
|
||||
self._logger.debug( "LAUNCH!" )
|
||||
self._launch_config = {}
|
||||
self._launch_config.update( self._adapter.get( 'configuration', {} ) )
|
||||
self._launch_config.update( self._configuration[ 'configuration' ] )
|
||||
if self._launch_config is None:
|
||||
self._launch_config = {}
|
||||
self._launch_config.update( self._adapter.get( 'configuration', {} ) )
|
||||
self._launch_config.update( self._configuration[ 'configuration' ] )
|
||||
|
||||
request = self._configuration.get(
|
||||
'remote-request',
|
||||
|
|
@ -1270,37 +1306,6 @@ 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
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue