From c3b2a12f750ecbecef855b01460c72d77ece2908 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 23 Aug 2020 14:48:38 +0100 Subject: [PATCH 001/200] Split gadget specs into separate commands --- python3/vimspector/gadgets.py | 956 +++++++++++++++++----------------- 1 file changed, 485 insertions(+), 471 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 2ea6bbc..76b8097 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -19,514 +19,528 @@ import sys import os -GADGETS = { - 'vscode-cpptools': { - 'language': 'c', - 'download': { - 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' - '${version}/${file_name}', - }, - 'do': lambda name, root, gadget: installer.InstallCppTools( name, - root, - gadget ), - 'all': { - 'version': '0.27.0', - "adapters": { - "vscode-cpptools": { - "name": "cppdbg", - "command": [ - "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" - ], - "attach": { - "pidProperty": "processId", - "pidSelect": "ask" - }, - "configuration": { - "type": "cppdbg", - "args": [], - "cwd": "${workspaceRoot}", - "environment": [], - } - }, - }, - }, - 'linux': { - 'file_name': 'cpptools-linux.vsix', - 'checksum': - '3695202e1e75a03de18049323b66d868165123f26151f8c974a480eaf0205435', - }, - 'macos': { - 'file_name': 'cpptools-osx.vsix', - 'checksum': - 'cb061e3acd7559a539e5586f8d3f535101c4ec4e8a48195856d1d39380b5cf3c', - }, - 'windows': { - 'file_name': 'cpptools-win32.vsix', - 'checksum': - 'aa294368ed16d48c59e49c8000e146eae5a19ad07b654efed5db8ec93b24229e', - "adapters": { - "vscode-cpptools": { - "name": "cppdbg", - "command": [ - "${gadgetDir}/vscode-cpptools/debugAdapters/bin/OpenDebugAD7.exe" - ], - "attach": { - "pidProperty": "processId", - "pidSelect": "ask" - }, - "configuration": { - "type": "cppdbg", - "args": [], - "cwd": "${workspaceRoot}", - "environment": [], - "MIMode": "gdb", - "MIDebuggerPath": "gdb.exe" - } - }, - }, - }, +GADGETS = {} + +GADGETS[ 'vscode-cpptools' ] = { + 'language': 'c', + 'download': { + 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' + '${version}/${file_name}', }, - '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", + 'do': lambda name, root, gadget: installer.InstallCppTools( name, + root, + gadget ), + 'all': { + 'version': '0.27.0', + "adapters": { + "vscode-cpptools": { + "name": "cppdbg", "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', - 'checksum': - '210632bba2221fbb841c9785a615258819ceec401d1abdbeb5f2326f12cc72a1' - }, - 'do': lambda name, root, gadget: installer.InstallDebugpy( name, - root, - gadget ), - 'adapters': { - 'debugpy': { - "command": [ - sys.executable, # TODO: Will this work from within Vim ? - "${gadgetDir}/debugpy/build/lib/debugpy/adapter" - ], - "name": "debugpy", - "configuration": { - "python": sys.executable, # TODO: Will this work from within Vim ? - # Don't debug into subprocesses, as this leads to problems (vimspector - # doesn't support the custom messages) - # https://github.com/puremourning/vimspector/issues/141 - "subProcess": False, - } - } - }, - }, - 'vscode-java-debug': { - 'language': 'java', - 'enabled': False, - 'download': { - 'url': 'https://github.com/microsoft/vscode-java-debug/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': '0.26.0', - 'file_name': 'vscjava.vscode-java-debug-0.26.0.vsix', - 'checksum': - 'de49116ff3a3c941dad0c36d9af59baa62cd931e808a2ab392056cbb235ad5ef', - }, - 'adapters': { - "vscode-java": { - "name": "vscode-java", - "port": "${DAPPort}", - "configuration": { - "cwd": "${workspaceRoot}" - } - } - }, - }, - 'java-language-server': { - 'language': 'javac', - 'enabled': False, - 'download': { - 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' - 'publishers/georgewfraser/vsextensions/vscode-javac/${version}/' - 'vspackage', - 'target': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', - 'format': 'zip.gz', - }, - 'all': { - 'version': '0.2.31', - 'file_name': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', - 'checksum': - '5b0248ec1198d3ece9a9c6b9433b30c22e308f0ae6e4c7bd09cd943c454e3e1d', - }, - 'adapters': { - "vscode-javac": { - "name": "vscode-javac", - "type": "vscode-javac", - "command": [ - "${gadgetDir}/java-language-server/dist/debug_adapter_mac.sh" - ], - "attach": { - "pidSelect": "none" - } - } - }, - }, - 'tclpro': { - 'language': 'tcl', - 'repo': { - 'url': 'https://github.com/puremourning/TclProDebug', - 'ref': 'v1.0.0' - }, - 'do': lambda name, root, gadget: installer.InstallTclProDebug( name, - root, - gadget ), - 'adapters': { - "tclpro": { - "name": "tclpro", - "type": "tclpro", - "command": [ - "${gadgetDir}/tclpro/bin/debugadapter" - ], - "attach": { - "pidSelect": "none" - }, - "configuration": { - "target": "${file}", - "args": [ "*${args}" ], - "tclsh": "tclsh", - "cwd": "${workspaceRoot}", - "extensionDirs": [ - "${workspaceRoot}/.tclpro/extensions", - "${HOME}/.tclpro/extensions", - ] - } - } - }, - }, - 'netcoredbg': { - 'language': 'csharp', - 'enabled': False, - 'download': { - 'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/' - '${version}/${file_name}' ), - 'format': 'tar', - }, - 'all': { - 'version': '1.2.0-635' - }, - 'macos': { - 'file_name': 'netcoredbg-osx.tar.gz', - 'checksum': - '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', - }, - 'linux': { - 'file_name': 'netcoredbg-linux-bionic.tar.gz', - 'checksum': '', - }, - 'windows': { - 'file_name': 'netcoredbg-win64.zip', - 'checksum': '', - }, - 'do': lambda name, root, gadget: installer.MakeSymlink( - name, - os.path.join( root, 'netcoredbg' ) ), - 'adapters': { - 'netcoredbg': { - "name": "netcoredbg", - "command": [ - "${gadgetDir}/netcoredbg/netcoredbg", - "--interpreter=vscode" + "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" ], "attach": { "pidProperty": "processId", "pidSelect": "ask" }, "configuration": { - "cwd": "${workspaceRoot}" + "type": "cppdbg", + "args": [], + "cwd": "${workspaceRoot}", + "environment": [], } }, - } + }, }, - '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.16.2', - 'checksum': - '121eca297d83daeeb1e6e1d791305d1827998dbd595c330086b3b94d33dba3b9', - }, - 'adapters': { - 'vscode-mono-debug': { - "name": "mono-debug", + 'linux': { + 'file_name': 'cpptools-linux.vsix', + 'checksum': + '3695202e1e75a03de18049323b66d868165123f26151f8c974a480eaf0205435', + }, + 'macos': { + 'file_name': 'cpptools-osx.vsix', + 'checksum': + 'cb061e3acd7559a539e5586f8d3f535101c4ec4e8a48195856d1d39380b5cf3c', + }, + 'windows': { + 'file_name': 'cpptools-win32.vsix', + 'checksum': + 'aa294368ed16d48c59e49c8000e146eae5a19ad07b654efed5db8ec93b24229e', + "adapters": { + "vscode-cpptools": { + "name": "cppdbg", "command": [ - "mono", - "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" + "${gadgetDir}/vscode-cpptools/debugAdapters/bin/OpenDebugAD7.exe" ], "attach": { - "pidSelect": "none" + "pidProperty": "processId", + "pidSelect": "ask" }, "configuration": { - "cwd": "${workspaceRoot}", - "console": "integratedTerminal", + "type": "cppdbg", "args": [], - "env": {} + "cwd": "${workspaceRoot}", + "environment": [], + "MIMode": "gdb", + "MIDebuggerPath": "gdb.exe" } }, + }, + }, +} + +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", + ], } }, - 'vscode-bash-debug': { - 'language': 'bash', - 'download': { - 'url': 'https://github.com/rogalmic/vscode-bash-debug/releases/' - 'download/${version}/${file_name}', - }, - 'all': { - 'file_name': 'bash-debug-0.3.7.vsix', - 'version': 'v0.3.7', - 'checksum': - '7b73e5b4604375df8658fb5a72c645c355785a289aa785a986e508342c014bb4', - }, - 'do': lambda name, root, gadget: installer.InstallBashDebug( name, - root, - gadget ), - 'adapters': { - "vscode-bash": { - "name": "bashdb", - "command": [ - "node", - "${gadgetDir}/vscode-bash-debug/out/bashDebug.js" - ], - "variables": { - "BASHDB_HOME": "${gadgetDir}/vscode-bash-debug/bashdb_dir" - }, - "configuration": { - "request": "launch", - "type": "bashdb", - "program": "${file}", - "args": [], - "env": {}, - "pathBash": "bash", - "pathBashdb": "${BASHDB_HOME}/bashdb", - "pathBashdbLib": "${BASHDB_HOME}", - "pathCat": "cat", - "pathMkfifo": "mkfifo", - "pathPkill": "pkill", - "cwd": "${workspaceRoot}", - "terminalKind": "integrated", - } +} + +GADGETS[ 'debugpy' ] = { + 'language': 'python', + 'download': { + 'url': 'https://github.com/microsoft/debugpy/archive/${file_name}' + }, + 'all': { + 'version': '1.0.0b12', + 'file_name': 'v1.0.0b12.zip', + 'checksum': + '210632bba2221fbb841c9785a615258819ceec401d1abdbeb5f2326f12cc72a1' + }, + 'do': lambda name, root, gadget: installer.InstallDebugpy( name, + root, + gadget ), + 'adapters': { + 'debugpy': { + "command": [ + sys.executable, # TODO: Will this work from within Vim ? + "${gadgetDir}/debugpy/build/lib/debugpy/adapter" + ], + "name": "debugpy", + "configuration": { + "python": sys.executable, # TODO: Will this work from within Vim ? + # Don't debug into subprocesses, as this leads to problems (vimspector + # doesn't support the custom messages) + # https://github.com/puremourning/vimspector/issues/141 + "subProcess": False, } } }, - 'vscode-go': { - 'language': 'go', - 'download': { - 'url': 'https://github.com/golang/vscode-go/releases/download/' - 'v${version}/${file_name}' - }, - 'all': { - 'version': '0.18.1', - 'file_name': 'Go-0.18.1.vsix', - 'checksum': - '80d4522c6cf482cfa6141997e5b458034f67d7065d92e1ce24a0456c405d6061', - }, - 'adapters': { - 'vscode-go': { - 'name': 'delve', - 'command': [ - 'node', - '${gadgetDir}/vscode-go/dist/debugAdapter.js' - ], - "configuration": { - "cwd": "${workspaceRoot}", - } - }, - }, +} + +GADGETS[ 'vscode-java-debug' ] = { + 'language': 'java', + 'enabled': False, + 'download': { + 'url': 'https://github.com/microsoft/vscode-java-debug/releases/download/' + '${version}/${file_name}', }, - 'vscode-php-debug': { - 'language': 'php', - 'enabled': False, - 'download': { - 'url': - 'https://github.com/felixfbecker/vscode-php-debug/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': 'v1.13.0', - 'file_name': 'php-debug.vsix', - 'checksum': - '8a51e593458fd14623c1c89ebab87347b087d67087717f18bcf77bb788052718', - }, - 'adapters': { - 'vscode-php-debug': { - 'name': "php-debug", - 'command': [ - 'node', - "${gadgetDir}/vscode-php-debug/out/phpDebug.js", + 'all': { + 'version': '0.26.0', + 'file_name': 'vscjava.vscode-java-debug-0.26.0.vsix', + 'checksum': + 'de49116ff3a3c941dad0c36d9af59baa62cd931e808a2ab392056cbb235ad5ef', + }, + 'adapters': { + "vscode-java": { + "name": "vscode-java", + "port": "${DAPPort}", + "configuration": { + "cwd": "${workspaceRoot}" + } + } + }, +} + +GADGETS[ 'java-language-server' ] = { + 'language': 'javac', + 'enabled': False, + 'download': { + 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' + 'publishers/georgewfraser/vsextensions/vscode-javac/${version}/' + 'vspackage', + 'target': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', + 'format': 'zip.gz', + }, + 'all': { + 'version': '0.2.31', + 'file_name': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', + 'checksum': + '5b0248ec1198d3ece9a9c6b9433b30c22e308f0ae6e4c7bd09cd943c454e3e1d', + }, + 'adapters': { + "vscode-javac": { + "name": "vscode-javac", + "type": "vscode-javac", + "command": [ + "${gadgetDir}/java-language-server/dist/debug_adapter_mac.sh" + ], + "attach": { + "pidSelect": "none" + } + } + }, +} + +GADGETS[ 'tclpro' ] = { + 'language': 'tcl', + 'repo': { + 'url': 'https://github.com/puremourning/TclProDebug', + 'ref': 'v1.0.0' + }, + 'do': lambda name, root, gadget: installer.InstallTclProDebug( name, + root, + gadget ), + 'adapters': { + "tclpro": { + "name": "tclpro", + "type": "tclpro", + "command": [ + "${gadgetDir}/tclpro/bin/debugadapter" + ], + "attach": { + "pidSelect": "none" + }, + "configuration": { + "target": "${file}", + "args": [ "*${args}" ], + "tclsh": "tclsh", + "cwd": "${workspaceRoot}", + "extensionDirs": [ + "${workspaceRoot}/.tclpro/extensions", + "${HOME}/.tclpro/extensions", ] } } }, - 'vscode-node-debug2': { - 'language': 'node', - 'enabled': False, - 'repo': { - 'url': 'https://github.com/microsoft/vscode-node-debug2', - 'ref': 'v1.42.5' - }, - 'do': lambda name, root, gadget: installer.InstallNodeDebug( name, - root, - gadget ), - 'adapters': { - 'vscode-node': { - 'name': 'node2', - 'type': 'node2', - 'command': [ - 'node', - '${gadgetDir}/vscode-node-debug2/out/src/nodeDebug.js' - ] - }, - }, +} + +GADGETS[ 'netcoredbg' ] = { + 'language': 'csharp', + 'enabled': False, + 'download': { + 'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/' + '${version}/${file_name}' ), + 'format': 'tar', }, - 'debugger-for-chrome': { - 'language': 'chrome', - 'enabled': False, - 'download': { - 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' - 'publishers/msjsdiag/vsextensions/' - 'debugger-for-chrome/${version}/vspackage', - 'target': 'msjsdiag.debugger-for-chrome-4.12.10.vsix.gz', - 'format': 'zip.gz', - }, - 'all': { - 'version': '4.12.10', - 'file_name': 'msjsdiag.debugger-for-chrome-4.12.10.vsix', - 'checksum': - '' - }, - 'adapters': { - 'chrome': { - 'name': 'debugger-for-chrome', - 'type': 'chrome', - 'command': [ - 'node', - '${gadgetDir}/debugger-for-chrome/out/src/chromeDebug.js' - ], - }, - }, + 'all': { + 'version': '1.2.0-635' }, - 'CodeLLDB': { - 'language': 'rust', - 'enabled': True, - 'download': { - 'url': 'https://github.com/vadimcn/vscode-lldb/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': 'v1.5.3', - }, - 'macos': { - 'file_name': 'codelldb-x86_64-darwin.vsix', - 'checksum': - '7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a', - 'make_executable': [ - 'adapter/codelldb', - 'lldb/bin/debugserver', - 'lldb/bin/lldb', - 'lldb/bin/lldb-argdumper', + 'macos': { + 'file_name': 'netcoredbg-osx.tar.gz', + 'checksum': + '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', + }, + 'linux': { + 'file_name': 'netcoredbg-linux-bionic.tar.gz', + 'checksum': '', + }, + 'windows': { + 'file_name': 'netcoredbg-win64.zip', + 'checksum': '', + }, + 'do': lambda name, root, gadget: installer.MakeSymlink( + name, + os.path.join( root, 'netcoredbg' ) ), + 'adapters': { + 'netcoredbg': { + "name": "netcoredbg", + "command": [ + "${gadgetDir}/netcoredbg/netcoredbg", + "--interpreter=vscode" ], - }, - 'linux': { - 'file_name': 'codelldb-x86_64-linux.vsix', - 'checksum': - 'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139', - 'make_executable': [ - 'adapter/codelldb', - 'lldb/bin/lldb', - 'lldb/bin/lldb-server', - 'lldb/bin/lldb-argdumper', - ], - }, - 'windows': { - 'file_name': 'codelldb-x86_64-windows.vsix', - 'checksum': - '', - 'make_executable': [] - }, - 'adapters': { - 'CodeLLDB': { - 'name': 'CodeLLDB', - 'type': 'CodeLLDB', - "command": [ - "${gadgetDir}/CodeLLDB/adapter/codelldb", - "--port", "${unusedLocalPort}" - ], - "port": "${unusedLocalPort}", - "configuration": { - "type": "lldb", - "name": "lldb", - "cargo": {}, - "args": [], - "cwd": "${workspaceRoot}", - "env": {}, - "terminal": "integrated", - } + "attach": { + "pidProperty": "processId", + "pidSelect": "ask" }, + "configuration": { + "cwd": "${workspaceRoot}" + } }, + } +} + +GADGETS[ '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', }, - 'local-lua-debugger-vscode': { - 'language': 'lua', - 'enabled': True, - 'repo': { - 'url': 'https://github.com/tomblind/local-lua-debugger-vscode.git', - 'ref': 'release-${version}' + 'all': { + 'file_name': 'vscode-mono-debug.vsix', + 'version': '0.16.2', + 'checksum': + '121eca297d83daeeb1e6e1d791305d1827998dbd595c330086b3b94d33dba3b9', + }, + 'adapters': { + 'vscode-mono-debug': { + "name": "mono-debug", + "command": [ + "mono", + "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" + ], + "attach": { + "pidSelect": "none" + }, + "configuration": { + "cwd": "${workspaceRoot}", + "console": "integratedTerminal", + "args": [], + "env": {} + } }, - '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' - } + } +} + +GADGETS[ 'vscode-bash-debug' ] = { + 'language': 'bash', + 'download': { + 'url': 'https://github.com/rogalmic/vscode-bash-debug/releases/' + 'download/${version}/${file_name}', + }, + 'all': { + 'file_name': 'bash-debug-0.3.7.vsix', + 'version': 'v0.3.7', + 'checksum': + '7b73e5b4604375df8658fb5a72c645c355785a289aa785a986e508342c014bb4', + }, + 'do': lambda name, root, gadget: installer.InstallBashDebug( name, + root, + gadget ), + 'adapters': { + "vscode-bash": { + "name": "bashdb", + "command": [ + "node", + "${gadgetDir}/vscode-bash-debug/out/bashDebug.js" + ], + "variables": { + "BASHDB_HOME": "${gadgetDir}/vscode-bash-debug/bashdb_dir" + }, + "configuration": { + "request": "launch", + "type": "bashdb", + "program": "${file}", + "args": [], + "env": {}, + "pathBash": "bash", + "pathBashdb": "${BASHDB_HOME}/bashdb", + "pathBashdbLib": "${BASHDB_HOME}", + "pathCat": "cat", + "pathMkfifo": "mkfifo", + "pathPkill": "pkill", + "cwd": "${workspaceRoot}", + "terminalKind": "integrated", + } + } + } +} + +GADGETS[ 'vscode-go' ] = { + 'language': 'go', + 'download': { + 'url': 'https://github.com/golang/vscode-go/releases/download/' + 'v${version}/${file_name}' + }, + 'all': { + 'version': '0.18.1', + 'file_name': 'Go-0.18.1.vsix', + 'checksum': + '80d4522c6cf482cfa6141997e5b458034f67d7065d92e1ce24a0456c405d6061', + }, + 'adapters': { + 'vscode-go': { + 'name': 'delve', + 'command': [ + 'node', + '${gadgetDir}/vscode-go/dist/debugAdapter.js' + ], + "configuration": { + "cwd": "${workspaceRoot}", } }, }, } + +GADGETS[ 'vscode-php-debug' ] = { + 'language': 'php', + 'enabled': False, + 'download': { + 'url': + 'https://github.com/felixfbecker/vscode-php-debug/releases/download/' + '${version}/${file_name}', + }, + 'all': { + 'version': 'v1.13.0', + 'file_name': 'php-debug.vsix', + 'checksum': + '8a51e593458fd14623c1c89ebab87347b087d67087717f18bcf77bb788052718', + }, + 'adapters': { + 'vscode-php-debug': { + 'name': "php-debug", + 'command': [ + 'node', + "${gadgetDir}/vscode-php-debug/out/phpDebug.js", + ] + } + } +} + +GADGETS[ 'vscode-node-debug2' ] = { + 'language': 'node', + 'enabled': False, + 'repo': { + 'url': 'https://github.com/microsoft/vscode-node-debug2', + 'ref': 'v1.42.5' + }, + 'do': lambda name, root, gadget: installer.InstallNodeDebug( name, + root, + gadget ), + 'adapters': { + 'vscode-node': { + 'name': 'node2', + 'type': 'node2', + 'command': [ + 'node', + '${gadgetDir}/vscode-node-debug2/out/src/nodeDebug.js' + ] + }, + }, +} + +GADGETS[ 'debugger-for-chrome' ] = { + 'language': 'chrome', + 'enabled': False, + 'download': { + 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' + 'publishers/msjsdiag/vsextensions/' + 'debugger-for-chrome/${version}/vspackage', + 'target': 'msjsdiag.debugger-for-chrome-4.12.10.vsix.gz', + 'format': 'zip.gz', + }, + 'all': { + 'version': '4.12.10', + 'file_name': 'msjsdiag.debugger-for-chrome-4.12.10.vsix', + 'checksum': + '' + }, + 'adapters': { + 'chrome': { + 'name': 'debugger-for-chrome', + 'type': 'chrome', + 'command': [ + 'node', + '${gadgetDir}/debugger-for-chrome/out/src/chromeDebug.js' + ], + }, + }, +} + +GADGETS[ 'CodeLLDB' ] = { + 'language': 'rust', + 'enabled': True, + 'download': { + 'url': 'https://github.com/vadimcn/vscode-lldb/releases/download/' + '${version}/${file_name}', + }, + 'all': { + 'version': 'v1.5.3', + }, + 'macos': { + 'file_name': 'codelldb-x86_64-darwin.vsix', + 'checksum': + '7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a', + 'make_executable': [ + 'adapter/codelldb', + 'lldb/bin/debugserver', + 'lldb/bin/lldb', + 'lldb/bin/lldb-argdumper', + ], + }, + 'linux': { + 'file_name': 'codelldb-x86_64-linux.vsix', + 'checksum': + 'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139', + 'make_executable': [ + 'adapter/codelldb', + 'lldb/bin/lldb', + 'lldb/bin/lldb-server', + 'lldb/bin/lldb-argdumper', + ], + }, + 'windows': { + 'file_name': 'codelldb-x86_64-windows.vsix', + 'checksum': + '', + 'make_executable': [] + }, + 'adapters': { + 'CodeLLDB': { + 'name': 'CodeLLDB', + 'type': 'CodeLLDB', + "command": [ + "${gadgetDir}/CodeLLDB/adapter/codelldb", + "--port", "${unusedLocalPort}" + ], + "port": "${unusedLocalPort}", + "configuration": { + "type": "lldb", + "name": "lldb", + "cargo": {}, + "args": [], + "cwd": "${workspaceRoot}", + "env": {}, + "terminal": "integrated", + } + }, + }, +} + +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' + } + } + }, +} From a3240745858936055edae255e0009f76381237df Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 25 Nov 2020 23:21:37 +0000 Subject: [PATCH 002/200] Move gadgets into plugins --- install_gadget.py | 4 +- python3/vimspector/debug_session.py | 5 +- python3/vimspector/gadgets.py | 541 +------------------ python3/vimspector/installer.py | 76 +-- python3/vimspector/{ => plugins}/__init__.py | 0 python3/vimspector/plugins/bash.py | 70 +++ python3/vimspector/plugins/chrome.py | 46 ++ python3/vimspector/plugins/cpp.py | 167 ++++++ python3/vimspector/plugins/dotnet.py | 64 +++ python3/vimspector/plugins/go.py | 44 ++ python3/vimspector/plugins/java.py | 73 +++ python3/vimspector/plugins/lua.py | 51 ++ python3/vimspector/plugins/mono.py | 54 ++ python3/vimspector/plugins/node.py | 45 ++ python3/vimspector/plugins/php.py | 43 ++ python3/vimspector/plugins/python.py | 86 +++ python3/vimspector/plugins/tcl.py | 85 +++ 17 files changed, 853 insertions(+), 601 deletions(-) rename python3/vimspector/{ => plugins}/__init__.py (100%) create mode 100644 python3/vimspector/plugins/bash.py create mode 100644 python3/vimspector/plugins/chrome.py create mode 100644 python3/vimspector/plugins/cpp.py create mode 100644 python3/vimspector/plugins/dotnet.py create mode 100644 python3/vimspector/plugins/go.py create mode 100644 python3/vimspector/plugins/java.py create mode 100644 python3/vimspector/plugins/lua.py create mode 100644 python3/vimspector/plugins/mono.py create mode 100644 python3/vimspector/plugins/node.py create mode 100644 python3/vimspector/plugins/php.py create mode 100644 python3/vimspector/plugins/python.py create mode 100644 python3/vimspector/plugins/tcl.py diff --git a/install_gadget.py b/install_gadget.py index 52621c3..2aa910e 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -113,7 +113,7 @@ parser.add_argument( '--sudo', "run this as root via sudo, pass this flag." ) done_languages = set() -for name, gadget in gadgets.GADGETS.items(): +for name, gadget in gadgets.Gadgets().items(): lang = gadget[ 'language' ] if lang in done_languages: continue @@ -181,7 +181,7 @@ all_adapters = installer.ReadAdapters( read_existing = args.update_gadget_config ) manifest = installer.Manifest() -for name, gadget in gadgets.GADGETS.items(): +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' ] ) ): diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 63cd140..c9a7a39 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -93,8 +93,9 @@ class DebugSession( object ): 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 {} ) + if database: + configurations.update( database.get( 'configurations' or {} ) ) + adapters.update( database.get( 'adapters' ) or {} ) return launch_config_file, configurations diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 76b8097..13fa28a 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -14,533 +14,28 @@ # limitations under the License. -from vimspector import installer -import sys -import os - +import pkgutil +import importlib +import vimspector.plugins +LOADED = 0 GADGETS = {} -GADGETS[ 'vscode-cpptools' ] = { - 'language': 'c', - 'download': { - 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' - '${version}/${file_name}', - }, - 'do': lambda name, root, gadget: installer.InstallCppTools( name, - root, - gadget ), - 'all': { - 'version': '0.27.0', - "adapters": { - "vscode-cpptools": { - "name": "cppdbg", - "command": [ - "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" - ], - "attach": { - "pidProperty": "processId", - "pidSelect": "ask" - }, - "configuration": { - "type": "cppdbg", - "args": [], - "cwd": "${workspaceRoot}", - "environment": [], - } - }, - }, - }, - 'linux': { - 'file_name': 'cpptools-linux.vsix', - 'checksum': - '3695202e1e75a03de18049323b66d868165123f26151f8c974a480eaf0205435', - }, - 'macos': { - 'file_name': 'cpptools-osx.vsix', - 'checksum': - 'cb061e3acd7559a539e5586f8d3f535101c4ec4e8a48195856d1d39380b5cf3c', - }, - 'windows': { - 'file_name': 'cpptools-win32.vsix', - 'checksum': - 'aa294368ed16d48c59e49c8000e146eae5a19ad07b654efed5db8ec93b24229e', - "adapters": { - "vscode-cpptools": { - "name": "cppdbg", - "command": [ - "${gadgetDir}/vscode-cpptools/debugAdapters/bin/OpenDebugAD7.exe" - ], - "attach": { - "pidProperty": "processId", - "pidSelect": "ask" - }, - "configuration": { - "type": "cppdbg", - "args": [], - "cwd": "${workspaceRoot}", - "environment": [], - "MIMode": "gdb", - "MIDebuggerPath": "gdb.exe" - } - }, - }, - }, -} -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", - ], - } - }, -} +def RegisterGadget( name, spec ): + GADGETS[ name ] = spec -GADGETS[ 'debugpy' ] = { - 'language': 'python', - 'download': { - 'url': 'https://github.com/microsoft/debugpy/archive/${file_name}' - }, - 'all': { - 'version': '1.0.0b12', - 'file_name': 'v1.0.0b12.zip', - 'checksum': - '210632bba2221fbb841c9785a615258819ceec401d1abdbeb5f2326f12cc72a1' - }, - 'do': lambda name, root, gadget: installer.InstallDebugpy( name, - root, - gadget ), - 'adapters': { - 'debugpy': { - "command": [ - sys.executable, # TODO: Will this work from within Vim ? - "${gadgetDir}/debugpy/build/lib/debugpy/adapter" - ], - "name": "debugpy", - "configuration": { - "python": sys.executable, # TODO: Will this work from within Vim ? - # Don't debug into subprocesses, as this leads to problems (vimspector - # doesn't support the custom messages) - # https://github.com/puremourning/vimspector/issues/141 - "subProcess": False, - } - } - }, -} -GADGETS[ 'vscode-java-debug' ] = { - 'language': 'java', - 'enabled': False, - 'download': { - 'url': 'https://github.com/microsoft/vscode-java-debug/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': '0.26.0', - 'file_name': 'vscjava.vscode-java-debug-0.26.0.vsix', - 'checksum': - 'de49116ff3a3c941dad0c36d9af59baa62cd931e808a2ab392056cbb235ad5ef', - }, - 'adapters': { - "vscode-java": { - "name": "vscode-java", - "port": "${DAPPort}", - "configuration": { - "cwd": "${workspaceRoot}" - } - } - }, -} +def Gadgets(): + global LOADED + if not LOADED: + mod = vimspector.plugins + # vimspector.plugins is a namespace package + # Following: + # https://packaging.python.org/guides/creating-and-discovering-plugins/#using-namespace-packages + for finder, name, ispkg in pkgutil.iter_modules( mod.__path__, + mod.__name__ + '.' ): + importlib.import_module( name ) + LOADED = 1 -GADGETS[ 'java-language-server' ] = { - 'language': 'javac', - 'enabled': False, - 'download': { - 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' - 'publishers/georgewfraser/vsextensions/vscode-javac/${version}/' - 'vspackage', - 'target': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', - 'format': 'zip.gz', - }, - 'all': { - 'version': '0.2.31', - 'file_name': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', - 'checksum': - '5b0248ec1198d3ece9a9c6b9433b30c22e308f0ae6e4c7bd09cd943c454e3e1d', - }, - 'adapters': { - "vscode-javac": { - "name": "vscode-javac", - "type": "vscode-javac", - "command": [ - "${gadgetDir}/java-language-server/dist/debug_adapter_mac.sh" - ], - "attach": { - "pidSelect": "none" - } - } - }, -} - -GADGETS[ 'tclpro' ] = { - 'language': 'tcl', - 'repo': { - 'url': 'https://github.com/puremourning/TclProDebug', - 'ref': 'v1.0.0' - }, - 'do': lambda name, root, gadget: installer.InstallTclProDebug( name, - root, - gadget ), - 'adapters': { - "tclpro": { - "name": "tclpro", - "type": "tclpro", - "command": [ - "${gadgetDir}/tclpro/bin/debugadapter" - ], - "attach": { - "pidSelect": "none" - }, - "configuration": { - "target": "${file}", - "args": [ "*${args}" ], - "tclsh": "tclsh", - "cwd": "${workspaceRoot}", - "extensionDirs": [ - "${workspaceRoot}/.tclpro/extensions", - "${HOME}/.tclpro/extensions", - ] - } - } - }, -} - -GADGETS[ 'netcoredbg' ] = { - 'language': 'csharp', - 'enabled': False, - 'download': { - 'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/' - '${version}/${file_name}' ), - 'format': 'tar', - }, - 'all': { - 'version': '1.2.0-635' - }, - 'macos': { - 'file_name': 'netcoredbg-osx.tar.gz', - 'checksum': - '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', - }, - 'linux': { - 'file_name': 'netcoredbg-linux-bionic.tar.gz', - 'checksum': '', - }, - 'windows': { - 'file_name': 'netcoredbg-win64.zip', - 'checksum': '', - }, - 'do': lambda name, root, gadget: installer.MakeSymlink( - name, - os.path.join( root, 'netcoredbg' ) ), - 'adapters': { - 'netcoredbg': { - "name": "netcoredbg", - "command": [ - "${gadgetDir}/netcoredbg/netcoredbg", - "--interpreter=vscode" - ], - "attach": { - "pidProperty": "processId", - "pidSelect": "ask" - }, - "configuration": { - "cwd": "${workspaceRoot}" - } - }, - } -} - -GADGETS[ '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.16.2', - 'checksum': - '121eca297d83daeeb1e6e1d791305d1827998dbd595c330086b3b94d33dba3b9', - }, - 'adapters': { - 'vscode-mono-debug': { - "name": "mono-debug", - "command": [ - "mono", - "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" - ], - "attach": { - "pidSelect": "none" - }, - "configuration": { - "cwd": "${workspaceRoot}", - "console": "integratedTerminal", - "args": [], - "env": {} - } - }, - } -} - -GADGETS[ 'vscode-bash-debug' ] = { - 'language': 'bash', - 'download': { - 'url': 'https://github.com/rogalmic/vscode-bash-debug/releases/' - 'download/${version}/${file_name}', - }, - 'all': { - 'file_name': 'bash-debug-0.3.7.vsix', - 'version': 'v0.3.7', - 'checksum': - '7b73e5b4604375df8658fb5a72c645c355785a289aa785a986e508342c014bb4', - }, - 'do': lambda name, root, gadget: installer.InstallBashDebug( name, - root, - gadget ), - 'adapters': { - "vscode-bash": { - "name": "bashdb", - "command": [ - "node", - "${gadgetDir}/vscode-bash-debug/out/bashDebug.js" - ], - "variables": { - "BASHDB_HOME": "${gadgetDir}/vscode-bash-debug/bashdb_dir" - }, - "configuration": { - "request": "launch", - "type": "bashdb", - "program": "${file}", - "args": [], - "env": {}, - "pathBash": "bash", - "pathBashdb": "${BASHDB_HOME}/bashdb", - "pathBashdbLib": "${BASHDB_HOME}", - "pathCat": "cat", - "pathMkfifo": "mkfifo", - "pathPkill": "pkill", - "cwd": "${workspaceRoot}", - "terminalKind": "integrated", - } - } - } -} - -GADGETS[ 'vscode-go' ] = { - 'language': 'go', - 'download': { - 'url': 'https://github.com/golang/vscode-go/releases/download/' - 'v${version}/${file_name}' - }, - 'all': { - 'version': '0.18.1', - 'file_name': 'Go-0.18.1.vsix', - 'checksum': - '80d4522c6cf482cfa6141997e5b458034f67d7065d92e1ce24a0456c405d6061', - }, - 'adapters': { - 'vscode-go': { - 'name': 'delve', - 'command': [ - 'node', - '${gadgetDir}/vscode-go/dist/debugAdapter.js' - ], - "configuration": { - "cwd": "${workspaceRoot}", - } - }, - }, -} - -GADGETS[ 'vscode-php-debug' ] = { - 'language': 'php', - 'enabled': False, - 'download': { - 'url': - 'https://github.com/felixfbecker/vscode-php-debug/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': 'v1.13.0', - 'file_name': 'php-debug.vsix', - 'checksum': - '8a51e593458fd14623c1c89ebab87347b087d67087717f18bcf77bb788052718', - }, - 'adapters': { - 'vscode-php-debug': { - 'name': "php-debug", - 'command': [ - 'node', - "${gadgetDir}/vscode-php-debug/out/phpDebug.js", - ] - } - } -} - -GADGETS[ 'vscode-node-debug2' ] = { - 'language': 'node', - 'enabled': False, - 'repo': { - 'url': 'https://github.com/microsoft/vscode-node-debug2', - 'ref': 'v1.42.5' - }, - 'do': lambda name, root, gadget: installer.InstallNodeDebug( name, - root, - gadget ), - 'adapters': { - 'vscode-node': { - 'name': 'node2', - 'type': 'node2', - 'command': [ - 'node', - '${gadgetDir}/vscode-node-debug2/out/src/nodeDebug.js' - ] - }, - }, -} - -GADGETS[ 'debugger-for-chrome' ] = { - 'language': 'chrome', - 'enabled': False, - 'download': { - 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' - 'publishers/msjsdiag/vsextensions/' - 'debugger-for-chrome/${version}/vspackage', - 'target': 'msjsdiag.debugger-for-chrome-4.12.10.vsix.gz', - 'format': 'zip.gz', - }, - 'all': { - 'version': '4.12.10', - 'file_name': 'msjsdiag.debugger-for-chrome-4.12.10.vsix', - 'checksum': - '' - }, - 'adapters': { - 'chrome': { - 'name': 'debugger-for-chrome', - 'type': 'chrome', - 'command': [ - 'node', - '${gadgetDir}/debugger-for-chrome/out/src/chromeDebug.js' - ], - }, - }, -} - -GADGETS[ 'CodeLLDB' ] = { - 'language': 'rust', - 'enabled': True, - 'download': { - 'url': 'https://github.com/vadimcn/vscode-lldb/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': 'v1.5.3', - }, - 'macos': { - 'file_name': 'codelldb-x86_64-darwin.vsix', - 'checksum': - '7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a', - 'make_executable': [ - 'adapter/codelldb', - 'lldb/bin/debugserver', - 'lldb/bin/lldb', - 'lldb/bin/lldb-argdumper', - ], - }, - 'linux': { - 'file_name': 'codelldb-x86_64-linux.vsix', - 'checksum': - 'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139', - 'make_executable': [ - 'adapter/codelldb', - 'lldb/bin/lldb', - 'lldb/bin/lldb-server', - 'lldb/bin/lldb-argdumper', - ], - }, - 'windows': { - 'file_name': 'codelldb-x86_64-windows.vsix', - 'checksum': - '', - 'make_executable': [] - }, - 'adapters': { - 'CodeLLDB': { - 'name': 'CodeLLDB', - 'type': 'CodeLLDB', - "command": [ - "${gadgetDir}/CodeLLDB/adapter/codelldb", - "--port", "${unusedLocalPort}" - ], - "port": "${unusedLocalPort}", - "configuration": { - "type": "lldb", - "name": "lldb", - "cargo": {}, - "args": [], - "cwd": "${workspaceRoot}", - "env": {}, - "terminal": "integrated", - } - }, - }, -} - -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' - } - } - }, -} + return GADGETS diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index b39398f..2d8c874 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -225,7 +225,7 @@ def GadgetListToInstallerArgs( *gadget_list ): continue try: - gadget = gadgets.GADGETS[ name ] + gadget = gadgets.Gadgets()[ name ] except KeyError: continue @@ -239,7 +239,7 @@ def GadgetListToInstallerArgs( *gadget_list ): def FindGadgetForAdapter( adapter_name ): candidates = [] - for name, gadget in gadgets.GADGETS.items(): + for name, gadget in gadgets.Gadgets().items(): v = {} v.update( gadget.get( 'all', {} ) ) v.update( gadget.get( install.GetOS(), {} ) ) @@ -347,29 +347,6 @@ def InstallGeneric( name, root, gadget ): MakeExtensionSymlink( name, root ) -def InstallCppTools( name, root, gadget ): - extension = os.path.join( root, 'extension' ) - - # 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' ) ) - with open( os.path.join( extension, 'package.json' ) ) as f: - package = json.load( f ) - runtime_dependencies = package[ 'runtimeDependencies' ] - for dependency in runtime_dependencies: - for binary in dependency.get( 'binaries' ): - file_path = os.path.abspath( os.path.join( extension, binary ) ) - if os.path.exists( file_path ): - MakeExecutable( os.path.join( extension, binary ) ) - - MakeExtensionSymlink( name, root ) - - -def InstallBashDebug( name, root, gadget ): - MakeExecutable( os.path.join( root, 'extension', 'bashdb_dir', 'bashdb' ) ) - MakeExtensionSymlink( name, root ) - def InstallDebugpy( name, root, gadget ): wd = os.getcwd() @@ -383,55 +360,6 @@ def InstallDebugpy( name, root, gadget ): MakeSymlink( name, root ) -def InstallTclProDebug( name, root, gadget ): - configure = [ 'sh', './configure' ] - - if install.GetOS() == 'macos': - # Apple removed the headers from system frameworks because they are - # determined to make life difficult. And the TCL configure scripts are super - # old so don't know about this. So we do their job for them and try and find - # a tclConfig.sh. - # - # NOTE however that in Apple's infinite wisdom, installing the "headers" in - # the other location is actually broken because the paths in the - # tclConfig.sh are pointing at the _old_ location. You actually do have to - # run the package installation which puts the headers back in order to work. - # This is why the below list is does not contain stuff from - # /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform - # '/Applications/Xcode.app/Contents/Developer/Platforms' - # '/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System' - # '/Library/Frameworks/Tcl.framework', - # '/Applications/Xcode.app/Contents/Developer/Platforms' - # '/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System' - # '/Library/Frameworks/Tcl.framework/Versions' - # '/Current', - for p in [ '/usr/local/opt/tcl-tk/lib' ]: - if os.path.exists( os.path.join( p, 'tclConfig.sh' ) ): - configure.append( '--with-tcl=' + p ) - break - - - with CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ): - CheckCall( configure ) - CheckCall( [ 'make' ] ) - - MakeSymlink( name, root ) - - -def InstallNodeDebug( name, root, gadget ): - with CurrentWorkingDir( root ): - CheckCall( [ 'npm', 'install' ] ) - CheckCall( [ 'npm', 'run', 'build' ] ) - 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, diff --git a/python3/vimspector/__init__.py b/python3/vimspector/plugins/__init__.py similarity index 100% rename from python3/vimspector/__init__.py rename to python3/vimspector/plugins/__init__.py diff --git a/python3/vimspector/plugins/bash.py b/python3/vimspector/plugins/bash.py new file mode 100644 index 0000000..c197daf --- /dev/null +++ b/python3/vimspector/plugins/bash.py @@ -0,0 +1,70 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +from vimspector import gadgets, installer + + +# FIXME: InstallGeneric would work here +def InstallBashDebug( name, root, gadget ): + installer.MakeExecutable( os.path.join( root, + 'extension', + 'bashdb_dir', + 'bashdb' ) ) + installer.MakeExtensionSymlink( name, root ) + + +gadgets.RegisterGadget( 'vscode-bash-debug', { + 'language': 'bash', + 'download': { + 'url': 'https://github.com/rogalmic/vscode-bash-debug/releases/' + 'download/${version}/${file_name}', + }, + 'all': { + 'file_name': 'bash-debug-0.3.7.vsix', + 'version': 'v0.3.7', + 'checksum': + '7b73e5b4604375df8658fb5a72c645c355785a289aa785a986e508342c014bb4', + }, + 'do': lambda name, root, gadget: InstallBashDebug( name, root, gadget ), + 'adapters': { + "vscode-bash": { + "name": "bashdb", + "command": [ + "node", + "${gadgetDir}/vscode-bash-debug/out/bashDebug.js" + ], + "variables": { + "BASHDB_HOME": "${gadgetDir}/vscode-bash-debug/bashdb_dir" + }, + "configuration": { + "request": "launch", + "type": "bashdb", + "program": "${file}", + "args": [], + "env": {}, + "pathBash": "bash", + "pathBashdb": "${BASHDB_HOME}/bashdb", + "pathBashdbLib": "${BASHDB_HOME}", + "pathCat": "cat", + "pathMkfifo": "mkfifo", + "pathPkill": "pkill", + "cwd": "${workspaceRoot}", + "terminalKind": "integrated", + } + } + } +} ) diff --git a/python3/vimspector/plugins/chrome.py b/python3/vimspector/plugins/chrome.py new file mode 100644 index 0000000..2af57e2 --- /dev/null +++ b/python3/vimspector/plugins/chrome.py @@ -0,0 +1,46 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets + + +gadgets.RegisterGadget( 'debugger-for-chrome', { + 'language': 'chrome', + 'enabled': False, + 'download': { + 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' + 'publishers/msjsdiag/vsextensions/' + 'debugger-for-chrome/${version}/vspackage', + 'target': 'msjsdiag.debugger-for-chrome-4.12.10.vsix.gz', + 'format': 'zip.gz', + }, + 'all': { + 'version': '4.12.10', + 'file_name': 'msjsdiag.debugger-for-chrome-4.12.10.vsix', + 'checksum': + '' + }, + 'adapters': { + 'chrome': { + 'name': 'debugger-for-chrome', + 'type': 'chrome', + 'command': [ + 'node', + '${gadgetDir}/debugger-for-chrome/out/src/chromeDebug.js' + ], + }, + }, +} ) diff --git a/python3/vimspector/plugins/cpp.py b/python3/vimspector/plugins/cpp.py new file mode 100644 index 0000000..8115739 --- /dev/null +++ b/python3/vimspector/plugins/cpp.py @@ -0,0 +1,167 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import json +import os +from vimspector import gadgets, installer + + +def InstallCppTools( name, root, gadget ): + extension = os.path.join( root, 'extension' ) + + # 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. + installer.MakeExecutable( os.path.join( extension, + 'debugAdapters', + 'OpenDebugAD7' ) ) + with open( os.path.join( extension, 'package.json' ) ) as f: + package = json.load( f ) + runtime_dependencies = package[ 'runtimeDependencies' ] + for dependency in runtime_dependencies: + for binary in dependency.get( 'binaries' ): + file_path = os.path.abspath( os.path.join( extension, binary ) ) + if os.path.exists( file_path ): + installer.MakeExecutable( os.path.join( extension, binary ) ) + + installer.MakeExtensionSymlink( name, root ) + + +gadgets.RegisterGadget( 'vscode-cpptools', { + 'language': 'c', + 'download': { + 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' + '${version}/${file_name}', + }, + 'do': lambda name, root, gadget: InstallCppTools( name, root, gadget ), + 'all': { + 'version': '0.27.0', + "adapters": { + "vscode-cpptools": { + "name": "cppdbg", + "command": [ + "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" + ], + "attach": { + "pidProperty": "processId", + "pidSelect": "ask" + }, + "configuration": { + "type": "cppdbg", + "args": [], + "cwd": "${workspaceRoot}", + "environment": [], + } + }, + }, + }, + 'linux': { + 'file_name': 'cpptools-linux.vsix', + 'checksum': + '3695202e1e75a03de18049323b66d868165123f26151f8c974a480eaf0205435', + }, + 'macos': { + 'file_name': 'cpptools-osx.vsix', + 'checksum': + 'cb061e3acd7559a539e5586f8d3f535101c4ec4e8a48195856d1d39380b5cf3c', + }, + 'windows': { + 'file_name': 'cpptools-win32.vsix', + 'checksum': + 'aa294368ed16d48c59e49c8000e146eae5a19ad07b654efed5db8ec93b24229e', + "adapters": { + "vscode-cpptools": { + "name": "cppdbg", + "command": [ + "${gadgetDir}/vscode-cpptools/debugAdapters/bin/OpenDebugAD7.exe" + ], + "attach": { + "pidProperty": "processId", + "pidSelect": "ask" + }, + "configuration": { + "type": "cppdbg", + "args": [], + "cwd": "${workspaceRoot}", + "environment": [], + "MIMode": "gdb", + "MIDebuggerPath": "gdb.exe" + } + }, + }, + }, +} ) + + +gadgets.RegisterGadget( 'CodeLLDB', { + 'language': 'rust', + 'enabled': True, + 'download': { + 'url': 'https://github.com/vadimcn/vscode-lldb/releases/download/' + '${version}/${file_name}', + }, + 'all': { + 'version': 'v1.5.3', + }, + 'macos': { + 'file_name': 'codelldb-x86_64-darwin.vsix', + 'checksum': + '7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a', + 'make_executable': [ + 'adapter/codelldb', + 'lldb/bin/debugserver', + 'lldb/bin/lldb', + 'lldb/bin/lldb-argdumper', + ], + }, + 'linux': { + 'file_name': 'codelldb-x86_64-linux.vsix', + 'checksum': + 'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139', + 'make_executable': [ + 'adapter/codelldb', + 'lldb/bin/lldb', + 'lldb/bin/lldb-server', + 'lldb/bin/lldb-argdumper', + ], + }, + 'windows': { + 'file_name': 'codelldb-x86_64-windows.vsix', + 'checksum': + '', + 'make_executable': [] + }, + 'adapters': { + 'CodeLLDB': { + 'name': 'CodeLLDB', + 'type': 'CodeLLDB', + "command": [ + "${gadgetDir}/CodeLLDB/adapter/codelldb", + "--port", "${unusedLocalPort}" + ], + "port": "${unusedLocalPort}", + "configuration": { + "type": "lldb", + "name": "lldb", + "cargo": {}, + "args": [], + "cwd": "${workspaceRoot}", + "env": {}, + "terminal": "integrated", + } + }, + }, +} ) diff --git a/python3/vimspector/plugins/dotnet.py b/python3/vimspector/plugins/dotnet.py new file mode 100644 index 0000000..6d92d6f --- /dev/null +++ b/python3/vimspector/plugins/dotnet.py @@ -0,0 +1,64 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +from vimspector import gadgets, installer + + +gadgets.RegisterGadget( 'netcoredbg', { + 'language': 'csharp', + 'enabled': False, + 'download': { + 'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/' + '${version}/${file_name}' ), + 'format': 'tar', + }, + 'all': { + 'version': '1.2.0-635' + }, + 'macos': { + 'file_name': 'netcoredbg-osx.tar.gz', + 'checksum': + '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', + }, + 'linux': { + 'file_name': 'netcoredbg-linux-bionic.tar.gz', + 'checksum': '', + }, + 'windows': { + 'file_name': 'netcoredbg-win64.zip', + 'checksum': '', + }, + 'do': lambda name, root, gadget: installer.MakeSymlink( + name, + os.path.join( root, 'netcoredbg' ) ), + 'adapters': { + 'netcoredbg': { + "name": "netcoredbg", + "command": [ + "${gadgetDir}/netcoredbg/netcoredbg", + "--interpreter=vscode" + ], + "attach": { + "pidProperty": "processId", + "pidSelect": "ask" + }, + "configuration": { + "cwd": "${workspaceRoot}" + } + }, + } +} ) diff --git a/python3/vimspector/plugins/go.py b/python3/vimspector/plugins/go.py new file mode 100644 index 0000000..f723df8 --- /dev/null +++ b/python3/vimspector/plugins/go.py @@ -0,0 +1,44 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets + + +gadgets.RegisterGadget( 'vscode-go', { + 'language': 'go', + 'download': { + 'url': 'https://github.com/golang/vscode-go/releases/download/' + 'v${version}/${file_name}' + }, + 'all': { + 'version': '0.18.1', + 'file_name': 'Go-0.18.1.vsix', + 'checksum': + '80d4522c6cf482cfa6141997e5b458034f67d7065d92e1ce24a0456c405d6061', + }, + 'adapters': { + 'vscode-go': { + 'name': 'delve', + 'command': [ + 'node', + '${gadgetDir}/vscode-go/dist/debugAdapter.js' + ], + "configuration": { + "cwd": "${workspaceRoot}", + } + }, + }, +} ) diff --git a/python3/vimspector/plugins/java.py b/python3/vimspector/plugins/java.py new file mode 100644 index 0000000..7e778ea --- /dev/null +++ b/python3/vimspector/plugins/java.py @@ -0,0 +1,73 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets + + +gadgets.RegisterGadget( 'java-language-server', { + 'language': 'javac', + 'enabled': False, + 'download': { + 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' + 'publishers/georgewfraser/vsextensions/vscode-javac/${version}/' + 'vspackage', + 'target': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', + 'format': 'zip.gz', + }, + 'all': { + 'version': '0.2.31', + 'file_name': 'georgewfraser.vscode-javac-0.2.31.vsix.gz', + 'checksum': + '5b0248ec1198d3ece9a9c6b9433b30c22e308f0ae6e4c7bd09cd943c454e3e1d', + }, + 'adapters': { + "vscode-javac": { + "name": "vscode-javac", + "type": "vscode-javac", + "command": [ + "${gadgetDir}/java-language-server/dist/debug_adapter_mac.sh" + ], + "attach": { + "pidSelect": "none" + } + } + }, +} ) + + +gadgets.RegisterGadget( 'vscode-java-debug', { + 'language': 'java', + 'enabled': False, + 'download': { + 'url': 'https://github.com/microsoft/vscode-java-debug/releases/download/' + '${version}/${file_name}', + }, + 'all': { + 'version': '0.26.0', + 'file_name': 'vscjava.vscode-java-debug-0.26.0.vsix', + 'checksum': + 'de49116ff3a3c941dad0c36d9af59baa62cd931e808a2ab392056cbb235ad5ef', + }, + 'adapters': { + "vscode-java": { + "name": "vscode-java", + "port": "${DAPPort}", + "configuration": { + "cwd": "${workspaceRoot}" + } + } + }, +} ) diff --git a/python3/vimspector/plugins/lua.py b/python3/vimspector/plugins/lua.py new file mode 100644 index 0000000..e18fef0 --- /dev/null +++ b/python3/vimspector/plugins/lua.py @@ -0,0 +1,51 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets, installer + + +def InstallLuaLocal( name, root, gadget ): + with installer.CurrentWorkingDir( root ): + installer.CheckCall( [ 'npm', 'install' ] ) + installer.CheckCall( [ 'npm', 'run', 'build' ] ) + installer.MakeSymlink( name, root ) + + +gadgets.RegisterGadget( '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: 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' + } + } + }, +} ) diff --git a/python3/vimspector/plugins/mono.py b/python3/vimspector/plugins/mono.py new file mode 100644 index 0000000..cea36d8 --- /dev/null +++ b/python3/vimspector/plugins/mono.py @@ -0,0 +1,54 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets + + +gadgets.RegisterGadget( '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.16.2', + 'checksum': + '121eca297d83daeeb1e6e1d791305d1827998dbd595c330086b3b94d33dba3b9', + }, + 'adapters': { + 'vscode-mono-debug': { + "name": "mono-debug", + "command": [ + "mono", + "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" + ], + "attach": { + "pidSelect": "none" + }, + "configuration": { + "cwd": "${workspaceRoot}", + "console": "integratedTerminal", + "args": [], + "env": {} + } + }, + } +} ) diff --git a/python3/vimspector/plugins/node.py b/python3/vimspector/plugins/node.py new file mode 100644 index 0000000..1feef4a --- /dev/null +++ b/python3/vimspector/plugins/node.py @@ -0,0 +1,45 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets, installer + + +def InstallNodeDebug( name, root, gadget ): + with installer.CurrentWorkingDir( root ): + installer.CheckCall( [ 'npm', 'install' ] ) + installer.CheckCall( [ 'npm', 'run', 'build' ] ) + installer.MakeSymlink( name, root ) + + +gadgets.RegisterGadget( 'vscode-node-debug2', { + 'language': 'node', + 'enabled': False, + 'repo': { + 'url': 'https://github.com/microsoft/vscode-node-debug2', + 'ref': 'v1.42.5' + }, + 'do': lambda name, root, gadget: InstallNodeDebug( name, root, gadget ), + 'adapters': { + 'vscode-node': { + 'name': 'node2', + 'type': 'node2', + 'command': [ + 'node', + '${gadgetDir}/vscode-node-debug2/out/src/nodeDebug.js' + ] + }, + }, +} ) diff --git a/python3/vimspector/plugins/php.py b/python3/vimspector/plugins/php.py new file mode 100644 index 0000000..11ef484 --- /dev/null +++ b/python3/vimspector/plugins/php.py @@ -0,0 +1,43 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +from vimspector import gadgets + + +gadgets.RegisterGadget( 'vscode-php-debug', { + 'language': 'php', + 'enabled': False, + 'download': { + 'url': + 'https://github.com/felixfbecker/vscode-php-debug/releases/download/' + '${version}/${file_name}', + }, + 'all': { + 'version': 'v1.13.0', + 'file_name': 'php-debug.vsix', + 'checksum': + '8a51e593458fd14623c1c89ebab87347b087d67087717f18bcf77bb788052718', + }, + 'adapters': { + 'vscode-php-debug': { + 'name': "php-debug", + 'command': [ + 'node', + "${gadgetDir}/vscode-php-debug/out/phpDebug.js", + ] + } + } +} ) diff --git a/python3/vimspector/plugins/python.py b/python3/vimspector/plugins/python.py new file mode 100644 index 0000000..d0602e9 --- /dev/null +++ b/python3/vimspector/plugins/python.py @@ -0,0 +1,86 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +from vimspector import gadgets, installer + + +def InstallDebugpy( name, root, gadget ): + wd = os.getcwd() + root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) ) + os.chdir( root ) + try: + installer.CheckCall( [ sys.executable, 'setup.py', 'build' ] ) + finally: + os.chdir( wd ) + + installer.MakeSymlink( name, root ) + + +gadgets.RegisterGadget( 'debugpy', { + 'language': 'python', + 'download': { + 'url': 'https://github.com/microsoft/debugpy/archive/${file_name}' + }, + 'all': { + 'version': '1.0.0b12', + 'file_name': 'v1.0.0b12.zip', + 'checksum': + '210632bba2221fbb841c9785a615258819ceec401d1abdbeb5f2326f12cc72a1' + }, + 'do': lambda name, root, gadget: InstallDebugpy( name, root, gadget ), + 'adapters': { + 'debugpy': { + "command": [ + sys.executable, # TODO: Will this work from within Vim ? + "${gadgetDir}/debugpy/build/lib/debugpy/adapter" + ], + "name": "debugpy", + "configuration": { + "python": sys.executable, # TODO: Will this work from within Vim ? + # Don't debug into subprocesses, as this leads to problems (vimspector + # doesn't support the custom messages) + # https://github.com/puremourning/vimspector/issues/141 + "subProcess": False, + } + } + }, +} ) + + +gadgets.RegisterGadget( '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", + ], + } + }, +} ) diff --git a/python3/vimspector/plugins/tcl.py b/python3/vimspector/plugins/tcl.py new file mode 100644 index 0000000..d8df75b --- /dev/null +++ b/python3/vimspector/plugins/tcl.py @@ -0,0 +1,85 @@ +# vimspector - A multi-language debugging system for Vim +# Copyright 2020 Ben Jackson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +from vimspector import gadgets, installer, install + + +def InstallTclProDebug( name, root, gadget ): + configure = [ 'sh', './configure' ] + + if install.GetOS() == 'macos': + # Apple removed the headers from system frameworks because they are + # determined to make life difficult. And the TCL configure scripts are super + # old so don't know about this. So we do their job for them and try and find + # a tclConfig.sh. + # + # NOTE however that in Apple's infinite wisdom, installing the "headers" in + # the other location is actually broken because the paths in the + # tclConfig.sh are pointing at the _old_ location. You actually do have to + # run the package installation which puts the headers back in order to work. + # This is why the below list is does not contain stuff from + # /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform + # '/Applications/Xcode.app/Contents/Developer/Platforms' + # '/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System' + # '/Library/Frameworks/Tcl.framework', + # '/Applications/Xcode.app/Contents/Developer/Platforms' + # '/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System' + # '/Library/Frameworks/Tcl.framework/Versions' + # '/Current', + for p in [ '/usr/local/opt/tcl-tk/lib' ]: + if os.path.exists( os.path.join( p, 'tclConfig.sh' ) ): + configure.append( '--with-tcl=' + p ) + break + + + with installer.CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ): + installer.CheckCall( configure ) + installer.CheckCall( [ 'make' ] ) + + installer.MakeSymlink( name, root ) + + +gadgets.RegisterGadget( 'tclpro', { + 'language': 'tcl', + 'repo': { + 'url': 'https://github.com/puremourning/TclProDebug', + 'ref': 'v1.0.0' + }, + 'do': lambda name, root, gadget: InstallTclProDebug( name, root, gadget ), + 'adapters': { + "tclpro": { + "name": "tclpro", + "type": "tclpro", + "command": [ + "${gadgetDir}/tclpro/bin/debugadapter" + ], + "attach": { + "pidSelect": "none" + }, + "configuration": { + "target": "${file}", + "args": [ "*${args}" ], + "tclsh": "tclsh", + "cwd": "${workspaceRoot}", + "extensionDirs": [ + "${workspaceRoot}/.tclpro/extensions", + "${HOME}/.tclpro/extensions", + ] + } + } + }, +} ) From dd4460598af5c4c8f90a78070d07f506e517268f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 28 Nov 2020 18:04:36 +0000 Subject: [PATCH 003/200] Print errors when json parsing fails Closes #258 --- python3/vimspector/debug_session.py | 34 ++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index c9a7a39..6a231a0 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -91,11 +91,17 @@ class DebugSession( object ): 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() ) ) - if database: - configurations.update( database.get( 'configurations' or {} ) ) - adapters.update( database.get( 'adapters' ) or {} ) + try: + with open( launch_config_file, 'r' ) as f: + database = json.loads( minify( f.read() ) ) + if database: + configurations.update( database.get( 'configurations' or {} ) ) + adapters.update( database.get( 'adapters' ) or {} ) + except json.JSONDecodeError as e: + self._logger.exception( f"Unable to read { launch_config_file }" ) + utils.UserMessage( f"Unable to read { launch_config_file }: { e }", + error = True, + persist = True ) return launch_config_file, configurations @@ -115,9 +121,11 @@ class DebugSession( object ): launch_config_file, configurations = self.GetConfigurations( adapters ) if not configurations: - utils.UserMessage( 'Unable to find any debug configurations. ' + utils.UserMessage( 'Unable to find any valid debug configurations. ' 'You need to tell vimspector how to launch your ' - 'application.' ) + 'application. See :messages for any errors.', + persist = True, + error = True ) return glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME ) ) @@ -127,9 +135,15 @@ class DebugSession( object ): if not gadget_config_file or not os.path.exists( gadget_config_file ): continue - with open( gadget_config_file, 'r' ) as f: - a = json.loads( minify( f.read() ) ).get( 'adapters' ) or {} - adapters.update( a ) + try: + with open( gadget_config_file, 'r' ) as f: + a = json.loads( minify( f.read() ) ).get( 'adapters' ) or {} + adapters.update( a ) + except json.JSONDecodeError as e: + self._logger.exception( f'Unable to read { gadget_config_file }' ) + utils.UserMessage( f"Unable to read { gadget_config_file }: { e }", + error = True, + persist = True ) if 'configuration' in launch_variables: configuration_name = launch_variables.pop( 'configuration' ) From b5e0da6c089cbd6ec72a2befd9ff8bb895f6ce96 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 2 Dec 2020 20:55:33 +0000 Subject: [PATCH 004/200] Remove duplicate InsatllDebubgpy from instaler.py --- python3/vimspector/installer.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 2d8c874..e586d23 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -348,18 +348,6 @@ def InstallGeneric( name, root, gadget ): -def InstallDebugpy( name, root, gadget ): - wd = os.getcwd() - root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) ) - os.chdir( root ) - try: - CheckCall( [ sys.executable, 'setup.py', 'build' ] ) - finally: - os.chdir( wd ) - - MakeSymlink( name, root ) - - def InstallGagdet( name: str, gadget: dict, manifest: Manifest, From 8261cde3c993b20211e79bd16aa72b840b3e0308 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 5 Dec 2020 16:38:27 +0000 Subject: [PATCH 005/200] 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. --- python3/vimspector/debug_session.py | 6 +----- .../cpp/simple_c_program/.vimspector.json | 10 ++++++++- support/test/cpp/simple_c_program/test_c.cpp | 4 ++++ .../python/simple_python/.vimspector.json | 21 +++++++++++++++++-- .../python/simple_python/run_with_debugpy | 11 +++++----- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 63cd140..4e912ac 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -740,11 +740,7 @@ class DebugSession( object ): self._connection_type = self._api_prefix + 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() diff --git a/support/test/cpp/simple_c_program/.vimspector.json b/support/test/cpp/simple_c_program/.vimspector.json index ae61ee8..7b8c53a 100644 --- a/support/test/cpp/simple_c_program/.vimspector.json +++ b/support/test/cpp/simple_c_program/.vimspector.json @@ -1,12 +1,20 @@ { "configurations": { - "simple_c_program - Launch": { + "CodeLLDB": { "adapter": "CodeLLDB", "configuration": { "request": "launch", "program": "${workspaceRoot}/test", "stopAtEntry": true } + }, + "lldb-vscode": { + "adapter": "lldb-vscode", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/test", + "stopAtEntry": true + } } } } diff --git a/support/test/cpp/simple_c_program/test_c.cpp b/support/test/cpp/simple_c_program/test_c.cpp index 4a95936..8dcc2dc 100644 --- a/support/test/cpp/simple_c_program/test_c.cpp +++ b/support/test/cpp/simple_c_program/test_c.cpp @@ -1,3 +1,5 @@ +#include +#include #include 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 ); } diff --git a/support/test/python/simple_python/.vimspector.json b/support/test/python/simple_python/.vimspector.json index 5eadb0c..2f63bc4 100644 --- a/support/test/python/simple_python/.vimspector.json +++ b/support/test/python/simple_python/.vimspector.json @@ -1,8 +1,12 @@ { "$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json", "adapters": { - "test_custom": { - "command": "This is a test" + "run_with_debugpy": { + "command": [ "${workspaceRoot}/run_with_debugpy" ], + "port": 9876, + "env": { + "DEBUG_PORT": "9876" + } } }, "configurations": { @@ -44,6 +48,19 @@ } } }, + "attach-run": { + "adapter": "run_with_debugpy", + "configuration": { + "request": "attach" + }, + "breakpoints": { + "exception": { + "raised": "N", + "uncaught": "", + "userUnhandled": "" + } + } + }, "run": { "adapter": "debugpy", "configuration": { diff --git a/support/test/python/simple_python/run_with_debugpy b/support/test/python/simple_python/run_with_debugpy index 03da11c..950ce83 100755 --- a/support/test/python/simple_python/run_with_debugpy +++ b/support/test/python/simple_python/run_with_debugpy @@ -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 From 28c5534704ea4b8ec9207220d0bb6b3932581824 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Mon, 14 Dec 2020 21:37:54 +0800 Subject: [PATCH 006/200] language list --- install_gadget.py | 68 +++++++++++++++++++-------------- python3/vimspector/gadgets.py | 4 +- python3/vimspector/installer.py | 7 +++- 3 files changed, 46 insertions(+), 33 deletions(-) diff --git a/install_gadget.py b/install_gadget.py index 52621c3..aaa07e6 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -114,32 +114,34 @@ 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 +184,23 @@ 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 ) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 2ea6bbc..182b8c3 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -21,7 +21,7 @@ import os GADGETS = { 'vscode-cpptools': { - 'language': 'c', + 'language': ['c','cpp'], 'download': { 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' '${version}/${file_name}', @@ -225,7 +225,7 @@ GADGETS = { }, }, 'netcoredbg': { - 'language': 'csharp', + 'language': ['csharp', 'fsharp', 'vbnet'], 'enabled': False, 'download': { 'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/' diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index b39398f..286cdd3 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -229,10 +229,13 @@ 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 From b65d9536ad8a0cf79fd8bf11fff4514884ddba19 Mon Sep 17 00:00:00 2001 From: cposture Date: Tue, 15 Dec 2020 00:22:35 +0800 Subject: [PATCH 007/200] update gadgets vscode-go version --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 2ea6bbc..0271069 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -353,10 +353,10 @@ GADGETS = { 'v${version}/${file_name}' }, 'all': { - 'version': '0.18.1', - 'file_name': 'Go-0.18.1.vsix', + 'version': '0.19.1', + 'file_name': 'go-0.19.1.vsix', 'checksum': - '80d4522c6cf482cfa6141997e5b458034f67d7065d92e1ce24a0456c405d6061', + '7f9dc014245b030d9f562b28f3ea9b1fd6e2708fac996c53ff6a707f8204ec64', }, 'adapters': { 'vscode-go': { From f161ce1e8cc62a956083d5b1d80c3499d614c5f5 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 14 Dec 2020 16:14:02 +0000 Subject: [PATCH 008/200] Remove redundant comments --- plugin/vimspector.vim | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 2dbbd82..05245cd 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -28,11 +28,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( ':p:h:h' ) From 61179b7670491a70b40cb34ddeefe793bee7fcb8 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 14 Dec 2020 20:54:58 +0000 Subject: [PATCH 009/200] Update CONTRIBUTING.md for PRs --- CONTRIBUTING.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cfa6c9d..067f7dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,6 +88,42 @@ vim -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 +131,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. From 66130389c521cad34400267efe58f6ad9aec3641 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Tue, 15 Dec 2020 16:25:26 +0800 Subject: [PATCH 010/200] code format fixes, update docs --- README.md | 31 ++++++++++++++++--------------- install_gadget.py | 9 ++++++--- python3/vimspector/gadgets.py | 2 +- python3/vimspector/installer.py | 3 ++- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d964445..75a1da1 100644 --- a/README.md +++ b/README.md @@ -134,21 +134,22 @@ runtime dependencies). They are categorised by their level of support: * `Experimental`: Working, but not frequently used and rarely tested * `Legacy`: No longer supported, please migrate your config -| Language | Status | Switch (for `install_gadget.py`) | Adapter (for `:VimspectorInstall`) | Dependencies | -|--------------------|--------------|----------------------------------|------------------------------------|--------------------------------------------| -| C, C++, etc. | Tested | `--all` or `--enable-c` | 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 | 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 | -| Python.legacy | Legacy | `--force-enable-python.legacy` | vscode-python | Node 10, Python 2.7 or Python 3 | +| 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 | 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 diff --git a/install_gadget.py b/install_gadget.py index aaa07e6..91ad887 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -115,7 +115,8 @@ parser.add_argument( '--sudo', done_languages = set() for name, gadget in gadgets.GADGETS.items(): langs = gadget[ 'language' ] - if not isinstance(langs, list): langs = [langs] + if not isinstance(langs, list): + langs = [langs] for lang in langs: if lang in done_languages: continue @@ -185,7 +186,8 @@ manifest = installer.Manifest() for name, gadget in gadgets.GADGETS.items(): langs = gadget[ 'language' ] - if not isinstance(langs, list): langs = [langs] + if not isinstance(langs, list): + langs = [langs] skip = 0 for lang in langs: if not gadget.get( 'enabled', True ): @@ -200,7 +202,8 @@ for name, gadget in gadgets.GADGETS.items(): if getattr( args, 'disable_' + lang ): skip = skip + 1 continue - if skip == len(langs): continue + if skip == len(langs): + continue if not args.upgrade: manifest.Clear( name ) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 182b8c3..99ed55e 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -21,7 +21,7 @@ import os GADGETS = { 'vscode-cpptools': { - 'language': ['c','cpp'], + 'language': ['c', 'cpp', 'rust'], 'download': { 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' '${version}/${file_name}', diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 286cdd3..cc8c3f2 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -230,7 +230,8 @@ def GadgetListToInstallerArgs( *gadget_list ): continue lang = gadget[ "language" ] - if isinstance(lang, list): lang = lang[0] + if isinstance(lang, list): + lang = lang[0] if not gadget.get( 'enabled', True ): installer_args.append( f'--force-enable-{lang}' ) From f8d1e484f95e742ea6dac3cdcaeb94a64c501e78 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 18 Dec 2020 17:10:29 +0000 Subject: [PATCH 011/200] Update CONTRIBUTING.md Minor fix and correct CI path --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 067f7dc..3ba53bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -167,10 +167,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: @@ -182,7 +182,7 @@ 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`. # Code of conduct From f20c4c9725d0fcfd195cefbe95f84bf7c3d18d2a Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Sat, 19 Dec 2020 22:35:12 +0800 Subject: [PATCH 012/200] fix linter errors --- install_gadget.py | 12 ++++++------ python3/vimspector/gadgets.py | 4 ++-- python3/vimspector/installer.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/install_gadget.py b/install_gadget.py index 91ad887..b6e2fd7 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -115,8 +115,8 @@ parser.add_argument( '--sudo', done_languages = set() for name, gadget in gadgets.GADGETS.items(): langs = gadget[ 'language' ] - if not isinstance(langs, list): - langs = [langs] + if not isinstance( langs, list ): + langs = [ langs ] for lang in langs: if lang in done_languages: continue @@ -186,13 +186,13 @@ manifest = installer.Manifest() for name, gadget in gadgets.GADGETS.items(): langs = gadget[ 'language' ] - if not isinstance(langs, list): - langs = [langs] + 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) ): + and not getattr( args, 'force_enable_' + lang ) ): skip = skip + 1 continue else: @@ -202,7 +202,7 @@ for name, gadget in gadgets.GADGETS.items(): if getattr( args, 'disable_' + lang ): skip = skip + 1 continue - if skip == len(langs): + if skip == len( langs ): continue if not args.upgrade: diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 99ed55e..58104b3 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -21,7 +21,7 @@ import os GADGETS = { 'vscode-cpptools': { - 'language': ['c', 'cpp', 'rust'], + 'language': [ 'c', 'cpp', 'rust' ], 'download': { 'url': 'https://github.com/Microsoft/vscode-cpptools/releases/download/' '${version}/${file_name}', @@ -225,7 +225,7 @@ GADGETS = { }, }, 'netcoredbg': { - 'language': ['csharp', 'fsharp', 'vbnet'], + 'language': [ 'csharp', 'fsharp', 'vbnet' ], 'enabled': False, 'download': { 'url': ( 'https://github.com/Samsung/netcoredbg/releases/download/' diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index cc8c3f2..f27f46e 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -230,8 +230,8 @@ def GadgetListToInstallerArgs( *gadget_list ): continue lang = gadget[ "language" ] - if isinstance(lang, list): - lang = lang[0] + if isinstance( lang, list ): + lang = lang[ 0 ] if not gadget.get( 'enabled', True ): installer_args.append( f'--force-enable-{lang}' ) From 0942aa4523d2a3bf75c6ea213ef2b0c577662a07 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 14 Dec 2020 17:53:06 +0000 Subject: [PATCH 013/200] 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. --- docs/configuration.md | 32 +- docs/schema/vimspector.schema.json | 283 ++++++++++-------- python3/vimspector/debug_session.py | 61 ++-- .../python/simple_python/.vimspector.json | 31 ++ support/test/python/simple_python/Dockerfile | 22 ++ .../test/python/simple_python/build-container | 11 + 6 files changed, 282 insertions(+), 158 deletions(-) create mode 100644 support/test/python/simple_python/Dockerfile create mode 100755 support/test/python/simple_python/build-container diff --git a/docs/configuration.md b/docs/configuration.md index acf77b4..f3d0814 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -633,19 +633,24 @@ 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": [ + "runCommand": [ "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}", "%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": { @@ -685,6 +690,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 } } }, @@ -754,7 +763,7 @@ and have to tell cpptools a few more options. "remote": { "host": "${host}", "account": "${account}", - "launchCommmand": [ + "runCommand": [ "gdbserver", "--once", "--no-startup-with-shell", @@ -838,19 +847,23 @@ port. // Command to launch the debugee and attach the debugger; // %CMD% replaced with the remote-cmdLine configured in the launch // configuration. (mandatory) - "launchCommmand": [ + "runCommand": [ "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}", "%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": { @@ -886,6 +899,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 } } }, diff --git a/docs/schema/vimspector.schema.json b/docs/schema/vimspector.schema.json index c8af196..97fea75 100644 --- a/docs/schema/vimspector.schema.json +++ b/docs/schema/vimspector.schema.json @@ -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 docker run -p 8765:8765 -it simple_python)." + } + } + }, + { + "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": "localhost", + "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." } - ] + } } ] } diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 4e912ac..ea72651 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -68,6 +68,7 @@ class DebugSession( object ): self._configuration = None self._adapter = None + self._launch_config = None self._ResetServerState() @@ -108,6 +109,7 @@ class DebugSession( object ): launch_variables ) self._configuration = None self._adapter = None + self._launch_config = None current_file = utils.GetBufferFilepath( vim.current.buffer ) adapters = {} @@ -280,6 +282,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 ) ) @@ -291,6 +294,7 @@ class DebugSession( object ): else: vim.current.tabpage = self._uiTab + self._Prepare() self._StartDebugAdapter() self._Initialise() @@ -723,7 +727,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 @@ -739,6 +742,7 @@ 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 }" ) self._adapter[ 'env' ] = self._adapter.get( 'env', {} ) @@ -794,16 +798,16 @@ class DebugSession( object ): 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 ? @@ -844,20 +848,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 ): @@ -890,6 +897,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', [] ) @@ -988,16 +1000,18 @@ 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( @@ -1005,7 +1019,7 @@ class DebugSession( object ): self._splash_screen, "Attaching to debugee..." ) - self._PrepareAttach( adapter_config, launch_config ) + self._PrepareAttach( self._adapter, self._launch_config ) elif request == "launch": self._splash_screen = utils.DisplaySplash( self._api_prefix, @@ -1014,14 +1028,16 @@ class DebugSession( object ): # 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', @@ -1034,12 +1050,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 ) diff --git a/support/test/python/simple_python/.vimspector.json b/support/test/python/simple_python/.vimspector.json index 2f63bc4..29d7d43 100644 --- a/support/test/python/simple_python/.vimspector.json +++ b/support/test/python/simple_python/.vimspector.json @@ -7,6 +7,23 @@ "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" + } } }, "configurations": { @@ -61,6 +78,20 @@ } } }, + "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": { diff --git a/support/test/python/simple_python/Dockerfile b/support/test/python/simple_python/Dockerfile new file mode 100644 index 0000000..7748fef --- /dev/null +++ b/support/test/python/simple_python/Dockerfile @@ -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 diff --git a/support/test/python/simple_python/build-container b/support/test/python/simple_python/build-container new file mode 100755 index 0000000..bc6450a --- /dev/null +++ b/support/test/python/simple_python/build-container @@ -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 . From 523ea29faa1237e6536aa3ff6035a9a8b87e45ea Mon Sep 17 00:00:00 2001 From: Alex Weigl Date: Tue, 22 Dec 2020 23:49:25 +0200 Subject: [PATCH 014/200] Fix Typo in PHP section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d964445..994081e 100644 --- a/README.md +++ b/README.md @@ -1284,7 +1284,7 @@ xdebug.remote_connect_back=true xdebug.remote_port=9000 ``` -* .vimspectory.json +* .vimspector.json ```json { "configurations": { From 47c404f823b124391ebf1475362185fe367f6bdc Mon Sep 17 00:00:00 2001 From: Allan Guigou Date: Thu, 24 Dec 2020 12:57:49 -0500 Subject: [PATCH 015/200] 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": { ... } } } } --- python3/vimspector/installer.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index b39398f..46a9e69 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -340,11 +340,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 ): @@ -699,8 +700,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 ): From ec68811c8a598fda979e6d21bc933bb6a31d50c1 Mon Sep 17 00:00:00 2001 From: Allan Guigou Date: Thu, 24 Dec 2020 14:59:03 -0500 Subject: [PATCH 016/200] Add support test for kotlin --- support/test/kotlin/.gitignore | 2 + support/test/kotlin/.vimspector.json | 21 ++ support/test/kotlin/build.gradle.kts | 25 +++ .../kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + support/test/kotlin/gradlew | 185 ++++++++++++++++++ support/test/kotlin/gradlew.bat | 104 ++++++++++ support/test/kotlin/settings.gradle.kts | 1 + .../kotlin/vimspector/test/Application.kt | 5 + 9 files changed, 348 insertions(+) create mode 100644 support/test/kotlin/.gitignore create mode 100644 support/test/kotlin/.vimspector.json create mode 100644 support/test/kotlin/build.gradle.kts create mode 100644 support/test/kotlin/gradle/wrapper/gradle-wrapper.jar create mode 100644 support/test/kotlin/gradle/wrapper/gradle-wrapper.properties create mode 100755 support/test/kotlin/gradlew create mode 100644 support/test/kotlin/gradlew.bat create mode 100644 support/test/kotlin/settings.gradle.kts create mode 100644 support/test/kotlin/src/main/kotlin/vimspector/test/Application.kt diff --git a/support/test/kotlin/.gitignore b/support/test/kotlin/.gitignore new file mode 100644 index 0000000..f8b92c3 --- /dev/null +++ b/support/test/kotlin/.gitignore @@ -0,0 +1,2 @@ +.gradle +build diff --git a/support/test/kotlin/.vimspector.json b/support/test/kotlin/.vimspector.json new file mode 100644 index 0000000..d2c2a63 --- /dev/null +++ b/support/test/kotlin/.vimspector.json @@ -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}" + } + } + } +} diff --git a/support/test/kotlin/build.gradle.kts b/support/test/kotlin/build.gradle.kts new file mode 100644 index 0000000..e93c004 --- /dev/null +++ b/support/test/kotlin/build.gradle.kts @@ -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" +} + diff --git a/support/test/kotlin/gradle/wrapper/gradle-wrapper.jar b/support/test/kotlin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 zcma&ObC74zk}X`WF59+k+qTVL*+!RbS9RI8Z5v&-ZFK4Nn|tqzcjwK__x+Iv5xL`> zj94dg?X`0sMHx^qXds{;KY)OMg#H>35XgTVfq6#vc9ww|9) z@UMfwUqk)B9p!}NrNqTlRO#i!ALOPcWo78-=iy}NsAr~T8T0X0%G{DhX~u-yEwc29WQ4D zuv2j{a&j?qB4wgCu`zOXj!~YpTNFg)TWoV>DhYlR^Gp^rkOEluvxkGLB?!{fD!T@( z%3cy>OkhbIKz*R%uoKqrg1%A?)uTZD&~ssOCUBlvZhx7XHQ4b7@`&sPdT475?*zWy z>xq*iK=5G&N6!HiZaD{NSNhWL;+>Quw_#ZqZbyglna!Fqn3N!$L`=;TFPrhodD-Q` z1l*=DP2gKJP@)cwI@-M}?M$$$%u~=vkeC%>cwR$~?y6cXx-M{=wdT4|3X(@)a|KkZ z`w$6CNS@5gWS7s7P86L<=vg$Mxv$?)vMj3`o*7W4U~*Nden}wz=y+QtuMmZ{(Ir1D zGp)ZsNiy{mS}Au5;(fYf93rs^xvi(H;|H8ECYdC`CiC&G`zw?@)#DjMc7j~daL_A$ z7e3nF2$TKlTi=mOftyFBt8*Xju-OY@2k@f3YBM)-v8+5_o}M?7pxlNn)C0Mcd@87?+AA4{Ti2ptnYYKGp`^FhcJLlT%RwP4k$ad!ho}-^vW;s{6hnjD0*c39k zrm@PkI8_p}mnT&5I@=O1^m?g}PN^8O8rB`;t`6H+?Su0IR?;8txBqwK1Au8O3BZAX zNdJB{bpQWR@J|e=Z>XSXV1DB{uhr3pGf_tb)(cAkp)fS7*Qv))&Vkbb+cvG!j}ukd zxt*C8&RN}5ck{jkw0=Q7ldUp0FQ&Pb_$M7a@^nf`8F%$ftu^jEz36d#^M8Ia{VaTy z5(h$I)*l3i!VpPMW+XGgzL~fcN?{~1QWu9!Gu0jOWWE zNW%&&by0DbXL&^)r-A*7R@;T$P}@3eOj#gqJ!uvTqBL5bupU91UK#d|IdxBUZAeh1 z>rAI#*Y4jv>uhOh7`S@mnsl0g@1C;k$Z%!d*n8#_$)l}-1&z2kr@M+xWoKR z!KySy-7h&Bf}02%JeXmQGjO3ntu={K$jy$rFwfSV8!zqAL_*&e2|CJ06`4&0+ceI026REfNT>JzAdwmIlKLEr2? zaZ#d*XFUN*gpzOxq)cysr&#6zNdDDPH% zd8_>3B}uA7;bP4fKVdd~Og@}dW#74ceETOE- zlZgQqQfEc?-5ly(Z5`L_CCM!&Uxk5#wgo=OLs-kFHFG*cTZ)$VE?c_gQUW&*!2@W2 z7Lq&_Kf88OCo?BHCtwe*&fu&8PQ(R5&lnYo8%+U73U)Ec2&|A)Y~m7(^bh299REPe zn#gyaJ4%o4>diN3z%P5&_aFUmlKytY$t21WGwx;3?UC}vlxi-vdEQgsKQ;=#sJ#ll zZeytjOad$kyON4XxC}frS|Ybh`Yq!<(IrlOXP3*q86ImyV*mJyBn$m~?#xp;EplcM z+6sez%+K}Xj3$YN6{}VL;BZ7Fi|iJj-ywlR+AP8lq~mnt5p_%VmN{Sq$L^z!otu_u znVCl@FgcVXo510e@5(wnko%Pv+^r^)GRh;>#Z(|#cLnu_Y$#_xG&nvuT+~gzJsoSi zBvX`|IS~xaold!`P!h(v|=>!5gk)Q+!0R1Ge7!WpRP{*Ajz$oGG$_?Ajvz6F0X?809o`L8prsJ*+LjlGfSziO;+ zv>fyRBVx#oC0jGK8$%$>Z;0+dfn8x;kHFQ?Rpi7(Rc{Uq{63Kgs{IwLV>pDK7yX-2 zls;?`h!I9YQVVbAj7Ok1%Y+F?CJa-Jl>1x#UVL(lpzBBH4(6v0^4 z3Tf`INjml5`F_kZc5M#^J|f%7Hgxg3#o}Zwx%4l9yYG!WaYUA>+dqpRE3nw#YXIX%= ziH3iYO~jr0nP5xp*VIa#-aa;H&%>{mfAPPlh5Fc!N7^{!z$;p-p38aW{gGx z)dFS62;V;%%fKp&i@+5x=Cn7Q>H`NofJGXmNeh{sOL+Nk>bQJJBw3K*H_$}%*xJM=Kh;s#$@RBR z|75|g85da@#qT=pD777m$wI!Q8SC4Yw3(PVU53bzzGq$IdGQoFb-c_(iA_~qD|eAy z@J+2!tc{|!8fF;%6rY9`Q!Kr>MFwEH%TY0y>Q(D}xGVJM{J{aGN0drG&|1xO!Ttdw z-1^gQ&y~KS5SeslMmoA$Wv$ly={f}f9<{Gm!8ycp*D9m*5Ef{ymIq!MU01*)#J1_! zM_i4{LYButqlQ>Q#o{~W!E_#(S=hR}kIrea_67Z5{W>8PD>g$f;dTvlD=X@T$8D0;BWkle@{VTd&D5^)U>(>g(jFt4lRV6A2(Te->ooI{nk-bZ(gwgh zaH4GT^wXPBq^Gcu%xW#S#p_&x)pNla5%S5;*OG_T^PhIIw1gXP&u5c;{^S(AC*+$> z)GuVq(FT@zq9;i{*9lEsNJZ)??BbSc5vF+Kdh-kL@`(`l5tB4P!9Okin2!-T?}(w% zEpbEU67|lU#@>DppToestmu8Ce=gz=e#V+o)v)#e=N`{$MI5P0O)_fHt1@aIC_QCv=FO`Qf=Ga%^_NhqGI)xtN*^1n{ z&vgl|TrKZ3Vam@wE0p{c3xCCAl+RqFEse@r*a<3}wmJl-hoJoN<|O2zcvMRl<#BtZ z#}-bPCv&OTw`GMp&n4tutf|er`@#d~7X+);##YFSJ)BitGALu}-N*DJdCzs(cQ?I- z6u(WAKH^NUCcOtpt5QTsQRJ$}jN28ZsYx+4CrJUQ%egH zo#tMoywhR*oeIkS%}%WUAIbM`D)R6Ya&@sZvvUEM7`fR0Ga03*=qaEGq4G7-+30Ck zRkje{6A{`ebq?2BTFFYnMM$xcQbz0nEGe!s%}O)m={`075R0N9KTZ>vbv2^eml>@}722%!r#6Wto}?vNst? zs`IasBtcROZG9+%rYaZe^=5y3chDzBf>;|5sP0!sP(t^= z^~go8msT@|rp8LJ8km?4l?Hb%o10h7(ixqV65~5Y>n_zG3AMqM3UxUNj6K-FUgMT7 z*Dy2Y8Ws+%`Z*~m9P zCWQ8L^kA2$rf-S@qHow$J86t)hoU#XZ2YK~9GXVR|*`f6`0&8j|ss_Ai-x=_;Df^*&=bW$1nc{Gplm zF}VF`w)`5A;W@KM`@<9Bw_7~?_@b{Z`n_A6c1AG#h#>Z$K>gX6reEZ*bZRjCup|0# zQ{XAb`n^}2cIwLTN%5Ix`PB*H^(|5S{j?BwItu+MS`1)VW=TnUtt6{3J!WR`4b`LW z?AD#ZmoyYpL=903q3LSM=&5eNP^dwTDRD~iP=}FXgZ@2WqfdyPYl$9do?wX{RU*$S zgQ{OqXK-Yuf4+}x6P#A*la&^G2c2TC;aNNZEYuB(f25|5eYi|rd$;i0qk7^3Ri8of ziP~PVT_|4$n!~F-B1_Et<0OJZ*e+MN;5FFH`iec(lHR+O%O%_RQhvbk-NBQ+$)w{D+dlA0jxI;z|P zEKW`!X)${xzi}Ww5G&@g0akBb_F`ziv$u^hs0W&FXuz=Ap>SUMw9=M?X$`lgPRq11 zqq+n44qL;pgGO+*DEc+Euv*j(#%;>p)yqdl`dT+Og zZH?FXXt`<0XL2@PWYp|7DWzFqxLK)yDXae&3P*#+f+E{I&h=$UPj;ey9b`H?qe*Oj zV|-qgI~v%&oh7rzICXfZmg$8$B|zkjliQ=e4jFgYCLR%yi!9gc7>N z&5G#KG&Hr+UEfB;M(M>$Eh}P$)<_IqC_WKOhO4(cY@Gn4XF(#aENkp&D{sMQgrhDT zXClOHrr9|POHqlmm+*L6CK=OENXbZ+kb}t>oRHE2xVW<;VKR@ykYq04LM9L-b;eo& zl!QQo!Sw{_$-qosixZJWhciN>Gbe8|vEVV2l)`#5vKyrXc6E`zmH(76nGRdL)pqLb@j<&&b!qJRLf>d`rdz}^ZSm7E;+XUJ ziy;xY&>LM?MA^v0Fu8{7hvh_ynOls6CI;kQkS2g^OZr70A}PU;i^~b_hUYN1*j-DD zn$lHQG9(lh&sDii)ip*{;Sb_-Anluh`=l~qhqbI+;=ZzpFrRp&T+UICO!OoqX@Xr_ z32iJ`xSpx=lDDB_IG}k+GTYG@K8{rhTS)aoN8D~Xfe?ul&;jv^E;w$nhu-ICs&Q)% zZ=~kPNZP0-A$pB8)!`TEqE`tY3Mx^`%O`?EDiWsZpoP`e-iQ#E>fIyUx8XN0L z@S-NQwc;0HjSZKWDL}Au_Zkbh!juuB&mGL0=nO5)tUd_4scpPy&O7SNS^aRxUy0^< zX}j*jPrLP4Pa0|PL+nrbd4G;YCxCK-=G7TG?dby~``AIHwxqFu^OJhyIUJkO0O<>_ zcpvg5Fk$Wpj}YE3;GxRK67P_Z@1V#+pu>pRj0!mFf(m_WR3w3*oQy$s39~U7Cb}p(N&8SEwt+)@%o-kW9Ck=^?tvC2$b9% ze9(Jn+H`;uAJE|;$Flha?!*lJ0@lKfZM>B|c)3lIAHb;5OEOT(2453m!LgH2AX=jK zQ93An1-#l@I@mwB#pLc;M7=u6V5IgLl>E%gvE|}Hvd4-bE1>gs(P^C}gTv*&t>W#+ zASLRX$y^DD3Jrht zwyt`yuA1j(TcP*0p*Xkv>gh+YTLrcN_HuaRMso~0AJg`^nL#52dGBzY+_7i)Ud#X) zVwg;6$WV20U2uyKt8<)jN#^1>PLg`I`@Mmut*Zy!c!zshSA!e^tWVoKJD%jN&ml#{ z@}B$j=U5J_#rc%T7(DGKF+WwIblEZ;Vq;CsG~OKxhWYGJx#g7fxb-_ya*D0=_Ys#f zhXktl=Vnw#Z_neW>Xe#EXT(4sT^3p6srKby4Ma5LLfh6XrHGFGgM;5Z}jv-T!f~=jT&n>Rk z4U0RT-#2fsYCQhwtW&wNp6T(im4dq>363H^ivz#>Sj;TEKY<)dOQU=g=XsLZhnR>e zd}@p1B;hMsL~QH2Wq>9Zb; zK`0`09fzuYg9MLJe~cdMS6oxoAD{kW3sFAqDxvFM#{GpP^NU@9$d5;w^WgLYknCTN z0)N425mjsJTI@#2kG-kB!({*+S(WZ-{SckG5^OiyP%(6DpRsx60$H8M$V65a_>oME z^T~>oG7r!ew>Y)&^MOBrgc-3PezgTZ2xIhXv%ExMFgSf5dQbD=Kj*!J4k^Xx!Z>AW ziZfvqJvtm|EXYsD%A|;>m1Md}j5f2>kt*gngL=enh<>#5iud0dS1P%u2o+>VQ{U%(nQ_WTySY(s#~~> zrTsvp{lTSup_7*Xq@qgjY@1#bisPCRMMHnOL48qi*jQ0xg~TSW%KMG9zN1(tjXix()2$N}}K$AJ@GUth+AyIhH6Aeh7qDgt#t*`iF5#A&g4+ zWr0$h9Zx6&Uo2!Ztcok($F>4NA<`dS&Js%L+67FT@WmI)z#fF~S75TUut%V($oUHw z$IJsL0X$KfGPZYjB9jaj-LaoDD$OMY4QxuQ&vOGo?-*9@O!Nj>QBSA6n$Lx|^ zky)4+sy{#6)FRqRt6nM9j2Lzba!U;aL%ZcG&ki1=3gFx6(&A3J-oo|S2_`*w9zT)W z4MBOVCp}?4nY)1))SOX#6Zu0fQQ7V{RJq{H)S#;sElY)S)lXTVyUXTepu4N)n85Xo zIpWPT&rgnw$D2Fsut#Xf-hO&6uA0n~a;a3!=_!Tq^TdGE&<*c?1b|PovU}3tfiIUu z){4W|@PY}zJOXkGviCw^x27%K_Fm9GuKVpd{P2>NJlnk^I|h2XW0IO~LTMj>2<;S* zZh2uRNSdJM$U$@=`zz}%;ucRx{aKVxxF7?0hdKh6&GxO6f`l2kFncS3xu0Ly{ew0& zeEP*#lk-8-B$LD(5yj>YFJ{yf5zb41PlW7S{D9zC4Aa4nVdkDNH{UsFJp)q-`9OYt zbOKkigbmm5hF?tttn;S4g^142AF^`kiLUC?e7=*JH%Qe>uW=dB24NQa`;lm5yL>Dyh@HbHy-f%6Vz^ zh&MgwYsh(z#_fhhqY$3*f>Ha}*^cU-r4uTHaT?)~LUj5``FcS46oyoI5F3ZRizVD% zPFY(_S&5GN8$Nl2=+YO6j4d|M6O7CmUyS&}m4LSn6}J`$M0ZzT&Ome)ZbJDFvM&}A zZdhDn(*viM-JHf84$!I(8eakl#zRjJH4qfw8=60 z11Ely^FyXjVvtv48-Fae7p=adlt9_F^j5#ZDf7)n!#j?{W?@j$Pi=k`>Ii>XxrJ?$ z^bhh|X6qC8d{NS4rX5P!%jXy=>(P+r9?W(2)|(=a^s^l~x*^$Enw$~u%WRuRHHFan{X|S;FD(Mr z@r@h^@Bs#C3G;~IJMrERd+D!o?HmFX&#i|~q(7QR3f8QDip?ms6|GV_$86aDb|5pc?_-jo6vmWqYi{P#?{m_AesA4xX zi&ki&lh0yvf*Yw~@jt|r-=zpj!bw<6zI3Aa^Wq{|*WEC}I=O!Re!l~&8|Vu<$yZ1p zs-SlwJD8K!$(WWyhZ+sOqa8cciwvyh%zd`r$u;;fsHn!hub0VU)bUv^QH?x30#;tH zTc_VbZj|prj7)d%ORU;Vs{#ERb>K8>GOLSImnF7JhR|g$7FQTU{(a7RHQ*ii-{U3X z^7+vM0R$8b3k1aSU&kxvVPfOz3~)0O2iTYinV9_5{pF18j4b{o`=@AZIOAwwedB2@ ztXI1F04mg{<>a-gdFoRjq$6#FaevDn$^06L)k%wYq03&ysdXE+LL1#w$rRS1Y;BoS zH1x}{ms>LHWmdtP(ydD!aRdAa(d@csEo z0EF9L>%tppp`CZ2)jVb8AuoYyu;d^wfje6^n6`A?6$&%$p>HcE_De-Zh)%3o5)LDa zskQ}%o7?bg$xUj|n8gN9YB)z!N&-K&!_hVQ?#SFj+MpQA4@4oq!UQ$Vm3B`W_Pq3J z=ngFP4h_y=`Iar<`EESF9){%YZVyJqLPGq07TP7&fSDmnYs2NZQKiR%>){imTBJth zPHr@p>8b+N@~%43rSeNuOz;rgEm?14hNtI|KC6Xz1d?|2J`QS#`OW7gTF_;TPPxu@ z)9J9>3Lx*bc>Ielg|F3cou$O0+<b34_*ZJhpS&$8DP>s%47a)4ZLw`|>s=P_J4u z?I_%AvR_z8of@UYWJV?~c4Yb|A!9n!LEUE6{sn@9+D=0w_-`szJ_T++x3MN$v-)0d zy`?1QG}C^KiNlnJBRZBLr4G~15V3$QqC%1G5b#CEB0VTr#z?Ug%Jyv@a`QqAYUV~^ zw)d|%0g&kl{j#FMdf$cn(~L@8s~6eQ)6{`ik(RI(o9s0g30Li{4YoxcVoYd+LpeLz zai?~r)UcbYr@lv*Z>E%BsvTNd`Sc?}*}>mzJ|cr0Y(6rA7H_6&t>F{{mJ^xovc2a@ zFGGDUcGgI-z6H#o@Gj29C=Uy{wv zQHY2`HZu8+sBQK*_~I-_>fOTKEAQ8_Q~YE$c?cSCxI;vs-JGO`RS464Ft06rpjn+a zqRS0Y3oN(9HCP@{J4mOWqIyD8PirA!pgU^Ne{LHBG;S*bZpx3|JyQDGO&(;Im8!ed zNdpE&?3U?E@O~>`@B;oY>#?gXEDl3pE@J30R1;?QNNxZ?YePc)3=NS>!STCrXu*lM z69WkLB_RBwb1^-zEm*tkcHz3H;?v z;q+x0Jg$|?5;e1-kbJnuT+^$bWnYc~1qnyVTKh*cvM+8yJT-HBs1X@cD;L$su65;i z2c1MxyL~NuZ9+)hF=^-#;dS#lFy^Idcb>AEDXu1!G4Kd8YPy~0lZz$2gbv?su}Zn} zGtIbeYz3X8OA9{sT(aleold_?UEV{hWRl(@)NH6GFH@$<8hUt=dNte%e#Jc>7u9xi zuqv!CRE@!fmZZ}3&@$D>p0z=*dfQ_=IE4bG0hLmT@OP>x$e`qaqf_=#baJ8XPtOpWi%$ep1Y)o2(sR=v)M zt(z*pGS$Z#j_xq_lnCr+x9fwiT?h{NEn#iK(o)G&Xw-#DK?=Ms6T;%&EE${Gq_%99 z6(;P~jPKq9llc+cmI(MKQ6*7PcL)BmoI}MYFO)b3-{j>9FhNdXLR<^mnMP`I7z0v` zj3wxcXAqi4Z0kpeSf>?V_+D}NULgU$DBvZ^=0G8Bypd7P2>;u`yW9`%4~&tzNJpgp zqB+iLIM~IkB;ts!)exn643mAJ8-WlgFE%Rpq!UMYtB?$5QAMm)%PT0$$2{>Yu7&U@ zh}gD^Qdgu){y3ANdB5{75P;lRxSJPSpQPMJOiwmpMdT|?=q;&$aTt|dl~kvS z+*i;6cEQJ1V`R4Fd>-Uzsc=DPQ7A7#VPCIf!R!KK%LM&G%MoZ0{-8&99H!|UW$Ejv zhDLX3ESS6CgWTm#1ZeS2HJb`=UM^gsQ84dQpX(ESWSkjn>O zVxg%`@mh(X9&&wN$lDIc*@>rf?C0AD_mge3f2KkT6kGySOhXqZjtA?5z`vKl_{(5g z&%Y~9p?_DL{+q@siT~*3Q*$nWXQfNN;%s_eHP_A;O`N`SaoB z6xYR;z_;HQ2xAa9xKgx~2f2xEKiEDpGPH1d@||v#f#_Ty6_gY>^oZ#xac?pc-F`@ z*}8sPV@xiz?efDMcmmezYVw~qw=vT;G1xh+xRVBkmN66!u(mRG3G6P#v|;w@anEh7 zCf94arw%YB*=&3=RTqX?z4mID$W*^+&d6qI*LA-yGme;F9+wTsNXNaX~zl2+qIK&D-aeN4lr0+yP;W>|Dh?ms_ogT{DT+ ztXFy*R7j4IX;w@@R9Oct5k2M%&j=c_rWvoul+` z<18FH5D@i$P38W9VU2(EnEvlJ(SHCqTNBa)brkIjGP|jCnK&Qi%97tikU}Y#3L?s! z2ujL%YiHO-#!|g5066V01hgT#>fzls7P>+%D~ogOT&!Whb4iF=CnCto82Yb#b`YoVsj zS2q^W0Rj!RrM@=_GuPQy5*_X@Zmu`TKSbqEOP@;Ga&Rrr>#H@L41@ZX)LAkbo{G8+ z;!5EH6vv-ip0`tLB)xUuOX(*YEDSWf?PIxXe`+_B8=KH#HFCfthu}QJylPMTNmoV; zC63g%?57(&osaH^sxCyI-+gwVB|Xs2TOf=mgUAq?V~N_5!4A=b{AXbDae+yABuuu3B_XSa4~c z1s-OW>!cIkjwJf4ZhvT|*IKaRTU)WAK=G|H#B5#NB9<{*kt?7`+G*-^<)7$Iup@Um z7u*ABkG3F*Foj)W9-I&@BrN8(#$7Hdi`BU#SR1Uz4rh&=Ey!b76Qo?RqBJ!U+rh(1 znw@xw5$)4D8OWtB_^pJO*d~2Mb-f~>I!U#*=Eh*xa6$LX?4Evp4%;ENQR!mF4`f7F zpG!NX=qnCwE8@NAbQV`*?!v0;NJ(| zBip8}VgFVsXFqslXUV>_Z>1gmD(7p#=WACXaB|Y`=Kxa=p@_ALsL&yAJ`*QW^`2@% zW7~Yp(Q@ihmkf{vMF?kqkY%SwG^t&CtfRWZ{syK@W$#DzegcQ1>~r7foTw3^V1)f2Tq_5f$igmfch;8 zT-<)?RKcCdQh6x^mMEOS;4IpQ@F2q-4IC4%*dU@jfHR4UdG>Usw4;7ESpORL|2^#jd+@zxz{(|RV*1WKrw-)ln*8LnxVkKDfGDHA%7`HaiuvhMu%*mY9*Ya{Ti#{DW?i0 zXXsp+Bb(_~wv(3t70QU3a$*<$1&zm1t++x#wDLCRI4K)kU?Vm9n2c0m@TyUV&&l9%}fulj!Z9)&@yIcQ3gX}l0b1LbIh4S z5C*IDrYxR%qm4LVzSk{0;*npO_SocYWbkAjA6(^IAwUnoAzw_Uo}xYFo?Y<-4Zqec z&k7HtVlFGyt_pA&kX%P8PaRD8y!Wsnv}NMLNLy-CHZf(ObmzV|t-iC#@Z9*d-zUsx zxcYWw{H)nYXVdnJu5o-U+fn~W z-$h1ax>h{NlWLA7;;6TcQHA>UJB$KNk74T1xNWh9)kwK~wX0m|Jo_Z;g;>^E4-k4R zRj#pQb-Hg&dAh}*=2;JY*aiNZzT=IU&v|lQY%Q|=^V5pvTR7^t9+@+ST&sr!J1Y9a z514dYZn5rg6@4Cy6P`-?!3Y& z?B*5zw!mTiD2)>f@3XYrW^9V-@%YFkE_;PCyCJ7*?_3cR%tHng9%ZpIU}LJM=a+0s z(SDDLvcVa~b9O!cVL8)Q{d^R^(bbG=Ia$)dVN_tGMee3PMssZ7Z;c^Vg_1CjZYTnq z)wnF8?=-MmqVOMX!iE?YDvHCN?%TQtKJMFHp$~kX4}jZ;EDqP$?jqJZjoa2PM@$uZ zF4}iab1b5ep)L;jdegC3{K4VnCH#OV;pRcSa(&Nm50ze-yZ8*cGv;@+N+A?ncc^2z9~|(xFhwOHmPW@ zR5&)E^YKQj@`g=;zJ_+CLamsPuvppUr$G1#9urUj+p-mPW_QSSHkPMS!52t>Hqy|g z_@Yu3z%|wE=uYq8G>4`Q!4zivS}+}{m5Zjr7kMRGn_p&hNf|pc&f9iQ`^%78rl#~8 z;os@rpMA{ZioY~(Rm!Wf#Wx##A0PthOI341QiJ=G*#}pDAkDm+{0kz&*NB?rC0-)glB{0_Tq*^o zVS1>3REsv*Qb;qg!G^9;VoK)P*?f<*H&4Su1=}bP^Y<2PwFpoqw#up4IgX3L z`w~8jsFCI3k~Y9g(Y9Km`y$0FS5vHb)kb)Jb6q-9MbO{Hbb zxg?IWQ1ZIGgE}wKm{axO6CCh~4DyoFU+i1xn#oyfe+<{>=^B5tm!!*1M?AW8c=6g+%2Ft97_Hq&ZmOGvqGQ!Bn<_Vw`0DRuDoB6q8ME<;oL4kocr8E$NGoLI zXWmI7Af-DR|KJw!vKp2SI4W*x%A%5BgDu%8%Iato+pWo5`vH@!XqC!yK}KLzvfS(q z{!y(S-PKbk!qHsgVyxKsQWk_8HUSSmslUA9nWOjkKn0%cwn%yxnkfxn?Y2rysXKS=t-TeI%DN$sQ{lcD!(s>(4y#CSxZ4R} zFDI^HPC_l?uh_)-^ppeYRkPTPu~V^0Mt}#jrTL1Q(M;qVt4zb(L|J~sxx7Lva9`mh zz!#A9tA*6?q)xThc7(gB2Ryam$YG4qlh00c}r&$y6u zIN#Qxn{7RKJ+_r|1G1KEv!&uKfXpOVZ8tK{M775ws%nDyoZ?bi3NufNbZs)zqXiqc zqOsK@^OnlFMAT&mO3`@3nZP$3lLF;ds|;Z{W(Q-STa2>;)tjhR17OD|G>Q#zJHb*> zMO<{WIgB%_4MG0SQi2;%f0J8l_FH)Lfaa>*GLobD#AeMttYh4Yfg22@q4|Itq};NB z8;o*+@APqy@fPgrc&PTbGEwdEK=(x5K!If@R$NiO^7{#j9{~w=RBG)ZkbOw@$7Nhl zyp{*&QoVBd5lo{iwl2gfyip@}IirZK;ia(&ozNl!-EEYc=QpYH_= zJkv7gA{!n4up6$CrzDJIBAdC7D5D<_VLH*;OYN>_Dx3AT`K4Wyx8Tm{I+xplKP6k7 z2sb!i7)~%R#J0$|hK?~=u~rnH7HCUpsQJujDDE*GD`qrWWog+C+E~GGy|Hp_t4--} zrxtrgnPh}r=9o}P6jpAQuDN}I*GI`8&%Lp-C0IOJt#op)}XSr!ova@w{jG2V=?GXl3zEJJFXg)U3N>BQP z*Lb@%Mx|Tu;|u>$-K(q^-HG!EQ3o93%w(A7@ngGU)HRWoO&&^}U$5x+T&#zri>6ct zXOB#EF-;z3j311K`jrYyv6pOPF=*`SOz!ack=DuEi({UnAkL5H)@R?YbRKAeP|06U z?-Ns0ZxD0h9D8)P66Sq$w-yF+1hEVTaul%&=kKDrQtF<$RnQPZ)ezm1`aHIjAY=!S z`%vboP`?7mItgEo4w50C*}Ycqp9_3ZEr^F1;cEhkb`BNhbc6PvnXu@wi=AoezF4~K zkxx%ps<8zb=wJ+9I8o#do)&{(=yAlNdduaDn!=xGSiuo~fLw~Edw$6;l-qaq#Z7?# zGrdU(Cf-V@$x>O%yRc6!C1Vf`b19ly;=mEu8u9|zitcG^O`lbNh}k=$%a)UHhDwTEKis2yc4rBGR>l*(B$AC7ung&ssaZGkY-h(fpwcPyJSx*9EIJMRKbMP9}$nVrh6$g-Q^5Cw)BeWqb-qi#37ZXKL!GR;ql)~ z@PP*-oP?T|ThqlGKR84zi^CN z4TZ1A)7vL>ivoL2EU_~xl-P{p+sE}9CRwGJDKy{>0KP+gj`H9C+4fUMPnIB1_D`A- z$1`G}g0lQmqMN{Y&8R*$xYUB*V}dQPxGVZQ+rH!DVohIoTbh%#z#Tru%Px@C<=|og zGDDwGq7yz`%^?r~6t&>x*^We^tZ4!E4dhwsht#Pb1kCY{q#Kv;z%Dp#Dq;$vH$-(9 z8S5tutZ}&JM2Iw&Y-7KY4h5BBvS=Ove0#+H2qPdR)WyI zYcj)vB=MA{7T|3Ij_PN@FM@w(C9ANBq&|NoW30ccr~i#)EcH)T^3St~rJ0HKKd4wr z@_+132;Bj+>UC@h)Ap*8B4r5A1lZ!Dh%H7&&hBnlFj@eayk=VD*i5AQc z$uN8YG#PL;cuQa)Hyt-}R?&NAE1QT>svJDKt*)AQOZAJ@ zyxJoBebiobHeFlcLwu_iI&NEZuipnOR;Tn;PbT1Mt-#5v5b*8ULo7m)L-eti=UcGf zRZXidmxeFgY!y80-*PH-*=(-W+fK%KyUKpg$X@tuv``tXj^*4qq@UkW$ZrAo%+hay zU@a?z&2_@y)o@D!_g>NVxFBO!EyB&6Z!nd4=KyDP^hl!*(k{dEF6@NkXztO7gIh zQ&PC+p-8WBv;N(rpfKdF^@Z~|E6pa)M1NBUrCZvLRW$%N%xIbv^uv?=C!=dDVq3%* zgvbEBnG*JB*@vXx8>)7XL*!{1Jh=#2UrByF7U?Rj_}VYw88BwqefT_cCTv8aTrRVjnn z1HNCF=44?*&gs2`vCGJVHX@kO z240eo#z+FhI0=yy6NHQwZs}a+J~4U-6X`@ zZ7j+tb##m`x%J66$a9qXDHG&^kp|GkFFMmjD(Y-k_ClY~N$H|n@NkSDz=gg?*2ga5 z)+f)MEY>2Lp15;~o`t`qj;S>BaE;%dv@Ux11yq}I(k|o&`5UZFUHn}1kE^gIK@qV& z!S2IhyU;->VfA4Qb}m7YnkIa9%z{l~iPWo2YPk-`hy2-Eg=6E$21plQA5W2qMZDFU z-a-@Dndf%#on6chT`dOKnU9}BJo|kJwgGC<^nfo34zOKH96LbWY7@Wc%EoFF=}`VU zksP@wd%@W;-p!e^&-)N7#oR331Q)@9cx=mOoU?_Kih2!Le*8fhsZ8Qvo6t2vt+UOZ zw|mCB*t2%z21YqL>whu!j?s~}-L`OS+jdg1(XnmYw$rg~r(?5Y+qTg`$F}q3J?GtL z@BN&8#`u2RqkdG4yGGTus@7U_%{6C{XAhFE!2SelH?KtMtX@B1GBhEIDL-Bj#~{4! zd}p7!#XE9Lt;sy@p5#Wj*jf8zGv6tTotCR2X$EVOOup;GnRPRVU5A6N@Lh8?eA7k? zn~hz&gY;B0ybSpF?qwQ|sv_yO=8}zeg2$0n3A8KpE@q26)?707pPw?H76lCpjp=5r z6jjp|auXJDnW}uLb6d7rsxekbET9(=zdTqC8(F5@NNqII2+~yB;X5iJNQSiv`#ozm zf&p!;>8xAlwoxUC3DQ#!31ylK%VrcwS<$WeCY4V63V!|221oj+5#r}fGFQ}|uwC0) zNl8(CF}PD`&Sj+p{d!B&&JtC+VuH z#>US`)YQrhb6lIAYb08H22y(?)&L8MIQsA{26X`R5Km{YU)s!x(&gIsjDvq63@X`{ z=7{SiH*_ZsPME#t2m|bS76Uz*z{cpp1m|s}HIX}Ntx#v7Eo!1%G9__4dGSGl`p+xi zZ!VK#Qe;Re=9bqXuW+0DSP{uZ5-QXrNn-7qW19K0qU}OhVru7}3vqsG?#D67 zb}crN;QwsH*vymw(maZr_o|w&@sQki(X+D)gc5Bt&@iXisFG;eH@5d43~Wxq|HO(@ zV-rip4n#PEkHCWCa5d?@cQp^B;I-PzOfag|t-cuvTapQ@MWLmh*41NH`<+A+JGyKX zyYL6Ba7qqa5j@3lOk~`OMO7f0!@FaOeZxkbG@vXP(t3#U*fq8=GAPqUAS>vW2uxMk{a(<0=IxB;# zMW;M+owrHaZBp`3{e@7gJCHP!I(EeyGFF;pdFPdeP+KphrulPSVidmg#!@W`GpD&d z9p6R`dpjaR2E1Eg)Ws{BVCBU9-aCgN57N~uLvQZH`@T+2eOBD%73rr&sV~m#2~IZx zY_8f8O;XLu2~E3JDXnGhFvsyb^>*!D>5EtlKPe%kOLv6*@=Jpci`8h0z?+fbBUg_7 zu6DjqO=$SjAv{|Om5)nz41ZkS4E_|fk%NDY509VV5yNeo%O|sb>7C#wj8mL9cEOFh z>nDz%?vb!h*!0dHdnxDA>97~EoT~!N40>+)G2CeYdOvJr5^VnkGz)et&T9hrD(VAgCAJjQ7V$O?csICB*HFd^k@$M5*v$PZJD-OVL?Ze(U=XGqZPVG8JQ z<~ukO%&%nNXYaaRibq#B1KfW4+XMliC*Tng2G(T1VvP;2K~;b$EAqthc${gjn_P!b zs62UT(->A>!ot}cJXMZHuy)^qfqW~xO-In2);e>Ta{LD6VG2u&UT&a@>r-;4<)cJ9 zjpQThb4^CY)Ev0KR7TBuT#-v}W?Xzj{c7$S5_zJA57Qf=$4^npEjl9clH0=jWO8sX z3Fuu0@S!WY>0XX7arjH`?)I<%2|8HfL!~#c+&!ZVmhbh`wbzy0Ux|Jpy9A{_7GGB0 zadZ48dW0oUwUAHl%|E-Q{gA{z6TXsvU#Hj09<7i)d}wa+Iya)S$CVwG{4LqtB>w%S zKZx(QbV7J9pYt`W4+0~f{hoo5ZG<0O&&5L57oF%hc0xGJ@Zrg_D&lNO=-I^0y#3mxCSZFxN2-tN_mU@7<@PnWG?L5OSqkm8TR!`| zRcTeWH~0z1JY^%!N<(TtxSP5^G9*Vw1wub`tC-F`=U)&sJVfvmh#Pi`*44kSdG};1 zJbHOmy4Ot|%_?@$N?RA9fF?|CywR8Sf(SCN_luM8>(u0NSEbKUy7C(Sk&OuWffj)f za`+mo+kM_8OLuCUiA*CNE|?jra$M=$F3t+h-)?pXz&r^F!ck;r##`)i)t?AWq-9A9 zSY{m~TC1w>HdEaiR*%j)L);H{IULw)uxDO>#+WcBUe^HU)~L|9#0D<*Ld459xTyew zbh5vCg$a>`RCVk)#~ByCv@Ce!nm<#EW|9j><#jQ8JfTmK#~jJ&o0Fs9jz0Ux{svdM4__<1 zrb>H(qBO;v(pXPf5_?XDq!*3KW^4>(XTo=6O2MJdM^N4IIcYn1sZZpnmMAEdt}4SU zPO54j2d|(xJtQ9EX-YrlXU1}6*h{zjn`in-N!Ls}IJsG@X&lfycsoCemt_Ym(PXhv zc*QTnkNIV=Ia%tg%pwJtT^+`v8ng>;2~ps~wdqZSNI7+}-3r+#r6p`8*G;~bVFzg= z!S3&y)#iNSUF6z;%o)%h!ORhE?CUs%g(k2a-d576uOP2@QwG-6LT*G!I$JQLpd`cz z-2=Brr_+z96a0*aIhY2%0(Sz=|D`_v_7h%Yqbw2)8@1DwH4s*A82krEk{ zoa`LbCdS)R?egRWNeHV8KJG0Ypy!#}kslun?67}^+J&02!D??lN~t@;h?GS8#WX`)6yC**~5YNhN_Hj}YG<%2ao^bpD8RpgV|V|GQwlL27B zEuah|)%m1s8C6>FLY0DFe9Ob66fo&b8%iUN=y_Qj;t3WGlNqP9^d#75ftCPA*R4E8 z)SWKBKkEzTr4JqRMEs`)0;x8C35yRAV++n(Cm5++?WB@ya=l8pFL`N0ag`lWhrYo3 zJJ$< zQ*_YAqIGR*;`VzAEx1Pd4b3_oWtdcs7LU2#1#Ls>Ynvd8k^M{Ef?8`RxA3!Th-?ui{_WJvhzY4FiPxA?E4+NFmaC-Uh*a zeLKkkECqy>Qx&1xxEhh8SzMML=8VP}?b*sgT9ypBLF)Zh#w&JzP>ymrM?nnvt!@$2 zh>N$Q>mbPAC2kNd&ab;FkBJ}39s*TYY0=@e?N7GX>wqaM>P=Y12lciUmve_jMF0lY zBfI3U2{33vWo(DiSOc}!5##TDr|dgX1Uojq9!vW3$m#zM_83EGsP6&O`@v-PDdO3P z>#!BEbqpOXd5s?QNnN!p+92SHy{sdpePXHL{d@c6UilT<#~I!tH$S(~o}c#(j<2%! zQvm}MvAj-95Ekx3D4+|e%!?lO(F+DFw9bxb-}rsWQl)b44###eUg4N?N-P(sFH2hF z`{zu?LmAxn2=2wCE8?;%ZDi#Y;Fzp+RnY8fWlzVz_*PDO6?Je&aEmuS>=uCXgdP6r zoc_JB^TA~rU5*geh{G*gl%_HnISMS~^@{@KVC;(aL^ZA-De+1zwUSXgT>OY)W?d6~ z72znET0m`53q%AVUcGraYxIcAB?OZA8AT!uK8jU+=t;WneL~|IeQ>$*dWa#x%rB(+ z5?xEkZ&b{HsZ4Ju9TQ|)c_SIp`7r2qMJgaglfSBHhl)QO1aNtkGr0LUn{@mvAt=}nd7#>7ru}&I)FNsa*x?Oe3-4G`HcaR zJ}c%iKlwh`x)yX1vBB;-Nr=7>$~(u=AuPX2#&Eh~IeFw%afU+U)td0KC!pHd zyn+X$L|(H3uNit-bpn7%G%{&LsAaEfEsD?yM<;U2}WtD4KuVKuX=ec9X zIe*ibp1?$gPL7<0uj*vmj2lWKe`U(f9E{KVbr&q*RsO;O>K{i-7W)8KG5~~uS++56 zm@XGrX@x+lGEjDQJp~XCkEyJG5Y57omJhGN{^2z5lj-()PVR&wWnDk2M?n_TYR(gM zw4kQ|+i}3z6YZq8gVUN}KiYre^sL{ynS}o{z$s&I z{(rWaLXxcQ=MB(Cz7W$??Tn*$1y(7XX)tv;I-{7F$fPB%6YC7>-Dk#=Y8o1=&|>t5 zV_VVts>Eb@)&4%m}!K*WfLoLl|3FW)V~E1Z!yu`Sn+bAP5sRDyu7NEbLt?khAyz-ZyL-}MYb&nQ zU16f@q7E1rh!)d%f^tTHE3cVoa%Xs%rKFc|temN1sa)aSlT*)*4k?Z>b3NP(IRXfq zlB^#G6BDA1%t9^Nw1BD>lBV(0XW5c?l%vyB3)q*;Z5V~SU;HkN;1kA3Nx!$!9wti= zB8>n`gt;VlBt%5xmDxjfl0>`K$fTU-C6_Z;!A_liu0@Os5reMLNk;jrlVF^FbLETI zW+Z_5m|ozNBn7AaQ<&7zk}(jmEdCsPgmo%^GXo>YYt82n&7I-uQ%A;k{nS~VYGDTn zlr3}HbWQG6xu8+bFu^9%%^PYCbkLf=*J|hr>Sw+#l(Y#ZGKDufa#f-f0k-{-XOb4i zwVG1Oa0L2+&(u$S7TvedS<1m45*>a~5tuOZ;3x%!f``{=2QQlJk|b4>NpD4&L+xI+ z+}S(m3}|8|Vv(KYAGyZK5x*sgwOOJklN0jsq|BomM>OuRDVFf_?cMq%B*iQ*&|vS9 zVH7Kh)SjrCBv+FYAE=$0V&NIW=xP>d-s7@wM*sdfjVx6-Y@=~>rz%2L*rKp|*WXIz z*vR^4tV&7MQpS9%{9b*>E9d_ls|toL7J|;srnW{l-}1gP_Qr-bBHt=}PL@WlE|&KH zCUmDLZb%J$ZzNii-5VeygOM?K8e$EcK=z-hIk63o4y63^_*RdaitO^THC{boKstphXZ2Z+&3ToeLQUG(0Frs?b zCxB+65h7R$+LsbmL51Kc)pz_`YpGEzFEclzb=?FJ=>rJwgcp0QH-UuKRS1*yCHsO) z-8t?Zw|6t($Eh&4K+u$I7HqVJBOOFCRcmMMH};RX_b?;rnk`rz@vxT_&|6V@q0~Uk z9ax|!pA@Lwn8h7syrEtDluZ6G!;@=GL> zse#PRQrdDs=qa_v@{Wv(3YjYD0|qocDC;-F~&{oaTP?@pi$n z1L6SlmFU2~%)M^$@C(^cD!y)-2SeHo3t?u3JiN7UBa7E2 z;<+_A$V084@>&u)*C<4h7jw9joHuSpVsy8GZVT;(>lZ(RAr!;)bwM~o__Gm~exd`K zKEgh2)w?ReH&syI`~;Uo4`x4$&X+dYKI{e`dS~bQuS|p zA`P_{QLV3r$*~lb=9vR^H0AxK9_+dmHX}Y} zIV*#65%jRWem5Z($ji{!6ug$En4O*=^CiG=K zp4S?+xE|6!cn$A%XutqNEgUqYY3fw&N(Z6=@W6*bxdp~i_yz5VcgSj=lf-6X1Nz75 z^DabwZ4*70$$8NsEy@U^W67tcy7^lNbu;|kOLcJ40A%J#pZe0d#n zC{)}+p+?8*ftUlxJE*!%$`h~|KZSaCb=jpK3byAcuHk7wk@?YxkT1!|r({P*KY^`u z!hw#`5$JJZGt@nkBK_nwWA31_Q9UGvv9r-{NU<&7HHMQsq=sn@O?e~fwl20tnSBG* zO%4?Ew6`aX=I5lqmy&OkmtU}bH-+zvJ_CFy z_nw#!8Rap5Wcex#5}Ldtqhr_Z$}@jPuYljTosS1+WG+TxZ>dGeT)?ZP3#3>sf#KOG z0)s%{cEHBkS)019}-1A2kd*it>y65-C zh7J9zogM74?PU)0c0YavY7g~%j%yiWEGDb+;Ew5g5Gq@MpVFFBNOpu0x)>Yn>G6uo zKE%z1EhkG_N5$a8f6SRm(25iH#FMeaJ1^TBcBy<04ID47(1(D)q}g=_6#^V@yI?Y&@HUf z`;ojGDdsvRCoTmasXndENqfWkOw=#cV-9*QClpI03)FWcx(m5(P1DW+2-{Hr-`5M{v##Zu-i-9Cvt;V|n)1pR^y ztp3IXzHjYWqabuPqnCY9^^;adc!a%Z35VN~TzwAxq{NU&Kp35m?fw_^D{wzB}4FVXX5Zk@#={6jRh%wx|!eu@Xp;%x+{2;}!&J4X*_SvtkqE#KDIPPn@ z5BE$3uRlb>N<2A$g_cuRQM1T#5ra9u2x9pQuqF1l2#N{Q!jVJ<>HlLeVW|fN|#vqSnRr<0 zTVs=)7d`=EsJXkZLJgv~9JB&ay16xDG6v(J2eZy;U%a@EbAB-=C?PpA9@}?_Yfb&) zBpsih5m1U9Px<+2$TBJ@7s9HW>W){i&XKLZ_{1Wzh-o!l5_S+f$j^RNYo85}uVhN# zq}_mN-d=n{>fZD2Lx$Twd2)}X2ceasu91}n&BS+4U9=Y{aZCgV5# z?z_Hq-knIbgIpnkGzJz-NW*=p?3l(}y3(aPCW=A({g9CpjJfYuZ%#Tz81Y)al?!S~ z9AS5#&nzm*NF?2tCR#|D-EjBWifFR=da6hW^PHTl&km-WI9*F4o>5J{LBSieVk`KO z2(^9R(zC$@g|i3}`mK-qFZ33PD34jd_qOAFj29687wCUy>;(Hwo%Me&c=~)V$ua)V zsaM(aThQ3{TiM~;gTckp)LFvN?%TlO-;$y+YX4i`SU0hbm<})t0zZ!t1=wY&j#N>q zONEHIB^RW6D5N*cq6^+?T}$3m|L{Fe+L!rxJ=KRjlJS~|z-&CC{#CU8`}2|lo~)<| zk?Wi1;Cr;`?02-C_3^gD{|Ryhw!8i?yx5i0v5?p)9wZxSkwn z3C;pz25KR&7{|rc4H)V~y8%+6lX&KN&=^$Wqu+}}n{Y~K4XpI-#O?L=(2qncYNePX zTsB6_3`7q&e0K67=Kg7G=j#?r!j0S^w7;0?CJbB3_C4_8X*Q%F1%cmB{g%XE&|IA7 z(#?AeG{l)s_orNJp!$Q~qGrj*YnuKlV`nVdg4vkTNS~w$4d^Oc3(dxi(W5jq0e>x} z(GN1?u2%Sy;GA|B%Sk)ukr#v*UJU%(BE9X54!&KL9A^&rR%v zIdYt0&D59ggM}CKWyxGS@ z>T#})2Bk8sZMGJYFJtc>D#k0+Rrrs)2DG;(u(DB_v-sVg=GFMlSCx<&RL;BH}d6AG3VqP!JpC0Gv6f8d|+7YRC@g|=N=C2 zo>^0CE0*RW?W))S(N)}NKA)aSwsR{1*rs$(cZIs?nF9)G*bSr%%SZo^YQ|TSz={jX z4Z+(~v_>RH0(|IZ-_D_h@~p_i%k^XEi+CJVC~B zsPir zA0Jm2yIdo4`&I`hd%$Bv=Rq#-#bh{Mxb_{PN%trcf(#J3S1UKDfC1QjH2E;>wUf5= ze8tY9QSYx0J;$JUR-0ar6fuiQTCQP#P|WEq;Ez|*@d?JHu-(?*tTpGHC+=Q%H>&I> z*jC7%nJIy+HeoURWN%3X47UUusY2h7nckRxh8-)J61Zvn@j-uPA@99|y48pO)0XcW zX^d&kW^p7xsvdX?2QZ8cEUbMZ7`&n{%Bo*xgFr4&fd#tHOEboQos~xm8q&W;fqrj} z%KYnnE%R`=`+?lu-O+J9r@+$%YnqYq!SVs>xp;%Q8p^$wA~oynhnvIFp^)Z2CvcyC zIN-_3EUHW}1^VQ0;Oj>q?mkPx$Wj-i7QoXgQ!HyRh6Gj8p~gH22k&nmEqUR^)9qni{%uNeV{&0-H60C zibHZtbV=8=aX!xFvkO}T@lJ_4&ki$d+0ns3FXb+iP-VAVN`B7f-hO)jyh#4#_$XG%Txk6M<+q6D~ zi*UcgRBOoP$7P6RmaPZ2%MG}CMfs=>*~(b97V4+2qdwvwA@>U3QQAA$hiN9zi%Mq{ z*#fH57zUmi)GEefh7@`Uy7?@@=BL7cXbd{O9)*lJh*v!@ z-6}p9u0AreiGauxn7JBEa-2w&d=!*TLJ49`U@D7%2ppIh)ynMaAE2Q4dl@47cNu{9 z&3vT#pG$#%hrXzXsj=&Ss*0;W`Jo^mcy4*L8b^sSi;H{*`zW9xX2HAtQ*sO|x$c6UbRA(7*9=;D~(%wfo(Z6#s$S zuFk`dr%DfVX5KC|Af8@AIr8@OAVj=6iX!~8D_P>p7>s!Hj+X0_t}Y*T4L5V->A@Zx zcm1wN;TNq=h`5W&>z5cNA99U1lY6+!!u$ib|41VMcJk8`+kP{PEOUvc@2@fW(bh5pp6>C3T55@XlpsAd#vn~__3H;Dz2w=t9v&{v*)1m4)vX;4 zX4YAjM66?Z7kD@XX{e`f1t_ZvYyi*puSNhVPq%jeyBteaOHo7vOr8!qqp7wV;)%jtD5>}-a?xavZ;i|2P3~7c)vP2O#Fb`Y&Kce zQNr7%fr4#S)OOV-1piOf7NgQvR{lcvZ*SNbLMq(olrdDC6su;ubp5un!&oT=jVTC3uTw7|r;@&y*s)a<{J zkzG(PApmMCpMmuh6GkM_`AsBE@t~)EDcq1AJ~N@7bqyW_i!mtHGnVgBA`Dxi^P93i z5R;}AQ60wy=Q2GUnSwz+W6C^}qn`S-lY7=J(3#BlOK%pCl=|RVWhC|IDj1E#+|M{TV0vE;vMZLy7KpD1$Yk zi0!9%qy8>CyrcRK`juQ)I};r)5|_<<9x)32b3DT1M`>v^ld!yabX6@ihf`3ZVTgME zfy(l-ocFuZ(L&OM4=1N#Mrrm_<>1DZpoWTO70U8+x4r3BpqH6z@(4~sqv!A9_L}@7 z7o~;|?~s-b?ud&Wx6==9{4uTcS|0-p@dKi0y#tPm2`A!^o3fZ8Uidxq|uz2vxf;wr zM^%#9)h^R&T;}cxVI(XX7kKPEVb);AQO?cFT-ub=%lZPwxefymBk+!H!W(o(>I{jW z$h;xuNUr#^0ivvSB-YEbUqe$GLSGrU$B3q28&oA55l)ChKOrwiTyI~e*uN;^V@g-Dm4d|MK!ol8hoaSB%iOQ#i_@`EYK_9ZEjFZ8Ho7P^er z^2U6ZNQ{*hcEm?R-lK)pD_r(e=Jfe?5VkJ$2~Oq^7YjE^5(6a6Il--j@6dBHx2Ulq z!%hz{d-S~i9Eo~WvQYDt7O7*G9CP#nrKE#DtIEbe_uxptcCSmYZMqT2F}7Kw0AWWC zPjwo0IYZ6klc(h9uL|NY$;{SGm4R8Bt^^q{e#foMxfCSY^-c&IVPl|A_ru!ebwR#7 z3<4+nZL(mEsU}O9e`^XB4^*m)73hd04HH%6ok^!;4|JAENnEr~%s6W~8KWD)3MD*+ zRc46yo<}8|!|yW-+KulE86aB_T4pDgL$XyiRW(OOcnP4|2;v!m2fB7Hw-IkY#wYfF zP4w;k-RInWr4fbz=X$J;z2E8pvAuy9kLJUSl8_USi;rW`kZGF?*Ur%%(t$^{Rg!=v zg;h3@!Q$eTa7S0#APEDHLvK%RCn^o0u!xC1Y0Jg!Baht*a4mmKHy~88md{YmN#x) zBOAp_i-z2h#V~*oO-9k(BizR^l#Vm%uSa^~3337d;f=AhVp?heJ)nlZGm`}D(U^2w z#vC}o1g1h?RAV^90N|Jd@M00PoNUPyA?@HeX0P7`TKSA=*4s@R;Ulo4Ih{W^CD{c8 ze(ipN{CAXP(KHJ7UvpOc@9SUAS^wKo3h-}BDZu}-qjdNlVtp^Z{|CxKOEo?tB}-4; zEXyDzGbXttJ3V$lLo-D?HYwZm7vvwdRo}P#KVF>F|M&eJ44n*ZO~0)#0e0Vy&j00I z{%IrnUvKp70P?>~J^$^0Wo%>le>re2ZSvRfes@dC-*e=DD1-j%<$^~4^4>Id5w^Fr z{RWL>EbUCcyC%1980kOYqZAcgdz5cS8c^7%vvrc@CSPIx;X=RuodO2dxk17|am?HJ@d~Mp_l8H?T;5l0&WGFoTKM{eP!L-a0O8?w zgBPhY78tqf^+xv4#OK2I#0L-cSbEUWH2z+sDur85*!hjEhFfD!i0Eyr-RRLFEm5(n z-RV6Zf_qMxN5S6#8fr9vDL01PxzHr7wgOn%0Htmvk9*gP^Um=n^+7GLs#GmU&a#U^4jr)BkIubQO7oUG!4CneO2Ixa`e~+Jp9m{l6apL8SOqA^ zvrfEUPwnHQ8;yBt!&(hAwASmL?Axitiqvx%KZRRP?tj2521wyxN3ZD9buj4e;2y6U zw=TKh$4%tt(eh|y#*{flUJ5t4VyP*@3af`hyY^YU3LCE3Z|22iRK7M7E;1SZVHbXF zKVw!L?2bS|kl7rN4(*4h2qxyLjWG0vR@`M~QFPsf^KParmCX;Gh4OX6Uy9#4e_%oK zv1DRnfvd$pu(kUoV(MmAc09ckDiuqS$a%!AQ1Z>@DM#}-yAP$l`oV`BDYpkqpk(I|+qk!yoo$TwWr6dRzLy(c zi+qbVlYGz0XUq@;Fm3r~_p%by)S&SVWS+wS0rC9bk^3K^_@6N5|2rtF)wI>WJ=;Fz zn8$h<|Dr%kN|nciMwJAv;_%3XG9sDnO@i&pKVNEfziH_gxKy{l zo`2m4rnUT(qenuq9B0<#Iy(RPxP8R)=5~9wBku=%&EBoZ82x1GlV<>R=hIqf0PK!V zw?{z9e^B`bGyg2nH!^x}06oE%J_JLk)^QyHLipoCs2MWIqc>vaxsJj(=gg1ZSa=u{ zt}od#V;e7sA4S(V9^<^TZ#InyVBFT(V#$fvI7Q+pgsr_2X`N~8)IOZtX}e(Bn(;eF zsNj#qOF_bHl$nw5!ULY{lNx@93Fj}%R@lewUuJ*X*1$K`DNAFpE z7_lPE+!}uZ6c?+6NY1!QREg#iFy=Z!OEW}CXBd~wW|r_9%zkUPR0A3m+@Nk%4p>)F zXVut7$aOZ6`w}%+WV$te6-IX7g2yms@aLygaTlIv3=Jl#Nr}nN zp|vH-3L03#%-1-!mY`1z?+K1E>8K09G~JcxfS)%DZbteGQnQhaCGE2Y<{ut#(k-DL zh&5PLpi9x3$HM82dS!M?(Z zEsqW?dx-K_GMQu5K54pYJD=5+Rn&@bGjB?3$xgYl-|`FElp}?zP&RAd<522c$Rv6} zcM%rYClU%JB#GuS>FNb{P2q*oHy}UcQ-pZ2UlT~zXt5*k-ZalE(`p7<`0n7i(r2k{ zb84&^LA7+aW1Gx5!wK!xTbw0slM?6-i32CaOcLC2B>ZRI16d{&-$QBEu1fKF0dVU>GTP05x2>Tmdy`75Qx! z^IG;HB9V1-D5&&)zjJ&~G}VU1-x7EUlT3QgNT<&eIDUPYey$M|RD6%mVkoDe|;2`8Z+_{0&scCq>Mh3hj|E*|W3;y@{$qhu77D)QJ` znD9C1AHCKSAHQqdWBiP`-cAjq7`V%~JFES1=i-s5h6xVT<50kiAH_dn0KQB4t*=ua zz}F@mcKjhB;^7ka@WbSJFZRPeYI&JFkpJ-!B z!ju#!6IzJ;D@$Qhvz9IGY5!%TD&(db3<*sCpZ?U#1^9RWQ zs*O-)j!E85SMKtoZzE^8{w%E0R0b2lwwSJ%@E}Lou)iLmPQyO=eirG8h#o&E4~eew z;h><=|4m0$`ANTOixHQOGpksXlF0yy17E&JksB4_(vKR5s$Ve+i;gco2}^RRJI+~R zWJ82WGigLIUwP!uSELh3AAs9HmY-kz=_EL-w|9}noKE#(a;QBpEx9 z4BT-zY=6dJT>72Hkz=9J1E=}*MC;zzzUWb@x(Ho8cU_aRZ?fxse5_Ru2YOvcr?kg&pt@v;{ai7G--k$LQtoYj+Wjk+nnZty;XzANsrhoH#7=xVqfPIW(p zX5{YF+5=k4_LBnhLUZxX*O?29olfPS?u*ybhM_y z*XHUqM6OLB#lyTB`v<BZ&YRs$N)S@5Kn_b3;gjz6>fh@^j%y2-ya({>Hd@kv{CZZ2e)tva7gxLLp z`HoGW);eRtov~Ro5tetU2y72~ zQh>D`@dt@s^csdfN-*U&o*)i3c4oBufCa0e|BwT2y%Y~=U7A^ny}tx zHwA>Wm|!SCko~UN?hporyQHRUWl3djIc722EKbTIXQ6>>iC!x+cq^sUxVSj~u)dsY zW8QgfZlE*2Os%=K;_vy3wx{0u!2%A)qEG-$R^`($%AOfnA^LpkB_}Dd7AymC)zSQr z>C&N8V57)aeX8ap!|7vWaK6=-3~ko9meugAlBKYGOjc#36+KJwQKRNa_`W@7;a>ot zdRiJkz?+QgC$b}-Owzuaw3zBVLEugOp6UeMHAKo2$m4w zpw?i%Lft^UtuLI}wd4(-9Z^*lVoa}11~+0|Hs6zAgJ01`dEA&^>Ai=mr0nC%eBd_B zzgv2G_~1c1wr*q@QqVW*Wi1zn=}KCtSwLjwT>ndXE_Xa22HHL_xCDhkM( zhbw+j4uZM|r&3h=Z#YrxGo}GX`)AZyv@7#7+nd-D?BZV>thtc|3jt30j$9{aIw9)v zDY)*fsSLPQTNa&>UL^RWH(vpNXT7HBv@9=*=(Q?3#H*crA2>KYx7Ab?-(HU~a275)MBp~`P)hhzSsbj|d`aBe(L*(;zif{iFJu**ZR zkL-tPyh!#*r-JVQJq>5b0?cCy!uSKef+R=$s3iA7*k*_l&*e!$F zYwGI;=S^0)b`mP8&Ry@{R(dPfykD&?H)na^ihVS7KXkxb36TbGm%X1!QSmbV9^#>A z-%X>wljnTMU0#d;tpw?O1W@{X-k*>aOImeG z#N^x?ehaaQd}ReQykp>i;92q@%$a!y1PNyPYDIvMm& zyYVwn;+0({W@3h(r&i#FuCDE)AC(y&Vu>4?1@j0|CWnhHUx4|zL7cdaA32RSk?wl% zMK^n42@i5AU>f70(huWfOwaucbaToxj%+)7hnG^CjH|O`A}+GHZyQ-X57(WuiyRXV zPf>0N3GJ<2Myg!sE4XJY?Z7@K3ZgHy8f7CS5ton0Eq)Cp`iLROAglnsiEXpnI+S8; zZn>g2VqLxi^p8#F#Laf3<00AcT}Qh&kQnd^28u!9l1m^`lfh9+5$VNv=?(~Gl2wAl zx(w$Z2!_oESg_3Kk0hUsBJ<;OTPyL(?z6xj6LG5|Ic4II*P+_=ac7KRJZ`(k2R$L# zv|oWM@116K7r3^EL*j2ktjEEOY9c!IhnyqD&oy7+645^+@z5Y|;0+dyR2X6^%7GD* zXrbPqTO}O={ z4cGaI#DdpP;5u?lcNb($V`l>H7k7otl_jQFu1hh>=(?CTPN#IPO%O_rlVX}_Nq;L< z@YNiY>-W~&E@=EC5%o_z<^3YEw)i_c|NXxHF{=7U7Ev&C`c^0Z4-LGKXu*Hkk&Av= zG&RAv{cR7o4${k~f{F~J48Ks&o(D@j-PQ2`LL@I~b=ifx3q!p6`d>~Y!<-^mMk3)e zhi1;(YLU5KH}zzZNhl^`0HT(r`5FfmDEzxa zk&J7WQ|!v~TyDWdXQ)!AN_Y%xM*!jv^`s)A`|F%;eGg27KYsrCE2H}7*r)zvum6B{ z$k5Har9pv!dcG%f|3hE(#hFH+12RZPycVi?2y`-9I7JHryMn3 z9Y8?==_(vOAJ7PnT<0&85`_jMD0#ipta~Q3M!q5H1D@Nj-YXI$W%OQplM(GWZ5Lpq z-He6ul|3<;ZQsqs!{Y7x`FV@pOQc4|N;)qgtRe(Uf?|YqZv^$k8On7DJ5>f2%M=TV zw~x}9o=mh$JVF{v4H5Su1pq66+mhTG6?F>Do}x{V(TgFwuLfvNP^ijkrp5#s4UT!~ zEU7pr8aA)2z1zb|X9IpmJykQcqI#(rS|A4&=TtWu@g^;JCN`2kL}%+K!KlgC z>P)v+uCeI{1KZpewf>C=?N7%1e10Y3pQCZST1GT5fVyB1`q)JqCLXM zSN0qlreH1=%Zg-5`(dlfSHI&2?^SQdbEE&W4#%Eve2-EnX>NfboD<2l((>>34lE%) zS6PWibEvuBG7)KQo_`?KHSPk+2P;`}#xEs}0!;yPaTrR#j(2H|#-CbVnTt_?9aG`o z(4IPU*n>`cw2V~HM#O`Z^bv|cK|K};buJ|#{reT8R)f+P2<3$0YGh!lqx3&a_wi2Q zN^U|U$w4NP!Z>5|O)>$GjS5wqL3T8jTn%Vfg3_KnyUM{M`?bm)9oqZP&1w1)o=@+(5eUF@=P~ zk2B5AKxQ96n-6lyjh&xD!gHCzD$}OOdKQQk7LXS-fk2uy#h{ktqDo{o&>O!6%B|)` zg?|JgcH{P*5SoE3(}QyGc=@hqlB5w;bnmF#pL4iH`TSuft$dE5j^qP2S)?)@pjRQZ zBfo6g>c!|bN-Y|(Wah2o61Vd|OtXS?1`Fu&mFZ^yzUd4lgu7V|MRdGj3e#V`=mnk- zZ@LHn?@dDi=I^}R?}mZwduik!hC%=Hcl56u{Wrk1|1SxlgnzG&e7Vzh*wNM(6Y!~m z`cm8Ygc1$@z9u9=m5vs1(XXvH;q16fxyX4&e5dP-{!Kd555FD6G^sOXHyaCLka|8j zKKW^E>}>URx736WWNf?U6Dbd37Va3wQkiE;5F!quSnVKnmaIRl)b5rM_ICu4txs+w zj}nsd0I_VG^<%DMR8Zf}vh}kk;heOQTbl ziEoE;9@FBIfR7OO9y4Pwyz02OeA$n)mESpj zdd=xPwA`nO06uGGsXr4n>Cjot7m^~2X~V4yH&- zv2llS{|und45}Pm1-_W@)a-`vFBpD~>eVP(-rVHIIA|HD@%7>k8JPI-O*<7X{L*Ik zh^K`aEN!BteiRaY82FVo6<^8_22=aDIa8P&2A3V<(BQ;;x8Zs-1WuLRWjQvKv1rd2 zt%+fZ!L|ISVKT?$3iCK#7whp|1ivz1rV*R>yc5dS3kIKy_0`)n*%bfNyw%e7Uo}Mnnf>QwDgeH$X5eg_)!pI4EJjh6?kkG2oc6Af0py z(txE}$ukD|Zn=c+R`Oq;m~CSY{ebu9?!is}01sOK_mB?{lSY33E=!KkKtMeI*FO2b z%95awv9;Z|UDp3xm+aP*5I!R-_M2;GxeCRx3ATS0iF<_Do2Mi)Hk2 zjBF35VB>(oamIYjunu?g0O-?LuOvtfs5F(iiIicbu$HMPPF%F>pE@hIRjzT)>aa=m zwe;H9&+2|S!m74!E3xfO{l3E_ab`Q^tZ4yH9=~o2DUEtEMDqG=&D*8!>?2uao%w`&)THr z^>=L3HJquY>6)>dW4pCWbzrIB+>rdr{s}}cL_?#!sOPztRwPm1B=!jP7lQG|Iy6rP zVqZDNA;xaUx&xUt?Ox|;`9?oz`C0#}mc<1Urs#vTW4wd{1_r`eX=BeSV z_9WV*9mz>PH6b^z{VYQJ1nSTSqOFHE9u>cY)m`Q>=w1NzUShxcHsAxasnF2BG;NQ; zqL1tjLjImz_`q=|bAOr_i5_NEijqYZ^;d5y3ZFj6kCYakJh**N_wbfH;ICXq?-p#r z{{ljNDPSytOaG#7=yPmA&5gyYI%^7pLnMOw-RK}#*dk=@usL;|4US?{@K%7esmc&n z5$D*+l&C9)Bo@$d;Nwipd!68&+NnOj^<~vRcKLX>e03E|;to;$ndgR;9~&S-ly5gf z{rzj+j-g$;O|u?;wwxrEpD=8iFzUHQfl{B>bLHqH(9P zI59SS2PEBE;{zJUlcmf(T4DrcO?XRWR}?fekN<($1&AJTRDyW+D*2(Gyi?Qx-i}gy z&BpIO!NeVdLReO!YgdUfnT}7?5Z#~t5rMWqG+$N2n%5o#Np6ccNly}#IZQsW4?|NV zR9hrcyP(l#A+U4XcQvT;4{#i)dU>HK>aS!k1<3s2LyAhm2(!Nu%vRC9T`_yn9D+r} z1i&U~IcQ?4xhZYyH6WL-f%}qIhZkc&}n2N0PM| z6|XA9d-y;!`D{p;xu*gv7a|zaZ*MiQ)}zPzW4GB0mr)}N-DmB&hl1&x`2@sxN572_ zS)RdJyR%<7kW0v3Q_|57JKy&9tUdbqz}|hwn84}U*0r^jt6Ssrp+#1y=JBcZ+F`f(N?O0XL1OFGN`1-r?S<#t4*C9|y~e)!UYZ zRQ3M8m%~M)VriIvn~XzoP;5qeu(ZI>Y#r zAd)J)G9)*BeE%gmm&M@Olg3DI_zokjh9NvdGbT z+u4(Y&uC6tBBefIg~e=J#8i1Zxr>RT)#rGaB2C71usdsT=}mm`<#WY^6V{L*J6v&l z1^Tkr6-+^PA)yC;s1O^3Q!)Reb=fxs)P~I*?i&j{Vbb(Juc?La;cA5(H7#FKIj0Or zgV0BO{DUs`I9HgQ{-!g@5P^Vr|C4}~w6b=#`Zx0XcVSd?(04HUHwK(gJNafgQNB9Z zCi3TgNXAeJ+x|X|b@27$RxuYYuNSUBqo#uyiH6H(b~K*#!@g__4i%HP5wb<+Q7GSb zTZjJw96htUaGZ89$K_iBo4xEOJ#DT#KRu9ozu!GH0cqR>hP$nk=KXM%Y!(%vWQ#}s zy=O#BZ>xjUejMH^F39Bf0}>D}yiAh^toa-ts#gt6Mk9h1D<9_mGMBhLT0Ce2O3d_U znaTkBaxd-8XgwSp5)x-pqX5=+{cSuk6kyl@k|5DQ!5zLUVV%1X9vjY0gerbuG6nwZu5KDMdq(&UMLZ zy?jW#F6joUtVyz`Y?-#Yc0=i*htOFwQ3`hk$8oq35D}0m$FAOp#UFTV3|U3F>@N?d zeXLZCZjRC($%?dz(41e~)CN10qjh^1CdAcY(<=GMGk@`b1ptA&L*{L@_M{%Vd5b*x#b1(qh=7((<_l%ZUaHtmgq} zjchBdiis{Afxf@3CjPR09E*2#X(`W#-n`~6PcbaL_(^3tfDLk?Nb6CkW9v!v#&pWJ3iV-9hz zngp#Q`w`r~2wt&cQ9#S7z0CA^>Mzm7fpt72g<0y-KT{G~l-@L#edmjZQ}7{*$mLgSdJfS$Ge{hrD=mr;GD)uYq8}xS zT>(w_;}894Kb}(P5~FOpFIEjadhmxD(PsZbKwa-qxVa7Oc7~ebPKMeN(pCRzq8s@l z`|l^*X1eK1+Spz--WkSW_nK`Cs@JmkY4+p=U91nJoy{tSH;TzuIyS)Q_(S@;Iakua zpuDo5W54Mo;jY@Ly1dY)j|+M%$FJ0`C=FW#%UvOd&?p}0QqL20Xt!#pr8ujy6CA-2 zFz6Ex5H1i)c9&HUNwG{8K%FRK7HL$RJwvGakleLLo}tsb>t_nBCIuABNo$G--_j!gV&t8L^4N6wC|aLC)l&w04CD6Vc#h^(YH@Zs4nwUGkhc_-yt{dK zMZ<%$swLmUl8`E~RLihGt@J5v;r;vT&*Q!Cx zZ55-zpb;W7_Q{tf$mQvF61(K>kwTq0x{#Din||)B{+6O#ArLi)kiHWVC4`fOT&B(h zw&YV`J1|^FLx~9Q%r-SFhYl4PywI7sF2Q$>4o50~dfp5nn}XHv-_DM?RGs#+4gM;% znU>k=81G~f6u%^Z{bcX&sUv*h|L+|mNq=W43y@{~C zpL-TW3hYPs0^*OqS#KQwA^CGG_A-6#`_{1LBCD&*3nY0UHWJj1D|VP%oQlFxLllaA zVI@2^)HZ%E*=RbQcFOKIP7?+|_xVK+2oG(t_EGl2y;Ovox zZb^qVpe!4^reKvpIBFzx;Ji=PmrV>uu-Hb>`s?k?YZQ?>av45>i(w0V!|n?AP|v5H zm`e&Tgli#lqGEt?=(?~fy<(%#nDU`O@}Vjib6^rfE2xn;qgU6{u36j_+Km%v*2RLnGpsvS+THbZ>p(B zgb{QvqE?~50pkLP^0(`~K& zjT=2Pt2nSnwmnDFi2>;*C|OM1dY|CAZ5R|%SAuU|5KkjRM!LW_)LC*A zf{f>XaD+;rl6Y>Umr>M8y>lF+=nSxZX_-Z7lkTXyuZ(O6?UHw^q; z&$Zsm4U~}KLWz8>_{p*WQ!OgxT1JC&B&>|+LE3Z2mFNTUho<0u?@r^d=2 z-av!n8r#5M|F%l;=D=S1mGLjgFsiYAOODAR}#e^a8 zfVt$k=_o}kt3PTz?EpLkt54dY}kyd$rU zVqc9SN>0c z753j-gdN~UiW*FUDMOpYEkVzP)}{Ds*3_)ZBi)4v26MQr140|QRqhFoP=a|;C{#KS zD^9b-9HM11W+cb1Y)HAuk<^GUUo(ut!5kILBzAe)Vaxwu4Up!7Ql*#DDu z>EB84&xSrh>0jT!*X81jJQq$CRHqNj29!V3FN9DCx)~bvZbLwSlo3l^zPb1sqBnp) zfZpo|amY^H*I==3#8D%x3>zh#_SBf?r2QrD(Y@El!wa;Ja6G9Y1947P*DC|{9~nO& z*vDnnU!8(cV%HevsraF%Y%2{Z>CL0?64eu9r^t#WjW4~3uw8d}WHzsV%oq-T)Y z0-c!FWX5j1{1##?{aTeCW2b$PEnwe;t`VPCm@sQ`+$$L2=3kBR%2XU1{_|__XJ$xt zibjY2QlDVs)RgHH*kl&+jn*JqquF)k_Ypibo00lcc<2RYqsi-G%}k0r(N97H7JEn7@E3ZTH0JK>d8)E~A-D z!B&z9zJw0Bi^fgQZI%LirYaBKnWBXgc`An*qvO^*$xymqKOp(+3}IsnVhu?YnN7qz zNJxDN-JWd7-vIiv2M9ih>x3gNVY%DzzY~dCnA}76IRl!`VM=6=TYQ=o&uuE8kHqZT zoUNod0v+s9D)7aLJ|hVqL0li1hg)%&MAciI(4YJ=%D4H$fGQ&Lu-?@>>@pEgC;ERrL= zI^cS&3q8fvEGTJZgZwL5j&jp%j9U^Of6pR{wA^u=tVt#yCQepXNIbynGnuWbsC_EE zRyMFq{5DK692-*kyGy~An>AdVR9u___fzmmJ4;^s0yAGgO^h{YFmqJ%ZJ_^0BgCET zE6(B*SzeZ4pAxear^B-YW<%BK->X&Cr`g9_;qH~pCle# zdY|UB5cS<}DFRMO;&czbmV(?vzikf)Ks`d$LL801@HTP5@r><}$xp}+Ip`u_AZ~!K zT}{+R9Wkj}DtC=4QIqJok5(~0Ll&_6PPVQ`hZ+2iX1H{YjI8axG_Bw#QJy`6T>1Nn z%u^l`>XJ{^vX`L0 z1%w-ie!dE|!SP<>#c%ma9)8K4gm=!inHn2U+GR+~ zqZVoa!#aS0SP(|**WfQSe?cA=1|Jwk`UDsny%_y{@AV??N>xWekf>_IZLUEK3{Ksi zWWW$if&Go~@Oz)`#=6t_bNtD$d9FMBN#&97+XKa+K2C@I9xWgTE{?Xnhc9_KKPcujj@NprM@e|KtV_SR+ zSpeJ!1FGJ=Te6={;;+;a46-*DW*FjTnBfeuzI_=I1yk8M(}IwEIGWV0Y~wia;}^dg z{BK#G7^J`SE10z4(_Me=kF&4ld*}wpNs91%2Ute>Om`byv9qgK4VfwPj$`axsiZ)wxS4k4KTLb-d~!7I@^Jq`>?TrixHk|9 zqCX7@sWcVfNP8N;(T>>PJgsklQ#GF>F;fz_Rogh3r!dy*0qMr#>hvSua;$d z3TCZ4tlkyWPTD<=5&*bUck~J;oaIzSQ0E03_2x{?weax^jL3o`ZP#uvK{Z5^%H4b6 z%Kbp6K?>{;8>BnQy64Jy$~DN?l(ufkcs6TpaO&i~dC>0fvi-I^7YT#h?m;TVG|nba%CKRG%}3P*wejg) zI(ow&(5X3HR_xk{jrnkA-hbwxEQh|$CET9Qv6UpM+-bY?E!XVorBvHoU59;q<9$hK z%w5K-SK zWT#1OX__$ceoq0cRt>9|)v}$7{PlfwN}%Wh3rwSl;%JD|k~@IBMd5}JD#TOvp=S57 zae=J#0%+oH`-Av}a(Jqhd4h5~eG5ASOD)DfuqujI6p!;xF_GFcc;hZ9k^a7c%%h(J zhY;n&SyJWxju<+r`;pmAAWJmHDs{)V-x7(0-;E?I9FWK@Z6G+?7Py8uLc2~Fh1^0K zzC*V#P88(6U$XBjLmnahi2C!a+|4a)5Ho5>owQw$jaBm<)H2fR=-B*AI8G@@P-8I8 zHios92Q6Nk-n0;;c|WV$Q);Hu4;+y%C@3alP`cJ2{z~*m-@de%OKVgiWp;4Q)qf9n zJ!vmx(C=_>{+??w{U^Bh|LFJ<6t}Er<-Tu{C{dv8eb(kVQ4!fOuopTo!^x1OrG}0D zR{A#SrmN`=7T29bzQ}bwX8OUufW9d9T4>WY2n15=k3_rfGOp6sK0oj7(0xGaEe+-C zVuWa;hS*MB{^$=0`bWF(h|{}?53{5Wf!1M%YxVw}io4u-G2AYN|FdmhI13HvnoK zNS2fStm=?8ZpKt}v1@Dmz0FD(9pu}N@aDG3BY8y`O*xFsSz9f+Y({hFx;P_h>ER_& z`~{z?_vCNS>agYZI?ry*V96_uh;|EFc0*-x*`$f4A$*==p`TUVG;YDO+I4{gJGrj^ zn?ud(B4BlQr;NN?vaz_7{&(D9mfd z8esj=a4tR-ybJjCMtqV8>zn`r{0g$hwoWRUI3}X5=dofN){;vNoftEwX>2t@nUJro z#%7rpie2eH1sRa9i6TbBA4hLE8SBK@blOs=ouBvk{zFCYn4xY;v3QSM%y6?_+FGDn z4A;m)W?JL!gw^*tRx$gqmBXk&VU=Nh$gYp+Swu!h!+e(26(6*3Q!(!MsrMiLri`S= zKItik^R9g!0q7y$lh+L4zBc-?Fsm8`CX1+f>4GK7^X2#*H|oK}reQnT{Mm|0ar<+S zRc_dM%M?a3bC2ILD`|;6vKA`a3*N~(cjw~Xy`zhuY2s{(7KLB{S>QtR3NBQ3>vd+= z#}Q)AJr7Y_-eV(sMN#x!uGX08oE*g=grB*|bBs}%^3!RVA4f%m3=1f0K=T^}iI&2K zuM2GG5_%+#v-&V>?x4W9wQ|jE2Q7Be8mOyJtZrqn#gXy-1fF1P$C8+We&B*-pi#q5 zETp%H6g+%#sH+L4=ww?-h;MRCd2J9zwQUe4gHAbCbH08gDJY;F6F)HtWCRW1fLR;)ysGZanlz*a+|V&@(ipWdB!tz=m_0 z6F}`d$r%33bw?G*azn*}Z;UMr{z4d9j~s`0*foZkUPwpJsGgoR0aF>&@DC;$A&(av z?b|oo;`_jd>_5nye`DVOcMLr-*Nw&nA z82E8Dw^$Lpso)gEMh?N|Uc^X*NIhg=U%enuzZOGi-xcZRUZmkmq~(cP{S|*+A6P;Q zprIkJkIl51@ng)8cR6QSXJtoa$AzT@*(zN3M+6`BTO~ZMo0`9$s;pg0HE3C;&;D@q zd^0zcpT+jC%&=cYJF+j&uzX87d(gP9&kB9|-zN=69ymQS9_K@h3ph&wD5_!4q@qI@ zBMbd`2JJ2%yNX?`3(u&+nUUJLZ=|{t7^Rpw#v-pqD2_3}UEz!QazhRty%|Q~WCo7$ z+sIugHA%Lmm{lBP#bnu_>G}Ja<*6YOvSC;89z67M%iG0dagOt1HDpDn$<&H0DWxMU zxOYaaks6%R@{`l~zlZ*~2}n53mn2|O&gE+j*^ypbrtBv{xd~G(NF?Z%F3>S6+qcry z?ZdF9R*a;3lqX_!rI(Cov8ER_mOqSn6g&ZU(I|DHo7Jj`GJ}mF;T(vax`2+B8)H_D zD0I;%I?*oGD616DsC#j0x*p+ZpBfd=9gR|TvB)832CRhsW_7g&WI@zp@r7dhg}{+4f=(cO2s+)jg0x(*6|^+6W_=YIfSH0lTcK* z%)LyaOL6em@*-_u)}Swe8rU)~#zT-vNiW(D*~?Zp3NWl1y#fo!3sK-5Ek6F$F5l3| zrFFD~WHz1}WHmzzZ!n&O8rTgfytJG*7iE~0`0;HGXgWTgx@2fD`oodipOM*MOWN-} zJY-^>VMEi8v23ZlOn0NXp{7!QV3F1FY_URZjRKMcY(2PV_ms}EIC^x z=EYB5UUQ{@R~$2Mwiw$_JAcF+szKB*n(`MYpDCl>~ss54uDQ%Xf-8|dgO zY)B_qju=IaShS|XsQo=nSYxV$_vQR@hd~;qW)TEfU|BA0&-JSwO}-a*T;^}l;MgLM zz}CjPlJX|W2vCzm3oHw3vqsRc3RY=2()}iw_k2#eKf&VEP7TQ;(DDzEAUgj!z_h2Br;Z3u=K~LqM6YOrlh)v9`!n|6M-s z?XvA~y<5?WJ{+yM~uPh7uVM&g-(;IC3>uA}ud?B3F zelSyc)Nx>(?F=H88O&_70%{ATsLVTAp88F-`+|egQ7C4rpIgOf;1tU1au+D3 zlz?k$jJtTOrl&B2%}D}8d=+$NINOZjY$lb{O<;oT<zXoAp01KYG$Y4*=)!&4g|FL(!54OhR-?)DXC&VS5E|1HGk8LY;)FRJqnz zb_rV2F7=BGwHgDK&4J3{%&IK~rQx<&Kea|qEre;%A~5YD6x`mo>mdR)l?Nd%T2(5U z_ciT02-zt_*C|vn?BYDuqSFrk3R(4B0M@CRFmG{5sovIq4%8AhjXA5UwRGo)MxZlI zI%vz`v8B+#ff*XtGnciczFG}l(I}{YuCco#2E6|+5WJ|>BSDfz0oT+F z%QI^ixD|^(AN`MS6J$ zXlKNTFhb>KDkJp*4*LaZ2WWA5YR~{`={F^hwXGG*rJYQA7kx|nwnC58!eogSIvy{F zm1C#9@$LhK^Tl>&iM0wsnbG7Y^MnQ=q))MgApj4)DQt!Q5S`h+5a%c7M!m%)?+h65 z0NHDiEM^`W+M4)=q^#sk(g!GTpB}edwIe>FJQ+jAbCo#b zXmtd3raGJNH8vnqMtjem<_)9`gU_-RF&ZK!aIenv7B2Y0rZhon=2yh&VsHzM|`y|0x$Zez$bUg5Nqj?@~^ zPN43MB}q0kF&^=#3C;2T*bDBTyO(+#nZnULkVy0JcGJ36or7yl1wt7HI_>V7>mdud zv2II9P61FyEXZuF$=69dn%Z6F;SOwyGL4D5mKfW)q4l$8yUhv7|>>h_-4T*_CwAyu7;DW}_H zo>N_7Gm6eed=UaiEp_7aZko@CC61@(E1be&5I9TUq%AOJW>s^9w%pR5g2{7HW9qyF zh+ZvX;5}PN0!B4q2FUy+C#w5J?0Tkd&S#~94(AP4%fRb^742pgH7Tb1))siXWXHUT z1Wn5CG&!mGtr#jq6(P#!ck@K+FNprcWP?^wA2>mHA03W?kj>5b|P0ErXS) zg2qDTjQ|grCgYhrH-RapWCvMq5vCaF?{R%*mu}1)UDll~6;}3Q*^QOfj!dlt02lSzK z?+P)02Rrq``NbU3j&s*;<%i4Y>y9NK&=&KsYwvEmf5jwTG6?+Pu1q9M8lLlx)uZZ7 zizhr~e0ktGs-=$li-2jz^_48-jk**y&5u0`B2gc#i$T1~t+AS*kEfR*b{^Ec>2-F~ zKYRl&uQ5yO@EtAZX8ZSqx;8+AKf+CqhlUSpp*VfyBMv+%wxN5GukZEi^_to%MFRc0 zdXqJ*jk?#uYT6EJe446@(f6G4vhnxQP|pGeJ?-#|Ksq?g*ky=}x+Qnx+!<>Y(XStN zQIND`{KU}&l)E*ntI^}kJ=ly8DML{!(58Xk4_bzIc@v~e;>wKl_`7G%pGz~4KH*CTp;_|52)d!+ximd$|8v@zzEq%j68QXkgf$7eM~xdM5q5i z{?qFx_W|eq@L03bWJfjy^z@()-iCjzjREuf zb_a(yTz)ZKWCF%Lp>^2-%Q?*t{06}x#DLN3cO=i>h6#-a`z;<5rBGGM6GA(WqvRcX%Pn?Uvs1#e|ePSNJEC%+X(YI$x)`s$%>O#%}D9dgqWfq4yfVz^%FglokdFR}uJQhx|}_w`9Ulx38Ha>ZslKs58c-@IFI&f;?xM zbK>rKNfPFsf>%+k6%(A6=7Aac^_qrOCNqb3ZVJ;8pt!?1DR*ynJb#@II9h?)xB)A~ zm9Kk)Hy}!Z+W}i6ZJDy+?yY_=#kWrzgV)2eZAx_E=}Nh7*#<&mQz`Umfe$+l^P(xd zN}PA2qII4}ddCU+PN+yxkH%y!Qe(;iH3W%bwM3NKbU_saBo<8x9fGNtTAc_SizU=o zC3n2;c%LoU^j90Sz>B_p--Fzqv7x7*?|~-x{haH8RP)p|^u$}S9pD-}5;88pu0J~9 zj}EC`Q^Fw}`^pvAs4qOIuxKvGN@DUdRQ8p-RXh=3S#<`3{+Qv6&nEm)uV|kRVnu6f zco{(rJaWw(T0PWim?kkj9pJ)ZsUk9)dSNLDHf`y&@wbd;_ita>6RXFJ+8XC*-wsiN z(HR|9IF283fn=DI#3Ze&#y3yS5;!yoIBAH(v}3p5_Zr+F99*%+)cp!Sy8e+lG?dOc zuEz<;3X9Z5kkpL_ZYQa`sioR_@_cG z8tT~GOSTWnO~#?$u)AcaBSaV7P~RT?Nn8(OSL1RmzPWRWQ$K2`6*)+&7^zZBeWzud z*xb3|Fc~|R9eH+lQ#4wF#c;)Gka6lL(63C;>(bZob!i8F-3EhYU3|6-JBC0*5`y0| zBs!Frs=s!Sy0qmQNgIH|F`6(SrD1js2prni_QbG9Sv@^Pu2szR9NZl8GU89gWWvVg z2^-b*t+F{Nt>v?js7hnlC`tRU(an0qQG7;h6T~ z-`vf#R-AE$pzk`M{gCaia}F`->O2)60AuGFAJg> z*O2IZqTx=AzDvC49?A92>bQLdb&32_4>0Bgp0ESXXnd4B)!$t$g{*FG%HYdt3b3a^J9#so%BJMyr2 z{y?rzW!>lr097b9(75#&4&@lkB1vT*w&0E>!dS+a|ZOu6t^zro2tiP)bhcNNxn zbJs3_Fz+?t;4bkd8GfDI7ccJ5zU`Bs~ zN~bci`c`a%DoCMel<-KUCBdZRmew`MbZEPYE|R#|*hhvhyhOL#9Yt7$g_)!X?fK^F z8UDz)(zpsvriJ5aro5>qy`Fnz%;IR$@Kg3Z3EE!fv9CAdrAym6QU82=_$_N5*({_1 z7!-=zy(R{xg9S519S6W{HpJZ8Is|kQ!0?`!vxDggmslD59)>iQ15f z7J8NqdR`9f8H|~iFGNsPV!N)(CC9JRmzL9S}7U-K@`X893f3f<8|8Ls!^eA^#(O6nA+ByFIXcz_WLbfeG|nHJ5_sJJ^gNJ%SI9#XEfNRbzV+!RkI zXS$MOVYb2!0vU}Gt7oUy*|WpF^*orBot~b2J@^be?Gq;U%#am8`PmH-UCFZ&uTJlnetYij0z{K1mmivk$bdPbLodu;-R@@#gAV!=d%(caz$E?r zURX0pqAn7UuF6dULnoF1dZ$WM)tHAM{eZK6DbU1J`V5Dw<;xk}Nl`h+nfMO_Rdv z3SyOMzAbYaD;mkxA7_I_DOs#Bk;e5D%gsS3q)hlmi1w{FsjKNJE22`AjmNiAPRnIc zcIkN25;rOn3FipAFd(PnlK9{03w6Q<(68#1Jw`{axEGQE{Ac>^U$h);h2ADICmaNxrfpb`Jdr*)Y1SicpYKCFv$3vf~;5aW>n^7QGa63MJ z;B1+Z>WQ615R2D8JmmT`T{QcgZ+Kz1hTu{9FOL}Q8+iFx-Vyi}ZVVcGjTe>QfA`7W zFoS__+;E_rQIQxd(Bq4$egKeKsk#-9=&A!)(|hBvydsr5ts0Zjp*%*C0lM2sIOx1s zg$xz?Fh?x!P^!vWa|}^+SY8oZHub7f;E!S&Q;F?dZmvBxuFEISC}$^B_x*N-xRRJh zn4W*ThEWaPD*$KBr8_?}XRhHY7h^U1aN6>m=n~?YJQd8+!Uyq_3^)~4>XjelM&!c9 zCo|0KsGq7!KsZ~9@%G?i>LaU7#uSTMpypocm*oqJHR|wOgVWc7_8PVuuw>x{kEG4T z$p^DV`}jUK39zqFc(d5;N+M!Zd3zhZN&?Ww(<@AV-&f!v$uV>%z+dg9((35o@4rqLvTC-se@hkn^6k7+xHiK-vTRvM8{bCejbU;1@U=*r}GTI?Oc$!b6NRcj83-zF; z=TB#ESDB`F`jf4)z=OS76Se}tQDDHh{VKJk#Ad6FDB_=afpK#pyRkGrk~OuzmQG)} z*$t!nZu$KN&B;|O-aD=H<|n6aGGJZ=K9QFLG0y=Jye_ElJFNZJT;fU8P8CZcLBERjioAOC0Vz_pIXIc};)8HjfPwNy zE!g|lkRv3qpmU?shz(BBt5%TbpJC3HzP9!t7k*Fh48!-HlJ4TTgdCr3rCU!iF}kgu z4Qs;K@XOY~4f~N}Jl8V_mGbwzvNLbl&0e9UG4W;kvjTK|5`-Ld+eQ6YRF`N0ct%u% z^3J_{7r#_W1zm|>IPN!yWCRrN)N!7v`~ptNkIXKipQ6ogFvcnI5ugxdoa{d;uD67g zgo^}QuZRkB540Vc!@c80(wFG=$ct}oHq(#W0+-XX(;Rrt`x=<45X}ficNtI2(&}=~ zb(!}tNz?s`wm{gK?2tdf+OEF;tzx<(3fMd7_tM@Ghs$Z(Os-H(kYq#qB|J-aC9Ku?fsWwJhB36c)A zu|a7ZF?V8X7l2g5~xqZf>2=6Dsi5lfo zKIRL&@MLJyaBE)V_9=pJYu%U2wxR*-(0MI5_|yqP`?h@cks(5LR@XUKLMI_xuVtiu zRvpDS8MyUMRFM6`P+Sjc!A_e^H38Qu7b{b7QZ>NHyA6k-YYygQuW&C_OGO(7V7?}r)zedSVpBI zuk29Z4GW3C0GpfozbZQya454sjt@ndQmsp=DA&@sWw&xmOlDk1JIcMNp~-ES$&A~k zG#W(6hBj?!Fu8Q4WYexoSBa8_5=v20xnx6H?e;$t)5|f&{7=vOye^&3_c-Ug?|a@e z=X`&qT_5B7N9vZoPBhXOTEDV;4&x2Je4}T(UB~O-$D#CjX77$R?RZ*`ed~$G;$4YS z4n*|Pop(!NN79Hk2}U#cfEEwdxM)xQm}$~rV03xc=#U@@Y*}qEmot5KvDb=8{!E-n zl4p?}&g2h^sUGyTcGh=0aQzQb*k;K;dvbeZUgmwEv>%#(EPtj=gHKdi|E8@w+|>KC zxEU>b>P+9Xf}pEyQK(}#QrBG4Jaf!iE!qpMbTu>gb!gtdq<`@xO+roQl+S_7)!G(% zdy)$iGmJ1cwP?F=IyyV1-$|kf|EKM3B@I&lZ%NI@VV;*mQdLWjc#t|Vbk_Q~>&O03 zIcSr$(qLAINj7a z;!||v&1D5SX#X@5jNd}jUsi-CH_Scjyht&}q2p*CJCC-`&NyXf)vD5{e!HO629D-O z%bZelTcq=DoRX>zeWCa^RmR3*{x9;3lZ75M#S)!W0bRIFH#P6b%{|HRSZ5!!I#s)W z_|XXZQ<0_`>b^^0Z>LU64Yg1w)8}#M^9se(OZ9~baZ7fsKFc;EtnB>kesci#>=icG zuHdjax2^=!_(9?0l7;G7^-}9>Y#M zm;9*GT~dBuYWdk49%mZM0=H#FY1)}7NE5DE_vsqrA0`?0R0q535qHjWXcl|gz9Fq$ zMKxgL;68l!gm3y0durIr3LHv~y*ABm` zYhQG0UW#hg@*A{&G!;$FS43}rIF$e6yRdGJWVR<}uuJ_5_8qa3xaHH^!VzUteVp;> z<0`M>3tnY$ZFb$(`0sg93TwGyP;`9UYUWxO&CvAnSzei&ap))NcW;R`tA=y^?mBmG+M*&bqW5kL$V(O;(p)aEk`^ci?2Jwxu>0sy>a7+Wa9t z5#I2o;+gr^9^&km^z7>xJWbN&Ft>Vna34E zI@BBzwX)R}K3SL?)enrDJ45QLt;-7CFJk{`cF3L4Z^CtG_r5)0)HV>BOYPIUh#D%| zYQAu31f{bm-D*`_k7DTTr?Nkw_gY%J1cb2&TdtibY?V=|SSIOlA;|5C!2@?YQ z-$?G0jj^mG|MP>DmbF7}T~C$H6=CpZ~hd zZ1C|xV@=h#^~`3LSCnmI(vZ|5r3>eq5*UB)dhdy``*gKY3Eg%jSK8I-`G+OWWlD)T zt$wSQ=||lSkiKy}YF-k}@W9EiS?)z`hK{R!dd-$BCJvBtAN-yXn3njU$MisEtp!?Q z%Vk-*(wy9dd15(-WFw_&^tT;;IpF?ox1`Qq3-0zVTk+$W_?q}GfAQlPcrB^?&tWSI z2BB!K=sH7FUYmXa_dcV^Z3>5z8}~W{S!$jVR_3hu_|wl2|gmRH8ftn^z@fW75*;-`;wU+fY+BR_yx6BZnE5_Hna({jrPiubRp$jZ=T=t$hx&NeCV1!vuCcl4PJ0p0Fjp>6K} zHkoD1gQk=P2hYcT%)cJ2Q5WuA|5_x+dX0%hnozfTF>$#Wz~X!MY>){H4#fB#7^ID* z1*o2Hzp}?WVs&gbS?Uq(CT0sP+F)u9{xfgg6o_{8J#m;|NeJqDHhb(Q8%z8aM_qeM zn83>d`uDd47WIuKp78JBYo2SYupGcNXIzeou^eMY`@%Bv8elZ>q~3uq#~IX)g%g;h zoUXymEd>|kVsMkyb&1l~lrE-`w(0PObapYa35DJ4Y03Jv_!DKp}0HTbOgZRM=;PSsuAJJJ1 zItc+tu9;ANG;qHaCI|T85!euhFK~VK^G2LZV1+cbzS?>ar@>emg;JTI5VAn1g5U~| zU=p&k0OlSzc$U=s#9_uL3&n|6A1X$XvrE9vFV@`A4G#!D1QcFCeE`F2N(deJx>)*A z$XIW0P~-NbAd=5i6`s<~(vAQX9t$dbVqc5|E|CHRtb$1(l&KSNh_t2#k_l95KnP86 z)ns_DGspv-M0z0#h2a+*oH|{5~j{ zXGD=}cLrBSESQ0u$XmQlFfWMCAWaS;wKK%#aSSYK=qljBiY(s zT$v;We24&$w=avIILsMt0%1fDyah|AlLNg#WL$Lu)tf}YfqO%+pH~QC*bZO4aM*i9 zrPFf|5!hv@XY8CzaFh*Dy9vH|2fKKr(@x}`L#9^*vOae|lk`adG#oZZAyk|TOV8`9L zc-sQu%y1MQes&J?)a1}Zc*>-P!6j-T#75V$lLC!TuMB(!G-+D2;XptUxymSPFI-K&0x}B1?h$ z3-9**-9!);fwyiWB5gS$i;P~c=^}5-6G@{4TWDBRDc6(M|%qa-mS`z`u9kWo{Xl_uc;hXOkRd literal 0 HcmV?d00001 diff --git a/support/test/kotlin/gradle/wrapper/gradle-wrapper.properties b/support/test/kotlin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..622ab64 --- /dev/null +++ b/support/test/kotlin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/support/test/kotlin/gradlew b/support/test/kotlin/gradlew new file mode 100755 index 0000000..fbd7c51 --- /dev/null +++ b/support/test/kotlin/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# 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 +# +# https://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. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/support/test/kotlin/gradlew.bat b/support/test/kotlin/gradlew.bat new file mode 100644 index 0000000..a9f778a --- /dev/null +++ b/support/test/kotlin/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/support/test/kotlin/settings.gradle.kts b/support/test/kotlin/settings.gradle.kts new file mode 100644 index 0000000..8cbc5be --- /dev/null +++ b/support/test/kotlin/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "vimspector-test" diff --git a/support/test/kotlin/src/main/kotlin/vimspector/test/Application.kt b/support/test/kotlin/src/main/kotlin/vimspector/test/Application.kt new file mode 100644 index 0000000..99655da --- /dev/null +++ b/support/test/kotlin/src/main/kotlin/vimspector/test/Application.kt @@ -0,0 +1,5 @@ +package vimspector.test + +fun main(args: Array) { + println("Hello World!") +} From ce8dd9113cf94d958461be96321bf7eb1958900b Mon Sep 17 00:00:00 2001 From: Allan Guigou Date: Thu, 31 Dec 2020 10:39:01 -0500 Subject: [PATCH 017/200] 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. --- .../kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - support/test/kotlin/gradlew | 185 ------------------ support/test/kotlin/gradlew.bat | 104 ---------- 4 files changed, 294 deletions(-) delete mode 100644 support/test/kotlin/gradle/wrapper/gradle-wrapper.jar delete mode 100644 support/test/kotlin/gradle/wrapper/gradle-wrapper.properties delete mode 100755 support/test/kotlin/gradlew delete mode 100644 support/test/kotlin/gradlew.bat diff --git a/support/test/kotlin/gradle/wrapper/gradle-wrapper.jar b/support/test/kotlin/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 62d4c053550b91381bbd28b1afc82d634bf73a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58910 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 diff --git a/support/test/kotlin/gradle/wrapper/gradle-wrapper.properties b/support/test/kotlin/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 622ab64..0000000 --- a/support/test/kotlin/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/support/test/kotlin/gradlew b/support/test/kotlin/gradlew deleted file mode 100755 index fbd7c51..0000000 --- a/support/test/kotlin/gradlew +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env sh - -# -# Copyright 2015 the original author or authors. -# -# 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 -# -# https://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. -# - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -exec "$JAVACMD" "$@" diff --git a/support/test/kotlin/gradlew.bat b/support/test/kotlin/gradlew.bat deleted file mode 100644 index a9f778a..0000000 --- a/support/test/kotlin/gradlew.bat +++ /dev/null @@ -1,104 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega From 7bd22d2bbd2b6f8a88db5bf47481536febad52b9 Mon Sep 17 00:00:00 2001 From: Gabriel Filion Date: Sat, 2 Jan 2021 15:41:16 -0500 Subject: [PATCH 018/200] 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 --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 0271069..d167fed 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -115,10 +115,10 @@ GADGETS = { '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, From b72aa18dec9b239b4bb454613c2c2a62bcc6a2cb Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 11:06:28 +0000 Subject: [PATCH 019/200] Add a list to tcl tets --- support/test/tcl/test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/support/test/tcl/test b/support/test/tcl/test index e77a486..a77f56f 100644 --- a/support/test/tcl/test +++ b/support/test/tcl/test @@ -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 } From d52eb3a6e9cd1daa208f1616d1fea3ca4eee70b0 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 11:30:17 +0000 Subject: [PATCH 020/200] 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. --- python3/vimspector/stack_trace.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index df650b9..f38e4ba 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -188,11 +188,12 @@ class StackTraceView( object ): return def consume_threads( message ): + 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 ) - return + requesting = True self._requesting_threads = StackTraceView.ThreadRequestState.NO self._pending_thread_request = None @@ -211,8 +212,6 @@ class StackTraceView( object ): stoppedThreadId = stopEvent.get( 'threadId' ) allThreadsStopped = stopEvent.get( 'allThreadsStopped', False ) - requesting = False - # FIXME: This is horribly inefficient for t in message[ 'body' ][ 'threads' ]: thread = None @@ -240,7 +239,10 @@ class StackTraceView( object ): # 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. - if infer_current_frame: + # + # 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 ) From 4206d0e57cbe48c541ec64c09ecbe3ad96b851bd Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 15:54:45 +0000 Subject: [PATCH 021/200] Use 127.0.0.1 rather than localhost to avoid issues with ipv6, and long timeout connecting the socket --- autoload/vimspector/internal/channel.vim | 2 +- autoload/vimspector/internal/neochannel.vim | 2 +- docs/schema/vimspector.schema.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/autoload/vimspector/internal/channel.vim b/autoload/vimspector/internal/channel.vim index b05d8e8..b44436b 100644 --- a/autoload/vimspector/internal/channel.vim +++ b/autoload/vimspector/internal/channel.vim @@ -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, diff --git a/autoload/vimspector/internal/neochannel.vim b/autoload/vimspector/internal/neochannel.vim index 5414568..f20684d 100644 --- a/autoload/vimspector/internal/neochannel.vim +++ b/autoload/vimspector/internal/neochannel.vim @@ -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 diff --git a/docs/schema/vimspector.schema.json b/docs/schema/vimspector.schema.json index 97fea75..cd79f11 100644 --- a/docs/schema/vimspector.schema.json +++ b/docs/schema/vimspector.schema.json @@ -200,7 +200,7 @@ "properties": { "host": { "type": "string", - "default": "localhost", + "default": "127.0.0.1", "description": "Connect to this host in multi-session mode" }, "port": { From e010d3217c0ccc12f715ccb76c0414af451fa34c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 9 Jan 2021 12:02:30 +0000 Subject: [PATCH 022/200] add some links to the new issue page --- .github/ISSUE_TEMPLATE/config.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..f182c32 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -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 + From 1f20115960ed18d9843496dedc3bcd02692ff6a1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 9 Jan 2021 12:15:27 +0000 Subject: [PATCH 023/200] Update docs bundle to stfu security warnings --- docs/Gemfile | 2 ++ docs/Gemfile.lock | 71 ++++++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/docs/Gemfile b/docs/Gemfile index 3f49941..18f79a6 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -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" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index c28eebb..d2eb55f 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.3.2) + activesupport (6.0.3.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -17,37 +17,40 @@ GEM commonmarker (0.17.13) ruby-enum (~> 0.5) concurrent-ruby (1.1.7) - dnsruby (1.61.4) + 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.0) + ffi (1.14.2) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (207) + github-pages (209) github-pages-health-check (= 1.16.1) 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.2) jekyll-sass-converter (= 1.5.2) jekyll-seo-tag (= 2.6.1) jekyll-sitemap (= 1.4.0) @@ -55,7 +58,7 @@ GEM 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,14 +69,14 @@ 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) + jemoji (= 0.12.0) 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.19.0) + rouge (= 3.23.0) terminal-table (~> 1.4) github-pages-health-check (1.16.1) addressable (~> 2.3) @@ -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,14 +132,15 @@ 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.2) 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) @@ -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,7 +192,7 @@ 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) @@ -197,32 +201,35 @@ GEM kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.3) - listen (3.2.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.4.0) + 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.1) + minitest (5.14.3) multipart-post (2.1.1) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) - octokit (4.18.0) + nokogiri (1.11.1) + 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) + 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) + rouge (3.23.0) ruby-enum (0.8.0) i18n + ruby2_keywords (0.0.2) rubyzip (2.3.0) safe_yaml (1.0.5) sass (3.7.4) @@ -240,13 +247,14 @@ GEM 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.1.4 + 2.2.3 From d38da376c2dbb19b7443d1b0e8f507e45229070b Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 9 Jan 2021 12:46:13 +0000 Subject: [PATCH 024/200] There are mappings --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 8bc0a0d..5eae743 100644 --- a/README.md +++ b/README.md @@ -602,9 +602,6 @@ That said, many people are familiar with particular debuggers, so the following mappings can be enabled by setting `g:vimspector_enable_mappings` to the specified value. -Please note: Currently there are no `` mappings. These will be added in -future to make custom mappings much easier. - ## Visual Studio / VSCode To use Visual Studio-like mappings, add the following to your `vimrc` **before From 35f7e08fbbd3e9330ed956def0ab5d83f13c01b1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 9 Jan 2021 13:14:14 +0000 Subject: [PATCH 025/200] Bit of readme restructuring and improve docs on breakpionts API --- README.md | 256 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 155 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 5eae743..6460adb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ # vimspector - A multi language graphical debugger for Vim For a tutorial and usage overview, take a look at the -[Vimspector website][website] +[Vimspector website][website]. + +For detailed explanatin of the `.vimspector.json` format, see the +[reference guide][vimspector-ref]. ![Build](https://github.com/puremourning/vimspector/workflows/Build/badge.svg?branch=master) [![Gitter](https://badges.gitter.im/vimspector/Lobby.svg)](https://gitter.im/vimspector/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) @@ -27,15 +30,21 @@ For a tutorial and usage overview, take a look at the * [Background](#background) * [Status](#status) * [Experimental](#experimental) + * [Motivation](#motivation) + * [License](#license) + * [Sponsorship](#sponsorship) * [Mappings](#mappings) * [Visual Studio / VSCode](#visual-studio--vscode) * [Human Mode](#human-mode) - * [Usage](#usage) + * [Usage and API](#usage-and-api) * [Launch and attach by PID:](#launch-and-attach-by-pid) * [Launch with options](#launch-with-options) * [Debug configuration selection](#debug-configuration-selection) * [Get configurations](#get-configurations) * [Breakpoints](#breakpoints) + * [Summary](#summary) + * [Line breakpoints](#line-breakpoints) + * [Conditional breakpoints](#conditional-breakpoints) * [Exception breakpoints](#exception-breakpoints) * [Clear breakpoints](#clear-breakpoints) * [Run to Cursor](#run-to-cursor) @@ -49,14 +58,14 @@ For a tutorial and usage overview, take a look at the * [Console autocompletion](#console-autocompletion) * [Log View](#log-view) * [Closing debugger](#closing-debugger) - * [Debug adapter configuration](#debug-adapter-configuration) + * [Debug profile configuration](#debug-profile-configuration) * [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) - * [Remote debugging](#remote-debugging) - * [Remote launch and attach](#remote-launch-and-attach) * [Python](#python) - * [Remote Debugging](#remote-debugging-1) - * [Remote launch and attach](#remote-launch-and-attach-1) + * [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) @@ -79,11 +88,8 @@ For a tutorial and usage overview, take a look at the * [Customising the WinBar](#customising-the-winbar) * [Example](#example) * [FAQ](#faq) - * [Motivation](#motivation) - * [License](#license) - * [Sponsorship](#sponsorship) - + @@ -570,6 +576,65 @@ However, I commit to only doing this in the most extreme cases and to annouce such changes on Gitter well in advance. There's nothing more annoying than stuff just breaking on you. I get that. +## Motivation + +A message from the author about the motivation for this plugin: + +> Many development environments have a built-in debugger. I spend an inordinate +> amount of my time in Vim. I do all my development in Vim and I have even +> customised my workflows for building code, running tests etc. +> +> For many years I have observed myself, friends and colleagues have been +> writing `printf`, `puts`, `print`, etc. debugging statements in all sorts of +> files simply because there is no _easy_ way to run a debugger for _whatever_ +> language we happen to be developing in. +> +> I truly believe that interactive, graphical debugging environments are the +> best way to understand and reason about both unfamiliar and familiar code, and +> that the lack of ready, simple access to a debugger is a huge hidden +> productivity hole for many. +> +> Don't get me wrong, I know there are literally millions of developers out +> there that are more than competent at developing without a graphical debugger, +> but I maintain that if they had the ability to _just press a key_ and jump +> into the debugger, it would be faster and more enjoyable that just cerebral +> code comprehension. +> +> I created Vimspector because I find changing tools frustrating. `gdb` for c++, +> `pdb` for python, etc. Each has its own syntax. Each its own lexicon. Each its +> own foibles. +> +> I designed the configuration system in such a way that the configuration can +> be committed to source control so that it _just works_ for any of your +> colleagues, friends, collaborators or complete strangers. +> +> I made remote debugging a first-class feature because that's a primary use +> case for me in my job. +> +> With Vimspector I can _just hit ``_ in all of the languages I develop in +> and debug locally or remotely using the exact same workflow, mappings and UI. +> I have integrated this with my Vim in such a way that I can hit a button and +> _run the test under the cursor in Vimspector_. This kind of integration has +> massively improved my workflow and productivity. It's even made the process +> of learning a new codebase... fun. +> +> \- Ben Jackson, Creator. + +## License + +[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) + +Copyright © 2018 Ben Jackson + +## Sponsorship + +If you like Vimspector so much that you're wiling to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the author of Vimspector (in order of prefernce): + +* [Greyhound Rescue Wales](https://greyhoundrescuewales.co.uk) +* [Cancer Research UK](https://www.cancerresearchuk.org) +* [ICCF Holland](https://iccf.nl) +* Any charity of your choosing. + # Mappings By default, vimspector does not change any of your mappings. Mappings are very @@ -650,7 +715,12 @@ let g:vimspector_enable_mappings = 'HUMAN' | `F11` | Step Into | `vimspector#StepInto()` | | `F12` | Step out of current function scope | `vimspector#StepOut()` | -# Usage +# Usage and API + +This section defines detailed usage instructions, organised by feature. For most +users, the [mappings](#mappings) section contains the most common commands and +default usage. This section can be used as a reference to create your own +mappings or custom behaviours. ## Launch and attach by PID: @@ -714,13 +784,54 @@ For example, to get an array of configurations and fuzzy matching on the result ## Breakpoints -* Use `vimspector#ToggleBreakpoint([ { 'condition': '' } ])` - to set/disable/delete a line breakpoint, with optional condition. -* Use `vimspector#AddFunctionBreakpoint( '' [, { 'condition': '' } ] )` - to add a function breakpoint with optional condition. +See the [mappings](€mappings) section for the default mappngs for working with +breakpoints. This section describes the full API in vimscript functions. -Both of these functions take a single optional argument which is a dictionary of -options. The dictionary can have the following keys: +### Summary + +* Use `vimspector#ToggleBreakpoint( { options dict } )` to set/disable/delete + a line breakpoint. The argument is optional (see below). +* Use `vimspector#AddFunctionBreakpoint( '', { options dict} )` + to add a function breakpoint. The second argument is optional (see below). +* Use `vimspector#SetLineBreakpoint( file_name, line_num, { options dict } )` to + set a breakpoint at a specific file/line. The last argument is optional + (see below) +* Use `vimspector#ClearLineBreakpoint( file_name, line_num )` to + remove a breakpoint at a specific file/line +* Use `vimspector#ClearBreakpoints()` to clear all breakpoints + +Examples: + +* `call vimspector#ToggleBreakpoint()` - toggle breakpoint on current line +* `call vimspector#SetLineBreakpoint( 'some_file.py', 10 )` - set a breakpoint + on `some_filepy:10` +* `call vimspector#AddFunctionBreakpoint( 'main' )` - add a function breakpoint + on the `main` funciton +* `call vimspector#ToggleBreakpoint( { 'condition': 'i > 5' } )` - add a + breakpoint on the current line that triggers only when `i > 5` is `true` +* `call vimspector#SetLineBreakpoint( 'some_file.py', 10, { 'condition': 'i > 5' } )` - add a + breakpoint at `some_file.py:10` that triggers only when `i > 5` is `true` +* `call vimspector#ClearLineBreakpoint( 'some_file.py', 10 )` - delete the + breakpoint at `some_file.py:10` +* `call vimspector#ClearBreakpoints()` - clear all breakpoints + +### Line breakpoints + +The simplest and most common form of breakpoint is a line breakpoint. Exectuion +is paused when the specified line is executed. + +For most debugging scenarios, users will just hit `` to create a line +breakpoint on the current line and `` to launch the application. + +### Conditional breakpoints + +Some debug adatpers support conditional breakpionts. Note that vimspector does +not tell you if the debugger doesn't support conditional breakpoints (yet). A +conditional breakpiont is a breakpiont which only triggers if some expression +evaluates to true, or has some other constraints met. + +Some of these functions above take a single optional argument which is a +dictionary of options. The dictionary can have the following keys: * `condition`: An optional expression evaluated to deterimie if the breakpoint should fire. Not supported by all debug adapters. For example, to break when @@ -738,9 +849,10 @@ expressions in a command line (with history). ### Exception breakpoints -When starting debugging, you may be asekd a few questions about how to handle -exceptoins. These are "exception breakpoints" and vimspector remembers your -choices while Vim is still running. +Exception breakpoints typically fire when an exception is throw or other error +condition occurs. Depending on the debugger, when starting debugging, you may be +asekd a few questions about how to handle exceptoins. These are "exception +breakpoints" and vimspector remembers your choices while Vim is still running. Typically you can accept the defaults (just keep pressing ``!) as most debug adapter defaults are sane, but if you want to break on, say `uncaught exception` @@ -751,14 +863,14 @@ You can configure your choices in the `.vimspector.json`. See ### Clear breakpoints -* Use `vimspector#ClearBreakpoints()` - to clear all breakpoints including the memory of exception breakpoint choices. +Use `vimspector#ClearBreakpoints()` +to clear all breakpoints including the memory of exception breakpoint choices. ### Run to Cursor -* Use `vimspector#RunToCursor` or ``: this creates a temporary - breakpoint on the current line, then continues execution, clearing the - breakpiont when it is hit. +Use `vimspector#RunToCursor` or ``: this creates a temporary +breakpoint on the current line, then continues execution, clearing the +breakpoint when it is hit. ## Stepping @@ -844,7 +956,7 @@ The stack trace is represented by the buffer `vimspector.StackTrace`. ## Program Output -* In the outputs window use the WinBar to select the output channel. +* In the outputs window, use the WinBar to select the output channel. * Alternatively, use `:VimspectorShowOutput `. Use command-line completion to see the categories. * The debugee prints to the stdout channel. @@ -859,7 +971,7 @@ options). ### Console The console window is a prompt buffer, where that's available, and can be used -as an interactive CLI for the debug adapter. Support for this varies amongt +as an interactive CLI for the debug adapter. Support for this varies amongst adapters. * Enter insert mode to enter a command to evaluate. @@ -906,7 +1018,7 @@ To close the debugger, use: * `:VimspectorReset` when the WinBar is not available. * `call vimspector#Reset()` -# Debug adapter configuration +# Debug profile configuration For an introduction to the configuration of `.vimspector.json`, take a look at the Getting Started section of the [Vimspector website][website]. @@ -983,6 +1095,17 @@ licensing. } ``` +### C++ Remote debugging + +The cpptools documentation describes how to attach cpptools to gdbserver using +`miDebuggerAddress`. Note that when doing this you should use the +`"request": "attach"`. + +### C++ Remote launch and attach + +If you're feeling fancy, checkout the [reference guide][remote-debugging] for +an example of getting Vimspector to remotely launch and attach. + * CodeLLDB (MacOS) CodeLLDB is superior to vscode-cpptools in a number of ways on macOS at least. @@ -1049,17 +1172,6 @@ Rust is supported with any gdb/lldb-based debugger. So it works fine with -### Remote debugging - -The cpptools documentation describes how to attach cpptools to gdbserver using -`miDebuggerAddress`. Note that when doing this you should use the -`"request": "attach"`. - -### Remote launch and attach - -If you're feeling fancy, checkout the [reference guide][remote-debugging] for -an example of getting Vimspector to remotely launch and attach. - ## Python * Python: [debugpy][] @@ -1094,7 +1206,7 @@ an example of getting Vimspector to remotely launch and attach. } ``` -### Remote Debugging +### Python Remote Debugging In order to use remote debugging with debugpy, you have to connect Vimspector directly to the application that is being debugged. This is easy, but it's a @@ -1133,7 +1245,7 @@ Additional documentation, including how to do this when the remote machine can only be contacted via SSH [are provided by debugpy](https://github.com/microsoft/debugpy/wiki/Debugging-over-SSH). -### Remote launch and attach +### Python Remote launch and attach If you're feeling fancy, checkout the [reference guide][remote-debugging] for an example of getting Vimspector to remotely launch and attach. @@ -1559,7 +1671,7 @@ define them in your `vimrc`. | Sign | Description | Priority | |------------------------|-------------------------------------|----------| | `vimspectorBP` | Line breakpoint | 9 | -| `vimspectorBPCond` | Conditional line breakpiont | 9 | +| `vimspectorBPCond` | Conditional line breakpoint | 9 | | `vimspectorBPDisabled` | Disabled breakpoint | 9 | | `vimspectorPC` | Program counter (i.e. current line) | 200 | | `vimspectorPCBP` | Program counter and breakpoint | 200 | @@ -1834,64 +1946,6 @@ hi link jsonComment Comment 8. The signs and winbar display funny symbols. How do i fix them? See [this](#changing-the-default-signs) and [this](#customising-the-winbar) -# Motivation - -A message from the author about the motivation for this plugin: - -> Many development environments have a built-in debugger. I spend an inordinate -> amount of my time in Vim. I do all my development in Vim and I have even -> customised my workflows for building code, running tests etc. -> -> For many years I have observed myself, friends and colleagues have been -> writing `printf`, `puts`, `print`, etc. debugging statements in all sorts of -> files simply because there is no _easy_ way to run a debugger for _whatever_ -> language we happen to be developing in. -> -> I truly believe that interactive, graphical debugging environments are the -> best way to understand and reason about both unfamiliar and familiar code, and -> that the lack of ready, simple access to a debugger is a huge hidden -> productivity hole for many. -> -> Don't get me wrong, I know there are literally millions of developers out -> there that are more than competent at developing without a graphical debugger, -> but I maintain that if they had the ability to _just press a key_ and jump -> into the debugger, it would be faster and more enjoyable that just cerebral -> code comprehension. -> -> I created Vimspector because I find changing tools frustrating. `gdb` for c++, -> `pdb` for python, etc. Each has its own syntax. Each its own lexicon. Each its -> own foibles. -> -> I designed the configuration system in such a way that the configuration can -> be committed to source control so that it _just works_ for any of your -> colleagues, friends, collaborators or complete strangers. -> -> I made remote debugging a first-class feature because that's a primary use -> case for me in my job. -> -> With Vimspector I can _just hit ``_ in all of the languages I develop in -> and debug locally or remotely using the exact same workflow, mappings and UI. -> I have integrated this with my Vim in such a way that I can hit a button and -> _run the test under the cursor in Vimspector_. This kind of integration has -> massively improved my workflow and productivity. It's even made the process -> of learning a new codebase... fun. -> -> \- Ben Jackson, Creator. - -# License - -[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) - -Copyright © 2018 Ben Jackson - -# Sponsorship - -If you like Vimspector so much that you're wiling to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the author of Vimspector (in order of prefernce): - -* [Greyhound Rescue Wales](https://greyhoundrescuewales.co.uk) -* [Cancer Research UK](https://www.cancerresearchuk.org) -* [ICCF Holland](https://iccf.nl) -* Any charity of your choosing. [ycmd]: https://github.com/Valloric/ycmd [gitter]: https://gitter.im/vimspector/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link From 75e8450cf3ae7faf31c2c2891e763cf3acea2141 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 9 Jan 2021 07:47:33 -0800 Subject: [PATCH 026/200] fixed some typos in the readme --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 6460adb..0917bc9 100644 --- a/README.md +++ b/README.md @@ -340,7 +340,7 @@ In order for Vimspector to be useful, you need to have some adapters installed. There are a few ways to do this: -* If you downloaded a tarball, gadgets for main supported langauges are already +* If you downloaded a tarball, gadgets for main supported languages are already installed for you. * Using `:VimspectorInstall ` (use TAB `wildmenu` to see the options, also accepts any `install_gadget.py` option) @@ -350,7 +350,7 @@ There are a few ways to do this: * Using `:VimspectorUpdate` to install the latest supported versions of the gadgets. -Here's a demo of doing somee installs and an upgrade: +Here's a demo of doing some installs and an upgrade: [![asciicast](https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay.svg)](https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay) @@ -364,7 +364,7 @@ they will: install the gadgets manually. * Perform any necessary post-installation actions, such as: * Building any binary components - * Ensuring scripts are executable, because the VSIX pacakges are usually + * Ensuring scripts are executable, because the VSIX packages are usually broken in this regard. * Set up the `gadgetDir` symlinks for the platform. @@ -570,7 +570,7 @@ The plugin is currently _experimental_. That means that any part of it can (and probably will) change, including things like: - breaking changes to the configuration -- keys, layout, functionatlity of the UI +- keys, layout, functionality of the UI However, I commit to only doing this in the most extreme cases and to annouce such changes on Gitter well in advance. There's nothing more annoying than stuff @@ -628,7 +628,7 @@ Copyright © 2018 Ben Jackson ## Sponsorship -If you like Vimspector so much that you're wiling to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the author of Vimspector (in order of prefernce): +If you like Vimspector so much that you're wiling to part with your hard-earned cash, please consider donating to one of the following charities, which are meaningful to the author of Vimspector (in order of preference): * [Greyhound Rescue Wales](https://greyhoundrescuewales.co.uk) * [Cancer Research UK](https://www.cancerresearchuk.org) @@ -784,7 +784,7 @@ For example, to get an array of configurations and fuzzy matching on the result ## Breakpoints -See the [mappings](€mappings) section for the default mappngs for working with +See the [mappings](€mappings) section for the default mappings for working with breakpoints. This section describes the full API in vimscript functions. ### Summary @@ -806,7 +806,7 @@ Examples: * `call vimspector#SetLineBreakpoint( 'some_file.py', 10 )` - set a breakpoint on `some_filepy:10` * `call vimspector#AddFunctionBreakpoint( 'main' )` - add a function breakpoint - on the `main` funciton + on the `main` function * `call vimspector#ToggleBreakpoint( { 'condition': 'i > 5' } )` - add a breakpoint on the current line that triggers only when `i > 5` is `true` * `call vimspector#SetLineBreakpoint( 'some_file.py', 10, { 'condition': 'i > 5' } )` - add a @@ -817,7 +817,7 @@ Examples: ### Line breakpoints -The simplest and most common form of breakpoint is a line breakpoint. Exectuion +The simplest and most common form of breakpoint is a line breakpoint. Execution is paused when the specified line is executed. For most debugging scenarios, users will just hit `` to create a line @@ -825,7 +825,7 @@ breakpoint on the current line and `` to launch the application. ### Conditional breakpoints -Some debug adatpers support conditional breakpionts. Note that vimspector does +Some debug adapters support conditional breakpionts. Note that vimspector does not tell you if the debugger doesn't support conditional breakpoints (yet). A conditional breakpiont is a breakpiont which only triggers if some expression evaluates to true, or has some other constraints met. @@ -833,11 +833,11 @@ evaluates to true, or has some other constraints met. Some of these functions above take a single optional argument which is a dictionary of options. The dictionary can have the following keys: -* `condition`: An optional expression evaluated to deterimie if the breakpoint +* `condition`: An optional expression evaluated to determine if the breakpoint should fire. Not supported by all debug adapters. For example, to break when `abc` is `10`, enter something like `abc == 10`, depending on the language. * `hitCondition`: An optional expression evaluated to determine a number of - times the breakpoint should be ignored. Should (probablty?) not be used in + times the breakpoint should be ignored. Should (probably?) not be used in combination with `condition`. Not supported by all debug adapters. For example, to break on the 3rd time hitting this line, enter `3`. @@ -851,7 +851,7 @@ expressions in a command line (with history). Exception breakpoints typically fire when an exception is throw or other error condition occurs. Depending on the debugger, when starting debugging, you may be -asekd a few questions about how to handle exceptoins. These are "exception +asked a few questions about how to handle exceptions. These are "exception breakpoints" and vimspector remembers your choices while Vim is still running. Typically you can accept the defaults (just keep pressing ``!) as most debug @@ -912,7 +912,7 @@ The watches are represented by the buffer `vimspector.StackTrace`. ### Watch autocompletion The watch prompt buffer has its `omnifunc` set to a function that will -calcualte completion for the current expression. This is trivailly used with +calculate completion for the current expression. This is trivially used with `` (see `:help ins-completion`), or integrated with your favourite completion system. The filetype in the buffer is set to `VimspectorPrompt`. @@ -927,8 +927,8 @@ let g:ycm_semantic_triggers = { ## Stack Traces -The stack trace window shows the state of each progream thread. Threads which -are stopped can be expanded to show the strack trace of that thread. +The stack trace window shows the state of each program thread. Threads which +are stopped can be expanded to show the stack trace of that thread. Often, but not always, all threads are stopped when a breakpoint is hit. The status of a thread is show in parentheses after the thread's name. Where @@ -988,7 +988,7 @@ If the output window is closed, a new one can be opened with ### Console autocompletion The console prompt buffer has its `omnifunc` set to a function that will -calcualte completion for the current command/expression. This is trivailly used +calculate completion for the current command/expression. This is trivially used with `` (see `:help ins-completion`), or integrated with your favourite completion system. The filetype in the buffer is set to `VimspectorPrompt`. @@ -1659,7 +1659,7 @@ This debugger uses stdio to communicate with the running process, so calls to # Customisation -There is very limited support for customistaion of the UI. +There is very limited support for customisation of the UI. ## Changing the default signs @@ -1687,7 +1687,7 @@ sign define vimspectorPCBP text=●▶ texthl=MatchParen linehl=CursorLin ``` If the signs don't display properly, your font probably doesn't contain these -glyphs. You can easily change them by deifining the sign in your vimrc. For +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 @@ -1733,7 +1733,7 @@ smaller ones. ## Changing the default window sizes > ***Please Note***: This cusomiation API is ***unstable***, meaning that it may -change at any time. I will endeavour to reduce the impact of this and annouce +change at any time. I will endeavour to reduce the impact of this and announce changes in Gitter. The following options control the default sizes of the UI windows (all of them @@ -1786,7 +1786,7 @@ let g:vimspector_terminal_minwidth = 20 ## Advanced UI customisation > ***Please Note***: This cusomiation API is ***unstable***, meaning that it may -change at any time. I will endeavour to reduce the impact of this and annouce +change at any time. I will endeavour to reduce the impact of this and announce changes in Gitter. The above customisation of window sizes is limited intentionally to keep things @@ -1818,7 +1818,7 @@ keys: * `g:vimspector_session_windows.variables`: Window ID of the variables window, containing the `vimspector.Variables` buffer. * `g:vimspector_session_windows.watches`: Window ID of the watches window, - containng the `vimspector.Watches` buffer. + containing the `vimspector.Watches` buffer. * `g:vimspector_session_windows.stack_trace`: Window ID of the stack trade window containing the `vimspector.StackTrace` buffer. * `g:vimspector_session_windows.code`: Window ID of the code window. @@ -1877,7 +1877,7 @@ augroup END There is some example code in `support/custom_ui_vimrc` showing how you can use the window IDs to modify various aspects of the UI using some basic vim -commands, primarily `win_gotoid` funciton and the `wincmd` ex command. +commands, primarily `win_gotoid` function and the `wincmd` ex command. To try this out `vim -Nu support/custom_ui_vimrc `. @@ -1937,7 +1937,7 @@ hi link jsonComment Comment ``` 7. What is the difference between a `gadget` and an `adapter`? A gadget is - somethin you install with `:VimspectorInstall` or `install_gadget.py`, an + something you install with `:VimspectorInstall` or `install_gadget.py`, an `adapter` is something that Vimspector talks to (actually it's the Vimspector config describing that thing). These are _usually_ one-to-one, but in theory a single gadget can supply multiple `adapter` configs. From 52eff3265181bbbe5338818dc5bc196e234cea45 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 10 Jan 2021 12:59:59 +0000 Subject: [PATCH 027/200] Telemetry data myth busted. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0917bc9..4dc3580 100644 --- a/README.md +++ b/README.md @@ -1945,6 +1945,10 @@ hi link jsonComment Comment for, say remote debugging, or debugging in a container, etc. 8. The signs and winbar display funny symbols. How do i fix them? See [this](#changing-the-default-signs) and [this](#customising-the-winbar) +9. What's thie telemetry stuff all about? Are you sending my data to evil companies? + 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. [ycmd]: https://github.com/Valloric/ycmd From 30eec0d93cd265dad9dfdc07479b6a3d014572fb Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 6 Feb 2021 20:05:33 +0000 Subject: [PATCH 028/200] 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. --- python3/vimspector/utils.py | 4 +- tests/lib/run_test.vim | 14 +++- tests/python/Test_ExpandReferencesInDict.py | 79 +++++++++++++++++++++ tests/utils.test.vim | 28 ++++++++ 4 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 tests/python/Test_ExpandReferencesInDict.py create mode 100644 tests/utils.test.vim diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 5ab9872..770b750 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -460,8 +460,8 @@ VAR_MATCH = re.compile( {(?P # or An {id:default} - default param, as (?P[_a-z][_a-z0-9]*) # an ID : # then a colon - (?P(?:[^}]|\})*) # then anything up to }, or a \} - )} | # + (?P(?:\\}|[^}])+) # then anything up to }, or a \} + )} | # then a } (?P) # or Something else - invalid ) """, diff --git a/tests/lib/run_test.vim b/tests/lib/run_test.vim index 9006af1..b2f1095 100644 --- a/tests/lib/run_test.vim +++ b/tests/lib/run_test.vim @@ -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 diff --git a/tests/python/Test_ExpandReferencesInDict.py b/tests/python/Test_ExpandReferencesInDict.py new file mode 100644 index 0000000..db1ce14 --- /dev/null +++ b/tests/python/Test_ExpandReferencesInDict.py @@ -0,0 +1,79 @@ +import sys +import unittest +from unittest.mock import patch +from vimspector import utils + + +class TestExpandReferencesInDict( unittest.TestCase ): + def test_ExpandReferencesInDict( self ): + mapping = { + 'one': 'one', + 'two': 'TWO', + 'bool': True, + 'words': 'these are some words' + } + calculus = { + 'three': lambda : 1 + 2 + } + CHOICES = { + 'five': '5ive!' + } + + def AskForInput( prompt, default_value = None ): + if default_value is not None: + return default_value + + return 'typed text' + + d = { + 'dollar': '$$', + 'not_a_var': '$${test}', + 'one': '${one}', + 'two': '${one} and ${two}', + 'three': '${three}', + 'four': '${four}', + 'five': '${five}', + 'list': [ '*${words}' ], + 'list1': [ 'start', '*${words}', 'end' ], + 'list2': [ '*${words}', '${three}' ], + 'list3': [ '${one}', '*${words}', 'three' ], + 'dict#json': '{ "key": "value" }', + 'bool#json': 'false', + 'one_default': '${one_default:one}', + 'two_default': '${two_default_1:one} and ${two_default_2:two}', + 'one_default2': '${one_default2:${one\\}}', + 'two_default2': + '${two_default2_1:${one\\}} and ${two_default2_2:${two\\}}', + } + + e = { + 'dollar': '$', + 'not_a_var': '${test}', + 'one': 'one', + 'two': 'one and TWO', + 'three': '3', + 'four': 'typed text', + 'five': '5ive!', + 'list': [ 'these', 'are', 'some', 'words' ], + 'list1': [ 'start', 'these', 'are', 'some', 'words', 'end' ], + 'list2': [ 'these', 'are', 'some', 'words', '3' ], + 'list3': [ 'one', 'these', 'are', 'some', 'words', 'three' ], + 'dict': { + 'key': 'value', + }, + 'bool': False, + 'one_default': 'one', + 'two_default': 'one and two', + 'one_default2': 'one', + 'two_default2': 'one and TWO', + } + + with patch( 'vimspector.utils.AskForInput', side_effect = AskForInput ): + utils.ExpandReferencesInDict( d, mapping, calculus, CHOICES ) + + self.assertDictEqual( d, e ) + + +unittest.main( module=__name__, + testRunner=unittest.TextTestRunner( sys.stdout ), + exit=False ) diff --git a/tests/utils.test.vim b/tests/utils.test.vim new file mode 100644 index 0000000..ad485ce --- /dev/null +++ b/tests/utils.test.vim @@ -0,0 +1,28 @@ +function! SetUp() + call vimspector#test#setup#SetUpWithMappings( v:none ) + py3 import vim + py3 __import__( 'vimspector' ) +endfunction + +function! ClearDown() + call vimspector#test#setup#ClearDown() +endfunction + +function! s:RunPyFile( file_name ) + redir => py_output + try + let v:errmsg = '' + silent! execute 'py3file python/' .. a:file_name + finally + redir END + call TestLog( [ a:file_name .. ' output:' ] + split( py_output, '\n' ) ) + endtry + + if v:errmsg !=# '' + call assert_report( v:errmsg ) + endif +endfunction + +function! Test_ExpandReferencesInDict() + call s:RunPyFile( 'Test_ExpandReferencesInDict.py' ) +endfunction From 7f77842ab89524d2d3b45a4fe7198fb51ac9e0a8 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 6 Feb 2021 22:07:53 +0000 Subject: [PATCH 029/200] Make sure that tests fail properly; ensure that empty string is a valid default --- python3/vimspector/utils.py | 2 +- tests/python/Test_ExpandReferencesInDict.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 770b750..e621d33 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -460,7 +460,7 @@ VAR_MATCH = re.compile( {(?P # or An {id:default} - default param, as (?P[_a-z][_a-z0-9]*) # an ID : # then a colon - (?P(?:\\}|[^}])+) # then anything up to }, or a \} + (?P(?:\\}|[^}])*) # then anything up to }, or a \} )} | # then a } (?P) # or Something else - invalid ) diff --git a/tests/python/Test_ExpandReferencesInDict.py b/tests/python/Test_ExpandReferencesInDict.py index db1ce14..4998350 100644 --- a/tests/python/Test_ExpandReferencesInDict.py +++ b/tests/python/Test_ExpandReferencesInDict.py @@ -5,6 +5,10 @@ from vimspector import utils class TestExpandReferencesInDict( unittest.TestCase ): + def __init__( self, *args, **kwargs ): + super().__init__( *args, **kwargs ) + self.maxDiff = 4096 + def test_ExpandReferencesInDict( self ): mapping = { 'one': 'one', @@ -13,7 +17,7 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'words': 'these are some words' } calculus = { - 'three': lambda : 1 + 2 + 'three': lambda : 1 + 2, } CHOICES = { 'five': '5ive!' @@ -44,6 +48,8 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'one_default2': '${one_default2:${one\\}}', 'two_default2': '${two_default2_1:${one\\}} and ${two_default2_2:${two\\}}', + 'unlikely_name#json#s': 'true', + 'empty_splice': [ '*${empty:}' ], } e = { @@ -66,6 +72,8 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'two_default': 'one and two', 'one_default2': 'one', 'two_default2': 'one and TWO', + 'unlikely_name#json': 'true', + 'empty_splice': [], } with patch( 'vimspector.utils.AskForInput', side_effect = AskForInput ): @@ -74,6 +82,6 @@ class TestExpandReferencesInDict( unittest.TestCase ): self.assertDictEqual( d, e ) -unittest.main( module=__name__, - testRunner=unittest.TextTestRunner( sys.stdout ), - exit=False ) +assert unittest.main( module=__name__, + testRunner=unittest.TextTestRunner( sys.stdout ), + exit=False ).result.wasSuccessful() From 0cc4322b18b54239304723d93c6a3fb76eeb7755 Mon Sep 17 00:00:00 2001 From: Mark Wu Date: Wed, 10 Feb 2021 20:01:18 +0800 Subject: [PATCH 030/200] Update vscode-php-debug to 1.14.9, it works for both Xdebug 2/3 --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index fecb363..d1b6872 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -376,14 +376,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', + 'version': 'v1.14.9', 'file_name': 'php-debug.vsix', 'checksum': - '8a51e593458fd14623c1c89ebab87347b087d67087717f18bcf77bb788052718', + '0c5709cbbffe26b12aa63a88142195a9a045a5d8fca7fe63d62c789fe601630d', }, 'adapters': { 'vscode-php-debug': { From cb922bdc839200092f85485c8332782416e90d0d Mon Sep 17 00:00:00 2001 From: Tim Tyrrell Date: Sun, 14 Feb 2021 11:56:27 -0700 Subject: [PATCH 031/200] Update README typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4dc3580..8e7a036 100644 --- a/README.md +++ b/README.md @@ -1446,7 +1446,7 @@ php Requires: * `install_gadget.py --force-enable-node` -* For installation, a Node.js environemt that is < node 12. I believe this is an +* For installation, a Node.js environment that is < node 12. I believe this is an incompatibility with gulp. Advice, use [nvm][] with `nvm install --lts 10; nvm use --lts 10; ./install_gadget.py --force-enable-node ...` * Options described here: From 7c4eef909626e6cc1e9fdf9baba201e42210e7d0 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 29 Nov 2020 00:53:11 -0500 Subject: [PATCH 032/200] finally got float window working with variable evaluation --- autoload/vimspector/internal/balloon.vim | 12 ++++++++++++ autoload/vimspector/internal/state.vim | 22 ++++++++++++++++++++++ python3/vimspector/utils.py | 4 ++++ 3 files changed, 38 insertions(+) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 360ed08..bdceec4 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -29,6 +29,18 @@ function! vimspector#internal#balloon#BalloonExpr() abort \ . 'vim.eval( "v:beval_text" ) )' ) endfunction +" Returns: py.ShowBalloon( winnr, expresssion ) +function! vimspector#internal#balloon#Tooltip() 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( "expand(\"\")" ) )' ) +endfunction + + + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index f1e690a..d9d8cd2 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -47,6 +47,28 @@ function! vimspector#internal#state#GetAPIPrefix() abort return s:prefix endfunction +" REMOVEME: this is just a temporary thing to get float window working +" Returns: py.ShowBalloon( winnr, expresssion ) +function! vimspector#internal#state#Tooltip() 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( "winnr()" ) ) ,' + \ . 'vim.eval( "expand(\"\")" ) )' ) +endfunction + +function! vimspector#internal#state#TooltipExec(body) abort + let buf = nvim_create_buf(v:false, v:true) + call nvim_buf_set_lines(buf, 0, -1, v:true, a:body) + let opts = { 'relative': 'cursor', 'width': 40, 'height': 2, 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } + let g:float_win = nvim_open_win(buf, 0, opts) + + augroup vimspector#internal#balloon#nvim_float + autocmd! + autocmd CursorMoved * :call nvim_win_close(g:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float + augroup END +endfunction " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index e621d33..576c493 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -635,6 +635,10 @@ def ParseVariables( variables_list, def DisplayBaloon( is_term, display ): + if int(vim.eval("has('nvim')")): + vim.eval("vimspector#internal#state#TooltipExec({})".format(display)) + return + if not is_term: display = '\n'.join( display ) # To enable the Windows GUI to display the balloon correctly From 4c0ba92ac61db2ea422270d9b997d0099116825d Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 8 Dec 2020 21:03:40 -0500 Subject: [PATCH 033/200] working on variables view --- autoload/vimspector/internal/state.vim | 20 +++++- python3/vimspector/variables.py | 91 ++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index d9d8cd2..ade14bb 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -58,10 +58,28 @@ function! vimspector#internal#state#Tooltip() abort \ . 'vim.eval( "expand(\"\")" ) )' ) endfunction +function! vimspector#internal#state#CreateTooltip() abort + +endfunction + function! vimspector#internal#state#TooltipExec(body) abort let buf = nvim_create_buf(v:false, v:true) call nvim_buf_set_lines(buf, 0, -1, v:true, a:body) - let opts = { 'relative': 'cursor', 'width': 40, 'height': 2, 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } + + " get the max width on a line + let width = 0 + let maxWidth = winwidth() + + for w in a:body + let width = max(len(w), width) + " reached the max size, no point in looping more + if width > maxWidth + let width = maxWidth + break + endif + endfor + + let opts = { 'relative': 'cursor', 'width': width, 'height': len(a:body), 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } let g:float_win = nvim_open_win(buf, 0, opts) augroup vimspector#internal#balloon#nvim_float diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 4028722..a67c06e 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -371,6 +371,10 @@ class VariablesView( object ): }, } ) + + + + def _DrawVariables( self, view, variables, indent ): assert indent > 0 for variable in variables: @@ -531,5 +535,92 @@ class VariablesView( object ): syntax, self._vars.buf, self._watch.buf ) +class VariableEval + def __init__(self, stackTrace): + self.stackTrace = stackTrace + self._connection = None + self.variable = Variable() + def _ConsumeVariables(self, parent, message): + new_variables = [] + for variable_body in message[ 'body' ][ 'variables' ]: + if parent.variables is None: + parent.variables = [] + + # Find the variable in parent + found = False + for index, v in enumerate( parent.variables ): + if v.variable[ 'name' ] == variable_body[ 'name' ]: + variable = v + found = True + break + + if not found: + variable = Variable( variable_body ) + else: + variable.Update( variable_body ) + + new_variables.append( variable ) + + if variable.IsExpandable() and variable.IsExpanded(): + self._connection.DoRequest( partial( self._ConsumeVariables, + draw, + variable ), { + 'command': 'variables', + 'arguments': { + 'variablesReference': variable.VariablesReference() + }, + } ) + + parent.variables = new_variables + + def _DrawVariables( self, variables, indent ): + assert indent > 0 + for variable in variables: + line = utils.AppendToBuffer( + view.buf, + '{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' ], + type_ = variable.variable.get( 'type', '' ), + value = variable.variable.get( 'value', + '' ) ).split( '\n' ) ) + view.lines[ line ] = variable + + if variable.ShouldDrawDrillDown(): + self._DrawVariables( view, variable.variables, indent + 2 ) + + def AddVariableEval( self, bufid ): + current_symbol = vim.eval("expand('')") + + 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. + _ConsumeVariables(self, self.variable, message) + variableEvalView = View( variables_win, {}, self._DrawScopes ) + _DrawVariables(self, self.variable, 0) + + + def failure_handler(reason, message): + vim.eval("echom {}".format(message)) + + self._connection.DoRequest( handler, { + 'command': 'evaluate', + 'arguments': { + 'expression': expression, + 'frameId': frame[ 'id' ], + 'context': 'hover', + } + }, failure_handler ) + + def ConnectionUp( self, connection ): + self._connection = connection + + def ConnectionClosed(self): + self._connection = None # vim: sw=2 From 07858cc250291f18b5621a88615fa6061c65302b Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 8 Dec 2020 23:00:13 -0500 Subject: [PATCH 034/200] adding on the fly eval of inside a floating window --- autoload/vimspector/internal/state.vim | 12 +- python3/vimspector/debug_session.py | 20 +++ python3/vimspector/variables.py | 165 +++++++++++-------------- 3 files changed, 103 insertions(+), 94 deletions(-) diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index ade14bb..6d3aad4 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -53,7 +53,7 @@ function! vimspector#internal#state#Tooltip() 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(' + return py3eval('_vimspector_session.ShowTooltip(' \ . 'int( vim.eval( "winnr()" ) ) ,' \ . 'vim.eval( "expand(\"\")" ) )' ) endfunction @@ -62,16 +62,20 @@ function! vimspector#internal#state#CreateTooltip() abort endfunction +function! vimspector#internal#state#ShowTooltip() abort + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"\")" ) )') +endfunction + function! vimspector#internal#state#TooltipExec(body) abort let buf = nvim_create_buf(v:false, v:true) call nvim_buf_set_lines(buf, 0, -1, v:true, a:body) " get the max width on a line let width = 0 - let maxWidth = winwidth() + let maxWidth = winwidth(0) for w in a:body - let width = max(len(w), width) + let width = max([len(w), width]) " reached the max size, no point in looping more if width > maxWidth let width = maxWidth @@ -79,8 +83,10 @@ function! vimspector#internal#state#TooltipExec(body) abort endif endfor + let opts = { 'relative': 'cursor', 'width': width, 'height': len(a:body), 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } let g:float_win = nvim_open_win(buf, 0, opts) + call setwinvar(g:float_win, '&wrap', 0) augroup vimspector#internal#balloon#nvim_float autocmd! diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index ea72651..e741d88 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -538,6 +538,26 @@ class DebugSession( object ): def DeleteWatch( self ): self._variablesView.DeleteWatch() + + @IfConnected() + def ShowTooltip(self, winnr, expression): + """Proxy: ballonexpr -> variables.ShowBallon""" + frame = self._stackTraceView.GetCurrentFrame() + # Check if RIP is in a frame + if frame is None: + self._logger.debug( 'Balloon: Not in a stack frame' ) + return '' + + # Check if cursor in code window + if winnr != int( self._codeView._window.number ): + self._logger.debug( 'Winnr %s is not the code window %s', + winnr, + self._codeView._window.number ) + return '' + + # Return variable aware function + return self._variablesView.VariableEval(frame, expression) + @IfConnected() def ShowBalloon( self, winnr, expression ): """Proxy: ballonexpr -> variables.ShowBallon""" diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index a67c06e..ec18a71 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -125,9 +125,9 @@ class View: def __init__( self, win, lines, draw ): self.lines = lines self.draw = draw - self.buf = win.buffer - - utils.SetUpUIWindow( win ) + if (win is not None): + self.buf = win.buffer + utils.SetUpUIWindow( win ) class VariablesView( object ): @@ -138,6 +138,8 @@ class VariablesView( object ): self._connection = None self._current_syntax = '' + self._variable_eval = None + def AddExpandMappings(): vim.command( 'nnoremap ' ':call vimspector#ExpandVariable()' ) @@ -267,6 +269,75 @@ class VariablesView( object ): }, } ) + def _DrawEval(self): + # TODO: create vim functin that creates a floating window and returns window id + # use that window id to retrieve the buffer + # use that buffer in order to populate the results of the query + indent = 0 + icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' + + line = utils.AppendToBuffer( self._vars.buf, + '{0}{1} Scope: {2}'.format( + ' ' * indent, + icon, + self._variable_eval.scope[ 'name' ] ) ) + self._vars.lines[ line ] = self._variable_eval + + if self._variable_eval.ShouldDrawDrillDown(): + indent += 2 + # replace with a newly created view for the purposes of evaluation + self._DrawVariables( self._vars, self._variable_eval.variables, indent ) + + # vim.eval("vimspector#internal#state#TooltipExec({})".format([self._variable_eval])) + + + def VariableEval(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', '' ), + 'Value: ' + result + ] + + self._variable_eval = Scope(body) + + self._connection.DoRequest( partial( self._ConsumeVariables, + self._DrawEval, + self._variable_eval ), { + 'command': 'variables', + 'arguments': { + 'variablesReference': self._variable_eval.VariablesReference(), + }, + } ) + + + 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 AddWatch( self, frame, expression ): watch = { 'expression': expression, @@ -535,92 +606,4 @@ class VariablesView( object ): syntax, self._vars.buf, self._watch.buf ) -class VariableEval - def __init__(self, stackTrace): - self.stackTrace = stackTrace - self._connection = None - self.variable = Variable() - - def _ConsumeVariables(self, parent, message): - new_variables = [] - for variable_body in message[ 'body' ][ 'variables' ]: - if parent.variables is None: - parent.variables = [] - - # Find the variable in parent - found = False - for index, v in enumerate( parent.variables ): - if v.variable[ 'name' ] == variable_body[ 'name' ]: - variable = v - found = True - break - - if not found: - variable = Variable( variable_body ) - else: - variable.Update( variable_body ) - - new_variables.append( variable ) - - if variable.IsExpandable() and variable.IsExpanded(): - self._connection.DoRequest( partial( self._ConsumeVariables, - draw, - variable ), { - 'command': 'variables', - 'arguments': { - 'variablesReference': variable.VariablesReference() - }, - } ) - - parent.variables = new_variables - - def _DrawVariables( self, variables, indent ): - assert indent > 0 - for variable in variables: - line = utils.AppendToBuffer( - view.buf, - '{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' ], - type_ = variable.variable.get( 'type', '' ), - value = variable.variable.get( 'value', - '' ) ).split( '\n' ) ) - view.lines[ line ] = variable - - if variable.ShouldDrawDrillDown(): - self._DrawVariables( view, variable.variables, indent + 2 ) - - def AddVariableEval( self, bufid ): - current_symbol = vim.eval("expand('')") - - 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. - _ConsumeVariables(self, self.variable, message) - variableEvalView = View( variables_win, {}, self._DrawScopes ) - _DrawVariables(self, self.variable, 0) - - - def failure_handler(reason, message): - vim.eval("echom {}".format(message)) - - self._connection.DoRequest( handler, { - 'command': 'evaluate', - 'arguments': { - 'expression': expression, - 'frameId': frame[ 'id' ], - 'context': 'hover', - } - }, failure_handler ) - - def ConnectionUp( self, connection ): - self._connection = connection - - def ConnectionClosed(self): - self._connection = None # vim: sw=2 From 7432be95329c0fe1ed531c75acb672be4646e835 Mon Sep 17 00:00:00 2001 From: dsych Date: Wed, 9 Dec 2020 23:19:32 -0500 Subject: [PATCH 035/200] implemented dynamic float windows for nvim --- autoload/vimspector/internal/state.vim | 27 ++++++---- python3/vimspector/variables.py | 74 +++++++++++++------------- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index 6d3aad4..b80a4b7 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -47,19 +47,24 @@ function! vimspector#internal#state#GetAPIPrefix() abort return s:prefix endfunction -" REMOVEME: this is just a temporary thing to get float window working -" Returns: py.ShowBalloon( winnr, expresssion ) -function! vimspector#internal#state#Tooltip() 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.ShowTooltip(' - \ . 'int( vim.eval( "winnr()" ) ) ,' - \ . 'vim.eval( "expand(\"\")" ) )' ) -endfunction - function! vimspector#internal#state#CreateTooltip() abort + let buf = nvim_create_buf(v:false, v:true) + call nvim_buf_set_lines(buf, 0, -1, v:true, []) + " default the dimensions for now. they can be easily overwritten later + let opts = { 'relative': 'cursor', 'width': 50, 'height': 2, 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } + let g:float_win = nvim_open_win(buf, 0, opts) + call setwinvar(g:float_win, '&wrap', 0) + + call win_gotoid(g:float_win) + + " make sure we clean up the float after it loses focus + augroup vimspector#internal#balloon#nvim_float + autocmd! + autocmd WinLeave * :call nvim_win_close(g:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float + augroup END + + return g:float_win endfunction function! vimspector#internal#state#ShowTooltip() abort diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index ec18a71..7019168 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -139,6 +139,8 @@ class VariablesView( object ): self._current_syntax = '' self._variable_eval = None + self._variable_eval_view = None + self._variable_eval_win = None def AddExpandMappings(): vim.command( 'nnoremap ' @@ -270,25 +272,12 @@ class VariablesView( object ): } ) def _DrawEval(self): - # TODO: create vim functin that creates a floating window and returns window id - # use that window id to retrieve the buffer - # use that buffer in order to populate the results of the query - indent = 0 - icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' + self._variable_eval_win.height = min(5, len(self._variable_eval.variables)) + with utils.RestoreCursorPosition(): + utils.ClearBuffer( self._variable_eval_view.buf ) + icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' - line = utils.AppendToBuffer( self._vars.buf, - '{0}{1} Scope: {2}'.format( - ' ' * indent, - icon, - self._variable_eval.scope[ 'name' ] ) ) - self._vars.lines[ line ] = self._variable_eval - - if self._variable_eval.ShouldDrawDrillDown(): - indent += 2 - # replace with a newly created view for the purposes of evaluation - self._DrawVariables( self._vars, self._variable_eval.variables, indent ) - - # vim.eval("vimspector#internal#state#TooltipExec({})".format([self._variable_eval])) + self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 ) def VariableEval(self, frame, expression): @@ -297,28 +286,38 @@ class VariablesView( object ): 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', '' ), - 'Value: ' + result - ] self._variable_eval = Scope(body) - self._connection.DoRequest( partial( self._ConsumeVariables, - self._DrawEval, - self._variable_eval ), { - 'command': 'variables', - 'arguments': { - 'variablesReference': self._variable_eval.VariablesReference(), - }, - } ) + float_win_id = vim.eval("vimspector#internal#state#CreateTooltip()") + self._variable_eval_win = vim.current.window + + with utils.LetCurrentWindow( self._variable_eval_win ): + vim.command( 'nnoremap ' + ':call vimspector#ExpandVariable()' ) + vim.command( 'nnoremap ' + ':quit' ) + vim.command( 'nnoremap <2-LeftMouse> ' + ':call vimspector#ExpandVariable()' ) + + + if(self._variable_eval.VariablesReference() > 0): + self._variable_eval_view = View(self._variable_eval_win, {}, self._DrawEval) + self._connection.DoRequest( partial( self._ConsumeVariables, + self._DrawEval, + self._variable_eval ), { + 'command': 'variables', + 'arguments': { + 'variablesReference': self._variable_eval.VariablesReference(), + }, + } ) + else: + # in case that there is nothing to expand, we need to simulate a response from 'variables' request + # it returns [Variable] + self._variable_eval_view = View(self._variable_eval_win, {}, self._DrawEval) + self._variable_eval.variables = [Variable({'name': expression, 'value': body['result']})] + self._DrawEval() def failure_handler( reason, message ): @@ -414,6 +413,8 @@ class VariablesView( object ): view = self._vars elif vim.current.buffer == self._watch.buf: view = self._watch + elif vim.current.buffer == self._variable_eval_view.buf: + view = self._variable_eval_view else: return @@ -542,7 +543,6 @@ class VariablesView( object ): variable = v found = True break - if not found: variable = Variable( variable_body ) else: From 4e994968ffff31cdf30030f66b94a36b861468d7 Mon Sep 17 00:00:00 2001 From: dsych Date: Sat, 12 Dec 2020 17:48:50 -0500 Subject: [PATCH 036/200] added popup support for vim, still need to figure out how to expand variables --- autoload/vimspector/internal/state.vim | 97 +++++++++++++++++++++----- python3/vimspector/variables.py | 21 ++---- 2 files changed, 88 insertions(+), 30 deletions(-) diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index b80a4b7..bf2abde 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -47,24 +47,89 @@ function! vimspector#internal#state#GetAPIPrefix() abort return s:prefix endfunction +let s:float_win = 0 + function! vimspector#internal#state#CreateTooltip() abort - let buf = nvim_create_buf(v:false, v:true) - call nvim_buf_set_lines(buf, 0, -1, v:true, []) + if has('nvim') + let buf = nvim_create_buf(v:false, v:true) + call nvim_buf_set_lines(buf, 0, -1, v:true, []) - " default the dimensions for now. they can be easily overwritten later - let opts = { 'relative': 'cursor', 'width': 50, 'height': 2, 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } - let g:float_win = nvim_open_win(buf, 0, opts) - call setwinvar(g:float_win, '&wrap', 0) + " default the dimensions for now. they can be easily overwritten later + let opts = { + \ 'relative': 'cursor', + \ 'width': 50, + \ 'height': 2, + \ 'col': 0, + \ 'row': 1, + \ 'anchor': 'NW', + \ 'style': 'minimal' + \ } + let s:float_win = nvim_open_win(buf, 0, opts) + call setwinvar(s:float_win, '&wrap', 1) + call setwinvar(s:float_win, '&cursorline', 1) - call win_gotoid(g:float_win) + call win_gotoid(s:float_win) - " make sure we clean up the float after it loses focus - augroup vimspector#internal#balloon#nvim_float - autocmd! - autocmd WinLeave * :call nvim_win_close(g:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float - augroup END + nnoremap :call vimspector#ExpandVariable() + nnoremap :quit + nnoremap <2-LeftMouse>:call vimspector#ExpandVariable() - return g:float_win + " make sure we clean up the float after it loses focus + augroup vimspector#internal#balloon#nvim_float + autocmd! + autocmd WinLeave * :call nvim_win_close(s:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float + augroup END + + else + " assume we are inside vim + func! MyFilter(winid, key) + if index(['j', 'k', 'h', 'l'], a:key) >= 0 + call win_execute(a:winid, ':normal '.a:key) + " do something + return 1 + elseif a:key == "\" + echo 'pressed left mouse' + let mouse_coords = getmousepos() + " close the popup if mouse is clicked outside the window + if mouse_coords['winid'] != a:winid + call popup_close(a:winid) + endif + + echo 'clicked line '.mouse_coords['line'] + call win_execute(a:winid, ":call cursor(".mouse_coords['line'].", ".mouse_coords['column'].")") + return 1 + elseif a:key == "\" + echo 'pressed enter at line '.line(".", a:winid) + echo 'here' + call vimspector#ExpandVariable() + + return 1 + elseif a:key == "\" + call popup_close(a:winid) + let s:float_win = 0 + return 1 + endif + return 0 + endfunc + + if s:float_win != 0 + popup_close(s:float_win) + endif + + let s:float_win = popup_create([], #{ + \ filter: "MyFilter", + \ cursorline: 1, + \ wrap: 1, + \ filtermode: "n", + \ maxwidth: 50, + \ maxheight: 5, + \ scrollbar: 1, + \ moved: "any", + \ }) + + endif + + return s:float_win endfunction function! vimspector#internal#state#ShowTooltip() abort @@ -90,12 +155,12 @@ function! vimspector#internal#state#TooltipExec(body) abort let opts = { 'relative': 'cursor', 'width': width, 'height': len(a:body), 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } - let g:float_win = nvim_open_win(buf, 0, opts) - call setwinvar(g:float_win, '&wrap', 0) + let s:float_win = nvim_open_win(buf, 0, opts) + call setwinvar(s:float_win, '&wrap', 0) augroup vimspector#internal#balloon#nvim_float autocmd! - autocmd CursorMoved * :call nvim_win_close(g:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float + autocmd CursorMoved * :call nvim_win_close(s:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float augroup END endfunction " Boilerplate {{{ diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 7019168..f7f8f02 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -140,7 +140,6 @@ class VariablesView( object ): self._variable_eval = None self._variable_eval_view = None - self._variable_eval_win = None def AddExpandMappings(): vim.command( 'nnoremap ' @@ -272,7 +271,6 @@ class VariablesView( object ): } ) def _DrawEval(self): - self._variable_eval_win.height = min(5, len(self._variable_eval.variables)) with utils.RestoreCursorPosition(): utils.ClearBuffer( self._variable_eval_view.buf ) icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' @@ -291,19 +289,14 @@ class VariablesView( object ): self._variable_eval = Scope(body) float_win_id = vim.eval("vimspector#internal#state#CreateTooltip()") - self._variable_eval_win = vim.current.window - - with utils.LetCurrentWindow( self._variable_eval_win ): - vim.command( 'nnoremap ' - ':call vimspector#ExpandVariable()' ) - vim.command( 'nnoremap ' - ':quit' ) - vim.command( 'nnoremap <2-LeftMouse> ' - ':call vimspector#ExpandVariable()' ) + float_buf_nr = int(vim.eval("winbufnr({})".format(float_win_id))) + # since vim's popup cant be focused there is no way + # to get a reference to its window + # we will emulate python's window object overselves + self._variable_eval_view = View(type('__vim__window__', (object,), {'options': {}, 'buffer': vim.buffers[float_buf_nr]}), {}, self._DrawEval) if(self._variable_eval.VariablesReference() > 0): - self._variable_eval_view = View(self._variable_eval_win, {}, self._DrawEval) self._connection.DoRequest( partial( self._ConsumeVariables, self._DrawEval, self._variable_eval ), { @@ -315,7 +308,6 @@ class VariablesView( object ): else: # in case that there is nothing to expand, we need to simulate a response from 'variables' request # it returns [Variable] - self._variable_eval_view = View(self._variable_eval_win, {}, self._DrawEval) self._variable_eval.variables = [Variable({'name': expression, 'value': body['result']})] self._DrawEval() @@ -418,7 +410,8 @@ class VariablesView( object ): else: return - current_line = vim.current.window.cursor[ 0 ] + current_line = int(vim.eval("getbufinfo({})['lnum']".format(view.buf.name))) + print(current_line) if current_line not in view.lines: return From 819d6366aca4808e2b9fe8be562fa1adf6b64ae2 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 13 Dec 2020 20:52:16 -0500 Subject: [PATCH 037/200] fully implemented the hover function for vim --- autoload/vimspector.vim | 4 + autoload/vimspector/internal/balloon.vim | 93 ++++++++++++++++++ autoload/vimspector/internal/state.vim | 116 ----------------------- python3/vimspector/debug_session.py | 7 +- python3/vimspector/variables.py | 21 ++-- 5 files changed, 112 insertions(+), 129 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 35ecd03..fd4b0c5 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -523,6 +523,10 @@ function! vimspector#OnBufferCreated( file_name ) abort py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) ) endfunction +function! vimspector#ShowTooltip() abort + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"\")" ) )') +endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index bdceec4..dc34261 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -40,6 +40,99 @@ function! vimspector#internal#balloon#Tooltip() abort endfunction +let s:float_win = 0 + +function! vimspector#internal#balloon#closeCallback() abort + let s:float_win = 0 + return py3eval('_vimspector_session._CleanUpTooltip()') +endfunction + +function! vimspector#internal#balloon#CreateTooltip() abort + if has('nvim') + let buf = nvim_create_buf(v:false, v:true) + " call nvim_buf_set_option(buf, 'modifiable', v:false) + call nvim_buf_set_lines(buf, 0, -1, v:true, []) + + " default the dimensions for now. they can be easily overwritten later + let opts = #{ + \ relative: 'cursor', + \ width: 50, + \ height: 5, + \ col: 0, + \ row: 1, + \ anchor: 'NW', + \ style: 'minimal' + \ } + let s:float_win = nvim_open_win(buf, 0, opts) + call nvim_win_set_option(s:float_win, 'wrap', v:true) + call nvim_win_set_option(s:float_win, 'cursorline', v:true) + call nvim_win_set_option(s:float_win, 'signcolumn', 'no') + call nvim_win_set_option(s:float_win, 'relativenumber', v:false) + call nvim_win_set_option(s:float_win, 'number', v:false) + + noa call win_gotoid(s:float_win) + + nnoremap :call vimspector#ExpandVariable() + nnoremap :quit + nnoremap <2-LeftMouse>:call vimspector#ExpandVariable() + + " make sure we clean up the float after it loses focus + augroup vimspector#internal#balloon#nvim_float + autocmd! + autocmd WinLeave * :call nvim_win_close(s:float_win, 1) | :call vimspector#internal#balloon#closeCallback() | autocmd! vimspector#internal#balloon#nvim_float + augroup END + + else + " assume we are inside vim + func! MyFilter(winid, key) + if index(['j', 'k'], a:key) >= 0 + call win_execute(a:winid, ':normal '.a:key) + " do something + return 1 + elseif a:key == "\" + let mouse_coords = getmousepos() + " close the popup if mouse is clicked outside the window + if mouse_coords['winid'] != a:winid + call popup_close(a:winid) + endif + + call win_execute(a:winid, ":call cursor(".mouse_coords['line'].", ".mouse_coords['column'].")") + return 1 + elseif a:key == "\" + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") + + return 1 + elseif a:key == "\" + call popup_close(a:winid) + call vimspector#internal#balloon#closeCallback() + return 1 + endif + return 0 + endfunc + + if s:float_win != 0 + call popup_close(s:float_win) + call vimspector#internal#balloon#closeCallback() + endif + + let s:float_win = popup_create([], #{ + \ filter: "MyFilter", + \ cursorline: 1, + \ wrap: 1, + \ filtermode: "n", + \ maxwidth: 50, + \ maxheight: 5, + \ scrollbar: 1, + \ moved: "any", + \ }) + " call setbufvar(winbufnr(s:float_win), '&buflisted', 1) + + endif + + return s:float_win +endfunction " Boilerplate {{{ let &cpoptions=s:save_cpo diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index bf2abde..f1e690a 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -47,122 +47,6 @@ function! vimspector#internal#state#GetAPIPrefix() abort return s:prefix endfunction -let s:float_win = 0 - -function! vimspector#internal#state#CreateTooltip() abort - if has('nvim') - let buf = nvim_create_buf(v:false, v:true) - call nvim_buf_set_lines(buf, 0, -1, v:true, []) - - " default the dimensions for now. they can be easily overwritten later - let opts = { - \ 'relative': 'cursor', - \ 'width': 50, - \ 'height': 2, - \ 'col': 0, - \ 'row': 1, - \ 'anchor': 'NW', - \ 'style': 'minimal' - \ } - let s:float_win = nvim_open_win(buf, 0, opts) - call setwinvar(s:float_win, '&wrap', 1) - call setwinvar(s:float_win, '&cursorline', 1) - - call win_gotoid(s:float_win) - - nnoremap :call vimspector#ExpandVariable() - nnoremap :quit - nnoremap <2-LeftMouse>:call vimspector#ExpandVariable() - - " make sure we clean up the float after it loses focus - augroup vimspector#internal#balloon#nvim_float - autocmd! - autocmd WinLeave * :call nvim_win_close(s:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float - augroup END - - else - " assume we are inside vim - func! MyFilter(winid, key) - if index(['j', 'k', 'h', 'l'], a:key) >= 0 - call win_execute(a:winid, ':normal '.a:key) - " do something - return 1 - elseif a:key == "\" - echo 'pressed left mouse' - let mouse_coords = getmousepos() - " close the popup if mouse is clicked outside the window - if mouse_coords['winid'] != a:winid - call popup_close(a:winid) - endif - - echo 'clicked line '.mouse_coords['line'] - call win_execute(a:winid, ":call cursor(".mouse_coords['line'].", ".mouse_coords['column'].")") - return 1 - elseif a:key == "\" - echo 'pressed enter at line '.line(".", a:winid) - echo 'here' - call vimspector#ExpandVariable() - - return 1 - elseif a:key == "\" - call popup_close(a:winid) - let s:float_win = 0 - return 1 - endif - return 0 - endfunc - - if s:float_win != 0 - popup_close(s:float_win) - endif - - let s:float_win = popup_create([], #{ - \ filter: "MyFilter", - \ cursorline: 1, - \ wrap: 1, - \ filtermode: "n", - \ maxwidth: 50, - \ maxheight: 5, - \ scrollbar: 1, - \ moved: "any", - \ }) - - endif - - return s:float_win -endfunction - -function! vimspector#internal#state#ShowTooltip() abort - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"\")" ) )') -endfunction - -function! vimspector#internal#state#TooltipExec(body) abort - let buf = nvim_create_buf(v:false, v:true) - call nvim_buf_set_lines(buf, 0, -1, v:true, a:body) - - " get the max width on a line - let width = 0 - let maxWidth = winwidth(0) - - for w in a:body - let width = max([len(w), width]) - " reached the max size, no point in looping more - if width > maxWidth - let width = maxWidth - break - endif - endfor - - - let opts = { 'relative': 'cursor', 'width': width, 'height': len(a:body), 'col': 0, 'row': 1, 'anchor': 'NW', 'style': 'minimal' } - let s:float_win = nvim_open_win(buf, 0, opts) - call setwinvar(s:float_win, '&wrap', 0) - - augroup vimspector#internal#balloon#nvim_float - autocmd! - autocmd CursorMoved * :call nvim_win_close(s:float_win, 1) | autocmd! vimspector#internal#balloon#nvim_float - augroup END -endfunction " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index e741d88..8b2196f 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -520,8 +520,8 @@ class DebugSession( object ): self._stackTraceView.SetCurrentThread() @IfConnected() - def ExpandVariable( self ): - self._variablesView.ExpandVariable() + def ExpandVariable( self, lineNum = -1 ): + self._variablesView.ExpandVariable(lineNum) @IfConnected() def AddWatch( self, expression ): @@ -558,6 +558,9 @@ class DebugSession( object ): # Return variable aware function return self._variablesView.VariableEval(frame, expression) + def _CleanUpTooltip(self): + return self._variablesView._CleanUpTooltip() + @IfConnected() def ShowBalloon( self, winnr, expression ): """Proxy: ballonexpr -> variables.ShowBallon""" diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index f7f8f02..2e9d2b2 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -122,7 +122,7 @@ class View: lines: typing.Dict[ int, Expandable ] draw: typing.Callable - def __init__( self, win, lines, draw ): + def __init__( self, win, lines, draw): self.lines = lines self.draw = draw if (win is not None): @@ -277,6 +277,10 @@ class VariablesView( object ): self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 ) + def _CleanUpTooltip(self): + # remove reference to old tooltip window + self._variable_eval_view = None + return '' def VariableEval(self, frame, expression): """Callback to display variable under cursor `:h ballonexpr`""" @@ -288,12 +292,12 @@ class VariablesView( object ): self._variable_eval = Scope(body) - float_win_id = vim.eval("vimspector#internal#state#CreateTooltip()") + float_win_id = vim.eval("vimspector#internal#balloon#CreateTooltip()") float_buf_nr = int(vim.eval("winbufnr({})".format(float_win_id))) # since vim's popup cant be focused there is no way # to get a reference to its window - # we will emulate python's window object overselves + # we will emulate python's window object ourselves self._variable_eval_view = View(type('__vim__window__', (object,), {'options': {}, 'buffer': vim.buffers[float_buf_nr]}), {}, self._DrawEval) if(self._variable_eval.VariablesReference() > 0): @@ -400,18 +404,17 @@ class VariablesView( object ): watch.result = WatchFailure( reason ) self._DrawWatches() - def ExpandVariable( self ): + def ExpandVariable( self, lineNum = -1 ): if vim.current.buffer == self._vars.buf: view = self._vars elif vim.current.buffer == self._watch.buf: view = self._watch - elif vim.current.buffer == self._variable_eval_view.buf: + elif self._variable_eval_view is not None: view = self._variable_eval_view else: return - current_line = int(vim.eval("getbufinfo({})['lnum']".format(view.buf.name))) - print(current_line) + current_line = vim.current.window.cursor[0] if lineNum <= 0 else lineNum if current_line not in view.lines: return @@ -436,10 +439,6 @@ class VariablesView( object ): }, } ) - - - - def _DrawVariables( self, view, variables, indent ): assert indent > 0 for variable in variables: From d2990d7baed2c31aaf79a777f5b337d6d0b16064 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 13 Dec 2020 22:25:27 -0500 Subject: [PATCH 038/200] making sure to open popup relative to cursor --- autoload/vimspector.vim | 2 +- autoload/vimspector/internal/balloon.vim | 31 ++++++++++++++---------- python3/vimspector/debug_session.py | 4 +-- python3/vimspector/utils.py | 12 +++------ python3/vimspector/variables.py | 11 ++++----- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index fd4b0c5..d8018a0 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -524,7 +524,7 @@ function! vimspector#OnBufferCreated( file_name ) abort endfunction function! vimspector#ShowTooltip() abort - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"\")" ) )') + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"\")" ), 0)') endfunction diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index dc34261..89f2b11 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -30,13 +30,8 @@ function! vimspector#internal#balloon#BalloonExpr() abort endfunction " Returns: py.ShowBalloon( winnr, expresssion ) -function! vimspector#internal#balloon#Tooltip() 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( "expand(\"\")" ) )' ) +function! vimspector#internal#balloon#HoverTooltip() abort + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') endfunction @@ -47,11 +42,16 @@ function! vimspector#internal#balloon#closeCallback() abort return py3eval('_vimspector_session._CleanUpTooltip()') endfunction -function! vimspector#internal#balloon#CreateTooltip() abort +function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) + let body = [] + if a:0 > 0 + let body = a:1 + endif + if has('nvim') let buf = nvim_create_buf(v:false, v:true) " call nvim_buf_set_option(buf, 'modifiable', v:false) - call nvim_buf_set_lines(buf, 0, -1, v:true, []) + call nvim_buf_set_lines(buf, 0, -1, v:true, body) " default the dimensions for now. they can be easily overwritten later let opts = #{ @@ -117,7 +117,7 @@ function! vimspector#internal#balloon#CreateTooltip() abort call vimspector#internal#balloon#closeCallback() endif - let s:float_win = popup_create([], #{ + let config = #{ \ filter: "MyFilter", \ cursorline: 1, \ wrap: 1, @@ -125,9 +125,14 @@ function! vimspector#internal#balloon#CreateTooltip() abort \ maxwidth: 50, \ maxheight: 5, \ scrollbar: 1, - \ moved: "any", - \ }) - " call setbufvar(winbufnr(s:float_win), '&buflisted', 1) + \ } + if a:is_hover + let config['mousemoved'] = "word" + let s:float_win = popup_beval(body, config) + else + let config['moved'] = "any" + let s:float_win = popup_atcursor(body, config) + endif endif diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 8b2196f..de5a7c6 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -540,7 +540,7 @@ class DebugSession( object ): @IfConnected() - def ShowTooltip(self, winnr, expression): + def ShowTooltip(self, winnr, expression, is_hover): """Proxy: ballonexpr -> variables.ShowBallon""" frame = self._stackTraceView.GetCurrentFrame() # Check if RIP is in a frame @@ -556,7 +556,7 @@ class DebugSession( object ): return '' # Return variable aware function - return self._variablesView.VariableEval(frame, expression) + return self._variablesView.VariableEval(frame, expression, is_hover) def _CleanUpTooltip(self): return self._variablesView._CleanUpTooltip() diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 576c493..788f03e 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -634,19 +634,13 @@ def ParseVariables( variables_list, return new_variables -def DisplayBaloon( is_term, display ): - if int(vim.eval("has('nvim')")): - vim.eval("vimspector#internal#state#TooltipExec({})".format(display)) - return - +def DisplayBaloon( 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 ) ) ) + return int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format(is_hover, json.dumps( display )) ) ) def GetBufferFilepath( buf ): diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 2e9d2b2..71abc45 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -186,7 +186,7 @@ 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: @@ -282,7 +282,7 @@ class VariablesView( object ): self._variable_eval_view = None return '' - def VariableEval(self, frame, expression): + def VariableEval(self, frame, expression, is_hover): """Callback to display variable under cursor `:h ballonexpr`""" if not self._connection: return '' @@ -291,8 +291,7 @@ class VariablesView( object ): body = message[ 'body' ] self._variable_eval = Scope(body) - - float_win_id = vim.eval("vimspector#internal#balloon#CreateTooltip()") + float_win_id = utils.DisplayBaloon(self._is_term, [], is_hover) float_buf_nr = int(vim.eval("winbufnr({})".format(float_win_id))) # since vim's popup cant be focused there is no way @@ -318,7 +317,7 @@ class VariablesView( object ): def failure_handler( reason, message ): display = [ reason ] - utils.DisplayBaloon( self._is_term, display ) + utils.DisplayBaloon( self._is_term, display, is_hover ) # Send async request self._connection.DoRequest( handler, { @@ -331,7 +330,7 @@ class VariablesView( object ): }, failure_handler ) # Return working (meanwhile) - return '...' + return '' def AddWatch( self, frame, expression ): watch = { From 747ad9b8042a9d0af3635628e1285381b1413fac Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 22 Dec 2020 13:03:37 -0500 Subject: [PATCH 039/200] removing literal dictionary syntax, as it is not included in nvim-4.4 --- autoload/vimspector/internal/balloon.vim | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 89f2b11..866eb65 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -54,14 +54,14 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) call nvim_buf_set_lines(buf, 0, -1, v:true, body) " default the dimensions for now. they can be easily overwritten later - let opts = #{ - \ relative: 'cursor', - \ width: 50, - \ height: 5, - \ col: 0, - \ row: 1, - \ anchor: 'NW', - \ style: 'minimal' + let opts = { + \ 'relative': 'cursor', + \ 'width': 50, + \ 'height': 5, + \ 'col': 0, + \ 'row': 1, + \ 'anchor': 'NW', + \ 'style': 'minimal' \ } let s:float_win = nvim_open_win(buf, 0, opts) call nvim_win_set_option(s:float_win, 'wrap', v:true) @@ -117,14 +117,14 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) call vimspector#internal#balloon#closeCallback() endif - let config = #{ - \ filter: "MyFilter", - \ cursorline: 1, - \ wrap: 1, - \ filtermode: "n", - \ maxwidth: 50, - \ maxheight: 5, - \ scrollbar: 1, + let config = { + \ 'filter': "MyFilter", + \ 'cursorline': 1, + \ 'wrap': 1, + \ 'filtermode': "n", + \ 'maxwidth': 50, + \ 'maxheight': 5, + \ 'scrollbar': 1, \ } if a:is_hover let config['mousemoved'] = "word" From 0ced5eb1d42269c03ef9aa3ad7ff8a58e68857d7 Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 22 Dec 2020 13:57:25 -0500 Subject: [PATCH 040/200] splitting mouse and cursor filtering to avoid trapping keyboard for hover --- autoload/vimspector/internal/balloon.vim | 34 ++++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 866eb65..007c8b0 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -84,19 +84,34 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) else " assume we are inside vim - func! MyFilter(winid, key) - if index(['j', 'k'], a:key) >= 0 - call win_execute(a:winid, ':normal '.a:key) - " do something - return 1 - elseif a:key == "\" + func! MouseFilter(winid, key) + if index(["\", "\<2-leftmouse>"], a:key) >= 0 let mouse_coords = getmousepos() " close the popup if mouse is clicked outside the window if mouse_coords['winid'] != a:winid call popup_close(a:winid) + call vimspector#internal#balloon#closeCallback() 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>" && mouse_coords['winid'] == a:winid + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") + endif + + return 1 + endif + return 0 + endfunc + + func! CursorFiler(winid, key) + if index(['j', 'k'], a:key) >= 0 + call win_execute(a:winid, ':normal '.a:key) + return 1 elseif a:key == "\" " forward line number to python, since vim does not allow us to focus @@ -107,8 +122,10 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) elseif a:key == "\" call popup_close(a:winid) call vimspector#internal#balloon#closeCallback() + return 1 endif + return 0 endfunc @@ -118,7 +135,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) endif let config = { - \ 'filter': "MyFilter", \ 'cursorline': 1, \ 'wrap': 1, \ 'filtermode': "n", @@ -127,9 +143,11 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'scrollbar': 1, \ } if a:is_hover - let config['mousemoved'] = "word" + let config['filter'] = "MouseFilter" + let config['mousemoved'] = [0, 0, 0] let s:float_win = popup_beval(body, config) else + let config['filter'] = "CursorFiler" let config['moved'] = "any" let s:float_win = popup_atcursor(body, config) endif From 4617250f412017a38afe7b2f77ecfa962e17bada Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 22 Dec 2020 23:56:18 -0500 Subject: [PATCH 041/200] adding border to popup --- autoload/vimspector/internal/balloon.vim | 63 +++++++++++++++++++----- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 007c8b0..e2f041d 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -32,13 +32,23 @@ endfunction " Returns: py.ShowBalloon( winnr, expresssion ) function! vimspector#internal#balloon#HoverTooltip() abort return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') + endfunction let s:float_win = 0 +let s:nvim_related_win = 0 function! vimspector#internal#balloon#closeCallback() abort + if has('nvim') + call nvim_win_close(s:float_win, v:true) + call nvim_win_close(s:nvim_related_win, v:true) + else + call popup_close(s:float_win) + endif + let s:float_win = 0 + let s:nvim_related_win = 0 return py3eval('_vimspector_session._CleanUpTooltip()') endfunction @@ -48,22 +58,53 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let body = a:1 endif + " tooltip dimensions + let max_height = 5 + let max_width = 50 + if has('nvim') - let buf = nvim_create_buf(v:false, v:true) - " call nvim_buf_set_option(buf, 'modifiable', v:false) - call nvim_buf_set_lines(buf, 0, -1, v:true, body) + " 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 top = "╭" . repeat("─", max_width) . "╮" + let mid = "│" . repeat(" ", max_width) . "│" + let bot = "╰" . repeat("─", max_width) . "╯" + let lines = [top] + repeat([mid], max_height) + [bot] + + let buf_id = nvim_create_buf(v:false, v:true) + call nvim_buf_set_lines(buf_id, 0, -1, v:true, lines) " default the dimensions for now. they can be easily overwritten later let opts = { \ 'relative': 'cursor', - \ 'width': 50, - \ 'height': 5, + \ 'width': max_width + 2, + \ 'height': max_height + 2, \ 'col': 0, \ 'row': 1, \ 'anchor': 'NW', \ 'style': 'minimal' \ } - let s:float_win = nvim_open_win(buf, 0, opts) + " this is the border window + let s:nvim_related_win = nvim_open_win(buf_id, 0, opts) + call nvim_win_set_option(s:nvim_related_win, 'wrap', v:true) + call nvim_win_set_option(s:nvim_related_win, 'cursorline', v:true) + call nvim_win_set_option(s:nvim_related_win, 'signcolumn', 'no') + call nvim_win_set_option(s:nvim_related_win, 'relativenumber', v:false) + call nvim_win_set_option(s:nvim_related_win, 'number', v:false) + + " when calculating where to display the content window, we need to account + " for the border + set winhl=Normal:Floating + 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, body) + let s:float_win = nvim_open_win(buf_id, v:false, opts) + call nvim_win_set_option(s:float_win, 'wrap', v:true) call nvim_win_set_option(s:float_win, 'cursorline', v:true) call nvim_win_set_option(s:float_win, 'signcolumn', 'no') @@ -79,7 +120,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) " make sure we clean up the float after it loses focus augroup vimspector#internal#balloon#nvim_float autocmd! - autocmd WinLeave * :call nvim_win_close(s:float_win, 1) | :call vimspector#internal#balloon#closeCallback() | autocmd! vimspector#internal#balloon#nvim_float + autocmd WinLeave * :call vimspector#internal#balloon#closeCallback() | autocmd! vimspector#internal#balloon#nvim_float augroup END else @@ -89,7 +130,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let mouse_coords = getmousepos() " close the popup if mouse is clicked outside the window if mouse_coords['winid'] != a:winid - call popup_close(a:winid) call vimspector#internal#balloon#closeCallback() endif @@ -120,7 +160,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) return 1 elseif a:key == "\" - call popup_close(a:winid) call vimspector#internal#balloon#closeCallback() return 1 @@ -130,7 +169,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) endfunc if s:float_win != 0 - call popup_close(s:float_win) call vimspector#internal#balloon#closeCallback() endif @@ -138,9 +176,10 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'cursorline': 1, \ 'wrap': 1, \ 'filtermode': "n", - \ 'maxwidth': 50, - \ 'maxheight': 5, + \ 'maxwidth': max_width, + \ 'maxheight': max_height, \ 'scrollbar': 1, + \ 'border': [] \ } if a:is_hover let config['filter'] = "MouseFilter" From b95ae00054accd645dba06affc026dad85c331d7 Mon Sep 17 00:00:00 2001 From: dsych Date: Wed, 23 Dec 2020 00:17:19 -0500 Subject: [PATCH 042/200] enabling a close button for popup --- autoload/vimspector/internal/balloon.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index e2f041d..fd37e79 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -184,6 +184,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) if a:is_hover let config['filter'] = "MouseFilter" let config['mousemoved'] = [0, 0, 0] + let config['close'] = "button" let s:float_win = popup_beval(body, config) else let config['filter'] = "CursorFiler" From f60b259dbc499b25cb5c8549cd365e22e2e8f653 Mon Sep 17 00:00:00 2001 From: dsych Date: Wed, 23 Dec 2020 23:12:57 -0500 Subject: [PATCH 043/200] adding type information for simple types --- python3/vimspector/variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 71abc45..f5930f8 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -311,7 +311,7 @@ class VariablesView( object ): else: # in case that there is nothing to expand, we need to simulate a response from 'variables' request # it returns [Variable] - self._variable_eval.variables = [Variable({'name': expression, 'value': body['result']})] + self._variable_eval.variables = [Variable({'name': expression, 'type': body['type'], 'value': body['result']})] self._DrawEval() From 04a5e889f95d0f09615d782b94661e615f578447 Mon Sep 17 00:00:00 2001 From: dsych Date: Wed, 23 Dec 2020 23:32:37 -0500 Subject: [PATCH 044/200] making sure that float window is not modifiable inside nvim --- autoload/vimspector/internal/balloon.vim | 1 + python3/vimspector/variables.py | 1 + 2 files changed, 2 insertions(+) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index fd37e79..467de90 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -103,6 +103,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) " 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, body) + call nvim_buf_set_option(buf_id, 'modifiable', v:false) let s:float_win = nvim_open_win(buf_id, v:false, opts) call nvim_win_set_option(s:float_win, 'wrap', v:true) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index f5930f8..a81991a 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -272,6 +272,7 @@ class VariablesView( object ): def _DrawEval(self): with utils.RestoreCursorPosition(): + with utils.ModifiableScratchBuffer( self._variable_eval_view.buf ): utils.ClearBuffer( self._variable_eval_view.buf ) icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' From b9ed7f34b46f30d451a174005b64fd151ac14764 Mon Sep 17 00:00:00 2001 From: dsych Date: Thu, 24 Dec 2020 00:08:02 -0500 Subject: [PATCH 045/200] 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 --- python3/vimspector/variables.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index a81991a..b30c473 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -276,7 +276,7 @@ class VariablesView( object ): utils.ClearBuffer( self._variable_eval_view.buf ) icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' - self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 ) + self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 , True) def _CleanUpTooltip(self): # remove reference to old tooltip window @@ -312,7 +312,7 @@ class VariablesView( object ): else: # in case that there is nothing to expand, we need to simulate a response from 'variables' request # it returns [Variable] - self._variable_eval.variables = [Variable({'name': expression, 'type': body['type'], 'value': body['result']})] + self._variable_eval.variables = [Variable({ 'type': body['type'], 'value': body['result']})] self._DrawEval() @@ -439,9 +439,18 @@ class VariablesView( object ): }, } ) - def _DrawVariables( self, view, variables, indent ): + def _DrawVariables( self, view, variables, indent, is_short = False ): assert indent > 0 for variable in variables: + type_ = variable.variable.get( 'type', '' ) + value = variable.variable.get( 'value', '' ) + + if is_short: + if( len(type_) > 20): + type_ = type_[0:16] + " ..." + if( len(value) > 100 ): + value = value[0:96] + " ..." + line = utils.AppendToBuffer( view.buf, '{indent}{marker}{icon} {name} ({type_}): {value}'.format( @@ -450,14 +459,13 @@ class VariablesView( object ): marker = '*' if variable.changed else ' ', icon = '+' if ( variable.IsExpandable() and not variable.IsExpanded() ) else '-', - name = variable.variable[ 'name' ], - type_ = variable.variable.get( 'type', '' ), - value = variable.variable.get( 'value', - '' ) ).split( '\n' ) ) + name = variable.variable.get( 'name', '' ), + type_ = type_, + value = value ).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 From cb441be7bc1a4479cffb7a22d890e685cc6dcbe6 Mon Sep 17 00:00:00 2001 From: dsych Date: Sat, 2 Jan 2021 12:27:46 -0500 Subject: [PATCH 046/200] allowing resizing and dragging with a mouse --- autoload/vimspector/internal/balloon.vim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 467de90..48e1d05 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -175,7 +175,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let config = { \ 'cursorline': 1, - \ 'wrap': 1, + \ 'wrap': 0, \ 'filtermode': "n", \ 'maxwidth': max_width, \ 'maxheight': max_height, @@ -186,6 +186,8 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let config['filter'] = "MouseFilter" let config['mousemoved'] = [0, 0, 0] let config['close'] = "button" + let config['drag'] = 1 + let config['resize'] = 1 let s:float_win = popup_beval(body, config) else let config['filter'] = "CursorFiler" From 2f1c93a2ace0feffde737ddffa3dad3ef7df866a Mon Sep 17 00:00:00 2001 From: dsych Date: Sat, 2 Jan 2021 12:29:18 -0500 Subject: [PATCH 047/200] only diplaying relevant info like name and value for nested types and value only for simple types --- python3/vimspector/variables.py | 44 +++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index b30c473..4f6e4ff 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -274,9 +274,15 @@ class VariablesView( object ): with utils.RestoreCursorPosition(): with utils.ModifiableScratchBuffer( self._variable_eval_view.buf ): utils.ClearBuffer( self._variable_eval_view.buf ) - icon = '+' if self._variable_eval.IsExpandable() and not self._variable_eval.IsExpanded() else '-' - - self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 , True) + # if we only have a single non-expandable variable, it means we ran into a simple type + # hence, there is no need to draw additional fluff around the value + if(len(self._variable_eval.variables) == 1 and self._variable_eval.variables[0].IsExpandable() == False): + utils.AppendToBuffer( + self._variable_eval_view.buf, + self._variable_eval.variables[0].variable.get( 'value', '' ) + ) + else: + self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 , True) def _CleanUpTooltip(self): # remove reference to old tooltip window @@ -442,26 +448,32 @@ class VariablesView( object ): def _DrawVariables( self, view, variables, indent, is_short = False ): assert indent > 0 for variable in variables: - type_ = variable.variable.get( 'type', '' ) - value = variable.variable.get( 'value', '' ) - + text = '' if is_short: - if( len(type_) > 20): - type_ = type_[0:16] + " ..." - if( len(value) > 100 ): - value = value[0:96] + " ..." - - line = utils.AppendToBuffer( - view.buf, - '{indent}{marker}{icon} {name} ({type_}): {value}'.format( + 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', '' ) + ) + 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.get( 'name', '' ), - type_ = type_, - value = value ).split( '\n' )) + type_ = variable.variable.get( 'type', '' ), + value = variable.variable.get( 'value', '' ) + ) + + line = utils.AppendToBuffer( + view.buf, + text.split( '\n' )) + view.lines[ line ] = variable if variable.ShouldDrawDrillDown(): From 3c857cebf41f554e80330c710140adcb7ab0600b Mon Sep 17 00:00:00 2001 From: dsych Date: Sat, 2 Jan 2021 15:55:52 -0500 Subject: [PATCH 048/200] dynamically adjusting window size for nvim's floating window based on the buffer size --- autoload/vimspector/internal/balloon.vim | 68 +++++++++++++++++++----- python3/vimspector/utils.py | 6 ++- python3/vimspector/variables.py | 2 + 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 48e1d05..3c0f02e 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -38,6 +38,12 @@ endfunction let s:float_win = 0 let s:nvim_related_win = 0 +" +" tooltip dimensions +let s:min_width = 1 +let s:min_height = 1 +let s:max_width = 50 +let s:max_height = 5 function! vimspector#internal#balloon#closeCallback() abort if has('nvim') @@ -52,33 +58,66 @@ function! vimspector#internal#balloon#closeCallback() abort return py3eval('_vimspector_session._CleanUpTooltip()') endfunction +function! vimspector#internal#balloon#nvim_generate_border(width, height) + 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! vimspector#internal#balloon#nvim_resize_tooltip() + if !has('nvim') || s:float_win <= 0 || s:nvim_related_win <= 0 + return + endif + + noa call win_gotoid(s:float_win) + 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:float_win, opts) + + " resize the border window + let opts['width'] = width + 4 + let opts['height'] = height + 2 + call nvim_win_set_config(s:nvim_related_win, opts) + call nvim_buf_set_lines(nvim_win_get_buf(s:nvim_related_win), 0, -1, v:true, vimspector#internal#balloon#nvim_generate_border(width, height)) + +endfunction + function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let body = [] if a:0 > 0 let body = a:1 endif - " tooltip dimensions - let max_height = 5 - let max_width = 50 - if has('nvim') " 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 top = "╭" . repeat("─", max_width) . "╮" - let mid = "│" . repeat(" ", max_width) . "│" - let bot = "╰" . repeat("─", max_width) . "╯" - let lines = [top] + repeat([mid], max_height) + [bot] - let buf_id = nvim_create_buf(v:false, v:true) - call nvim_buf_set_lines(buf_id, 0, -1, v:true, lines) + call nvim_buf_set_lines(buf_id, 0, -1, v:true, vimspector#internal#balloon#nvim_generate_border(s:max_width, s:max_height)) " default the dimensions for now. they can be easily overwritten later let opts = { \ 'relative': 'cursor', - \ 'width': max_width + 2, - \ 'height': max_height + 2, + \ 'width': s:max_width + 2, + \ 'height': s:max_height + 2, \ 'col': 0, \ 'row': 1, \ 'anchor': 'NW', @@ -122,6 +161,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) augroup vimspector#internal#balloon#nvim_float autocmd! autocmd WinLeave * :call vimspector#internal#balloon#closeCallback() | autocmd! vimspector#internal#balloon#nvim_float + autocmd BufModifiedSet * :echo execute(eval("nvim_win_get_buf(".s:float_win.")")."bufdo echom &modified") augroup END else @@ -177,8 +217,8 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'cursorline': 1, \ 'wrap': 0, \ 'filtermode': "n", - \ 'maxwidth': max_width, - \ 'maxheight': max_height, + \ 'maxwidth': s:max_width, + \ 'maxheight': s:max_height, \ 'scrollbar': 1, \ 'border': [] \ } diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 788f03e..05df29c 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -640,7 +640,11 @@ def DisplayBaloon( is_term, display, is_hover = False ): # Refer https://github.com/vim/vim/issues/1512#issuecomment-492070685 display = '\n'.join( display ) - return int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format(is_hover, json.dumps( display )) ) ) + rc = int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format(is_hover, json.dumps( display )) ) ) + + vim.eval("vimspector#internal#balloon#nvim_resize_tooltip()") + + return rc def GetBufferFilepath( buf ): diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 4f6e4ff..205efe7 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -284,6 +284,8 @@ class VariablesView( object ): else: self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 , True) + vim.eval("vimspector#internal#balloon#nvim_resize_tooltip()") + def _CleanUpTooltip(self): # remove reference to old tooltip window self._variable_eval_view = None From e0b1d6ed8164b42cebd8900a039dc644129405e6 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 3 Jan 2021 00:42:06 -0500 Subject: [PATCH 049/200] fixing linting errors in python files --- python3/vimspector/debug_session.py | 8 ++-- python3/vimspector/utils.py | 8 +++- python3/vimspector/variables.py | 70 +++++++++++++++++++---------- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index de5a7c6..9ebc6ab 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -521,7 +521,7 @@ class DebugSession( object ): @IfConnected() def ExpandVariable( self, lineNum = -1 ): - self._variablesView.ExpandVariable(lineNum) + self._variablesView.ExpandVariable( lineNum ) @IfConnected() def AddWatch( self, expression ): @@ -540,7 +540,7 @@ class DebugSession( object ): @IfConnected() - def ShowTooltip(self, winnr, expression, is_hover): + def ShowTooltip( self, winnr, expression, is_hover ): """Proxy: ballonexpr -> variables.ShowBallon""" frame = self._stackTraceView.GetCurrentFrame() # Check if RIP is in a frame @@ -556,9 +556,9 @@ class DebugSession( object ): return '' # Return variable aware function - return self._variablesView.VariableEval(frame, expression, is_hover) + return self._variablesView.VariableEval( frame, expression, is_hover ) - def _CleanUpTooltip(self): + def _CleanUpTooltip( self ): return self._variablesView._CleanUpTooltip() @IfConnected() diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 05df29c..0fbe03a 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -640,9 +640,13 @@ def DisplayBaloon( is_term, display, is_hover = False ): # Refer https://github.com/vim/vim/issues/1512#issuecomment-492070685 display = '\n'.join( display ) - rc = int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format(is_hover, json.dumps( display )) ) ) + rc = int( vim.eval( + "vimspector#internal#balloon#CreateTooltip({}, {})".format( + is_hover, json.dumps( display ) + ) + ) ) - vim.eval("vimspector#internal#balloon#nvim_resize_tooltip()") + vim.eval( "vimspector#internal#balloon#nvim_resize_tooltip()" ) return rc diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 205efe7..234fb16 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -122,10 +122,10 @@ class View: lines: typing.Dict[ int, Expandable ] draw: typing.Callable - def __init__( self, win, lines, draw): + def __init__( self, win, lines, draw ): self.lines = lines self.draw = draw - if (win is not None): + if ( win is not None ): self.buf = win.buffer utils.SetUpUIWindow( win ) @@ -138,8 +138,8 @@ class VariablesView( object ): self._connection = None self._current_syntax = '' - self._variable_eval = None - self._variable_eval_view = None + self._variable_eval: Scope = None + self._variable_eval_view: View = None def AddExpandMappings(): vim.command( 'nnoremap ' @@ -186,7 +186,9 @@ class VariablesView( object ): 'balloonexpr': vim.options[ 'balloonexpr' ], 'balloondelay': vim.options[ 'balloondelay' ], } - vim.options[ 'balloonexpr' ] = 'vimspector#internal#balloon#HoverTooltip()' + vim.options[ 'balloonexpr' ] = "vimspector#internal#" + "balloon#HoverTooltip()" + vim.options[ 'balloondelay' ] = 250 if has_balloon: @@ -270,28 +272,38 @@ class VariablesView( object ): }, } ) - def _DrawEval(self): + def _DrawEval( self ): with utils.RestoreCursorPosition(): with utils.ModifiableScratchBuffer( self._variable_eval_view.buf ): utils.ClearBuffer( self._variable_eval_view.buf ) - # if we only have a single non-expandable variable, it means we ran into a simple type + # if we only have a single non-expandable variable, + # it means we ran into a simple type # hence, there is no need to draw additional fluff around the value - if(len(self._variable_eval.variables) == 1 and self._variable_eval.variables[0].IsExpandable() == False): + if( + len( self._variable_eval.variables ) == 1 + and self._variable_eval.variables[ 0 ].IsExpandable() is False + ): utils.AppendToBuffer( self._variable_eval_view.buf, - self._variable_eval.variables[0].variable.get( 'value', '' ) - ) + self._variable_eval.variables[ 0 ] + .variable.get( 'value', '' ) + ) else: - self._DrawVariables( self._variable_eval_view, self._variable_eval.variables, 2 , True) + self._DrawVariables( + self._variable_eval_view, + self._variable_eval.variables, + 2, + True + ) - vim.eval("vimspector#internal#balloon#nvim_resize_tooltip()") + vim.eval( "vimspector#internal#balloon#nvim_resize_tooltip()" ) - def _CleanUpTooltip(self): + def _CleanUpTooltip( self ) : # remove reference to old tooltip window self._variable_eval_view = None return '' - def VariableEval(self, frame, expression, is_hover): + def VariableEval( self, frame, expression, is_hover ): """Callback to display variable under cursor `:h ballonexpr`""" if not self._connection: return '' @@ -299,16 +311,24 @@ class VariablesView( object ): def handler( message ): body = message[ 'body' ] - self._variable_eval = Scope(body) - float_win_id = utils.DisplayBaloon(self._is_term, [], is_hover) - float_buf_nr = int(vim.eval("winbufnr({})".format(float_win_id))) + self._variable_eval = Scope( body ) + float_win_id = utils.DisplayBaloon( self._is_term, [], is_hover ) + float_buf_nr = int( vim.eval( "winbufnr({})".format( float_win_id ) ) ) # since vim's popup cant be focused there is no way # to get a reference to its window # we will emulate python's window object ourselves - self._variable_eval_view = View(type('__vim__window__', (object,), {'options': {}, 'buffer': vim.buffers[float_buf_nr]}), {}, self._DrawEval) + self._variable_eval_view = View( + type( + '__vim__window__', + ( object, ), + { 'options': {}, 'buffer': vim.buffers[ float_buf_nr ] } + ), + {}, + self._DrawEval + ) - if(self._variable_eval.VariablesReference() > 0): + if( self._variable_eval.VariablesReference() > 0 ): self._connection.DoRequest( partial( self._ConsumeVariables, self._DrawEval, self._variable_eval ), { @@ -318,9 +338,12 @@ class VariablesView( object ): }, } ) else: - # in case that there is nothing to expand, we need to simulate a response from 'variables' request + # in case that there is nothing to expand, + # we need to simulate a response from 'variables' request # it returns [Variable] - self._variable_eval.variables = [Variable({ 'type': body['type'], 'value': body['result']})] + self._variable_eval.variables = [ + Variable( { 'type': body[ 'type' ], 'value': body[ 'result' ] } ) + ] self._DrawEval() @@ -422,7 +445,7 @@ class VariablesView( object ): else: return - current_line = vim.current.window.cursor[0] if lineNum <= 0 else lineNum + current_line = vim.current.window.cursor[ 0 ] if lineNum <= 0 else lineNum if current_line not in view.lines: return @@ -474,7 +497,8 @@ class VariablesView( object ): line = utils.AppendToBuffer( view.buf, - text.split( '\n' )) + text.split( '\n' ) + ) view.lines[ line ] = variable From 93568ba05d2c69abfff18eea66c39b75bdf49a54 Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 5 Jan 2021 22:13:20 -0500 Subject: [PATCH 050/200] removing test code --- autoload/vimspector/internal/balloon.vim | 1 - 1 file changed, 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 3c0f02e..dc8f543 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -161,7 +161,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) augroup vimspector#internal#balloon#nvim_float autocmd! autocmd WinLeave * :call vimspector#internal#balloon#closeCallback() | autocmd! vimspector#internal#balloon#nvim_float - autocmd BufModifiedSet * :echo execute(eval("nvim_win_get_buf(".s:float_win.")")."bufdo echom &modified") augroup END else From 052d63dee5929dbfbf91ee7d761c9eaf30010895 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 5 Jan 2021 22:11:48 +0000 Subject: [PATCH 051/200] Fix mouse interraction with the popup - don't handle events outside the window --- autoload/vimspector/internal/balloon.vim | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index dc8f543..7575be4 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -166,29 +166,29 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) else " assume we are inside vim func! MouseFilter(winid, key) + let handled = 0 if index(["\", "\<2-leftmouse>"], a:key) >= 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#closeCallback() + else + " 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>" && mouse_coords['winid'] == a:winid + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") + let handled = 1 + endif 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>" && mouse_coords['winid'] == a:winid - " forward line number to python, since vim does not allow us to focus - " the correct window - call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") - endif - - return 1 endif - return 0 + return handled endfunc - func! CursorFiler(winid, key) + func! CursorFilter(winid, key) if index(['j', 'k'], a:key) >= 0 call win_execute(a:winid, ':normal '.a:key) @@ -229,7 +229,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let config['resize'] = 1 let s:float_win = popup_beval(body, config) else - let config['filter'] = "CursorFiler" + let config['filter'] = "CursorFilter" let config['moved'] = "any" let s:float_win = popup_atcursor(body, config) endif From 0895c5e82900bd20de97d80668a28d7723a09c77 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 5 Jan 2021 22:12:14 +0000 Subject: [PATCH 052/200] Add 1 cell of padding to the x direction which makes the popup more readable --- autoload/vimspector/internal/balloon.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 7575be4..0b37c68 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -219,7 +219,8 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'maxwidth': s:max_width, \ 'maxheight': s:max_height, \ 'scrollbar': 1, - \ 'border': [] + \ 'border': [], + \ 'padding': [ 0, 1, 0, 1] \ } if a:is_hover let config['filter'] = "MouseFilter" From 64e38b57abfee39cb232fa9f013bf7b45b685085 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 5 Jan 2021 22:13:25 +0000 Subject: [PATCH 053/200] Fix crash; enable syntax highlighting in hover popup; use a Watch for the popup and re-use existing drawing code --- python3/vimspector/variables.py | 117 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 234fb16..797a6a9 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -117,14 +117,27 @@ 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.syntax = None if ( win is not None ): self.buf = win.buffer utils.SetUpUIWindow( win ) @@ -186,8 +199,8 @@ class VariablesView( object ): 'balloonexpr': vim.options[ 'balloonexpr' ], 'balloondelay': vim.options[ 'balloondelay' ], } - vim.options[ 'balloonexpr' ] = "vimspector#internal#" - "balloon#HoverTooltip()" + vim.options[ 'balloonexpr' ] = ( "vimspector#internal#" + "balloon#HoverTooltip()" ) vim.options[ 'balloondelay' ] = 250 @@ -273,28 +286,25 @@ class VariablesView( object ): } ) def _DrawEval( self ): + watch = self._variable_eval + view = self._variable_eval_view + with utils.RestoreCursorPosition(): - with utils.ModifiableScratchBuffer( self._variable_eval_view.buf ): - utils.ClearBuffer( self._variable_eval_view.buf ) - # if we only have a single non-expandable variable, - # it means we ran into a simple type - # hence, there is no need to draw additional fluff around the value - if( - len( self._variable_eval.variables ) == 1 - and self._variable_eval.variables[ 0 ].IsExpandable() is False - ): - utils.AppendToBuffer( - self._variable_eval_view.buf, - self._variable_eval.variables[ 0 ] - .variable.get( 'value', '' ) - ) - else: - self._DrawVariables( - self._variable_eval_view, - self._variable_eval.variables, - 2, - True - ) + with utils.ModifiableScratchBuffer( view.buf ): + utils.ClearBuffer( view.buf ) + # FIXME: This probably doesn't work reliably + view.syntax = utils.SetSyntax( view.syntax, + self._current_syntax, + view.buf ) + + utils.AppendToBuffer( + view.buf, + f"Expression: { watch.expression[ 'expression' ] }" ) + + self._DrawWatchResult( view, + 2, + watch, + is_short = True ) vim.eval( "vimspector#internal#balloon#nvim_resize_tooltip()" ) @@ -309,9 +319,13 @@ class VariablesView( object ): return '' def handler( message ): - body = message[ 'body' ] - self._variable_eval = Scope( body ) + watch = self._variable_eval + if watch.result is None: + watch.result = WatchResult( message[ 'body' ] ) + else: + watch.result.Update( message[ 'body' ] ) + float_win_id = utils.DisplayBaloon( self._is_term, [], is_hover ) float_buf_nr = int( vim.eval( "winbufnr({})".format( float_win_id ) ) ) @@ -328,51 +342,41 @@ class VariablesView( object ): self._DrawEval ) - if( self._variable_eval.VariablesReference() > 0 ): + 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._DrawEval, - self._variable_eval ), { + self._variable_eval_view.draw, + watch.result ), { 'command': 'variables', 'arguments': { - 'variablesReference': self._variable_eval.VariablesReference(), + 'variablesReference': watch.result.VariablesReference(), }, } ) - else: - # in case that there is nothing to expand, - # we need to simulate a response from 'variables' request - # it returns [Variable] - self._variable_eval.variables = [ - Variable( { 'type': body[ 'type' ], 'value': body[ 'result' ] } ) - ] - self._DrawEval() + self._DrawEval() def failure_handler( reason, message ): display = [ reason ] utils.DisplayBaloon( self._is_term, display, is_hover ) + self._variable_eval = Watch.New( frame, + expression, + 'hover' ) + # Send async request self._connection.DoRequest( handler, { 'command': 'evaluate', - 'arguments': { - 'expression': expression, - 'frameId': frame[ 'id' ], - 'context': 'hover', - } + 'arguments': self._variable_eval.expression, }, failure_handler ) # Return working (meanwhile) return '' def AddWatch( self, frame, expression ): - watch = { - 'expression': expression, - 'context': 'watch', - } - if frame: - watch[ 'frameId' ] = frame[ 'id' ] - - self._watches.append( Watch( watch ) ) + self._watches.append( Watch.New( frame, expression, 'watch' ) ) self.EvaluateWatches() def DeleteWatch( self ): @@ -470,7 +474,7 @@ class VariablesView( object ): }, } ) - def _DrawVariables( self, view, variables, indent, is_short = False ): + def _DrawVariables( self, view, variables, indent, is_short = False ): assert indent > 0 for variable in variables: text = '' @@ -530,7 +534,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 '-' @@ -546,7 +550,7 @@ 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 @@ -561,12 +565,12 @@ class VariablesView( object ): icon = icon, result = watch.result.result.get( 'result', '' ) ) - 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, is_short ) def _ConsumeVariables( self, draw, parent, message ): new_variables = [] @@ -640,6 +644,7 @@ class VariablesView( object ): def SetSyntax( self, syntax ): + # TODO: Switch to View.syntax self._current_syntax = utils.SetSyntax( self._current_syntax, syntax, self._vars.buf, From 0b4da4c82ba9f1be03aca66a62fffadd71e49624 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 6 Jan 2021 14:34:37 +0000 Subject: [PATCH 054/200] Remove more text from the hover popup --- python3/vimspector/variables.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 797a6a9..d8f2f53 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -297,12 +297,8 @@ class VariablesView( object ): self._current_syntax, view.buf ) - utils.AppendToBuffer( - view.buf, - f"Expression: { watch.expression[ 'expression' ] }" ) - self._DrawWatchResult( view, - 2, + 0, watch, is_short = True ) @@ -554,15 +550,25 @@ class VariablesView( object ): 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', '' ) ) line = utils.AppendToBuffer( view.buf, line.split( '\n' ) ) From cfae062da14bf3af6c9a177501eaa94bf1cfab41 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 6 Jan 2021 14:48:00 +0000 Subject: [PATCH 055/200] Disable cursorLine for the hover-only popup --- autoload/vimspector/internal/balloon.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 0b37c68..6007c31 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -213,7 +213,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) endif let config = { - \ 'cursorline': 1, \ 'wrap': 0, \ 'filtermode': "n", \ 'maxwidth': s:max_width, @@ -232,6 +231,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) else let config['filter'] = "CursorFilter" let config['moved'] = "any" + let config['cursorline'] = 1 let s:float_win = popup_atcursor(body, config) endif From f3c39e12ab3449b74603c025133445441d8cb490 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 6 Jan 2021 14:51:35 +0000 Subject: [PATCH 056/200] FixUp: Display in watch window, and indent in popup --- python3/vimspector/variables.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index d8f2f53..e657824 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -560,7 +560,7 @@ class VariablesView( object ): else: icon = '+' if ( watch.result.IsExpandable() and not watch.result.IsExpanded() ) else '-' - marker = '*' if watch.result.changed else ' ', + marker = '*' if watch.result.changed else ' ' leader = ' Result: ' line = '{indent}{marker}{icon}{leader}{result}'.format( @@ -575,8 +575,7 @@ class VariablesView( object ): view.lines[ line ] = watch.result if watch.result.ShouldDrawDrillDown(): - indent = 4 - self._DrawVariables( view, watch.result.variables, indent, is_short ) + self._DrawVariables( view, watch.result.variables, indent + 2, is_short ) def _ConsumeVariables( self, draw, parent, message ): new_variables = [] From 0d703779dc58cb1e11d09c0a74348c0995df1661 Mon Sep 17 00:00:00 2001 From: dsych Date: Thu, 7 Jan 2021 00:20:23 -0500 Subject: [PATCH 057/200] evaluating select range --- autoload/vimspector.vim | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index d8018a0..7f752e4 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -523,8 +523,39 @@ function! vimspector#OnBufferCreated( file_name ) abort py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) ) endfunction -function! vimspector#ShowTooltip() abort - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"\")" ), 0)') +function! vimspector#ShowTooltipForSelection() range + let [start, end] = [[line("'<"), col("'<") - 1], [line("'>"), col("'>")]] + " restor cursor position, since command mode puts it to the begining of the + " current line when invoked from visual mode + call cursor(end) + + " retrive the lines selected in visual mode + let lines = getbufline(bufnr('%'), start[0], end[0]) + + " make sure the leave only the parts we care about if multiple lines are + " selected + let lines[0] = strcharpart(lines[0], start[1]) + let lines_len = len(lines) - 1 + + if len(lines) == 1 + let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1] - start[1]) + else + let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1]) + endif + + let str = join(lines) + + call vimspector#ShowTooltip(str) +endfunction + +function! vimspector#ShowTooltip(...) abort + let str = "" + + if a:0 > 0 + let str = a:1 + endif + + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"'.str.'\")" ), 0)') endfunction From 2d082cc923c104650224a75af8a2cfb815e6c698 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 21:28:48 +0000 Subject: [PATCH 058/200] Use a more generous maximum size for the popup (TODO: option for this ?) --- autoload/vimspector/internal/balloon.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 6007c31..d5f0b6c 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -42,8 +42,8 @@ let s:nvim_related_win = 0 " tooltip dimensions let s:min_width = 1 let s:min_height = 1 -let s:max_width = 50 -let s:max_height = 5 +let s:max_width = 80 +let s:max_height = 20 function! vimspector#internal#balloon#closeCallback() abort if has('nvim') From cb174c176d75ee22e4858c139355a11e29205732 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 21:58:45 +0000 Subject: [PATCH 059/200] Disable wrapping long lines in neovim popup too --- autoload/vimspector/internal/balloon.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index d5f0b6c..4f4e064 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -145,7 +145,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) call nvim_buf_set_option(buf_id, 'modifiable', v:false) let s:float_win = nvim_open_win(buf_id, v:false, opts) - call nvim_win_set_option(s:float_win, 'wrap', v:true) + call nvim_win_set_option(s:float_win, 'wrap', v:false) call nvim_win_set_option(s:float_win, 'cursorline', v:true) call nvim_win_set_option(s:float_win, 'signcolumn', 'no') call nvim_win_set_option(s:float_win, 'relativenumber', v:false) From 64f2c8eb01d4d446b571c7366d356fff92aacd17 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 21:59:02 +0000 Subject: [PATCH 060/200] Use a fancy single line border in vim popup when we can --- autoload/vimspector/internal/balloon.vim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 4f4e064..47544c5 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -221,6 +221,11 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'border': [], \ 'padding': [ 0, 1, 0, 1] \ } + + if &ambiwidth ==# 'single' && &encoding == 'utf-8' + let config['borderchars'] = [ '─', '│', '─', '│', '╭', '╮', '╯', '╰' ] + endif + if a:is_hover let config['filter'] = "MouseFilter" let config['mousemoved'] = [0, 0, 0] From 672ac78fefdea0d5597e6f6b4a2e565e3083aa20 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 21:59:18 +0000 Subject: [PATCH 061/200] Fix flaky syntax highlighting toggling on/off --- python3/vimspector/variables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index e657824..138453e 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -293,7 +293,7 @@ class VariablesView( object ): with utils.ModifiableScratchBuffer( view.buf ): utils.ClearBuffer( view.buf ) # FIXME: This probably doesn't work reliably - view.syntax = utils.SetSyntax( view.syntax, + view.syntax = utils.SetSyntax( None, self._current_syntax, view.buf ) From fccafd6739e1a31905ea454fbe14aa537f3bc672 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 22:32:05 +0000 Subject: [PATCH 062/200] FixUp: border characters - indicate that the corner can be dragged --- autoload/vimspector/internal/balloon.vim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 47544c5..d9861cb 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -19,6 +19,8 @@ let s:save_cpo = &cpoptions set cpoptions&vim " }}} +scriptencoding utf-8 + " Returns: py.ShowBalloon( winnr, expresssion ) function! vimspector#internal#balloon#BalloonExpr() abort " winnr + 1 because for *no good reason* winnr is 0 based here unlike @@ -223,7 +225,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ } if &ambiwidth ==# 'single' && &encoding == 'utf-8' - let config['borderchars'] = [ '─', '│', '─', '│', '╭', '╮', '╯', '╰' ] + let config['borderchars'] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] endif if a:is_hover From d2ed8a828c65eaeaca10fcfec2fd8ce5e8bbedfc Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 22:32:52 +0000 Subject: [PATCH 063/200] Use popup_filter_menu for the keyboard-popup rather than 100% our own --- autoload/vimspector/internal/balloon.vim | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index d9861cb..88c6dd0 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -179,7 +179,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) 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>" && mouse_coords['winid'] == a:winid + if a:key == "\<2-leftmouse>" " forward line number to python, since vim does not allow us to focus " the correct window call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") @@ -191,23 +191,16 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) endfunc func! CursorFilter(winid, key) - if index(['j', 'k'], a:key) >= 0 - call win_execute(a:winid, ':normal '.a:key) - - return 1 - elseif a:key == "\" + if a:key == "\" " forward line number to python, since vim does not allow us to focus " the correct window call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") - - return 1 - elseif a:key == "\" - call vimspector#internal#balloon#closeCallback() - return 1 + elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 + return MouseFilter( a:winid, a:key ) endif - return 0 + return popup_filter_menu( a:winid, a:key ) endfunc if s:float_win != 0 From bc1146df3bb8d0ba925d0f8e42c49935dd19850c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 22:33:31 +0000 Subject: [PATCH 064/200] Use normal highlighting for the popup as it's probably more readable (debatable?) --- autoload/vimspector/internal/balloon.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 88c6dd0..1803a35 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -214,7 +214,8 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'maxheight': s:max_height, \ 'scrollbar': 1, \ 'border': [], - \ 'padding': [ 0, 1, 0, 1] + \ 'padding': [ 0, 1, 0, 1], + \ 'highlight': 'Normal', \ } if &ambiwidth ==# 'single' && &encoding == 'utf-8' From 322b7e0a383d26635c563b9e33331d412d2bedaf Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 22:33:52 +0000 Subject: [PATCH 065/200] Enable mouse interraction for the both popups in vim --- autoload/vimspector/internal/balloon.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 1803a35..caf906f 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -216,6 +216,8 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'border': [], \ 'padding': [ 0, 1, 0, 1], \ 'highlight': 'Normal', + \ 'drag': 1, + \ 'resize': 1 \ } if &ambiwidth ==# 'single' && &encoding == 'utf-8' @@ -226,8 +228,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let config['filter'] = "MouseFilter" let config['mousemoved'] = [0, 0, 0] let config['close'] = "button" - let config['drag'] = 1 - let config['resize'] = 1 let s:float_win = popup_beval(body, config) else let config['filter'] = "CursorFilter" From 894ca522d305ac2cf929d0aef2480e6fe1f7dae1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 22:48:20 +0000 Subject: [PATCH 066/200] Use the popup callback rather than manually trying to do it --- autoload/vimspector/internal/balloon.vim | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index caf906f..491acf5 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -47,14 +47,19 @@ let s:min_height = 1 let s:max_width = 80 let s:max_height = 20 -function! vimspector#internal#balloon#closeCallback() abort +function! vimspector#internal#balloon#Close() abort if has('nvim') call nvim_win_close(s:float_win, v:true) call nvim_win_close(s:nvim_related_win, v:true) + + call vimspector#internal#balloon#CloseCallback() else call popup_close(s:float_win) endif +endfunction + +function! vimspector#internal#balloon#CloseCallback( ... ) abort let s:float_win = 0 let s:nvim_related_win = 0 return py3eval('_vimspector_session._CleanUpTooltip()') @@ -162,7 +167,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) " make sure we clean up the float after it loses focus augroup vimspector#internal#balloon#nvim_float autocmd! - autocmd WinLeave * :call vimspector#internal#balloon#closeCallback() | autocmd! vimspector#internal#balloon#nvim_float + autocmd WinLeave * :call vimspector#internal#balloon#Close() | autocmd! vimspector#internal#balloon#nvim_float augroup END else @@ -173,7 +178,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let mouse_coords = getmousepos() " close the popup if mouse is clicked outside the window if mouse_coords['winid'] != a:winid - call vimspector#internal#balloon#closeCallback() + call vimspector#internal#balloon#Close() else " place the cursor according to the click call win_execute(a:winid, ":call cursor(".mouse_coords['line'].", ".mouse_coords['column'].")") @@ -204,7 +209,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) endfunc if s:float_win != 0 - call vimspector#internal#balloon#closeCallback() + call vimspector#internal#balloon#Close() endif let config = { @@ -217,7 +222,8 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'padding': [ 0, 1, 0, 1], \ 'highlight': 'Normal', \ 'drag': 1, - \ 'resize': 1 + \ 'resize': 1, + \ 'callback': 'vimspector#internal#balloon#CloseCallback' \ } if &ambiwidth ==# 'single' && &encoding == 'utf-8' From e5e13ffcdd09bfae55335c57626a93b0ce4d5afc Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 8 Jan 2021 22:48:34 +0000 Subject: [PATCH 067/200] Fix typo: Baloon -> Balloon --- python3/vimspector/utils.py | 2 +- python3/vimspector/variables.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 0fbe03a..2bd3c08 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -634,7 +634,7 @@ def ParseVariables( variables_list, return new_variables -def DisplayBaloon( is_term, display, is_hover = False ): +def DisplayBalloon( is_term, display, is_hover = False ): if not is_term: # To enable the Windows GUI to display the balloon correctly # Refer https://github.com/vim/vim/issues/1512#issuecomment-492070685 diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 138453e..c9b263c 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -322,7 +322,7 @@ class VariablesView( object ): else: watch.result.Update( message[ 'body' ] ) - float_win_id = utils.DisplayBaloon( self._is_term, [], is_hover ) + float_win_id = utils.DisplayBalloon( self._is_term, [], is_hover ) float_buf_nr = int( vim.eval( "winbufnr({})".format( float_win_id ) ) ) # since vim's popup cant be focused there is no way @@ -356,7 +356,7 @@ class VariablesView( object ): def failure_handler( reason, message ): display = [ reason ] - utils.DisplayBaloon( self._is_term, display, is_hover ) + utils.DisplayBalloon( self._is_term, display, is_hover ) self._variable_eval = Watch.New( frame, expression, @@ -628,11 +628,11 @@ class VariablesView( object ): 'Type: ' + body.get( 'type', '' ), 'Value: ' + result ] - utils.DisplayBaloon( self._is_term, display ) + utils.DisplayBalloon( self._is_term, display ) def failure_handler( reason, message ): display = [ reason ] - utils.DisplayBaloon( self._is_term, display ) + utils.DisplayBalloon( self._is_term, display ) # Send async request self._connection.DoRequest( handler, { From 31e44548d38a28169bd3a36f6f4dca660179bd1f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 9 Jan 2021 10:45:27 +0000 Subject: [PATCH 068/200] Tidy up MouseFilter --- autoload/vimspector/internal/balloon.vim | 42 +++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 491acf5..c292d5f 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -171,27 +171,31 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) augroup END else - " assume we are inside vim func! MouseFilter(winid, key) - let handled = 0 - if index(["\", "\<2-leftmouse>"], a:key) >= 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() - else - " 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>" - " forward line number to python, since vim does not allow us to focus - " the correct window - call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") - let handled = 1 - endif - endif + if index(["\", "\<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>" + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") + let handled = 1 + endif + return handled endfunc From 3239963893b285eaa456a2421c8a48e5fba39a51 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 9 Jan 2021 11:21:53 +0000 Subject: [PATCH 069/200] Set the correct highlights in both popups in neovim --- autoload/vimspector/internal/balloon.vim | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index c292d5f..0f0c8d9 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -140,7 +140,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) " when calculating where to display the content window, we need to account " for the border - set winhl=Normal:Floating let opts.row += 1 let opts.height -= 2 let opts.col += 2 @@ -158,7 +157,16 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) call nvim_win_set_option(s:float_win, 'relativenumber', v:false) call nvim_win_set_option(s:float_win, 'number', v:false) - noa call win_gotoid(s:float_win) + let old_curwin = win_getid() + try + noautocmd call win_gotoid(s:nvim_related_win) + set winhl=Normal:Floating + finally + noautocmd call win_gotoid(old_curwin) + endtry + + noautocmd call win_gotoid(s:float_win) + set winhl=Normal:Floating nnoremap :call vimspector#ExpandVariable() nnoremap :quit From 91bebc182602a1c98d17a0ae039f1a0ad95a6362 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 10 Jan 2021 14:56:23 -0500 Subject: [PATCH 070/200] adding a close button for keyboard triggered popup, since drag and resize are also enabled. removing wrap from border. --- autoload/vimspector/internal/balloon.vim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 0f0c8d9..1cb91c8 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -132,7 +132,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ } " this is the border window let s:nvim_related_win = nvim_open_win(buf_id, 0, opts) - call nvim_win_set_option(s:nvim_related_win, 'wrap', v:true) call nvim_win_set_option(s:nvim_related_win, 'cursorline', v:true) call nvim_win_set_option(s:nvim_related_win, 'signcolumn', 'no') call nvim_win_set_option(s:nvim_related_win, 'relativenumber', v:false) @@ -229,12 +228,15 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ '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], \ 'highlight': 'Normal', \ 'drag': 1, \ 'resize': 1, + \ 'close': 'button', \ 'callback': 'vimspector#internal#balloon#CloseCallback' \ } @@ -245,7 +247,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) if a:is_hover let config['filter'] = "MouseFilter" let config['mousemoved'] = [0, 0, 0] - let config['close'] = "button" let s:float_win = popup_beval(body, config) else let config['filter'] = "CursorFilter" From 13102dc7117d988415b17f78b48f39aecb725696 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 10 Jan 2021 15:25:02 -0500 Subject: [PATCH 071/200] reverting back the highlight group --- autoload/vimspector/internal/balloon.vim | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 1cb91c8..b7d101b 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -132,7 +132,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ } " this is the border window let s:nvim_related_win = nvim_open_win(buf_id, 0, opts) - call nvim_win_set_option(s:nvim_related_win, 'cursorline', v:true) call nvim_win_set_option(s:nvim_related_win, 'signcolumn', 'no') call nvim_win_set_option(s:nvim_related_win, 'relativenumber', v:false) call nvim_win_set_option(s:nvim_related_win, 'number', v:false) @@ -156,16 +155,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) call nvim_win_set_option(s:float_win, 'relativenumber', v:false) call nvim_win_set_option(s:float_win, 'number', v:false) - let old_curwin = win_getid() - try - noautocmd call win_gotoid(s:nvim_related_win) - set winhl=Normal:Floating - finally - noautocmd call win_gotoid(old_curwin) - endtry - noautocmd call win_gotoid(s:float_win) - set winhl=Normal:Floating nnoremap :call vimspector#ExpandVariable() nnoremap :quit @@ -233,7 +223,6 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'scrollbar': 1, \ 'border': [], \ 'padding': [ 0, 1, 0, 1], - \ 'highlight': 'Normal', \ 'drag': 1, \ 'resize': 1, \ 'close': 'button', From 4466fce20b15df37ad1463676f09e3d0825235f0 Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 10 Jan 2021 15:37:17 -0500 Subject: [PATCH 072/200] fixing styling inside vim files --- autoload/vimspector.vim | 4 +-- autoload/vimspector/internal/balloon.vim | 36 ++++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 7f752e4..941ec40 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -523,7 +523,7 @@ function! vimspector#OnBufferCreated( file_name ) abort py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) ) endfunction -function! vimspector#ShowTooltipForSelection() range +function! vimspector#ShowTooltipForSelection() range abort let [start, end] = [[line("'<"), col("'<") - 1], [line("'>"), col("'>")]] " restor cursor position, since command mode puts it to the begining of the " current line when invoked from visual mode @@ -549,7 +549,7 @@ function! vimspector#ShowTooltipForSelection() range endfunction function! vimspector#ShowTooltip(...) abort - let str = "" + let str = '' if a:0 > 0 let str = a:1 diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index b7d101b..b922397 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -65,16 +65,16 @@ function! vimspector#internal#balloon#CloseCallback( ... ) abort return py3eval('_vimspector_session._CleanUpTooltip()') endfunction -function! vimspector#internal#balloon#nvim_generate_border(width, height) - let top = "╭" . repeat("─",a:width + 2) . "╮" - let mid = "│" . repeat(" ",a:width + 2) . "│" - let bot = "╰" . repeat("─",a:width + 2) . "╯" +function! vimspector#internal#balloon#nvim_generate_border(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! vimspector#internal#balloon#nvim_resize_tooltip() +function! vimspector#internal#balloon#nvim_resize_tooltip() abort if !has('nvim') || s:float_win <= 0 || s:nvim_related_win <= 0 return endif @@ -107,7 +107,7 @@ function! vimspector#internal#balloon#nvim_resize_tooltip() endfunction -function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) +function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) abort let body = [] if a:0 > 0 let body = a:1 @@ -168,7 +168,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) augroup END else - func! MouseFilter(winid, key) + func! MouseFilter(winid, key) abort if index(["\", "\<2-leftmouse>"], a:key) < 0 return 0 endif @@ -183,24 +183,24 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) endif " place the cursor according to the click - call win_execute(a:winid, ":call cursor(".mouse_coords['line'].", ".mouse_coords['column'].")") + 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>" + if a:key ==? "\<2-leftmouse>" " forward line number to python, since vim does not allow us to focus " the correct window - call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") + call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') let handled = 1 endif return handled endfunc - func! CursorFilter(winid, key) - if a:key == "\" + func! CursorFilter(winid, key) abort + if a:key ==? "\" " forward line number to python, since vim does not allow us to focus " the correct window - call py3eval("_vimspector_session.ExpandVariable(".line('.', a:winid).")") + call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') return 1 elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 return MouseFilter( a:winid, a:key ) @@ -215,7 +215,7 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) let config = { \ 'wrap': 0, - \ 'filtermode': "n", + \ 'filtermode': 'n', \ 'maxwidth': s:max_width, \ 'maxheight': s:max_height, \ 'minwidth': s:min_width, @@ -229,17 +229,17 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) \ 'callback': 'vimspector#internal#balloon#CloseCallback' \ } - if &ambiwidth ==# 'single' && &encoding == 'utf-8' + if &ambiwidth ==# 'single' && &encoding ==? 'utf-8' let config['borderchars'] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] endif if a:is_hover - let config['filter'] = "MouseFilter" + let config['filter'] = 'MouseFilter' let config['mousemoved'] = [0, 0, 0] let s:float_win = popup_beval(body, config) else - let config['filter'] = "CursorFilter" - let config['moved'] = "any" + let config['filter'] = 'CursorFilter' + let config['moved'] = 'any' let config['cursorline'] = 1 let s:float_win = popup_atcursor(body, config) endif From 789377eab47ba3dee165443693146068853aa11a Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 00:35:24 -0500 Subject: [PATCH 073/200] adding the first test! --- python3/vimspector/debug_session.py | 1 + python3/vimspector/variables.py | 3 ++ tests/variables.test.vim | 64 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 9ebc6ab..18c4726 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -702,6 +702,7 @@ class DebugSession( object ): '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(): diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index c9b263c..e96a585 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -307,6 +307,7 @@ class VariablesView( object ): def _CleanUpTooltip( self ) : # remove reference to old tooltip window self._variable_eval_view = None + vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = None return '' def VariableEval( self, frame, expression, is_hover ): @@ -323,6 +324,8 @@ class VariablesView( object ): watch.result.Update( message[ 'body' ] ) float_win_id = utils.DisplayBalloon( self._is_term, [], is_hover ) + # record the global eval window id + vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = int( float_win_id ) float_buf_nr = int( vim.eval( "winbufnr({})".format( float_win_id ) ) ) # since vim's popup cant be focused there is no way diff --git a/tests/variables.test.vim b/tests/variables.test.vim index 9152875..5cf575f 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -591,3 +591,67 @@ function! Test_EvaluateFailure() call vimspector#test#setup#Reset() %bwipe! endfunction + +function! Test_VariableEval() + let fn = 'testdata/cpp/simple/struct.cpp' + call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ + \ configuration: 'run-to-breakpoint' + \ } } ) + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + + "evaluate the prev line + " call win_gotoid( g:vimspector_session_windows.code ) + call setpos('.', [ 0, 24, 8 ]) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) + call vimspector#ShowTooltip() + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 0', + \ ' + another_test: ', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + " Expand + call win_execute( g:vimspector_session_windows.eval, [ + \ 'call feedkeys( ''jjjj'', ''xt'' )', + \ 'call feedkeys( "\", ''xt'' )' + \ ] ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 0', + \ ' - another_test: ', + \ ' - choo: 0 ''\\0\{1,3}''', + \ ' + ints: ' + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + "Close + call win_execute( g:vimspector_session_windows.eval, 'call feedkeys( "\", ''xt'')') + + call WaitForAssert( {-> + \ assert_equal( 0, g:vimspector_session_windows.eval ) + \ } ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction From 0c79384529f413ee58d453a4c6ec41a5cde8b15d Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 08:50:39 -0500 Subject: [PATCH 074/200] there is no need to execute feedkeys inside a popup context, since keys are added into the global input buffer --- tests/variables.test.vim | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index 5cf575f..c587dea 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -623,10 +623,8 @@ function! Test_VariableEval() \ } ) " Expand - call win_execute( g:vimspector_session_windows.eval, [ - \ 'call feedkeys( ''jjjj'', ''xt'' )', - \ 'call feedkeys( "\", ''xt'' )' - \ ] ) + call feedkeys( 'jjjj', 'xt' ) + call feedkeys( "\", 'xt' ) call WaitForAssert( {-> \ AssertMatchist( @@ -646,11 +644,9 @@ function! Test_VariableEval() \ } ) "Close - call win_execute( g:vimspector_session_windows.eval, 'call feedkeys( "\", ''xt'')') + call feedkeys( "\", 'xt' ) - call WaitForAssert( {-> - \ assert_equal( 0, g:vimspector_session_windows.eval ) - \ } ) + call assert_equal( v:none, g:vimspector_session_windows.eval ) call vimspector#test#setup#Reset() %bwipe! From 0ff9dc5f9e6677288c4a015bc550270e184955dc Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 23:06:35 -0500 Subject: [PATCH 075/200] making sure that select marks were set before attempting to extract text --- autoload/vimspector.vim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 941ec40..1458060 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -532,6 +532,10 @@ function! vimspector#ShowTooltipForSelection() range abort " retrive the lines selected in visual mode let lines = getbufline(bufnr('%'), start[0], end[0]) + if(len(lines) < 1) + return + endif + " make sure the leave only the parts we care about if multiple lines are " selected let lines[0] = strcharpart(lines[0], start[1]) From e0b0a7f3d2edfaf447788adc744856b120b57995 Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 23:07:01 -0500 Subject: [PATCH 076/200] recording popup win id on the failed evaluation --- python3/vimspector/variables.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index e96a585..7666954 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -359,7 +359,9 @@ class VariablesView( object ): def failure_handler( reason, message ): display = [ reason ] - utils.DisplayBalloon( self._is_term, display, is_hover ) + 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, From 5a23ec5bebd1a0b527ffd27b70990fc5221429c4 Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 23:07:37 -0500 Subject: [PATCH 077/200] adding tests for select range, invalid eval and expand/collapse --- tests/variables.test.vim | 130 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 3 deletions(-) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index c587dea..caf2a67 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -602,11 +602,118 @@ function! Test_VariableEval() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) "evaluate the prev line - " call win_gotoid( g:vimspector_session_windows.code ) call setpos('.', [ 0, 24, 8 ]) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) call vimspector#ShowTooltip() + call WaitForAssert( {-> + \ assert_notequal( v:none, g:vimspector_session_windows.eval ) + \ } ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 0', + \ ' + another_test: ', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + "Close + call feedkeys( "\", 'xt' ) + + call assert_equal( v:none, g:vimspector_session_windows.eval ) + + " test selection + call setpos('.', [ 0, 24, 8 ]) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) + + " enter visual mode + " this is a hack, since usually, when user enters command mode from inside + " visual mode, the latter is immediately interrupted and the '<' '>' marks are + " set. for some odd reason, visual mode is not interupted from the script, + " so we need to manually escape and re-trigger previous visual selection + call execute('normal v') + call feedkeys("lllll\", 'xt') + call execute("normal gv") + + call vimspector#ShowTooltipForSelection() + + call WaitForAssert( {-> + \ assert_notequal( v:none, g:vimspector_session_windows.eval ) + \ } ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 0', + \ ' + another_test: ', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + "Close + call feedkeys( "\", 'xt' ) + + call assert_equal( v:none, g:vimspector_session_windows.eval ) + + " Evaluation error + call setpos('.', [ 0, 25, 1 ]) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 25, 1 ) + call vimspector#ShowTooltip() + + call WaitForAssert( {-> + \ assert_notequal( v:none, g:vimspector_session_windows.eval ) + \ } ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ 'Evaluation error', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + "Close + call feedkeys( "\", 'xt' ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! Test_VariableEvalExpand() + let fn = 'testdata/cpp/simple/struct.cpp' + call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ + \ configuration: 'run-to-breakpoint' + \ } } ) + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + + "evaluate the prev line + call setpos('.', [ 0, 24, 8 ]) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) + call vimspector#ShowTooltip() + + call WaitForAssert( {-> + \ assert_notequal( v:none, g:vimspector_session_windows.eval ) + \ } ) + call WaitForAssert( {-> \ AssertMatchist( \ [ @@ -623,8 +730,7 @@ function! Test_VariableEval() \ } ) " Expand - call feedkeys( 'jjjj', 'xt' ) - call feedkeys( "\", 'xt' ) + call feedkeys( "jjjj\", 'xt' ) call WaitForAssert( {-> \ AssertMatchist( @@ -643,6 +749,24 @@ function! Test_VariableEval() \ ) \ } ) + "Collapse + call feedkeys( "\", 'xt' ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 0', + \ ' + another_test: ', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + "Close call feedkeys( "\", 'xt' ) From 639e89f5db9e750fdbac45bccb3268aa798fb1cf Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 23:16:02 -0500 Subject: [PATCH 078/200] fixing linting --- autoload/vimspector.vim | 2 +- tests/variables.test.vim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 1458060..75ed961 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -541,7 +541,7 @@ function! vimspector#ShowTooltipForSelection() range abort let lines[0] = strcharpart(lines[0], start[1]) let lines_len = len(lines) - 1 - if len(lines) == 1 + if len( lines ) == 1 let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1] - start[1]) else let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1]) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index caf2a67..1e4a9ec 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -641,7 +641,7 @@ function! Test_VariableEval() " so we need to manually escape and re-trigger previous visual selection call execute('normal v') call feedkeys("lllll\", 'xt') - call execute("normal gv") + call execute('normal gv') call vimspector#ShowTooltipForSelection() From 8c39a861bdba156d6897a18aeef6594be7dba304 Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 15 Jan 2021 23:36:26 -0500 Subject: [PATCH 079/200] hopefully fixing tests on mac --- tests/variables.test.vim | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index 1e4a9ec..ae51ad8 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -628,7 +628,9 @@ function! Test_VariableEval() "Close call feedkeys( "\", 'xt' ) - call assert_equal( v:none, g:vimspector_session_windows.eval ) + call WaitForAssert( {-> + \ assert_equal( v:none, g:vimspector_session_windows.eval ) + \ } ) " test selection call setpos('.', [ 0, 24, 8 ]) @@ -665,9 +667,13 @@ function! Test_VariableEval() \ } ) "Close - call feedkeys( "\", 'xt' ) + " we need to send esc twice because of the weird interactions between visual + " mode and tests + call feedkeys( "\\", 'xt' ) - call assert_equal( v:none, g:vimspector_session_windows.eval ) + call WaitForAssert( {-> + \ assert_equal( v:none, g:vimspector_session_windows.eval ) + \ } ) " Evaluation error call setpos('.', [ 0, 25, 1 ]) @@ -692,6 +698,10 @@ function! Test_VariableEval() "Close call feedkeys( "\", 'xt' ) + call WaitForAssert( {-> + \ assert_equal( v:none, g:vimspector_session_windows.eval ) + \ } ) + call vimspector#test#setup#Reset() %bwipe! endfunction @@ -770,7 +780,9 @@ function! Test_VariableEvalExpand() "Close call feedkeys( "\", 'xt' ) - call assert_equal( v:none, g:vimspector_session_windows.eval ) + call WaitForAssert( {-> + \ assert_equal( v:none, g:vimspector_session_windows.eval ) + \ } ) call vimspector#test#setup#Reset() %bwipe! From 47680565c433be8947fa3b44de2b0e5474d611ac Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 2 Feb 2021 20:53:31 -0500 Subject: [PATCH 080/200] adding docs --- README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8e7a036..a18a89f 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Run to Cursor](#run-to-cursor) * [Stepping](#stepping) * [Variables and scopes](#variables-and-scopes) + * [Variable/selection hover evaluation](#variable-eval) * [Watches](#watches) * [Watch autocompletion](#watch-autocompletion) * [Stack Traces](#stack-traces) @@ -102,7 +103,7 @@ language that Visual Studio Code supports (but see caveats). The [Vimspector website][website] has an overview of the UI, along with basic instructions for configuration and setup. -But for now, here's a (rather old) screenshot of Vimsepctor debugging Vim: +But for now, here's a (rather old) screenshot of Vimspector debugging Vim: ![vimspector-vim-screenshot](https://puremourning.github.io/vimspector-web/img/vimspector-overview.png) @@ -249,7 +250,7 @@ neovim doesn't implement some features Vimspector relies on: the output window's current output. * Prompt Buffers - used to send commands in the Console and add Watches. (*Note*: prompt buffers are available in neovim nightly) -* Balloons - used to display the values of variables when debugging. +* Tooltips - used to display the values of variables when debugging. Workarounds are in place as follows: @@ -258,9 +259,9 @@ Workarounds are in place as follows: [`:VimspectorReset`](#closing-debugger) * Prompt Buffers - There are [`:VimspectorEval`](#console) and [`:VimspectorWatch`](#watches) - -There is no workaroud for the lack of balloons; you'll just have to use -`:VimspectorEval` or `:VimspectorWatch`, or switch to Vim. +* Functions - There are + [`:call vimspector#ShowTooltip()`](#variable-eval) and + [`:call vimspector#ShowTooltipForSelection()`](#variable-eval) ## Windows differences @@ -890,6 +891,17 @@ breakpoint when it is hit. Scopes and variables are represented by the buffer `vimspector.Variables`. +## Variable/selection hover evaluation + +All rules for `Variables and scopes` apply plus the following: +* With mouse enabled, hover over a variable and get the value it evaluates to. +* Use your mouse to hightlight a expression (e.g. a + b) and the result of the expression. +* Call `vimspector#ShowTooltip()` or `vimspector#ShowTooltipForSelection()` to evaluate expressions without mouse (the only way to use this feature in nvim). +* Use regular nagivation keys to chose the current selection and `` (or leave the tooltip window) to close the tooltip. + +Note: using a selection evaluation might lead to undesired consequences, since **the expression is actually executed**. E.g. `c = a + b;` once this entire line is evaluated, value of `c` becomes the sum of `a` and `b`. + + ## Watches The watch window is used to inspect variables and expressions. Expressions are From d6c68d691cecb5326b2686712ee04c67f62947e8 Mon Sep 17 00:00:00 2001 From: dsych Date: Tue, 2 Feb 2021 21:03:57 -0500 Subject: [PATCH 081/200] streamlining the docs --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a18a89f..a7519e8 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Run to Cursor](#run-to-cursor) * [Stepping](#stepping) * [Variables and scopes](#variables-and-scopes) - * [Variable/selection hover evaluation](#variable-eval) + * [Variable/selection hover evaluation](#variable-or-selection-hover-evaluation) * [Watches](#watches) * [Watch autocompletion](#watch-autocompletion) * [Stack Traces](#stack-traces) @@ -260,8 +260,8 @@ Workarounds are in place as follows: * Prompt Buffers - There are [`:VimspectorEval`](#console) and [`:VimspectorWatch`](#watches) * Functions - There are - [`:call vimspector#ShowTooltip()`](#variable-eval) and - [`:call vimspector#ShowTooltipForSelection()`](#variable-eval) + [`:call vimspector#ShowTooltip()`](#variable-or-selection-hover-evaluation) and + [`:call vimspector#ShowTooltipForSelection()`](#variable-or-selection-hover-evaluation) ## Windows differences @@ -891,13 +891,13 @@ breakpoint when it is hit. Scopes and variables are represented by the buffer `vimspector.Variables`. -## Variable/selection hover evaluation +## Variable or selection hover evaluation All rules for `Variables and scopes` apply plus the following: * With mouse enabled, hover over a variable and get the value it evaluates to. -* Use your mouse to hightlight a expression (e.g. a + b) and the result of the expression. +* Use your mouse to perform a visual selection of an expression (e.g. `a + b`) and get its result. * Call `vimspector#ShowTooltip()` or `vimspector#ShowTooltipForSelection()` to evaluate expressions without mouse (the only way to use this feature in nvim). -* Use regular nagivation keys to chose the current selection and `` (or leave the tooltip window) to close the tooltip. +* Use regular nagivation keys to chose the current selection; `` (or leave the tooltip window) to close the tooltip. Note: using a selection evaluation might lead to undesired consequences, since **the expression is actually executed**. E.g. `c = a + b;` once this entire line is evaluated, value of `c` becomes the sum of `a` and `b`. From ae137ecdd0a5daf47280e1672ff4fd4294fb0cde Mon Sep 17 00:00:00 2001 From: dsych Date: Sun, 7 Feb 2021 16:41:05 -0500 Subject: [PATCH 082/200] removing old balloon code --- autoload/vimspector/internal/balloon.vim | 17 ----------- python3/vimspector/debug_session.py | 23 ++------------- python3/vimspector/variables.py | 37 ------------------------ 3 files changed, 2 insertions(+), 75 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index b922397..86611f6 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -21,23 +21,6 @@ set cpoptions&vim scriptencoding utf-8 -" 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" ) )' ) -endfunction - -" Returns: py.ShowBalloon( winnr, expresssion ) -function! vimspector#internal#balloon#HoverTooltip() abort - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') - -endfunction - - let s:float_win = 0 let s:nvim_related_win = 0 " diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 18c4726..e6fff61 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -541,11 +541,11 @@ class DebugSession( object ): @IfConnected() def ShowTooltip( self, winnr, expression, is_hover ): - """Proxy: ballonexpr -> variables.ShowBallon""" + """Proxy: ballonexpr -> variables.ShowTooltip""" 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 @@ -561,25 +561,6 @@ class DebugSession( object ): def _CleanUpTooltip( self ): return self._variablesView._CleanUpTooltip() - @IfConnected() - def ShowBalloon( self, winnr, expression ): - """Proxy: ballonexpr -> variables.ShowBallon""" - frame = self._stackTraceView.GetCurrentFrame() - # Check if RIP is in a frame - if frame is None: - self._logger.debug( 'Balloon: Not in a stack frame' ) - return '' - - # Check if cursor in code window - if winnr != int( self._codeView._window.number ): - self._logger.debug( 'Winnr %s is not the code window %s', - winnr, - self._codeView._window.number ) - return '' - - # Return variable aware function - return self._variablesView.ShowBalloon( frame, expression ) - @IfConnected() def ExpandFrameOrThread( self ): self._stackTraceView.ExpandFrameOrThread() diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 7666954..c0cb2fd 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -616,43 +616,6 @@ 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', '' ), - 'Value: ' + result - ] - utils.DisplayBalloon( self._is_term, display ) - - def failure_handler( reason, message ): - display = [ reason ] - utils.DisplayBalloon( 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, From 51d551fe52ad5d12d22f81d9d110fc7cb506e243 Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 19 Feb 2021 23:39:54 -0500 Subject: [PATCH 083/200] replacing function calls with plug command --- autoload/vimspector.vim | 40 ++++-------------------- autoload/vimspector/internal/balloon.vim | 5 +++ plugin/vimspector.vim | 6 ++++ python3/vimspector/debug_session.py | 19 +++++++++++ python3/vimspector/utils.py | 23 +++++++++++++- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 75ed961..9ac7ff1 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -523,43 +523,15 @@ function! vimspector#OnBufferCreated( file_name ) abort py3 _vimspector_session.RefreshSigns( vim.eval( 'a:file_name' ) ) endfunction -function! vimspector#ShowTooltipForSelection() range abort - let [start, end] = [[line("'<"), col("'<") - 1], [line("'>"), col("'>")]] - " restor cursor position, since command mode puts it to the begining of the - " current line when invoked from visual mode - call cursor(end) - - " retrive the lines selected in visual mode - let lines = getbufline(bufnr('%'), start[0], end[0]) - - if(len(lines) < 1) - return - endif - - " make sure the leave only the parts we care about if multiple lines are - " selected - let lines[0] = strcharpart(lines[0], start[1]) - let lines_len = len(lines) - 1 - - if len( lines ) == 1 - let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1] - start[1]) +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) else - let lines[lines_len] = strcharpart(lines[lines_len], 0, end[1]) + let expr = expand('') endif - let str = join(lines) - - call vimspector#ShowTooltip(str) -endfunction - -function! vimspector#ShowTooltip(...) abort - let str = '' - - if a:0 > 0 - let str = a:1 - endif - - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "winnr()" ) ) ,vim.eval( "expand(\"'.str.'\")" ), 0)') + return py3eval( '_vimspector_session.ShowEvalBalloon( int( vim.eval( "winnr()" ) ), "'.expr.'", 0 )' ) endfunction diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 86611f6..bc445ba 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -21,6 +21,11 @@ set cpoptions&vim scriptencoding utf-8 +" Returns: py.ShowBalloon( winnr, expresssion ) +function! vimspector#internal#balloon#HoverTooltip() abort + return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') +endfunction + let s:float_win = 0 let s:nvim_related_win = 0 " diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 05245cd..6465c21 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -60,6 +60,12 @@ nnoremap VimspectorStepOut nnoremap VimspectorRunToCursor \ :call vimspector#RunToCursor() +nnoremap VimspectorBalloonEval + \ :call vimspector#ShowEvalBalloon(0) + +xnoremap VimspectorBalloonEval + \ :call vimspector#ShowEvalBalloon(1) + if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorContinue nmap VimspectorStop diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index e6fff61..db14ebc 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -539,6 +539,25 @@ class DebugSession( object ): self._variablesView.DeleteWatch() + @IfConnected() + 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( 'Tooltip: Not in a stack frame' ) + return '' + + # Check if cursor in code window + if winnr != int( self._codeView._window.number ): + self._logger.debug( 'Winnr %s is not the code window %s', + winnr, + self._codeView._window.number ) + return '' + + # Return variable aware function + return self._variablesView.VariableEval( frame, expression, is_hover ) + + @IfConnected() def ShowTooltip( self, winnr, expression, is_hover ): """Proxy: ballonexpr -> variables.ShowTooltip""" diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 2bd3c08..287f919 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -34,6 +34,12 @@ _log_handler = logging.FileHandler( LOG_FILE, mode = 'w' ) _log_handler.setFormatter( logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s' ) ) +# this is the "large number" that vim returns for col num, when getting '> mark +# with getpos() for line wise visual selection(V) +# see https://github.com/vim/vim/blob/eed9d46293f0842aad0d50ff3a526f9a48b12421/src/evalfunc.c#L4077 +# and https://github.com/vim/vim/blob/064095012c0b8e4e43e75834b337115950898fbf/src/vim.h#L1699 +MAX_COL = 2147483647 + def SetUpLogging( logger ): logger.setLevel( logging.DEBUG ) @@ -642,7 +648,7 @@ def DisplayBalloon( is_term, display, is_hover = False ): rc = int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format( - is_hover, json.dumps( display ) + int( is_hover ), json.dumps( display ) ) ) ) @@ -725,6 +731,21 @@ 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 as me why... + lines = vim.buffers[ bufnr ][ start_line - 1 : end_line ] + lines[ 0 ] = lines[ 0 ][ start_col : ] + # only trim the end if we are not in line-wise select mode + if( end_col < MAX_COL ): + lines[ -1 ] = lines[ -1 ][ : end_col + 1 ] + + return lines + + def DisplaySplash( api_prefix, splash, text ): if splash: return Call( f'vimspector#internal#{api_prefix}popup#UpdateSplash', From 0313efa06f009d1bb814c115b11bb0afa7f2db4d Mon Sep 17 00:00:00 2001 From: dsych Date: Fri, 19 Feb 2021 23:44:20 -0500 Subject: [PATCH 084/200] removing redundant check for array bounds --- python3/vimspector/utils.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 287f919..d03a344 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -34,13 +34,6 @@ _log_handler = logging.FileHandler( LOG_FILE, mode = 'w' ) _log_handler.setFormatter( logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s' ) ) -# this is the "large number" that vim returns for col num, when getting '> mark -# with getpos() for line wise visual selection(V) -# see https://github.com/vim/vim/blob/eed9d46293f0842aad0d50ff3a526f9a48b12421/src/evalfunc.c#L4077 -# and https://github.com/vim/vim/blob/064095012c0b8e4e43e75834b337115950898fbf/src/vim.h#L1699 -MAX_COL = 2147483647 - - def SetUpLogging( logger ): logger.setLevel( logging.DEBUG ) if _log_handler not in logger.handlers: @@ -739,9 +732,7 @@ def GetVisualSelection( bufnr ): # don't as me why... lines = vim.buffers[ bufnr ][ start_line - 1 : end_line ] lines[ 0 ] = lines[ 0 ][ start_col : ] - # only trim the end if we are not in line-wise select mode - if( end_col < MAX_COL ): - lines[ -1 ] = lines[ -1 ][ : end_col + 1 ] + lines[ -1 ] = lines[ -1 ][ : end_col + 1 ] return lines From 44711899cbb68c6f2b10b11ef3a842b7659d8f14 Mon Sep 17 00:00:00 2001 From: dsych Date: Sat, 20 Feb 2021 00:15:31 -0500 Subject: [PATCH 085/200] moving stuff around --- autoload/vimspector/internal/balloon.vim | 90 ++++++++++++------------ python3/vimspector/debug_session.py | 19 ----- 2 files changed, 45 insertions(+), 64 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index bc445ba..16ae4c8 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -21,9 +21,8 @@ set cpoptions&vim scriptencoding utf-8 -" Returns: py.ShowBalloon( winnr, expresssion ) function! vimspector#internal#balloon#HoverTooltip() abort - return py3eval('_vimspector_session.ShowTooltip(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') + return py3eval('_vimspector_session.ShowEvalBalloon(int( vim.eval( "v:beval_winnr" ) ) + 1 ,vim.eval( "v:beval_text"), 1)') endfunction let s:float_win = 0 @@ -35,6 +34,47 @@ let s:min_height = 1 let s:max_width = 80 let s:max_height = 20 +function! vimspector#internal#balloon#MouseFilter(winid, key) abort + if index(["\", "\<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>" + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') + let handled = 1 + endif + + return handled +endfunction + +function! vimspector#internal#balloon#CursorFilter(winid, key) abort + if a:key ==? "\" + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') + return 1 + elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 + return vimspector#internal#balloon#MouseFilter( a:winid, a:key ) + endif + + return popup_filter_menu( a:winid, a:key ) +endfunction + function! vimspector#internal#balloon#Close() abort if has('nvim') call nvim_win_close(s:float_win, v:true) @@ -152,50 +192,10 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) abort " make sure we clean up the float after it loses focus augroup vimspector#internal#balloon#nvim_float autocmd! - autocmd WinLeave * :call vimspector#internal#balloon#Close() | autocmd! vimspector#internal#balloon#nvim_float + autocmd BufLeave * :call vimspector#internal#balloon#Close() | autocmd! vimspector#internal#balloon#nvim_float augroup END else - func! MouseFilter(winid, key) abort - if index(["\", "\<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>" - " forward line number to python, since vim does not allow us to focus - " the correct window - call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') - let handled = 1 - endif - - return handled - endfunc - - func! CursorFilter(winid, key) abort - if a:key ==? "\" - " forward line number to python, since vim does not allow us to focus - " the correct window - call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') - return 1 - elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 - return MouseFilter( a:winid, a:key ) - endif - - return popup_filter_menu( a:winid, a:key ) - endfunc if s:float_win != 0 call vimspector#internal#balloon#Close() @@ -222,11 +222,11 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) abort endif if a:is_hover - let config['filter'] = 'MouseFilter' + let config['filter'] = 'vimspector#internal#balloon#MouseFilter' let config['mousemoved'] = [0, 0, 0] let s:float_win = popup_beval(body, config) else - let config['filter'] = 'CursorFilter' + let config['filter'] = 'vimspector#internal#balloon#CursorFilter' let config['moved'] = 'any' let config['cursorline'] = 1 let s:float_win = popup_atcursor(body, config) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index db14ebc..c91caa4 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -558,25 +558,6 @@ class DebugSession( object ): return self._variablesView.VariableEval( frame, expression, is_hover ) - @IfConnected() - def ShowTooltip( self, winnr, expression, is_hover ): - """Proxy: ballonexpr -> variables.ShowTooltip""" - frame = self._stackTraceView.GetCurrentFrame() - # Check if RIP is in a frame - if frame is None: - self._logger.debug( 'Tooltip: Not in a stack frame' ) - return '' - - # Check if cursor in code window - if winnr != int( self._codeView._window.number ): - self._logger.debug( 'Winnr %s is not the code window %s', - winnr, - self._codeView._window.number ) - return '' - - # Return variable aware function - return self._variablesView.VariableEval( frame, expression, is_hover ) - def _CleanUpTooltip( self ): return self._variablesView._CleanUpTooltip() From 7dcb15f11ccb89f3a0a29df8976d2cf9bfe71e0b Mon Sep 17 00:00:00 2001 From: dsych Date: Sat, 20 Feb 2021 00:27:11 -0500 Subject: [PATCH 086/200] cleaning up --- python3/vimspector/utils.py | 4 ++-- python3/vimspector/variables.py | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index d03a344..8010fb9 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -639,7 +639,7 @@ def DisplayBalloon( is_term, display, is_hover = False ): # Refer https://github.com/vim/vim/issues/1512#issuecomment-492070685 display = '\n'.join( display ) - rc = int( vim.eval( + created_win_id = int( vim.eval( "vimspector#internal#balloon#CreateTooltip({}, {})".format( int( is_hover ), json.dumps( display ) ) @@ -647,7 +647,7 @@ def DisplayBalloon( is_term, display, is_hover = False ): vim.eval( "vimspector#internal#balloon#nvim_resize_tooltip()" ) - return rc + return created_win_id def GetBufferFilepath( buf ): diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index c0cb2fd..7890e1b 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -138,7 +138,7 @@ class View: self.lines = lines self.draw = draw self.syntax = None - if ( win is not None ): + if win is not None: self.buf = win.buffer utils.SetUpUIWindow( win ) @@ -285,7 +285,7 @@ class VariablesView( object ): }, } ) - def _DrawEval( self ): + def _DrawBalloonEval( self ): watch = self._variable_eval view = self._variable_eval_view @@ -308,7 +308,6 @@ class VariablesView( object ): # remove reference to old tooltip window self._variable_eval_view = None vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = None - return '' def VariableEval( self, frame, expression, is_hover ): """Callback to display variable under cursor `:h ballonexpr`""" @@ -338,7 +337,7 @@ class VariablesView( object ): { 'options': {}, 'buffer': vim.buffers[ float_buf_nr ] } ), {}, - self._DrawEval + self._DrawBalloonEval ) if watch.result.IsExpandable(): @@ -355,7 +354,7 @@ class VariablesView( object ): }, } ) - self._DrawEval() + self._DrawBalloonEval() def failure_handler( reason, message ): display = [ reason ] From cc84e159329fbed068754b0bb6d3237f0ce5d14d Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 00:34:51 +0000 Subject: [PATCH 087/200] Tidy up, refactor and fix some bugs --- autoload/vimspector.vim | 13 +- autoload/vimspector/internal/balloon.vim | 411 +++++++++++++---------- plugin/vimspector.vim | 7 +- python3/vimspector/debug_session.py | 8 +- python3/vimspector/utils.py | 17 +- python3/vimspector/variables.py | 61 ++-- 6 files changed, 307 insertions(+), 210 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 9ac7ff1..d4bcfa7 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -525,13 +525,18 @@ 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) + let expr = py3eval( '__import__( "vimspector", fromlist = [ "utils" ] )' + \ . '.utils.GetVisualSelection(' + \ . ' int( vim.eval( "winbufnr( winnr() )" ) ) )' ) + let expr = join( expr, '\n' ) else - let expr = expand('') + let expr = expand( '' ) endif - return py3eval( '_vimspector_session.ShowEvalBalloon( int( vim.eval( "winnr()" ) ), "'.expr.'", 0 )' ) + return py3eval( '_vimspector_session.ShowEvalBalloon(' + \ . ' int( vim.eval( "winnr()" ) ), "' + \ . expr + \ . '", 0 )' ) endfunction diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 16ae4c8..5f25f3a 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -21,12 +21,8 @@ set cpoptions&vim scriptencoding utf-8 -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 - -let s:float_win = 0 -let s:nvim_related_win = 0 +let s:popup_win_id = 0 +let s:nvim_border_win_id = 0 " " tooltip dimensions let s:min_width = 1 @@ -34,173 +30,31 @@ let s:min_height = 1 let s:max_width = 80 let s:max_height = 20 -function! vimspector#internal#balloon#MouseFilter(winid, key) abort - if index(["\", "\<2-leftmouse>"], a:key) < 0 - return 0 - endif +let s:is_neovim = has( 'nvim' ) - 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>" - " forward line number to python, since vim does not allow us to focus - " the correct window - call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') - let handled = 1 - endif - - return handled +" 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#CursorFilter(winid, key) abort - if a:key ==? "\" - " forward line number to python, since vim does not allow us to focus - " the correct window - call py3eval('_vimspector_session.ExpandVariable('.line('.', a:winid).')') - return 1 - elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 - return vimspector#internal#balloon#MouseFilter( a:winid, a:key ) - endif - - return popup_filter_menu( a:winid, a:key ) -endfunction - -function! vimspector#internal#balloon#Close() abort - if has('nvim') - call nvim_win_close(s:float_win, v:true) - call nvim_win_close(s:nvim_related_win, v:true) - - call vimspector#internal#balloon#CloseCallback() - else - call popup_close(s:float_win) - endif - -endfunction - -function! vimspector#internal#balloon#CloseCallback( ... ) abort - let s:float_win = 0 - let s:nvim_related_win = 0 - return py3eval('_vimspector_session._CleanUpTooltip()') -endfunction - -function! vimspector#internal#balloon#nvim_generate_border(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! vimspector#internal#balloon#nvim_resize_tooltip() abort - if !has('nvim') || s:float_win <= 0 || s:nvim_related_win <= 0 - return - endif - - noa call win_gotoid(s:float_win) - 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:float_win, opts) - - " resize the border window - let opts['width'] = width + 4 - let opts['height'] = height + 2 - call nvim_win_set_config(s:nvim_related_win, opts) - call nvim_buf_set_lines(nvim_win_get_buf(s:nvim_related_win), 0, -1, v:true, vimspector#internal#balloon#nvim_generate_border(width, height)) - -endfunction - -function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) abort +function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort let body = [] if a:0 > 0 let body = a:1 endif - if has('nvim') - " 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, vimspector#internal#balloon#nvim_generate_border(s:max_width, s:max_height)) - - " default the dimensions for now. they can be easily overwritten later - 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_related_win = nvim_open_win(buf_id, 0, opts) - call nvim_win_set_option(s:nvim_related_win, 'signcolumn', 'no') - call nvim_win_set_option(s:nvim_related_win, 'relativenumber', v:false) - call nvim_win_set_option(s:nvim_related_win, '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, body) - call nvim_buf_set_option(buf_id, 'modifiable', v:false) - let s:float_win = nvim_open_win(buf_id, v:false, opts) - - call nvim_win_set_option(s:float_win, 'wrap', v:false) - call nvim_win_set_option(s:float_win, 'cursorline', v:true) - call nvim_win_set_option(s:float_win, 'signcolumn', 'no') - call nvim_win_set_option(s:float_win, 'relativenumber', v:false) - call nvim_win_set_option(s:float_win, 'number', v:false) - - noautocmd call win_gotoid(s:float_win) - - nnoremap :call vimspector#ExpandVariable() - nnoremap :quit - nnoremap <2-LeftMouse>:call vimspector#ExpandVariable() - - " make sure we clean up the float after it loses focus - augroup vimspector#internal#balloon#nvim_float - autocmd! - autocmd BufLeave * :call vimspector#internal#balloon#Close() | autocmd! vimspector#internal#balloon#nvim_float - augroup END + if s:popup_win_id != 0 + call vimspector#internal#balloon#Close() + endif + if s:is_neovim + call s:CreateNeovimTooltip( body ) else - - if s:float_win != 0 - call vimspector#internal#balloon#Close() - endif - let config = { \ 'wrap': 0, \ 'filtermode': 'n', @@ -217,26 +71,241 @@ function! vimspector#internal#balloon#CreateTooltip(is_hover, ...) abort \ 'callback': 'vimspector#internal#balloon#CloseCallback' \ } + " 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 config['borderchars'] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] + let config[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] endif if a:is_hover - let config['filter'] = 'vimspector#internal#balloon#MouseFilter' - let config['mousemoved'] = [0, 0, 0] - let s:float_win = popup_beval(body, config) + 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 s:float_win = popup_atcursor(body, config) + let config[ 'filter' ] = 'vimspector#internal#balloon#CursorFilter' + let config[ 'moved' ] = 'any' + let config[ 'cursorline' ] = 1 + let s:popup_win_id = popup_atcursor( body, config ) endif endif - return s:float_win + return s:popup_win_id endfunction +" Filters for vim {{{ +function! vimspector#internal#balloon#MouseFilter( winid, key ) abort + if a:key ==# "\" + call vimspector#internal#balloon#Close() + return 0 + endif + + if index( [ "\", "\<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>" + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval( '_vimspector_session.ExpandVariable(' + \ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],' + \ . 'line_num = ' . line( '.', a:winid ) + \ . ')' ) + let handled = 1 + endif + + return handled +endfunction + +function! vimspector#internal#balloon#CursorFilter( winid, key ) abort + if a:key ==? "\" + " forward line number to python, since vim does not allow us to focus + " the correct window + call py3eval( '_vimspector_session.ExpandVariable(' + \ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],' + \ . 'line_num = ' . line( '.', a:winid ) + \ . ')' ) + return 1 + elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 + return vimspector#internal#balloon#MouseFilter( a:winid, a:key ) + 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: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 ) + + 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 + \ call vimspector#ExpandVariable() + nnoremap + \ quit + nnoremap <2-LeftMouse> + \ call vimspector#ExpandVariable() + + " Close the popup whenever we leave this window + augroup vimspector#internal#balloon#nvim_float + autocmd! + autocmd WinLeave + \ :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 diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 6465c21..6691a2a 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -60,11 +60,12 @@ nnoremap VimspectorStepOut nnoremap VimspectorRunToCursor \ :call vimspector#RunToCursor() +" Eval for normal mode nnoremap VimspectorBalloonEval - \ :call vimspector#ShowEvalBalloon(0) - + \ :call vimspector#ShowEvalBalloon( 0 ) +" And for visual modes xnoremap VimspectorBalloonEval - \ :call vimspector#ShowEvalBalloon(1) + \ :call vimspector#ShowEvalBalloon( 1 ) if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorContinue diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index c91caa4..36e6feb 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -520,8 +520,8 @@ class DebugSession( object ): self._stackTraceView.SetCurrentThread() @IfConnected() - def ExpandVariable( self, lineNum = -1 ): - self._variablesView.ExpandVariable( lineNum ) + def ExpandVariable( self, buf = None, line_num = None ): + self._variablesView.ExpandVariable( buf, line_num ) @IfConnected() def AddWatch( self, expression ): @@ -558,8 +558,8 @@ class DebugSession( object ): return self._variablesView.VariableEval( frame, expression, is_hover ) - def _CleanUpTooltip( self ): - return self._variablesView._CleanUpTooltip() + def CleanUpTooltip( self ): + return self._variablesView.CleanUpTooltip() @IfConnected() def ExpandFrameOrThread( self ): diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 8010fb9..e2f96b0 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -645,8 +645,6 @@ def DisplayBalloon( is_term, display, is_hover = False ): ) ) ) - vim.eval( "vimspector#internal#balloon#nvim_resize_tooltip()" ) - return created_win_id @@ -728,11 +726,20 @@ 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 as me why... - lines = vim.buffers[ bufnr ][ start_line - 1 : end_line ] - lines[ 0 ] = lines[ 0 ][ start_col : ] + # 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 diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 7890e1b..74626ac 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -143,6 +143,12 @@ class View: utils.SetUpUIWindow( win ) +class BufView( View ): + def __init__( self, buf, lines, draw ): + super().__init__( None, lines, draw ) + self.buf = buf + + class VariablesView( object ): def __init__( self, variables_win, watches_win ): self._logger = logging.getLogger( __name__ ) @@ -219,6 +225,7 @@ 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 ): @@ -234,6 +241,8 @@ class VariablesView( object ): utils.CleanUpHiddenBuffer( self._vars.buf ) utils.CleanUpHiddenBuffer( self._watch.buf ) + self.ClearTooltip() + def LoadScopes( self, frame ): def scopes_consumer( message ): @@ -302,9 +311,14 @@ class VariablesView( object ): watch, is_short = True ) - vim.eval( "vimspector#internal#balloon#nvim_resize_tooltip()" ) + vim.eval( "vimspector#internal#balloon#ResizeTooltip()" ) - def _CleanUpTooltip( self ) : + 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 @@ -322,22 +336,17 @@ class VariablesView( object ): else: watch.result.Update( message[ 'body' ] ) - float_win_id = utils.DisplayBalloon( self._is_term, [], is_hover ) + popup_win_id = utils.DisplayBalloon( self._is_term, [], is_hover ) # record the global eval window id - vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = int( float_win_id ) - float_buf_nr = int( vim.eval( "winbufnr({})".format( float_win_id ) ) ) + vim.vars[ 'vimspector_session_windows' ][ 'eval' ] = int( popup_win_id ) + popup_bufnr = int( vim.eval( "winbufnr({})".format( popup_win_id ) ) ) - # since vim's popup cant be focused there is no way - # to get a reference to its window - # we will emulate python's window object ourselves - self._variable_eval_view = View( - type( - '__vim__window__', - ( object, ), - { 'options': {}, 'buffer': vim.buffers[ float_buf_nr ] } - ), - {}, - self._DrawBalloonEval + # 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(): @@ -439,21 +448,27 @@ class VariablesView( object ): watch.result = WatchFailure( reason ) self._DrawWatches() - def ExpandVariable( self, lineNum = -1 ): - if vim.current.buffer == self._vars.buf: + def ExpandVariable( self, buf = None, line_num = 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: + elif ( self._variable_eval_view is not None + and buf == self._variable_eval_view.buf ): view = self._variable_eval_view else: return - current_line = vim.current.window.cursor[ 0 ] if lineNum <= 0 else lineNum - if current_line not in view.lines: + if line_num not in view.lines: return - variable = view.lines[ current_line ] + variable = view.lines[ line_num ] if variable.IsExpanded(): # Collapse From 5a1eb9250a16491b520d980659c39944ebb65943 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 16:26:48 +0000 Subject: [PATCH 088/200] Fix test now that we're using a mapping --- tests/variables.test.vim | 40 ++++++++++++++++++++-------------------- tests/vimrc | 4 +++- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index ae51ad8..a43fafd 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -601,10 +601,14 @@ function! Test_VariableEval() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + " leader is , + xmap d VimspectorBalloonEval + nmap d VimspectorBalloonEval + "evaluate the prev line - call setpos('.', [ 0, 24, 8 ]) + call setpos( '.', [ 0, 24, 8 ] ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) - call vimspector#ShowTooltip() + call feedkeys( ',d', 'xt' ) call WaitForAssert( {-> \ assert_notequal( v:none, g:vimspector_session_windows.eval ) @@ -633,19 +637,10 @@ function! Test_VariableEval() \ } ) " test selection - call setpos('.', [ 0, 24, 8 ]) + call setpos( '.', [ 0, 24, 8 ] ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) - " enter visual mode - " this is a hack, since usually, when user enters command mode from inside - " visual mode, the latter is immediately interrupted and the '<' '>' marks are - " set. for some odd reason, visual mode is not interupted from the script, - " so we need to manually escape and re-trigger previous visual selection - call execute('normal v') - call feedkeys("lllll\", 'xt') - call execute('normal gv') - - call vimspector#ShowTooltipForSelection() + call feedkeys( 'viw,d', 'xt' ) call WaitForAssert( {-> \ assert_notequal( v:none, g:vimspector_session_windows.eval ) @@ -667,18 +662,19 @@ function! Test_VariableEval() \ } ) "Close - " we need to send esc twice because of the weird interactions between visual - " mode and tests - call feedkeys( "\\", 'xt' ) + call feedkeys( "\", 'xt' ) call WaitForAssert( {-> \ assert_equal( v:none, g:vimspector_session_windows.eval ) \ } ) + " Get back to normal mode + call feedkeys( "\", 'xt' ) + " Evaluation error - call setpos('.', [ 0, 25, 1 ]) + call setpos( '.', [ 0, 25, 1 ] ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 25, 1 ) - call vimspector#ShowTooltip() + call feedkeys( ',d', 'xt' ) call WaitForAssert( {-> \ assert_notequal( v:none, g:vimspector_session_windows.eval ) @@ -715,10 +711,14 @@ function! Test_VariableEvalExpand() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + " leader is , + xmap d VimspectorBalloonEval + nmap d VimspectorBalloonEval + "evaluate the prev line - call setpos('.', [ 0, 24, 8 ]) + call setpos( '.', [ 0, 24, 8 ] ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) - call vimspector#ShowTooltip() + call feedkeys( ',d', 'xt' ) call WaitForAssert( {-> \ assert_notequal( v:none, g:vimspector_session_windows.eval ) diff --git a/tests/vimrc b/tests/vimrc index e362824..c65efa8 100644 --- a/tests/vimrc +++ b/tests/vimrc @@ -1,8 +1,10 @@ let g:vimspector_test_plugin_path = expand( ':p:h:h' ) set mouse=a set noequalalways +let mapleader = ',' +let maplocalleader = "\" -let &rtp = &rtp . ',' . g:vimspector_test_plugin_path +let &runtimepath = &runtimepath . ',' . g:vimspector_test_plugin_path filetype plugin indent on syntax enable From 323e22b8a97a1d226d6e076c5476eda075a99ad5 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 16:58:45 +0000 Subject: [PATCH 089/200] Update readme --- README.md | 50 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index a7519e8..8475ab2 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ And a couple of brief demos: - locals and globals display - watch expressions with autocompletion - call stack display and navigation -- variable value display hover +- hierarchical variable value display popup (see `VimspectorBalloonEval`) - interactive debug console with autocompletion - launch debugee within Vim's embedded terminal - logging/stdout display @@ -231,8 +231,8 @@ Why such a new vim ? Well 2 reasons: if you hit them. Why is neovim experimental? Because the author doesn't use neovim regularly, and -there are no regression tests for vimspector in neovim, so it's likely to break -frequently. Issue reports are handled on best-efforts basis, and PRs are +there are no regression tests for vimspector in neovim, so it may break +occasionally. Issue reports are handled on best-efforts basis, and PRs are welcome to fix bugs. See also the next section descibing differences for neovim vs vim. @@ -250,7 +250,8 @@ neovim doesn't implement some features Vimspector relies on: the output window's current output. * Prompt Buffers - used to send commands in the Console and add Watches. (*Note*: prompt buffers are available in neovim nightly) -* Tooltips - used to display the values of variables when debugging. +* Balloons - this allows for the variable evaluation popup to be displayed when + hovering the mouse. See below for how to create a keyboard mapping instead. Workarounds are in place as follows: @@ -259,9 +260,18 @@ Workarounds are in place as follows: [`:VimspectorReset`](#closing-debugger) * Prompt Buffers - There are [`:VimspectorEval`](#console) and [`:VimspectorWatch`](#watches) -* Functions - There are - [`:call vimspector#ShowTooltip()`](#variable-or-selection-hover-evaluation) and - [`:call vimspector#ShowTooltipForSelection()`](#variable-or-selection-hover-evaluation) +* Balloons - There is the `VimspectorBalloonEval` mapping. There is no +default mapping for this, so I recommend something like this to get variable +display in a popup: + +```viml +" mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!) + +" for normal mode - the word under the cursor +nmap di VimspectorBalloonEval +" for visual mode, the visually selected text +xmap di VimspectorBalloonEval +``` ## Windows differences @@ -654,6 +664,7 @@ features to set your own mappings. To that end, Vimspector defines the following * `VimspectorStepInto` * `VimspectorStepOut` * `VimspectorRunToCursor` +* `VimspectorBalloonEval` These map roughly 1-1 with the API functions below. @@ -716,6 +727,18 @@ let g:vimspector_enable_mappings = 'HUMAN' | `F11` | Step Into | `vimspector#StepInto()` | | `F12` | Step out of current function scope | `vimspector#StepOut()` | +In addition, I recommend adding a mapping to `VimspectorBalloonEval`, in +normal and visual modes, for example: + +```viml +" mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!) + +" for normal mode - the word under the cursor +nmap di VimspectorBalloonEval +" for visual mode, the visually selected text +xmap di VimspectorBalloonEval +``` + # Usage and API This section defines detailed usage instructions, organised by feature. For most @@ -894,13 +917,16 @@ Scopes and variables are represented by the buffer `vimspector.Variables`. ## Variable or selection hover evaluation All rules for `Variables and scopes` apply plus the following: + * With mouse enabled, hover over a variable and get the value it evaluates to. -* Use your mouse to perform a visual selection of an expression (e.g. `a + b`) and get its result. -* Call `vimspector#ShowTooltip()` or `vimspector#ShowTooltipForSelection()` to evaluate expressions without mouse (the only way to use this feature in nvim). -* Use regular nagivation keys to chose the current selection; `` (or leave the tooltip window) to close the tooltip. - -Note: using a selection evaluation might lead to undesired consequences, since **the expression is actually executed**. E.g. `c = a + b;` once this entire line is evaluated, value of `c` becomes the sum of `a` and `b`. +* Use your mouse to perform a visual selection of an expression (e.g. `a + b`) + and get its result. +* Make a normal mode (`nmap`) and visual mode (`xmap`) mapping to + `VimspectorBalloonEval` to manually trigger the popup. +* Use regular nagivation keys (`j`, `k`) to chose the current selection; `` + (or leave the tooltip window) to close the tooltip. +![variable eval hover](https://puremourning.github.io/vimspector-web/img/vimspector-variable-eval-hover.png) ## Watches From 6b546cd621d171883d152f01c46ce6c8fcc1c77b Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 16:59:41 +0000 Subject: [PATCH 090/200] Update TOC --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8475ab2..b3088b7 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Run to Cursor](#run-to-cursor) * [Stepping](#stepping) * [Variables and scopes](#variables-and-scopes) - * [Variable/selection hover evaluation](#variable-or-selection-hover-evaluation) + * [Variable or selection hover evaluation](#variable-or-selection-hover-evaluation) * [Watches](#watches) * [Watch autocompletion](#watch-autocompletion) * [Stack Traces](#stack-traces) @@ -90,7 +90,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Example](#example) * [FAQ](#faq) - + From 4958de92d39809236433792197470cc672453e2b Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 18:05:59 +0000 Subject: [PATCH 091/200] Fix flake8 error --- python3/vimspector/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index e2f96b0..4022315 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -34,6 +34,7 @@ _log_handler = logging.FileHandler( LOG_FILE, mode = 'w' ) _log_handler.setFormatter( logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s' ) ) + def SetUpLogging( logger ): logger.setLevel( logging.DEBUG ) if _log_handler not in logger.handlers: From 5754e96067a5048308b84f402847776d1cac3d59 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 18:17:14 +0000 Subject: [PATCH 092/200] FixUp: Change of mapleader --- tests/breakpoints.test.vim | 8 ++++---- tests/breakpoints_doublewidth.test.vim | 8 ++++---- tests/mappings.test.vim | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/breakpoints.test.vim b/tests/breakpoints.test.vim index 2e3eef8..877c1cf 100644 --- a/tests/breakpoints.test.vim +++ b/tests/breakpoints.test.vim @@ -280,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( "\\\argc==0\\", 'xt' ) + " Add the conditional breakpoint (note , is the mapleader) + call feedkeys( ",\argc==0\\", 'xt' ) call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP', \ 16, \ 'vimspectorBPCond', @@ -360,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( "\\\\3\", 'xt' ) + " Add the conditional breakpoint (3 times) (note , is the mapleader) + call feedkeys( ",\\3\", 'xt' ) call vimspector#test#signs#AssertSignGroupSingletonAtLine( \ 'VimspectorBP', \ 14, diff --git a/tests/breakpoints_doublewidth.test.vim b/tests/breakpoints_doublewidth.test.vim index c646c3e..4bc0571 100644 --- a/tests/breakpoints_doublewidth.test.vim +++ b/tests/breakpoints_doublewidth.test.vim @@ -293,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( "\\\argc==0\\", 'xt' ) + " Add the conditional breakpoint (, is mapleader) + call feedkeys( ",\argc==0\\", 'xt' ) call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP', \ 16, \ 'vimspectorBPCond', @@ -370,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( "\\\\3\", 'xt' ) + " Add the conditional breakpoint (3 times) (, is mapleader) + call feedkeys( ",\\3\", 'xt' ) call vimspector#test#signs#AssertSignGroupSingletonAtLine( \ 'VimspectorBP', \ 14, diff --git a/tests/mappings.test.vim b/tests/mappings.test.vim index fcd19fe..0f9995d 100644 --- a/tests/mappings.test.vim +++ b/tests/mappings.test.vim @@ -106,9 +106,9 @@ function! Test_Use_Mappings_HUMAN() \ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 ) \ } ) - " Run to cursor + " Run to cursor (note , is the mapleader) call cursor( 9, 1 ) - call feedkeys( "\\\", 'xt' ) + call feedkeys( ",\", 'xt' ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 9, 1 ) call WaitForAssert( {-> \ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 9 ) From d81bdf30efaefc017eb4e6fc707d69e5dd94d02a Mon Sep 17 00:00:00 2001 From: __ <__@__> Date: Sat, 6 Feb 2021 00:52:11 +0100 Subject: [PATCH 093/200] Emit User VimspectorFrameWasSet event --- python3/vimspector/debug_session.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 36e6feb..275fa72 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -710,6 +710,7 @@ class DebugSession( object ): self._stackTraceView.SetSyntax( self._codeView.current_syntax ) self._variablesView.LoadScopes( frame ) self._variablesView.EvaluateWatches() + vim.command( 'doautocmd User VimspectorFrameWasSet' ) if reason == 'stopped': self._breakpoints.ClearTemporaryBreakpoint( frame[ 'source' ][ 'path' ], From 0bb8416e116254047e7822c0271006daeb71dce3 Mon Sep 17 00:00:00 2001 From: __ <__@__> Date: Sat, 6 Feb 2021 13:10:38 +0100 Subject: [PATCH 094/200] Add test --- tests/ui.test.vim | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/ui.test.vim b/tests/ui.test.vim index b6c8feb..ea90f82 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -409,3 +409,18 @@ function! Test_CustomWinBar() call vimspector#test#setup#Reset() %bwipe! endfunction + +function! Test_VimspectorFrameWasSet() + augroup TestVimspectorFrameWasSet + au! + au User VimspectorFrameWasSet let b:vimspectorStepIsThere = 'foo' + augroup END + + call s:StartDebugging() + call assert_equal( 'foo', getbufvar(bufnr(), 'vimspectorStepIsThere', 0) ) + + au! TestVimspectorFrameWasSet + unlet b:vimspectorStepIsThere + call vimspector#test#setup#Reset() + %bwipe! +endfunction From 840ee09242b107e815aad7306f3bfe7e34e3ac18 Mon Sep 17 00:00:00 2001 From: __ <__@__> Date: Sat, 6 Feb 2021 14:48:39 +0100 Subject: [PATCH 095/200] Send an event before leave buffer in window --- python3/vimspector/debug_session.py | 1 - python3/vimspector/utils.py | 7 +++++++ tests/ui.test.vim | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 275fa72..36e6feb 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -710,7 +710,6 @@ class DebugSession( object ): self._stackTraceView.SetSyntax( self._codeView.current_syntax ) self._variablesView.LoadScopes( frame ) self._variablesView.EvaluateWatches() - vim.command( 'doautocmd User VimspectorFrameWasSet' ) if reason == 'stopped': self._breakpoints.ClearTemporaryBreakpoint( frame[ 'source' ][ 'path' ], diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 4022315..eda958b 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -76,7 +76,14 @@ def WindowForBuffer( buf ): def OpenFileInCurrentWindow( file_name ): buffer_number = BufferNumberForFile( file_name ) try: + if "vimspectorStep" in vim.current.buffer.vars: + del vim.current.buffer.vars["vimspectorStep"] + # @todo: what if the same buffer is still visited by another thread + vim.command( 'doautocmd User VimspectorFrameLeavePre' ) + vim.current.buffer = vim.buffers[ buffer_number ] + vim.current.buffer.vars["vimspectorStep"] = 1 + vim.command( 'doautocmd User VimspectorFrameWasSet' ) except vim.error as e: if 'E325' not in str( e ): raise diff --git a/tests/ui.test.vim b/tests/ui.test.vim index ea90f82..91cd214 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -410,16 +410,16 @@ function! Test_CustomWinBar() %bwipe! endfunction -function! Test_VimspectorFrameWasSet() - augroup TestVimspectorFrameWasSet +function! Test_VimspectorFrameEnter() + augroup TestVimspectorFrameEnter au! - au User VimspectorFrameWasSet let b:vimspectorStepIsThere = 'foo' + au User VimspectorFrameEnter let b:vimspectorStepIsThere = 'foo' augroup END call s:StartDebugging() call assert_equal( 'foo', getbufvar(bufnr(), 'vimspectorStepIsThere', 0) ) - au! TestVimspectorFrameWasSet + au! TestVimspectorFrameEnter unlet b:vimspectorStepIsThere call vimspector#test#setup#Reset() %bwipe! From 716181e056eda0778179ff767cb9b5446a4f8aaf Mon Sep 17 00:00:00 2001 From: __ <__@__> Date: Sat, 6 Feb 2021 14:50:01 +0100 Subject: [PATCH 096/200] fixup! Send an event before leave buffer in window --- python3/vimspector/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index eda958b..3ab31bc 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -83,7 +83,7 @@ def OpenFileInCurrentWindow( file_name ): vim.current.buffer = vim.buffers[ buffer_number ] vim.current.buffer.vars["vimspectorStep"] = 1 - vim.command( 'doautocmd User VimspectorFrameWasSet' ) + vim.command( 'doautocmd User VimspectorFrameEnter' ) except vim.error as e: if 'E325' not in str( e ): raise From 50dc55e0e827d82babeab8c534cebdff3113ad90 Mon Sep 17 00:00:00 2001 From: __ <__@__> Date: Sat, 6 Feb 2021 15:01:54 +0100 Subject: [PATCH 097/200] Fix errors reported by flake8 --- python3/vimspector/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 3ab31bc..5281ec8 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -77,12 +77,12 @@ def OpenFileInCurrentWindow( file_name ): buffer_number = BufferNumberForFile( file_name ) try: if "vimspectorStep" in vim.current.buffer.vars: - del vim.current.buffer.vars["vimspectorStep"] + del vim.current.buffer.vars[ "vimspectorStep" ] # @todo: what if the same buffer is still visited by another thread vim.command( 'doautocmd User VimspectorFrameLeavePre' ) vim.current.buffer = vim.buffers[ buffer_number ] - vim.current.buffer.vars["vimspectorStep"] = 1 + vim.current.buffer.vars[ "vimspectorStep" ] = 1 vim.command( 'doautocmd User VimspectorFrameEnter' ) except vim.error as e: if 'E325' not in str( e ): From bcf4120ba48afea716f6fa1149265da79f0c2610 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Wed, 17 Feb 2021 01:04:49 +0100 Subject: [PATCH 098/200] Do not send event after leave buffer. --- python3/vimspector/code.py | 1 + python3/vimspector/utils.py | 7 ------- tests/ui.test.vim | 8 ++++---- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/python3/vimspector/code.py b/python3/vimspector/code.py index d3c6324..98aeca5 100644 --- a/python3/vimspector/code.py +++ b/python3/vimspector/code.py @@ -134,6 +134,7 @@ class CodeView( object ): utils.JumpToWindow( self._window ) try: utils.OpenFileInCurrentWindow( frame[ 'source' ][ 'path' ] ) + vim.command( 'doautocmd User VimspectorJumpedToFrame' ) except vim.error: self._logger.exception( 'Unexpected vim error opening file {}'.format( frame[ 'source' ][ 'path' ] ) ) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 5281ec8..4022315 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -76,14 +76,7 @@ def WindowForBuffer( buf ): def OpenFileInCurrentWindow( file_name ): buffer_number = BufferNumberForFile( file_name ) try: - if "vimspectorStep" in vim.current.buffer.vars: - del vim.current.buffer.vars[ "vimspectorStep" ] - # @todo: what if the same buffer is still visited by another thread - vim.command( 'doautocmd User VimspectorFrameLeavePre' ) - vim.current.buffer = vim.buffers[ buffer_number ] - vim.current.buffer.vars[ "vimspectorStep" ] = 1 - vim.command( 'doautocmd User VimspectorFrameEnter' ) except vim.error as e: if 'E325' not in str( e ): raise diff --git a/tests/ui.test.vim b/tests/ui.test.vim index 91cd214..390f870 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -410,16 +410,16 @@ function! Test_CustomWinBar() %bwipe! endfunction -function! Test_VimspectorFrameEnter() - augroup TestVimspectorFrameEnter +function! Test_VimspectorJumpedToFrame() + augroup TestVimspectorJumpedToFrame au! - au User VimspectorFrameEnter let b:vimspectorStepIsThere = 'foo' + au User VimspectorJumpedToFrame let b:vimspectorStepIsThere = 'foo' augroup END call s:StartDebugging() call assert_equal( 'foo', getbufvar(bufnr(), 'vimspectorStepIsThere', 0) ) - au! TestVimspectorFrameEnter + au! TestVimspectorJumpedToFrame unlet b:vimspectorStepIsThere call vimspector#test#setup#Reset() %bwipe! From 3c54cd268f210b9eefa802b7ac8a5eb09e23683c Mon Sep 17 00:00:00 2001 From: przepompownia Date: Wed, 17 Feb 2021 01:05:09 +0100 Subject: [PATCH 099/200] Send VimspectorDebugEnded event --- python3/vimspector/debug_session.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 36e6feb..954d2c6 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -412,6 +412,7 @@ class DebugSession( object ): self._outputView.Reset() self._codeView.Reset() vim.command( 'tabclose!' ) + vim.command( 'doautocmd User VimspectorDebugEnded' ) self._stackTraceView = None self._variablesView = None self._outputView = None From d561c4aea5fdedee2b44a2951310cd85baf43d45 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 20 Feb 2021 22:37:02 +0000 Subject: [PATCH 100/200] Add demo of new commands for local mappings --- support/custom_ui_vimrc | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index 95c3360..4e9f635 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -1,5 +1,7 @@ execute 'source' expand( ':p:h' ) . '/minimal_vimrc' set noequalalways +let mapleader = ',' +let maplocalleader = "\" function! s:CustomiseUI() let wins = g:vimspector_session_windows @@ -59,11 +61,52 @@ function! s:CustomiseWinBar() nnoremenu WinBar.✕\ ᶠ⁸ :call vimspector#Reset() endfunction +let s:mapped = {} + +function! s:OnJumpToFrame() abort + if has_key( s:mapped, string( bufnr() ) ) + return + endif + + nmap dn VimspectorStepOver + nmap ds VimspectorStepInto + nmap df VimspectorStepOut + nmap dc VimspectorContinue + + let s:mapped[ string( bufnr() ) ] = 1 +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 dn + silent! nunmap ds + silent! nunmap df + silent! nunmap dc + endtry + endfor + finally + execute 'noautocmd buffer' original_buf + let &hidden = hidden + endtry + + let s:mapped = {} +endfunction + augroup TestUICustomistaion autocmd! autocmd User VimspectorUICreated call s:CustomiseUI() autocmd User VimspectorTerminalOpened call s:SetUpTerminal() autocmd User VimspectorUICreated call s:CustomiseWinBar() + autocmd User VimspectorJumpedToFrame call s:OnJumpToFrame() + autocmd User VimspectorDebugEnded call s:OnDebugEnd() augroup END let g:vimspector_sign_priority = { From 3c7311e33a9a77d7d315cc473ccffc600119e2b3 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 20:49:56 +0000 Subject: [PATCH 101/200] Test that the commands are fired when stepping through and continuing --- tests/ui.test.vim | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/tests/ui.test.vim b/tests/ui.test.vim index 390f870..f251539 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -411,16 +411,54 @@ function! Test_CustomWinBar() endfunction function! Test_VimspectorJumpedToFrame() + let s:ended = 0 + let s:au_visited_buffers = {} + augroup TestVimspectorJumpedToFrame au! - au User VimspectorJumpedToFrame let b:vimspectorStepIsThere = 'foo' + au User VimspectorJumpedToFrame + \ let s:au_visited_buffers[ bufname() ] = get( s:au_visited_buffers, + \ bufname(), + \ 0 ) + 1 + au User VimspectorDebugEnded + \ let s:ended = 1 augroup END - call s:StartDebugging() - call assert_equal( 'foo', getbufvar(bufnr(), 'vimspectorStepIsThere', 0) ) + lcd ../support/test/python/multiple_files + edit moo.py + + let moo = 'moo.py' + let cow = getcwd() . '/cow.py' + + call vimspector#SetLineBreakpoint( 'moo.py', 13 ) + call vimspector#Launch() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 1, 1 ) + call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 1 ) + let expected = {} + let expected[ moo ] = 1 + call assert_equal( expected, s:au_visited_buffers ) + + call vimspector#Continue() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'moo.py', 13, 1 ) + call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'moo.py', 13 ) + let expected[ moo ] += 1 + call assert_equal( expected, s:au_visited_buffers ) + + call vimspector#SetLineBreakpoint( 'cow.py', 2 ) + call vimspector#Continue() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'cow.py', 2, 1 ) + call vimspector#test#signs#AssertPCIsAtLineInBuffer( 'cow.py', 2 ) + let expected[ cow ] = 1 + call assert_equal( expected, s:au_visited_buffers ) + + VimspectorReset + call WaitForAssert( { -> assert_equal( s:ended, 1 ) } ) au! TestVimspectorJumpedToFrame - unlet b:vimspectorStepIsThere + unlet! s:au_visited_buffers + unlet! s:ended + call vimspector#test#setup#Reset() + lcd - %bwipe! endfunction From ae289a88c76fe69531293eb6ce311028d3e78dfd Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 21:16:54 +0000 Subject: [PATCH 102/200] Update readme with example --- README.md | 30 ++++++++++++++++++++++++++- support/custom_ui_vimrc | 46 +++++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b3088b7..e13aae0 100644 --- a/README.md +++ b/README.md @@ -85,12 +85,13 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Sign priority](#sign-priority) * [Changing the default window sizes](#changing-the-default-window-sizes) * [Changing the terminal size](#changing-the-terminal-size) + * [Custom mappings while debugging](#custom-mappings-while-debugging) * [Advanced UI customisation](#advanced-ui-customisation) * [Customising the WinBar](#customising-the-winbar) * [Example](#example) * [FAQ](#faq) - + @@ -675,6 +676,10 @@ appropriate place, such as your `vimrc` (hint: run `:e $MYVIMRC`). nmap VimspectorContinue ``` +In addition, many users probably want to only enable certain Vimspector mappings +while debugging is active. This is also possible, though it requires writing +[some vimscipt](#custom-mappings-while-debugging). + That said, many people are familiar with particular debuggers, so the following mappings can be enabled by setting `g:vimspector_enable_mappings` to the specified value. @@ -1821,6 +1826,29 @@ let g:vimspector_terminal_maxwidth = 75 let g:vimspector_terminal_minwidth = 20 ``` +## Custom mappings while debugging + +It's useful to be able to define mappings only while debugging and remove those +mappings when debugging is complete. For this purpose, Vimspector provides 2 +`User` autocommds: + +* `VimspectorJumpedToFrame` - triggered whenever a 'break' event happens, or + when selecting a stack from to jump to. This can be used to create (for + example) buffer-local mappings for any files opened in the code window. +* `VimspectorDebugEnded` - triggered when the debug session is terminated + (actually when Vimspector is fully reset) + +An example way to use this is included in `support/custom_ui_vimrc`. In there, +these autocommands are used to create buffer-local mappings for any files +visited while debugging and to clear them when completing debugging. This is +particularly useful for commadns like `VimspectorBalloonEval` which only +make sense while debugging (and only in the code window). Check the commented +section `Custom mappings while debugging`. + +NOTE: This is a fairly advanced feature requiring some nontrivial vimscript. +It's possible that this feature will be incorporated into Vimspector in future +as it is a common requirement. + ## Advanced UI customisation > ***Please Note***: This cusomiation API is ***unstable***, meaning that it may diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index 4e9f635..51a7304 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -1,7 +1,12 @@ +" setup boilerplate to make this file usable with vim -Nu {{{ +scriptencoding utf-8 execute 'source' expand( ':p:h' ) . '/minimal_vimrc' set noequalalways let mapleader = ',' let maplocalleader = "\" +" }}} + +" Custom Layout {{{ function! s:CustomiseUI() let wins = g:vimspector_session_windows @@ -61,6 +66,27 @@ function! s:CustomiseWinBar() nnoremenu WinBar.✕\ ᶠ⁸ :call vimspector#Reset() endfunction +augroup TestUICustomistaion + autocmd! + autocmd User VimspectorUICreated call s:CustomiseUI() + autocmd User VimspectorTerminalOpened call s:SetUpTerminal() + 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 @@ -72,6 +98,8 @@ function! s:OnJumpToFrame() abort nmap ds VimspectorStepInto nmap df VimspectorStepOut nmap dc VimspectorContinue + nmap di VimspectorBalloonEval + xmap di VimspectorBalloonEval let s:mapped[ string( bufnr() ) ] = 1 endfunction @@ -90,6 +118,8 @@ function! s:OnDebugEnd() abort silent! nunmap ds silent! nunmap df silent! nunmap dc + silent! nunmap di + silent! xunmap di endtry endfor finally @@ -100,18 +130,12 @@ function! s:OnDebugEnd() abort let s:mapped = {} endfunction -augroup TestUICustomistaion - autocmd! - autocmd User VimspectorUICreated call s:CustomiseUI() - autocmd User VimspectorTerminalOpened call s:SetUpTerminal() - autocmd User VimspectorUICreated call s:CustomiseWinBar() +augroup TestCustomMappings + au! autocmd User VimspectorJumpedToFrame call s:OnJumpToFrame() autocmd User VimspectorDebugEnded call s:OnDebugEnd() augroup END -let g:vimspector_sign_priority = { - \ 'vimspectorBP': 3, - \ 'vimspectorBPCond': 2, - \ 'vimspectorBPDisabled': 1, - \ 'vimspectorPC': 999, - \ } +" }}} + +" vim: foldmethod=marker From 448ee33a6af11a32e4efb18814d1eb778089e58c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 21 Feb 2021 21:24:02 +0000 Subject: [PATCH 103/200] prevent annoying 'no matching autocmds' message --- plugin/vimspector.vim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 6691a2a..8482dfd 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -125,6 +125,8 @@ augroup VimspectorUserAutoCmds autocmd! autocmd User VimspectorUICreated silent autocmd User VimspectorTerminalOpened silent + autocmd user VimspectorJumpedToFrame silent + autocmd user VimspectorDebugEnded silent augroup END augroup Vimspector From 0e0cc6d4aec83c0020858e11663f0d82e45287ba Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 22 Feb 2021 11:49:25 +0000 Subject: [PATCH 104/200] 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: 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: 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'. --- autoload/vimspector/internal/channel.vim | 39 +++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/autoload/vimspector/internal/channel.vim b/autoload/vimspector/internal/channel.vim index b44436b..e033cff 100644 --- a/autoload/vimspector/internal/channel.vim +++ b/autoload/vimspector/internal/channel.vim @@ -95,21 +95,44 @@ EOF 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 ) - call s:_OnClose( s:ch ) endif - if exists( 's:job' ) - if job_status( s:job ) ==# 'run' - call job_stop( s:job, 'kill' ) - endif - unlet s:job - 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 ) + endwhile + call s:_OnClose( s:ch ) endfunction function! vimspector#internal#channel#Reset() abort From 476300f815c1378aa1b88447229c08739c01f283 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 22 Feb 2021 13:39:50 +0000 Subject: [PATCH 105/200] Fix errors resetting in neovim --- autoload/vimspector/internal/balloon.vim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 5f25f3a..384b18a 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -162,6 +162,10 @@ function! vimspector#internal#balloon#CloseCallback( ... ) abort 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 ) From 0810d7154c483e25e53d4a996f9cb1bb75f77c15 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 23 Feb 2021 09:03:45 +0000 Subject: [PATCH 106/200] Fix syntax occasionally not working in popup, and custom vimrc crashing in neovim --- autoload/vimspector/internal/balloon.vim | 1 + python3/vimspector/utils.py | 2 +- python3/vimspector/variables.py | 3 +-- support/custom_ui_vimrc | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 384b18a..a51d092 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -279,6 +279,7 @@ function! s:CreateNeovimTooltip( body ) abort 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' ) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 4022315..10da7e1 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -707,7 +707,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 diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 74626ac..9cd0b3e 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -301,8 +301,7 @@ class VariablesView( object ): with utils.RestoreCursorPosition(): with utils.ModifiableScratchBuffer( view.buf ): utils.ClearBuffer( view.buf ) - # FIXME: This probably doesn't work reliably - view.syntax = utils.SetSyntax( None, + view.syntax = utils.SetSyntax( view.syntax, self._current_syntax, view.buf ) diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index 51a7304..b1ffda1 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -38,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 From 6fac220ee55af66c0c2ab3dae630086da5b0263f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 23 Feb 2021 09:42:57 +0000 Subject: [PATCH 107/200] Disable mappings in the popup to ensure navigaion works --- autoload/vimspector/internal/balloon.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index a51d092..4d6aca2 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -68,7 +68,8 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort \ 'drag': 1, \ 'resize': 1, \ 'close': 'button', - \ 'callback': 'vimspector#internal#balloon#CloseCallback' + \ 'callback': 'vimspector#internal#balloon#CloseCallback', + \ 'mapping': 0 \ } " When ambiwidth is single, use prettier characters for the border. This From fd0c6e767588170784b0645dd6a49c696c9d9221 Mon Sep 17 00:00:00 2001 From: Ygor Oliveira Date: Tue, 23 Feb 2021 19:39:29 +0100 Subject: [PATCH 108/200] Fix typos in README --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e13aae0..40bb2ab 100644 --- a/README.md +++ b/README.md @@ -346,7 +346,7 @@ See support/doc/example_vimrc.vim for a minimal example. Vimspector is a generic client for Debug Adapters. Debug Adapters (referred to as 'gadgets' or 'adapters') are what actually do the work of talking to the real -debugers. +debuggers. In order for Vimspector to be useful, you need to have some adapters installed. @@ -464,7 +464,7 @@ You essentially need to get a working installation of the debug adapter, find out how to start it, and configure that in an `adapters` entry in either your `.vimspector.json` or in `.gadgets.json`. -The simplest way in practice is to install or start Visusal Studio Code and use +The simplest way in practice is to install or start Visual Studio Code and use its extension manager to install the relevant extension. You can then configure the adapter manually in the `adapters` section of your `.vimspector.json` or in a `gadgets.json`. @@ -545,7 +545,7 @@ format as `.gadgets.json` but are not overwritten when running ## Upgrade After updating the Vimspector code (either via `git pull` or whatever package -manager), run `:VimspectorUpdate` to update any already-installed gadets. +manager), run `:VimspectorUpdate` to update any already-installed gadgets. # About @@ -770,7 +770,7 @@ The argument is a `dict` with the following keys: * `configuration`: (optional) Name of the debug configuration to launch * ``: (optional) Name of a variable to set -This allows for some intergration and automation. For example, if you have a +This allows for some integration and automation. For example, if you have a configuration named `Run Test` that contains a [replacement variable][vimspector-ref-var] named `${Test}` you could write a mapping which ultimately executes: @@ -854,9 +854,9 @@ breakpoint on the current line and `` to launch the application. ### Conditional breakpoints -Some debug adapters support conditional breakpionts. Note that vimspector does +Some debug adapters support conditional breakpoints. Note that vimspector does not tell you if the debugger doesn't support conditional breakpoints (yet). A -conditional breakpiont is a breakpiont which only triggers if some expression +conditional breakpoint is a breakpoint which only triggers if some expression evaluates to true, or has some other constraints met. Some of these functions above take a single optional argument which is a @@ -928,7 +928,7 @@ All rules for `Variables and scopes` apply plus the following: and get its result. * Make a normal mode (`nmap`) and visual mode (`xmap`) mapping to `VimspectorBalloonEval` to manually trigger the popup. -* Use regular nagivation keys (`j`, `k`) to chose the current selection; `` +* Use regular nagivation keys (`j`, `k`) to choose the current selection; `` (or leave the tooltip window) to close the tooltip. ![variable eval hover](https://puremourning.github.io/vimspector-web/img/vimspector-variable-eval-hover.png) @@ -1775,7 +1775,7 @@ smaller ones. ## Changing the default window sizes -> ***Please Note***: This cusomiation API is ***unstable***, meaning that it may +> ***Please Note***: This customisation API is ***unstable***, meaning that it may change at any time. I will endeavour to reduce the impact of this and announce changes in Gitter. @@ -1797,7 +1797,7 @@ let g:vimspector_bottombar_height = 15 ## Changing the terminal size -The terminal is typically created as a vertical split to the righ of the code +The terminal is typically created as a vertical split to the right of the code window, and that window is re-used for subsequent terminal buffers. The following control the sizing of the terminal window used for debuggee input/output when using Vim's built-in terminal. @@ -1816,7 +1816,7 @@ least `g:vimspector_code_minwidth` columns for the main code window and that the terminal is no wider than `g:vimspector_terminal_maxwidth` columns. `g:vimspector_terminal_minwidth` is there to ensure that there's a reasonable number of columns for the terminal even when there isn't enough horizontal space -to satisfy the other contraints. +to satisfy the other constraints. Example: @@ -1830,7 +1830,7 @@ let g:vimspector_terminal_minwidth = 20 It's useful to be able to define mappings only while debugging and remove those mappings when debugging is complete. For this purpose, Vimspector provides 2 -`User` autocommds: +`User` autocommands: * `VimspectorJumpedToFrame` - triggered whenever a 'break' event happens, or when selecting a stack from to jump to. This can be used to create (for @@ -1841,7 +1841,7 @@ mappings when debugging is complete. For this purpose, Vimspector provides 2 An example way to use this is included in `support/custom_ui_vimrc`. In there, these autocommands are used to create buffer-local mappings for any files visited while debugging and to clear them when completing debugging. This is -particularly useful for commadns like `VimspectorBalloonEval` which only +particularly useful for commands like `VimspectorBalloonEval` which only make sense while debugging (and only in the code window). Check the commented section `Custom mappings while debugging`. @@ -1851,7 +1851,7 @@ as it is a common requirement. ## Advanced UI customisation -> ***Please Note***: This cusomiation API is ***unstable***, meaning that it may +> ***Please Note***: This customisation API is ***unstable***, meaning that it may change at any time. I will endeavour to reduce the impact of this and announce changes in Gitter. @@ -1898,7 +1898,7 @@ In addition, the following key is added when triggering the ## Customising the WinBar You can even customise the WinBar buttons by simply running the usual `menu` -(and `unmanu`) commands. +(and `unmenu`) commands. By default, Vimspector uses something a bit like this: @@ -2009,9 +2009,9 @@ hi link jsonComment Comment but in theory a single gadget can supply multiple `adapter` configs. Typically this happens when a `gadget` supplies different `adapter` config for, say remote debugging, or debugging in a container, etc. -8. The signs and winbar display funny symbols. How do i fix them? See +8. The signs and winbar display funny symbols. How do I fix them? See [this](#changing-the-default-signs) and [this](#customising-the-winbar) -9. What's thie telemetry stuff all about? Are you sending my data to evil companies? +9. What's this telemetry stuff all about? Are you sending my data to evil companies? 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. From 52019952792050b2eb26ecbb4e633692305e5ca4 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 15:10:57 +0000 Subject: [PATCH 109/200] 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. --- python3/vimspector/debug_session.py | 26 +++++++++++++++++++------- python3/vimspector/stack_trace.py | 12 ++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 954d2c6..e82febf 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -793,7 +793,12 @@ class DebugSession( object ): arguments = {} if self._server_capabilities.get( 'supportTerminateDebuggee' ): # If we attached, we should _not_ terminate the debuggee - arguments[ 'terminateDebuggee' ] = False + if self._stackTraceView.AnyThreadsRunning(): + choice = utils.AskForInput( "Terminate debugee [Y/N/default]? ", "" ) + if choice == "Y" or choice == "y": + arguments[ 'terminateDebuggee' ] = True + elif choice == "N" or choice == 'n': + arguments[ 'terminateDebuggee' ] = False self._connection.DoRequest( handler, { 'command': 'disconnect', @@ -1164,10 +1169,22 @@ 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 + # debugee 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( message[ 'body' ][ 'exitCode' ] ) ) - self.SetCurrentFrame( None ) + self._stackTraceView.OnExited( message ) + self._codeView.SetCurrentFrame( None ) def OnEvent_process( self, message ): utils.UserMessage( 'The debugee was started: {}'.format( @@ -1210,11 +1227,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." ) - self.SetCurrentFrame( None ) - def OnEvent_output( self, message ): if self._outputView: self._outputView.OnOutput( message[ 'body' ] ) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index f38e4ba..177998f 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -364,6 +364,14 @@ class StackTraceView( object ): self._JumpToFrame( frame ) + 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: @@ -459,6 +467,10 @@ class StackTraceView( object ): 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 From 09efcf5e509f262cdc52fb41398bf8f069d3cfcf Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 16:19:48 +0000 Subject: [PATCH 110/200] hide the controvertial telemetry data; it's not like anyone will ever look at it --- python3/vimspector/output.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index cf2a213..d3fe13e 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -33,7 +33,7 @@ BUFFER_MAP = { 'console': 'Console', 'stdout': 'Console', 'stderr': 'stderr', - 'telemetry': 'Telemetry', + 'telemetry': None, } @@ -77,6 +77,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 ) @@ -251,7 +255,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' ) From d8eb6a04639bd3f1171c53d64c142fd4ec8973ad Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 18:00:08 +0000 Subject: [PATCH 111/200] Only prompt in 'interactive' contexts to avoid annoying questions --- README.md | 35 ++++++++++++++++++++++------- autoload/vimspector.vim | 18 +++++++++++---- plugin/vimspector.vim | 2 +- python3/vimspector/debug_session.py | 29 ++++++++++++------------ 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 40bb2ab..b6009da 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ And a couple of brief demos: - call stack display and navigation - hierarchical variable value display popup (see `VimspectorBalloonEval`) - interactive debug console with autocompletion -- launch debugee within Vim's embedded terminal +- launch debuggee within Vim's embedded terminal - logging/stdout display - simple stable API for custom tooling (e.g. integrate with language server) @@ -698,7 +698,7 @@ let g:vimspector_enable_mappings = 'VISUAL_STUDIO' | `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | | `Shift F5` | Stop debugging. | `vimspector#Stop()` | | `Ctrl Shift F5` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debugee. | `vimspector#Pause()` | +| `F6` | Pause debuggee. | `vimspector#Pause()` | | `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | | `Shift F9` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | | `F10` | Step Over | `vimspector#StepOver()` | @@ -723,7 +723,7 @@ let g:vimspector_enable_mappings = 'HUMAN' | `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | | `F3` | Stop debugging. | `vimspector#Stop()` | | `F4` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debugee. | `vimspector#Pause()` | +| `F6` | Pause debuggee. | `vimspector#Pause()` | | `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | | `F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | | `F8` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | @@ -1002,7 +1002,7 @@ The stack trace is represented by the buffer `vimspector.StackTrace`. * In the outputs window, use the WinBar to select the output channel. * Alternatively, use `:VimspectorShowOutput `. Use command-line completion to see the categories. -* The debugee prints to the stdout channel. +* The debuggee prints to the stdout channel. * Other channels may be useful for debugging. ![output window](https://puremourning.github.io/vimspector-web/img/vimspector-output-window.png) @@ -1057,10 +1057,29 @@ which will tail it in a little window (doesn't work on Windows). To close the debugger, use: -* `Reset` WinBar button (`set mouse=a`) +* `Reset` WinBar button * `:VimspectorReset` when the WinBar is not available. * `call vimspector#Reset()` + +## Terminate debuggee + +If the debuggee is still running when stopping or resetting, then some debug +adapters allow you to specify what should happen to it when finishing debugging. +Typically, the default behaviour is sensible, and this is what happens most of +the time. These are the defaults according to DAP: + +* If the request was 'launch': terminate the debuggee +* If the request was 'attach': don't terminate the debuggee + +Some debug adapters allow you to choose what to do when disconnecting. If you +wish to control this behaviour, use `:VimspectorReset` or call +`vimspector#Reset( { 'interactive': v:true } )`. If the debug adapter offers a +choice as to whether or not to terminate the debuggee, you will be prompted to +choose. The same applies for `vimspector#Stop()` which can take an argument: +`vimspector#Stop( { 'interactive': v:true } )`. + + # Debug profile configuration For an introduction to the configuration of `.vimspector.json`, take a look at @@ -1903,14 +1922,14 @@ You can even customise the WinBar buttons by simply running the usual `menu` By default, Vimspector uses something a bit like this: ```viml -nnoremenu WinBar.■\ Stop :call vimspector#Stop() +nnoremenu WinBar.■\ Stop :call vimspector#Stop( { 'interactive': v:false } ) nnoremenu WinBar.▶\ Cont :call vimspector#Continue() nnoremenu WinBar.▷\ Pause :call vimspector#Pause() nnoremenu WinBar.↷\ Next :call vimspector#StepOver() nnoremenu WinBar.→\ Step :call vimspector#StepInto() nnoremenu WinBar.←\ Out :call vimspector#StepOut() nnoremenu WinBar.⟲: :call vimspector#Restart() -nnoremenu WinBar.✕ :call vimspector#Reset() +nnoremenu WinBar.✕ :call vimspector#Reset( { 'interactive': v:false } ) ``` If you prefer a different layout or if the unicode symbols don't render @@ -1923,7 +1942,7 @@ func! CustomiseUI() " Clear the existing WinBar created by Vimspector nunmenu WinBar " Cretae our own WinBar - nnoremenu WinBar.Kill :call vimspector#Stop() + nnoremenu WinBar.Kill :call vimspector#Stop( { 'interactive': v:true } ) nnoremenu WinBar.Continue :call vimspector#Continue() nnoremenu WinBar.Pause :call vimspector#Pause() nnoremenu WinBar.Step\ Over :call vimspector#StepOver() diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index d4bcfa7..e2e3833 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -55,11 +55,16 @@ function! vimspector#LaunchWithSettings( settings ) abort py3 _vimspector_session.Start( launch_variables = vim.eval( 'a:settings' ) ) endfunction -function! vimspector#Reset() abort +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 @@ -185,11 +190,16 @@ function! vimspector#SetCurrentThread() abort py3 _vimspector_session.SetCurrentThread() endfunction -function! vimspector#Stop() abort +function! vimspector#Stop( ... ) abort if !s:Enabled() return endif - py3 _vimspector_session.Stop() + if a:0 == 0 + options = {} + else + options = a:1 + endif + py3 _vimspector_session.Stop( **vim.eval( 'options' ) ) endfunction function! vimspector#ExpandVariable() abort diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 8482dfd..50f7e3d 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -105,7 +105,7 @@ command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr \ call vimspector#Evaluate( ) command! -bar \ VimspectorReset - \ call vimspector#Reset() + \ call vimspector#Reset( { 'interactive': v:true } ) " Installer commands command! -bar -bang -nargs=* -complete=custom,vimspector#CompleteInstall diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index e82febf..b36113d 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -320,7 +320,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() @@ -385,14 +385,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() @@ -772,7 +773,7 @@ class DebugSession( object ): self._logger.info( 'Debug Adapter Started' ) - def _StopDebugAdapter( self, callback = None ): + def _StopDebugAdapter( self, interactive = False, callback = None ): self._splash_screen = utils.DisplaySplash( self._api_prefix, self._splash_screen, @@ -791,10 +792,10 @@ class DebugSession( object ): self._connection_type ) ) arguments = {} - if self._server_capabilities.get( 'supportTerminateDebuggee' ): - # If we attached, we should _not_ terminate the debuggee + if ( interactive and + self._server_capabilities.get( 'supportTerminateDebuggee' ) ): if self._stackTraceView.AnyThreadsRunning(): - choice = utils.AskForInput( "Terminate debugee [Y/N/default]? ", "" ) + choice = utils.AskForInput( "Terminate debuggee [Y/N/default]? ", "" ) if choice == "Y" or choice == "y": arguments[ 'terminateDebuggee' ] = True elif choice == "N" or choice == 'n': @@ -1028,14 +1029,14 @@ class DebugSession( object ): self._splash_screen = utils.DisplaySplash( self._api_prefix, self._splash_screen, - "Attaching to debugee..." ) + "Attaching to debuggee..." ) 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', [] ), @@ -1171,7 +1172,7 @@ class DebugSession( object ): def OnEvent_terminated( self, message ): # The debugging _session_ has terminated. This does not mean that the - # debugee has terminated (that's the exited event). + # debuggee has terminated (that's the exited event). # # We will handle this when the server actually exists. # @@ -1181,13 +1182,13 @@ class DebugSession( object ): 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 ): From 11edcddd9c6208d1290c1ff1fc1c598a3b963aca Mon Sep 17 00:00:00 2001 From: Jake Zimmerman Date: Thu, 25 Feb 2021 03:04:12 -0800 Subject: [PATCH 112/200] 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. --- plugin/vimspector.vim | 2 +- tests/variables.test.vim | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 50f7e3d..c69414b 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -100,7 +100,7 @@ command! -bar -nargs=? -complete=custom,vimspector#CompleteOutput command! -bar \ VimspectorToggleLog \ call vimspector#ToggleLog() -command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr +command! -nargs=1 -complete=custom,vimspector#CompleteExpr \ VimspectorEval \ call vimspector#Evaluate( ) command! -bar diff --git a/tests/variables.test.vim b/tests/variables.test.vim index a43fafd..2da9c7f 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -513,6 +513,49 @@ function Test_EvaluateConsole() endfunction +function Test_EvaluateInput() + let fn = 'testdata/cpp/simple/struct.cpp' + call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ + \ configuration: 'run-to-breakpoint' + \ } } ) + + " Make sure the Test t is initialised + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 27, 1 ) + + VimspectorEval -exec print (int) printf("hello") + + call assert_equal( bufnr( 'vimspector.Console' ), + \ winbufnr( g:vimspector_session_windows.output ) ) + call WaitForAssert( {-> + \ assert_equal( + \ [ + \ '' + \ ], + \ getbufline( bufnr( 'vimspector.Console' ), '$', '$' ) + \ ) + \ } ) + + let len = getbufinfo( 'vimspector.Console' )[ 0 ].linecount + + call WaitForAssert( {-> + \ assert_equal( + \ [ + \ 'Evaluating: -exec print (int) printf("hello")', + \ ], + \ getbufline( bufnr( 'vimspector.Console' ), len-2, len-2 ) + \ ) + \ } ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( + \ 'vimspector.Console', len, v:null ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + + function Test_EvaluatePromptConsole() let fn = 'testdata/cpp/simple/struct.cpp' call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ From f40ac5db236772c66f5d72f60257337e744261fa Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 21:24:40 +0000 Subject: [PATCH 113/200] Delay launching the python interpreter until needed --- autoload/vimspector.vim | 24 +----------------------- python3/vimspector/debug_session.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index e2e3833..319c39b 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -320,28 +320,6 @@ function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort return join( buffers, "\n" ) endfunction -py3 < Date: Wed, 24 Feb 2021 16:17:35 +0000 Subject: [PATCH 114/200] 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. --- autoload/vimspector.vim | 7 +++ python3/vimspector/debug_session.py | 6 ++ python3/vimspector/variables.py | 96 ++++++++++++++++++++++++++--- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 319c39b..7cecca5 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -209,6 +209,13 @@ function! vimspector#ExpandVariable() abort py3 _vimspector_session.ExpandVariable() endfunction +function! vimspector#SetVariableValue() abort + if !s:Enabled() + return + endif + py3 _vimspector_session.SetVariableValue() +endfunction + function! vimspector#DeleteWatch() abort if !s:Enabled() return diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index e65af46..95524c5 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -525,6 +525,11 @@ class DebugSession( object ): def ExpandVariable( self, buf = None, line_num = None ): self._variablesView.ExpandVariable( buf, line_num ) + @IfConnected() + def SetVariableValue( self ): + # TODO: , buf = None, line_num = None ): + self._variablesView.SetVariableValue() + @IfConnected() def AddWatch( self, expression ): self._variablesView.AddWatch( self._stackTraceView.GetCurrentFrame(), @@ -999,6 +1004,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, { diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 9cd0b3e..8db007e 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -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 @@ -92,8 +96,8 @@ class WatchFailure( WatchResult ): 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 @@ -156,6 +160,7 @@ class VariablesView( object ): self._connection = None self._current_syntax = '' + self._server_capabilities = None self._variable_eval: Scope = None self._variable_eval_view: View = None @@ -165,12 +170,17 @@ class VariablesView( object ): ':call vimspector#ExpandVariable()' ) vim.command( 'nnoremap <2-LeftMouse> ' ':call vimspector#ExpandVariable()' ) + vim.command( 'nnoremap ' + ':call vimspector#SetVariableValue()' ) # 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 ): + if utils.UseWinBar(): + vim.command( 'nnoremenu 1.1 WinBar.Set ' + ':call vimspector#SetVariableValue()' ) AddExpandMappings() # Set up the "Watches" buffer in the watches_win (and create a WinBar in @@ -194,6 +204,8 @@ class VariablesView( object ): ':call vimspector#ExpandVariable()' ) vim.command( 'nnoremenu 1.3 WinBar.Delete ' ':call vimspector#DeleteWatch()' ) + vim.command( 'nnoremenu 1.1 WinBar.Set ' + ':call vimspector#SetVariableValue()' ) # Set the (global!) balloon expr if supported has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) ) @@ -231,11 +243,21 @@ class VariablesView( object ): def ConnectionUp( self, connection ): self._connection = connection + def SetServerCapabilities( self, capabilities ): + self._server_capabilities = capabilities + + if self._server_capabilities.get( 'supportsSetVariable' ): + # TODO add a winbar item ? add a mapping ? + pass + 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 @@ -447,7 +469,7 @@ class VariablesView( object ): watch.result = WatchFailure( reason ) self._DrawWatches() - def ExpandVariable( self, buf = None, line_num = None ): + def _GetVariable( self, buf = None, line_num = None ): if buf is None: buf = vim.current.buffer @@ -462,12 +484,17 @@ class VariablesView( object ): and buf == self._variable_eval_view.buf ): view = self._variable_eval_view else: - return + return None if line_num not in view.lines: - return + return None - variable = view.lines[ line_num ] + 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 @@ -488,6 +515,59 @@ class VariablesView( object ): }, } ) + def SetVariableValue( self ): + variable: Variable + view: View + + variable, view = self._GetVariable( buf = None, line_num = None ) + if variable is None: + return + + if not variable.IsContained(): + return + + new_value = utils.AskForInput( 'New Value: ', + variable.variable.get( 'value', '' ) ) + + 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() + + self._connection.DoRequest( handler, { + 'command': 'setVariable', + 'arguments': { + 'variablesReference': variable.container.VariablesReference(), + 'name': variable.variable[ 'name' ], + 'value': new_value + }, + } ) + + + def _DrawVariables( self, view, variables, indent, is_short = False ): assert indent > 0 for variable in variables: @@ -609,7 +689,7 @@ class VariablesView( object ): found = True break if not found: - variable = Variable( variable_body ) + variable = Variable( parent, variable_body ) else: variable.Update( variable_body ) From 32f9a6ec43f7acba6c262e59d6547f8af96ba6e9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 16:20:05 +0000 Subject: [PATCH 115/200] Use silent for winbar menus --- python3/vimspector/output.py | 2 +- python3/vimspector/stack_trace.py | 6 +++--- python3/vimspector/variables.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index d3fe13e..c453417 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -234,7 +234,7 @@ class OutputView( object ): raise vim.command( - "nnoremenu 1.{0} WinBar.{1}{2} " + "nnoremenu 1.{0} WinBar.{1}{2} " ":call vimspector#ShowOutputInWindow( {3}, '{1}' )".format( tab_buffer.index, utils.Escape( category ), diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index 177998f..df32462 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -116,11 +116,11 @@ class StackTraceView( object ): ':call vimspector#GoToFrame()' ) if utils.UseWinBar(): - vim.command( 'nnoremenu 1.1 WinBar.Pause/Continue ' + vim.command( 'nnoremenu 1.1 WinBar.Pause/Continue ' ':call vimspector#PauseContinueThread()' ) - vim.command( 'nnoremenu 1.2 WinBar.Expand/Collapse ' + vim.command( 'nnoremenu 1.2 WinBar.Expand/Collapse ' ':call vimspector#GoToFrame()' ) - vim.command( 'nnoremenu 1.3 WinBar.Focus ' + vim.command( 'nnoremenu 1.3 WinBar.Focus ' ':call vimspector#SetCurrentThread()' ) win.options[ 'cursorline' ] = False diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 8db007e..edd8f60 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -198,11 +198,11 @@ class VariablesView( object ): 'nnoremap :call vimspector#DeleteWatch()' ) if utils.UseWinBar(): - vim.command( 'nnoremenu 1.1 WinBar.New ' + vim.command( 'nnoremenu 1.1 WinBar.New ' ':call vimspector#AddWatch()' ) - vim.command( 'nnoremenu 1.2 WinBar.Expand/Collapse ' + vim.command( 'nnoremenu 1.2 WinBar.Expand/Collapse ' ':call vimspector#ExpandVariable()' ) - vim.command( 'nnoremenu 1.3 WinBar.Delete ' + vim.command( 'nnoremenu 1.3 WinBar.Delete ' ':call vimspector#DeleteWatch()' ) vim.command( 'nnoremenu 1.1 WinBar.Set ' ':call vimspector#SetVariableValue()' ) From 9e1a1ab4b5b383819732a4c2f465777d7148ad02 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 16:48:33 +0000 Subject: [PATCH 116/200] Report failures --- python3/vimspector/variables.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index edd8f60..123aa54 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -557,6 +557,9 @@ class VariablesView( object ): 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': { @@ -564,7 +567,7 @@ class VariablesView( object ): 'name': variable.variable[ 'name' ], 'value': new_value }, - } ) + }, failure_handler = failure_handler ) From c2082cffaeb9b9ebbbcd7f7306d462ad098432ed Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 17:23:30 +0000 Subject: [PATCH 117/200] Support setting from the balloon --- autoload/vimspector/internal/balloon.vim | 12 ++++++++---- python3/vimspector/debug_session.py | 5 ++--- python3/vimspector/variables.py | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 4d6aca2..1622d10 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -124,8 +124,6 @@ function! vimspector#internal#balloon#MouseFilter( winid, key ) abort " expand the variable if we got double click if a:key ==? "\<2-leftmouse>" - " forward line number to python, since vim does not allow us to focus - " the correct window call py3eval( '_vimspector_session.ExpandVariable(' \ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],' \ . 'line_num = ' . line( '.', a:winid ) @@ -138,13 +136,17 @@ endfunction function! vimspector#internal#balloon#CursorFilter( winid, key ) abort if a:key ==? "\" - " forward line number to python, since vim does not allow us to focus - " the correct window call py3eval( '_vimspector_session.ExpandVariable(' \ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],' \ . 'line_num = ' . line( '.', a:winid ) \ . ')' ) return 1 + elseif a:key ==? "\" + call py3eval( '_vimspector_session.SetVariableValue(' + \ . 'buf = vim.buffers[ ' . winbufnr( a:winid ) . ' ],' + \ . 'line_num = ' . line( '.', a:winid ) + \ . ')' ) + return 1 elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 return vimspector#internal#balloon#MouseFilter( a:winid, a:key ) endif @@ -293,6 +295,8 @@ function! s:CreateNeovimTooltip( body ) abort nnoremap \ call vimspector#ExpandVariable() + nnoremap + \ call vimspector#SetVariableValue() nnoremap \ quit nnoremap <2-LeftMouse> diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 95524c5..f5a62df 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -526,9 +526,8 @@ class DebugSession( object ): self._variablesView.ExpandVariable( buf, line_num ) @IfConnected() - def SetVariableValue( self ): - # TODO: , buf = None, line_num = None ): - self._variablesView.SetVariableValue() + def SetVariableValue( self, buf = None, line_num = None ): + self._variablesView.SetVariableValue( buf, line_num ) @IfConnected() def AddWatch( self, expression ): diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 123aa54..9b9b372 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -515,11 +515,11 @@ class VariablesView( object ): }, } ) - def SetVariableValue( self ): + def SetVariableValue( self, buf = None, line_num = None ): variable: Variable view: View - variable, view = self._GetVariable( buf = None, line_num = None ) + variable, view = self._GetVariable( buf, line_num ) if variable is None: return From 131cfcdd33280dcfd81fd7cd7a43274a1095e00d Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 18:06:35 +0000 Subject: [PATCH 118/200] Don't try and set a value if not supported --- python3/vimspector/variables.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 9b9b372..9e74345 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -246,10 +246,6 @@ class VariablesView( object ): def SetServerCapabilities( self, capabilities ): self._server_capabilities = capabilities - if self._server_capabilities.get( 'supportsSetVariable' ): - # TODO add a winbar item ? add a mapping ? - pass - def ConnectionClosed( self ): self.Clear() self._connection = None @@ -519,6 +515,9 @@ class VariablesView( object ): variable: Variable view: View + if not self._server_capabilities.get( 'supportsSetVariable' ): + return + variable, view = self._GetVariable( buf, line_num ) if variable is None: return From ec9122284ed480da9a3c1df2fa81c9ed8e590023 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 19:58:29 +0000 Subject: [PATCH 119/200] Add some notes on setting values to the readme --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6009da..00416e3 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,8 @@ And a couple of brief demos: - remote launch, remote attach - locals and globals display - watch expressions with autocompletion +- variable inspection tooltip on hover +- set variable value in locals, watch and hover windows - call stack display and navigation - hierarchical variable value display popup (see `VimspectorBalloonEval`) - interactive debug console with autocompletion @@ -912,6 +914,7 @@ breakpoint when it is hit. * Current scope shows values of locals. * Use ``, or double-click with left mouse to expand/collapse (+, -). +* Set the value of the variable with `` (control + ``) * When changing the stack frame the locals window updates. * While paused, hover to see values @@ -928,8 +931,9 @@ All rules for `Variables and scopes` apply plus the following: and get its result. * Make a normal mode (`nmap`) and visual mode (`xmap`) mapping to `VimspectorBalloonEval` to manually trigger the popup. -* Use regular nagivation keys (`j`, `k`) to choose the current selection; `` - (or leave the tooltip window) to close the tooltip. + * Set the value of the variable with `` (control + ``) + * Use regular nagivation keys (`j`, `k`) to choose the current selection; `` + (or leave the tooltip window) to close the tooltip. ![variable eval hover](https://puremourning.github.io/vimspector-web/img/vimspector-variable-eval-hover.png) @@ -946,6 +950,7 @@ to add a new watch expression. * Alternatively, use `:VimspectorWatch `. Tab-completion for expression is available in some debug adapters. * Expand result with ``, or double-click with left mouse. +* Set the value of the variable with `` (control + ``) * Delete with ``. ![watch window](https://puremourning.github.io/vimspector-web/img/vimspector-watch-window.png) From 26452289a81eaa5ada15274a8ed216215ac3e213 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 22:10:23 +0000 Subject: [PATCH 120/200] Allow overriding the variables/stack trace mappings in config --- autoload/vimspector/internal/balloon.vim | 30 +++++++++-- python3/vimspector/settings.py | 63 +++++++++++++++++++++--- python3/vimspector/stack_trace.py | 17 ++++--- python3/vimspector/variables.py | 22 +++++---- 4 files changed, 106 insertions(+), 26 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 1622d10..4770d81 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -134,21 +134,43 @@ function! vimspector#internal#balloon#MouseFilter( winid, key ) abort return handled endfunction +function! s:MatchKey( key, candidates ) abort + let mapped = '' + for candidate in a:candidates + try + " Try and expand the key code + execute 'let mapped = "\' . candidate . '"' + if mapped ==# a:key + return v:true + endif + endtry + endfor + + return v:false +endfunction + function! vimspector#internal#balloon#CursorFilter( winid, key ) abort - if a:key ==? "\" + let mappings = py3eval( + \ "__import__( 'vimspector'," + \." fromlist = [ 'settings' ] ).settings.Dict(" + \." 'mappings' )[ 'variables' ]" ) + + if index( [ "\", "\<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 a:key ==? "\" + 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 - elseif index( [ "\", "\<2-LeftMouse>" ], a:key ) >= 0 - return vimspector#internal#balloon#MouseFilter( a:winid, a:key ) endif return popup_filter_menu( a:winid, a:key ) diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index 5ff729b..53aafd2 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -17,6 +17,7 @@ import vim import builtins from vimspector import utils +from collections.abc import Mapping DEFAULTS = { # UI @@ -38,6 +39,19 @@ DEFAULTS = { # Installer 'install_gadgets': [], + + # Mappings + 'mappings': { + 'variables': { + 'expand_collapse': [ '', '<2-LeftMouse>' ], + 'delete': [ '' ], + 'set_value': [ '' ] + }, + 'stack_trace': { + 'expand_or_jump': [ '', '<2-LeftMouse>' ], + 'focus_thread': [ '' ], + } + } } @@ -69,9 +83,46 @@ 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, {} ) ), + utils.GetVimValue( vim.vars, + f'vimspector_{ option }', + {} ) ) + + +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, Mapping ): + target[ key ] = value + elif isinstance( value, Mapping ): + target[ key ] = _UpdateDict( current_value, value ) + else: + target[ key ] = value + + return target diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index df32462..c32cead 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -18,7 +18,7 @@ import os import logging import typing -from vimspector import utils, signs +from vimspector import utils, signs, settings class Thread: @@ -107,13 +107,16 @@ class StackTraceView( object ): utils.SetUpHiddenBuffer( self._buf, 'vimspector.StackTrace' ) utils.SetUpUIWindow( win ) + mappings = settings.Dict( 'mappings' )[ 'stack_trace' ] + with utils.LetCurrentWindow( win ): - vim.command( 'nnoremap ' - ':call vimspector#GoToFrame()' ) - vim.command( 'nnoremap ' - ':call vimspector#SetCurrentThread()' ) - vim.command( 'nnoremap <2-LeftMouse> ' - ':call vimspector#GoToFrame()' ) + for mapping in utils.GetVimList( mappings, 'expand_or_jump' ): + vim.command( f'nnoremap { mapping } ' + ':call vimspector#GoToFrame()' ) + + for mapping in utils.GetVimList( mappings, 'focus_thread' ): + vim.command( f'nnoremap { mapping } ' + ':call vimspector#SetCurrentThread()' ) if utils.UseWinBar(): vim.command( 'nnoremenu 1.1 WinBar.Pause/Continue ' diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 9e74345..e418a5e 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -19,7 +19,7 @@ import logging from functools import partial import typing -from vimspector import utils +from vimspector import utils, settings class Expandable: @@ -165,13 +165,16 @@ class VariablesView( object ): self._variable_eval: Scope = None self._variable_eval_view: View = None + mappings = settings.Dict( 'mappings' )[ 'variables' ] + def AddExpandMappings(): - vim.command( 'nnoremap ' - ':call vimspector#ExpandVariable()' ) - vim.command( 'nnoremap <2-LeftMouse> ' - ':call vimspector#ExpandVariable()' ) - vim.command( 'nnoremap ' - ':call vimspector#SetVariableValue()' ) + for mapping in utils.GetVimList( mappings, 'expand_collapse' ): + vim.command( f'nnoremap { mapping } ' + ':call vimspector#ExpandVariable()' ) + + for mapping in utils.GetVimList( mappings, 'set_value' ): + vim.command( f'nnoremap { mapping } ' + ':call vimspector#SetVariableValue()' ) # Set up the "Variables" buffer in the variables_win self._scopes: typing.List[ Scope ] = [] @@ -194,8 +197,9 @@ class VariablesView( object ): 'vimspector#OmniFuncWatch' ) with utils.LetCurrentWindow( watches_win ): AddExpandMappings() - vim.command( - 'nnoremap :call vimspector#DeleteWatch()' ) + for mapping in utils.GetVimList( mappings, 'delete' ): + vim.command( + f'nnoremap { mapping } :call vimspector#DeleteWatch()' ) if utils.UseWinBar(): vim.command( 'nnoremenu 1.1 WinBar.New ' From e1078375fec6446fec1655c120dd629331bacd8f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 22:12:02 +0000 Subject: [PATCH 121/200] Also allow in case modifyOtherKeys mode doesn't work --- python3/vimspector/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index 53aafd2..e72bedf 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -45,7 +45,7 @@ DEFAULTS = { 'variables': { 'expand_collapse': [ '', '<2-LeftMouse>' ], 'delete': [ '' ], - 'set_value': [ '' ] + 'set_value': [ '', '' ] }, 'stack_trace': { 'expand_or_jump': [ '', '<2-LeftMouse>' ], From 675a68c601b9fc3d721379955619971ed68759e5 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 24 Feb 2021 22:18:43 +0000 Subject: [PATCH 122/200] Make it work in neovim too --- autoload/vimspector/internal/balloon.vim | 12 ++++-------- python3/vimspector/variables.py | 25 +++++++++++++----------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 4770d81..4dc5096 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -315,14 +315,10 @@ function! s:CreateNeovimTooltip( body ) abort " interract with the popup in neovim noautocmd call win_gotoid( s:popup_win_id ) - nnoremap - \ call vimspector#ExpandVariable() - nnoremap - \ call vimspector#SetVariableValue() - nnoremap - \ quit - nnoremap <2-LeftMouse> - \ call vimspector#ExpandVariable() + nnoremap quit + call py3eval( "__import__( 'vimspector', " + \." fromlist = [ 'variables' ] )." + \.' variables.AddExpandMappings()' ) " Close the popup whenever we leave this window augroup vimspector#internal#balloon#nvim_float diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index e418a5e..507c495 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -153,6 +153,18 @@ class BufView( View ): 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 { mapping } ' + ':call vimspector#ExpandVariable()' ) + + for mapping in utils.GetVimList( mappings, 'set_value' ): + vim.command( f'nnoremap { mapping } ' + ':call vimspector#SetVariableValue()' ) + + class VariablesView( object ): def __init__( self, variables_win, watches_win ): self._logger = logging.getLogger( __name__ ) @@ -167,15 +179,6 @@ class VariablesView( object ): mappings = settings.Dict( 'mappings' )[ 'variables' ] - def AddExpandMappings(): - for mapping in utils.GetVimList( mappings, 'expand_collapse' ): - vim.command( f'nnoremap { mapping } ' - ':call vimspector#ExpandVariable()' ) - - for mapping in utils.GetVimList( mappings, 'set_value' ): - vim.command( f'nnoremap { mapping } ' - ':call vimspector#SetVariableValue()' ) - # Set up the "Variables" buffer in the variables_win self._scopes: typing.List[ Scope ] = [] self._vars = View( variables_win, {}, self._DrawScopes ) @@ -184,7 +187,7 @@ class VariablesView( object ): if utils.UseWinBar(): vim.command( 'nnoremenu 1.1 WinBar.Set ' ':call vimspector#SetVariableValue()' ) - AddExpandMappings() + AddExpandMappings( mappings ) # Set up the "Watches" buffer in the watches_win (and create a WinBar in # there) @@ -196,7 +199,7 @@ class VariablesView( object ): 'vimspector#AddWatchPrompt', 'vimspector#OmniFuncWatch' ) with utils.LetCurrentWindow( watches_win ): - AddExpandMappings() + AddExpandMappings( mappings ) for mapping in utils.GetVimList( mappings, 'delete' ): vim.command( f'nnoremap { mapping } :call vimspector#DeleteWatch()' ) From ba83a59e888cfbddfa58dfabbf091a7a873f3df7 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 12:04:35 +0000 Subject: [PATCH 123/200] TEst overriding the mappings --- autoload/vimspector/internal/balloon.vim | 5 ++++- python3/vimspector/settings.py | 9 +++------ support/custom_ui_vimrc | 11 +++++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 4dc5096..b8be41a 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -138,7 +138,10 @@ function! s:MatchKey( key, candidates ) abort let mapped = '' for candidate in a:candidates try - " Try and expand the key code + " Try and expand the key code. Note this won't work for non-special keys + " and it won't work for multple keys, which is kinda shitty. + " + " There's no vim api to run expand_keycodes() i don't think. execute 'let mapped = "\' . candidate . '"' if mapped ==# a:key return v:true diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index e72bedf..9ad9e41 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -17,7 +17,6 @@ import vim import builtins from vimspector import utils -from collections.abc import Mapping DEFAULTS = { # UI @@ -85,9 +84,7 @@ if hasattr( vim, 'Dictionary' ): def Dict( option ): return _UpdateDict( DICT_TYPE( DEFAULTS.get( option, {} ) ), - utils.GetVimValue( vim.vars, - f'vimspector_{ option }', - {} ) ) + vim.vars.get( f'vimspector_{ option }', DICT_TYPE() ) ) def _UpdateDict( target, override ): @@ -118,9 +115,9 @@ def _UpdateDict( target, override ): for key, value in override.items(): current_value = target.get( key ) - if not isinstance( current_value, Mapping ): + if not isinstance( current_value, DICT_TYPE ): target[ key ] = value - elif isinstance( value, Mapping ): + elif isinstance( value, DICT_TYPE ): target[ key ] = _UpdateDict( current_value, value ) else: target[ key ] = value diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index b1ffda1..3b132b4 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -142,4 +142,15 @@ augroup END " }}} +" Custom mappings for special buffers {{{ + +let g:vimspector_mappings = { + \ 'stack_trace': {}, + \ 'variables': { + \ 'set_value': [ '', '' ], + \ }, + \ } + +" }}} + " vim: foldmethod=marker From 94242fa5326aef0dd350ac1cfe1f91648651291b Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 16:41:55 +0000 Subject: [PATCH 124/200] CustomUI: Make buffers non-modifiable when opened for debugging --- support/custom_ui_vimrc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index 3b132b4..934d9f0 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -105,7 +105,10 @@ function! s:OnJumpToFrame() abort nmap di VimspectorBalloonEval xmap di VimspectorBalloonEval - let s:mapped[ string( bufnr() ) ] = 1 + let s:mapped[ string( bufnr() ) ] = { 'modifiable': &modifiable } + + setlocal nomodifiable + endfunction function! s:OnDebugEnd() abort @@ -124,6 +127,8 @@ function! s:OnDebugEnd() abort silent! nunmap dc silent! nunmap di silent! xunmap di + + let &l:modifiable = s:mapped[ bufnr ][ 'modifiable' ] endtry endfor finally @@ -148,7 +153,7 @@ let g:vimspector_mappings = { \ 'stack_trace': {}, \ 'variables': { \ 'set_value': [ '', '' ], - \ }, + \ } \ } " }}} From f2d407256e752a8f943e4638358871730aea5c83 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 16:53:55 +0000 Subject: [PATCH 125/200] Use expression completion for watch and set --- autoload/vimspector.vim | 4 +++- python3/vimspector/utils.py | 17 +++++++++++------ python3/vimspector/variables.py | 3 ++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 7cecca5..168a239 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -235,7 +235,9 @@ function! vimspector#AddWatch( ... ) abort 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 diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 10da7e1..e7cb537 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -356,16 +356,21 @@ 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 diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index 507c495..fb9080e 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -533,7 +533,8 @@ class VariablesView( object ): return new_value = utils.AskForInput( 'New Value: ', - variable.variable.get( 'value', '' ) ) + variable.variable.get( 'value', '' ), + completion = 'expr' ) if new_value is None: return From 49a9a4b36792a99a4fa2c35124934c12831cf2ec Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 21:14:05 +0000 Subject: [PATCH 126/200] Allow mappings which aren't special chars --- autoload/vimspector/internal/balloon.vim | 25 +++++++++++++----------- support/custom_ui_vimrc | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index b8be41a..32d17ab 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -135,18 +135,21 @@ function! vimspector#internal#balloon#MouseFilter( winid, key ) abort endfunction function! s:MatchKey( key, candidates ) abort - let mapped = '' for candidate in a:candidates - try - " Try and expand the key code. Note this won't work for non-special keys - " and it won't work for multple keys, which is kinda shitty. - " - " There's no vim api to run expand_keycodes() i don't think. - execute 'let mapped = "\' . candidate . '"' - if mapped ==# a:key - return v:true - endif - endtry + " 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 diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index 934d9f0..a8812cb 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -152,7 +152,7 @@ augroup END let g:vimspector_mappings = { \ 'stack_trace': {}, \ 'variables': { - \ 'set_value': [ '', '' ], + \ 'set_value': [ '', '', 'C' ], \ } \ } From 804b49928645f9ef77cb7dc59fb1e1e33827d70f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 21:52:27 +0000 Subject: [PATCH 127/200] Allow setting the value via the api --- autoload/vimspector.vim | 8 ++++++-- plugin/vimspector.vim | 1 + python3/vimspector/debug_session.py | 4 ++-- python3/vimspector/variables.py | 9 +++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 168a239..41d30dd 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -209,11 +209,15 @@ function! vimspector#ExpandVariable() abort py3 _vimspector_session.ExpandVariable() endfunction -function! vimspector#SetVariableValue() abort +function! vimspector#SetVariableValue( ... ) abort if !s:Enabled() return endif - py3 _vimspector_session.SetVariableValue() + 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 diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index c69414b..53855ef 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -129,6 +129,7 @@ augroup VimspectorUserAutoCmds autocmd user VimspectorDebugEnded silent augroup END +" FIXME: Only register this _while_ debugging is active augroup Vimspector autocmd! autocmd BufNew * call vimspector#OnBufferCreated( expand( '' ) ) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index f5a62df..6fb0b16 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -526,8 +526,8 @@ class DebugSession( object ): self._variablesView.ExpandVariable( buf, line_num ) @IfConnected() - def SetVariableValue( self, buf = None, line_num = None ): - self._variablesView.SetVariableValue( buf, line_num ) + def SetVariableValue( self, new_value = None, buf = None, line_num = None ): + self._variablesView.SetVariableValue( new_value, buf, line_num ) @IfConnected() def AddWatch( self, expression ): diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index fb9080e..d225af0 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -518,7 +518,7 @@ class VariablesView( object ): }, } ) - def SetVariableValue( self, buf = None, line_num = None ): + def SetVariableValue( self, new_value = None, buf = None, line_num = None ): variable: Variable view: View @@ -532,9 +532,10 @@ class VariablesView( object ): if not variable.IsContained(): return - new_value = utils.AskForInput( 'New Value: ', - variable.variable.get( 'value', '' ), - completion = 'expr' ) + if new_value is None: + new_value = utils.AskForInput( 'New Value: ', + variable.variable.get( 'value', '' ), + completion = 'expr' ) if new_value is None: return From 06f9bfc0572c113ffb406bcb34eabe0b51724039 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 21:52:41 +0000 Subject: [PATCH 128/200] Add basic tests for set variable value --- tests/variables.test.vim | 289 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index 2da9c7f..c7d373b 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -830,3 +830,292 @@ function! Test_VariableEvalExpand() call vimspector#test#setup#Reset() %bwipe! endfunction + +function! Test_SetVariableValue_Local() + let fn = 'testdata/cpp/simple/struct.cpp' + call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ + \ configuration: 'run-to-breakpoint' + \ } } ) + + " Make sure the Test t is initialised + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + + call WaitForAssert( {-> + \ assert_equal( + \ [ + \ '- Scope: Locals', + \ ' *+ t (Test): {...}', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.variables ), + \ 1, + \ '$' ) + \ ) + \ } ) + call assert_equal( 'cpp', + \ getbufvar( + \ winbufnr( g:vimspector_session_windows.variables ), + \ '&syntax' ) ) + + " Expand + call win_gotoid( g:vimspector_session_windows.variables ) + call setpos( '.', [ 0, 2, 1 ] ) + call feedkeys( "\", 'xt' ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Scope: Locals', + \ ' \*- t (Test): {...}', + \ ' \*- i (int): 0', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.variables ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call setpos( '.', [ 0, 3, 1 ] ) + + " We can't just fire the keys to the inpit prompt because we use inputsave() + " and inputrestore(), so mock that out and fire away. + py3 <\100\", "xt" )' ) +EOF + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Scope: Locals', + \ ' \*- t (Test): {...}', + \ ' \*- i (int): 100', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.variables ), + \ 1, + \ '$' ) + \ ) + \ } ) + + " Now set it via the more comforable scripting interface + call vimspector#SetVariableValue( '1234' ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Scope: Locals', + \ ' \*- t (Test): {...}', + \ ' \*- i (int): 1234', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.variables ), + \ 1, + \ '$' ) + \ ) + \ } ) + + " Something fails + call vimspector#SetVariableValue( 'this is invalid' ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Scope: Locals', + \ ' \*- t (Test): {...}', + \ ' \*- i (int): 1234', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.variables ), + \ 1, + \ '$' ) + \ ) + \ } ) + + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! Test_SetVariableValue_Watch() + let fn = 'testdata/cpp/simple/struct.cpp' + call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ + \ configuration: 'run-to-breakpoint' + \ } } ) + + " Make sure the Test t is initialised + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + + call win_gotoid( g:vimspector_session_windows.watches ) + call feedkeys( "it\", 'xt' ) + + call WaitForAssert( {-> + \ assert_equal( + \ [ + \ 'Watches: ----', + \ 'Expression: t', + \ ' *+ Result: {...}', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.watches ), + \ 1, + \ '$' ) + \ ) + \ } ) + call assert_equal( 'cpp', + \ getbufvar( + \ winbufnr( g:vimspector_session_windows.watches ), + \ '&syntax' ) ) + + " Expand + call win_gotoid( g:vimspector_session_windows.watches ) + call setpos( '.', [ 0, 3, 1 ] ) + call feedkeys( "\", 'xt' ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ 'Watches: ----', + \ 'Expression: t', + \ ' \*- Result: {...}', + \ ' \*- i (int): 0', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.watches ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call setpos( '.', [ 0, 4, 1 ] ) + + " We can't just fire the keys to the inpit prompt because we use inputsave() + " and inputrestore(), so mock that out and fire away. + " Note: mapleder is , + py3 <\100\", "xt" )' ) +EOF + + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ 'Watches: ----', + \ 'Expression: t', + \ ' \*- Result: {...}', + \ ' \*- i (int): 100', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.watches ), + \ 1, + \ '$' ) + \ ) + \ } ) + + " Now set it via the more comforable scripting interface + call vimspector#SetVariableValue( '1234' ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ 'Watches: ----', + \ 'Expression: t', + \ ' \*- Result: {...}', + \ ' \*- i (int): 1234', + \ ' \*- c (char): 0 ''\\0\{1,3}''', + \ ' \*- fffff (float): 0', + \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.watches ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! Test_SetVariableValue_Balloon() + let fn = 'testdata/cpp/simple/struct.cpp' + call s:StartDebugging( #{ fn: fn, line: 24, col: 1, launch: #{ + \ configuration: 'run-to-breakpoint' + \ } } ) + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 26, 1 ) + + " leader is , + xmap d VimspectorBalloonEval + nmap d VimspectorBalloonEval + + "evaluate the prev line + call setpos( '.', [ 0, 24, 8 ] ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 24, 8 ) + call feedkeys( ',d', 'xt' ) + + call WaitForAssert( {-> + \ assert_notequal( v:none, g:vimspector_session_windows.eval ) + \ } ) + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 0', + \ ' + another_test: ', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + " Move down to the ffff line + + call feedkeys( 'jjj', 'xt' ) + " We can't just fire the keys to the inpit prompt because we use inputsave() + " and inputrestore(), so mock that out and fire away. + " Note: mapleder is , + py3 <\100\", "xt" )' ) +EOF + + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '{...}', + \ ' - i: 0', + \ ' - c: 0 ''\\0\{1,3}''', + \ ' - fffff: 100', + \ ' + another_test: ', + \ ], + \ getbufline( winbufnr( g:vimspector_session_windows.eval ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction From edcb057ead0025678cb650a6cd6e07506aa8f584 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 25 Feb 2021 22:23:30 +0000 Subject: [PATCH 129/200] Add to docs --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 00416e3..42d4765 100644 --- a/README.md +++ b/README.md @@ -914,7 +914,8 @@ breakpoint when it is hit. * Current scope shows values of locals. * Use ``, or double-click with left mouse to expand/collapse (+, -). -* Set the value of the variable with `` (control + ``) +* Set the value of the variable with `` (control + ``) or + `` (if `modifyOtherKeys` doesn't work for you) * When changing the stack frame the locals window updates. * While paused, hover to see values @@ -931,7 +932,8 @@ All rules for `Variables and scopes` apply plus the following: and get its result. * Make a normal mode (`nmap`) and visual mode (`xmap`) mapping to `VimspectorBalloonEval` to manually trigger the popup. - * Set the value of the variable with `` (control + ``) + * Set the value of the variable with `` (control + ``) or + `` (if `modifyOtherKeys` doesn't work for you) * Use regular nagivation keys (`j`, `k`) to choose the current selection; `` (or leave the tooltip window) to close the tooltip. @@ -950,7 +952,8 @@ to add a new watch expression. * Alternatively, use `:VimspectorWatch `. Tab-completion for expression is available in some debug adapters. * Expand result with ``, or double-click with left mouse. -* Set the value of the variable with `` (control + ``) +* Set the value of the variable with `` (control + ``) or + `` (if `modifyOtherKeys` doesn't work for you) * Delete with ``. ![watch window](https://puremourning.github.io/vimspector-web/img/vimspector-watch-window.png) @@ -2054,3 +2057,4 @@ hi link jsonComment Comment [debugpy]: https://github.com/microsoft/debugpy [YouCompleteMe]: https://github.com/ycm-core/YouCompleteMe#java-semantic-completion [remote-debugging]: https://puremourning.github.io/vimspector/configuration.html#remote-debugging-support +[YcmJava]: https://github.com/ycm-core/YouCompleteMe#java-semantic-completion From 5bd83d3e37403d8cc7ad3378a58d58f06a53d318 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 27 Feb 2021 21:02:21 +0000 Subject: [PATCH 130/200] Add debugging instruction --- CONTRIBUTING.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ba53bf..578fd8f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -184,6 +184,30 @@ 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 `.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. ``). 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 Please see [code of conduct](CODE_OF_CONDUCT.md). From d2b92b7ce5446bf5aeaea177abeacda129876042 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 2 Mar 2021 10:48:38 +0000 Subject: [PATCH 131/200] Fix crash using STop function --- autoload/vimspector.vim | 4 ++-- tests/mappings.test.vim | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 41d30dd..e94a177 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -195,9 +195,9 @@ function! vimspector#Stop( ... ) abort return endif if a:0 == 0 - options = {} + let options = {} else - options = a:1 + let options = a:1 endif py3 _vimspector_session.Stop( **vim.eval( 'options' ) ) endfunction diff --git a/tests/mappings.test.vim b/tests/mappings.test.vim index 0f9995d..b0e288c 100644 --- a/tests/mappings.test.vim +++ b/tests/mappings.test.vim @@ -114,6 +114,26 @@ function! Test_Use_Mappings_HUMAN() \ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 9 ) \ } ) + " Stop + call feedkeys( "\", '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() From 82db32780baaac99319ffa264d36a002d6bfe4fb Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 4 Mar 2021 13:28:04 +0000 Subject: [PATCH 132/200] Add example of ssh to remote host --- docs/configuration.md | 8 +++-- .../python/simple_python/.vimspector.json | 35 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index f3d0814..e736985 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -634,7 +634,9 @@ Vimspector then orchestrates the various tools to set you up. // %CMD% replaced with the remote-cmdLine configured in the launch // configuration. (mandatory) "runCommand": [ - "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}", + "python", "-m", "debugpy", + "--listen", "0.0.0.0:${port}", + "--wait-for-client", "%CMD%" ] @@ -848,7 +850,9 @@ port. // %CMD% replaced with the remote-cmdLine configured in the launch // configuration. (mandatory) "runCommand": [ - "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}", + "python", "-m", "debugpy", + "--listen", "0.0.0.0:${port}", + "--wait-for-client", "%CMD%" ] diff --git a/support/test/python/simple_python/.vimspector.json b/support/test/python/simple_python/.vimspector.json index 29d7d43..69d37a6 100644 --- a/support/test/python/simple_python/.vimspector.json +++ b/support/test/python/simple_python/.vimspector.json @@ -24,6 +24,24 @@ }, "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": { @@ -164,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}" + } + ] + } } } } From 943ae6c7c9d0f256e444c3ddc5e876156335f997 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 5 Mar 2021 19:05:42 +0000 Subject: [PATCH 133/200] Fix error when nothing to expand --- python3/vimspector/variables.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index d225af0..8dcb493 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -473,6 +473,8 @@ class VariablesView( object ): self._DrawWatches() def _GetVariable( self, buf = None, line_num = None ): + none = ( None, None ) + if buf is None: buf = vim.current.buffer @@ -487,10 +489,10 @@ class VariablesView( object ): and buf == self._variable_eval_view.buf ): view = self._variable_eval_view else: - return None + return none if line_num not in view.lines: - return None + return none return view.lines[ line_num ], view From c012f9520ebf07d591f48174129467825fc2b766 Mon Sep 17 00:00:00 2001 From: Tony Dwire Date: Tue, 9 Mar 2021 19:45:27 -0600 Subject: [PATCH 134/200] Updated netcoredbg to 1.2.0-738 --- python3/vimspector/gadgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index d1b6872..f6c3639 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -233,7 +233,7 @@ GADGETS = { 'format': 'tar', }, 'all': { - 'version': '1.2.0-635' + 'version': '1.2.0-738' }, 'macos': { 'file_name': 'netcoredbg-osx.tar.gz', From 38c843219e36ec381b44a14c32a44850d418bc41 Mon Sep 17 00:00:00 2001 From: Tony Dwire Date: Tue, 9 Mar 2021 19:55:38 -0600 Subject: [PATCH 135/200] Updated file name for netcoredbg to reflect new filename. Overrode version for macos since there is no new build for it yet. --- python3/vimspector/gadgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index f6c3639..ab4c1e4 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -237,11 +237,12 @@ GADGETS = { }, 'macos': { 'file_name': 'netcoredbg-osx.tar.gz', + 'version': '1.2.0-536', 'checksum': '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', }, 'linux': { - 'file_name': 'netcoredbg-linux-bionic.tar.gz', + 'file_name': 'netcoredbg-linux-bionic-amd64.tar.gz', 'checksum': '', }, 'windows': { From 2a635294d0b549c8ab8f90cf2cacc8f597c2bad8 Mon Sep 17 00:00:00 2001 From: Tony Dwire Date: Tue, 9 Mar 2021 20:11:58 -0600 Subject: [PATCH 136/200] Fix wrong version number for macos version. --- python3/vimspector/gadgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index ab4c1e4..6974367 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -237,7 +237,7 @@ GADGETS = { }, 'macos': { 'file_name': 'netcoredbg-osx.tar.gz', - 'version': '1.2.0-536', + 'version': '1.2.0-635', 'checksum': '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', }, From 7d2770f3c486ba34acc7eab52dfc1df6af353056 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 8 Mar 2021 23:00:45 +0000 Subject: [PATCH 137/200] 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) --- python3/vimspector/debug_session.py | 91 +++++++ python3/vimspector/settings.py | 19 +- python3/vimspector/terminal.py | 55 ++++- tests/lib/autoload/vimspector/test/setup.vim | 56 +++++ tests/ui.test.vim | 247 +++++++++++++++++++ 5 files changed, 461 insertions(+), 7 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 6fb0b16..4a89cdf 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -655,6 +655,37 @@ class DebugSession( object ): vim.command( 'tab split' ) self._uiTab = vim.current.tabpage + mode = settings.Get( 'ui_mode' ) + + self._logger.debug( 'ui_mode = %s', 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' ) ) + + mode = ( 'vertical' + if vim.options[ 'columns' ] < min_width + else 'horizontal' ) + + self._logger.debug( 'min_width: %s, actual: %s - result: %s', + min_width, + vim.options[ 'columns' ], + mode ) + + if mode == 'vertical': + self._SetUpUIVertical() + else: + self._SetUpUIHorizontal() + + + def _SetUpUIHorizontal( self ): # Code window code_window = vim.current.window self._codeView = code.CodeView( code_window, self._api_prefix ) @@ -695,6 +726,66 @@ class DebugSession( object ): # TODO: If/when we support multiple sessions, we'll need some way to # indicate which tab was created and store all the tabs vim.vars[ 'vimspector_session_windows' ] = { + 'mode': 'horizontal', + 'tabpage': self._uiTab.number, + 'code': utils.WindowID( code_window, self._uiTab ), + 'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ), + 'variables': utils.WindowID( vars_window, self._uiTab ), + 'watches': utils.WindowID( watch_window, self._uiTab ), + 'output': utils.WindowID( output_window, self._uiTab ), + 'eval': None # this is going to be updated every time eval popup is opened + } + with utils.RestoreCursorPosition(): + with utils.RestoreCurrentWindow(): + with utils.RestoreCurrentBuffer( vim.current.window ): + vim.command( 'doautocmd User VimspectorUICreated' ) + + + def _SetUpUIVertical( self ): + # Code window + code_window = vim.current.window + self._codeView = code.CodeView( code_window, self._api_prefix ) + + # Call stack + vim.command( + f'topleft { settings.Int( "topbar_height" ) }new' ) + stack_trace_window = vim.current.window + one_third = int( vim.eval( 'winwidth( 0 )' ) ) / 3 + self._stackTraceView = stack_trace.StackTraceView( self, + stack_trace_window ) + + + # Watches + vim.command( 'leftabove vertical new' ) + watch_window = vim.current.window + + # Variables + vim.command( 'leftabove vertical new' ) + vars_window = vim.current.window + + + with utils.LetCurrentWindow( vars_window ): + vim.command( f'{ one_third }wincmd |' ) + with utils.LetCurrentWindow( watch_window ): + vim.command( f'{ one_third }wincmd |' ) + with utils.LetCurrentWindow( stack_trace_window ): + vim.command( f'{ one_third }wincmd |' ) + + self._variablesView = variables.VariablesView( vars_window, + watch_window ) + + + # Output/logging + vim.current.window = code_window + vim.command( f'rightbelow { settings.Int( "bottombar_height" ) }new' ) + output_window = vim.current.window + self._outputView = output.DAPOutputView( output_window, + self._api_prefix ) + + # TODO: If/when we support multiple sessions, we'll need some way to + # indicate which tab was created and store all the tabs + vim.vars[ 'vimspector_session_windows' ] = { + 'mode': 'vertical', 'tabpage': self._uiTab.number, 'code': utils.WindowID( code_window, self._uiTab ), 'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ), diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index 9ad9e41..e9e76ea 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -20,11 +20,20 @@ from vimspector import utils DEFAULTS = { # UI - 'bottombar_height': 10, - 'sidebar_width': 50, - 'code_minwidth': 82, - 'terminal_maxwidth': 80, - 'terminal_minwidth': 10, + 'ui_mode': 'auto', + 'bottombar_height': 10, + + # For ui_mode = 'horizontal': + 'sidebar_width': 50, + 'code_minwidth': 82, + 'terminal_maxwidth': 80, + 'terminal_minwidth': 10, + + # For ui_mode = 'vertical': + 'topbar_height': 15, + 'code_minheight': 20, + 'terminal_maxheight': 15, + 'terminal_minheight': 5, # Signs 'sign_priority': { diff --git a/python3/vimspector/terminal.py b/python3/vimspector/terminal.py index 6ffd56a..0c84704 100644 --- a/python3/vimspector/terminal.py +++ b/python3/vimspector/terminal.py @@ -23,12 +23,53 @@ def LaunchTerminal( api_prefix, env = params.get( 'env' ) or {} term_options = { - 'vertical': 1, 'norestore': 1, 'cwd': cwd, 'env': env, } + if settings.Get( 'ui_mode' ) == 'horizontal': + # force-horizontal + term_options[ 'vertical' ] = 1 + elif utils.GetVimValue( vim.vars[ 'vimspector_session_windows' ], + 'mode' ) == 'horizontal': + # horizontal, which means that we should have enough space for: + # - sidebar + # - code min + # - term min width + # - + 2 vertical spaders + # - + 3 columns for signs + term_options[ 'vertical' ] = 1 + + # if we don't have enough space for terminal_maxwidth, then see if we have + # enough vertically for terminal_maxheight, in which case, + # that seems a better fit + term_horiz_max = ( settings.Int( 'sidebar_width' ) + + 1 + 2 + 3 + + settings.Int( 'code_minwidth' ) + + 1 + settings.Int( 'terminal_maxwidth' ) ) + term_vert_max = ( settings.Int( 'bottombar_height' ) + 1 + + settings.Int( 'code_minheight' ) + 1 + + settings.Int( 'terminal_minheight' ) ) + + if ( vim.options[ 'columns' ] < term_horiz_max and + vim.options[ 'lines' ] >= term_vert_max ): + # Looks like it, let's try that layout + term_options[ 'vertical' ] = 0 + + + else: + # vertical - we need enough space horizontally for the code+terminal, but we + # may fit better with code above terminal + term_options[ 'vertical' ] = 0 + + term_horiz_max = ( settings.Int( 'code_minwidth' ) + 3 + + settings.Int( 'terminal_maxwidth' ) + 1 ) + + if vim.options[ 'columns' ] > term_horiz_max: + term_options[ 'vertical' ] = 1 + + if not window_for_start or not window_for_start.valid: # TOOD: Where? Maybe we should just use botright vertical ... window_for_start = vim.current.window @@ -50,13 +91,23 @@ def LaunchTerminal( api_prefix, # If we're making a vertical split from the code window, make it no more # than 80 columns and no fewer than 10. Also try and keep the code window # at least 82 columns - if term_options[ 'vertical' ] and not term_options.get( 'curwin', 0 ): + if term_options.get( 'curwin', 0 ): + pass + elif term_options[ 'vertical' ]: term_options[ 'term_cols' ] = max( min ( int( vim.eval( 'winwidth( 0 )' ) ) - settings.Int( 'code_minwidth' ), settings.Int( 'terminal_maxwidth' ) ), settings.Int( 'terminal_minwidth' ) ) + else: + term_options[ 'term_rows' ] = max( + min ( int( vim.eval( 'winheight( 0 )' ) ) + - settings.Int( 'code_minheight' ), + settings.Int( 'terminal_maxheight' ) ), + settings.Int( 'terminal_minheight' ) + ) + buffer_number = int( utils.Call( diff --git a/tests/lib/autoload/vimspector/test/setup.vim b/tests/lib/autoload/vimspector/test/setup.vim index b0296e0..6ab220c 100644 --- a/tests/lib/autoload/vimspector/test/setup.vim +++ b/tests/lib/autoload/vimspector/test/setup.vim @@ -50,3 +50,59 @@ function! vimspector#test#setup#Reset() abort call popup_clear() endfunction +let s:g_stack = {} + +function! vimspector#test#setup#PushGlobal( name, value ) abort + if !has_key( s:g_stack, a:name ) + let s:g_stack[ a:name ] = [] + endif + + let old_value = get( g:, a:name, v:null ) + call add( s:g_stack[ a:name ], old_value ) + let g:[ a:name ] = a:value + + return old_value +endfunction + +function! vimspector#test#setup#PopGlobal( name ) abort + if !has_key( s:g_stack, a:name ) || len( s:g_stack[ a:name ] ) == 0 + return v:null + endif + + let old_value = s:g_stack[ a:name ][ -1 ] + call remove( s:g_stack[ a:name ], -1 ) + + if old_value is v:null + silent! call remove( g:, a:name ) + else + let g:[ a:name ] = old_value + endif + + return old_value +endfunction + +let s:o_stack = {} + +function! vimspector#test#setup#PushOption( name, value ) abort + if !has_key( s:o_stack, a:name ) + let s:o_stack[ a:name ] = [] + endif + + let old_value = v:null + execute 'let old_value = &' . a:name + call add( s:o_stack[ a:name ], old_value ) + execute 'set ' . a:name . '=' . a:value + return old_value +endfunction + +function! vimspector#test#setup#PopOption( name ) abort + if !has_key( s:o_stack, a:name ) || len( s:o_stack[ a:name ] ) == 0 + return v:null + endif + + let old_value = s:o_stack[ a:name ][ -1 ] + call remove( s:o_stack[ a:name ], -1 ) + + execute 'set ' . a:name . '=' . old_value + return old_value +endfunction diff --git a/tests/ui.test.vim b/tests/ui.test.vim index f251539..1f7789e 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -1,6 +1,7 @@ let s:fn='../support/test/python/simple_python/main.py' function! SetUp() + let g:vimspector_ui_mode = get( s:, 'vimspector_ui_mode', 'horizontal' ) call vimspector#test#setup#SetUpWithMappings( 'HUMAN' ) endfunction @@ -16,12 +17,17 @@ function! s:StartDebugging() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 23, 1 ) endfunction +function! SetUp_Test_StandardLayout() + call vimspector#test#setup#PushOption( 'columns', 200 ) +endfunction + function! Test_StandardLayout() call s:StartDebugging() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) call assert_equal( \ [ 'row', [ \ [ 'col', [ @@ -43,6 +49,247 @@ function! Test_StandardLayout() %bwipe! endfunction +function! TearDown_Test_StandardLayout() + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_NarrowLayout() + call vimspector#test#setup#PushOption( 'columns', 100 ) + let s:vimspector_ui_mode = 'vertical' +endfunction + +function! Test_NarrowLayout() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'vertical', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_NarrowLayout() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalVert() + let s:vimspector_ui_mode = 'auto' + call vimspector#test#setup#PushOption( 'columns', 250 ) + call vimspector#test#setup#PushOption( 'lines', 30 ) +endfunction + +function! Test_AutoLayoutTerminalVert() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'row', [ + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ] + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalVert() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalHorizVert() + let s:vimspector_ui_mode = 'auto' + " Wide enough to be horizontal layout, but not wide enough to fully fit the + " terminal, with enough rows to fit the max terminal below + call vimspector#test#setup#PushOption( 'columns', + \ 50 + 82 + 3 + 2 + 12 ) + call vimspector#test#setup#PushOption( 'lines', 50 ) +endfunction + +function! Test_AutoLayoutTerminalHorizVert() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'row', [ + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ] + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalHorizVert() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalHorizVertButNotEnoughLines() + let s:vimspector_ui_mode = 'auto' + " Wide enough to be horizontal layout, but not wide enough to fully fit the + " terminal, with enough rows to fit the max terminal below, but there are not + " enough lines to do this + call vimspector#test#setup#PushOption( 'columns', + \ 50 + 82 + 3 + 2 + 12 ) + call vimspector#test#setup#PushOption( 'lines', 20 ) +endfunction + +function! Test_AutoLayoutTerminalHorizVertButNotEnoughLines() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'horizontal', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'row', [ + \ [ 'col', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalHorizVertButNotEnoughLines() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalHoriz() + let s:vimspector_ui_mode = 'vertical' + " Vertical layout, but we split the terminal horizonally + call vimspector#test#setup#PushOption( 'columns', 200 ) + call vimspector#test#setup#PushOption( 'lines', 50 ) +endfunction + +function! Test_AutoLayoutTerminalHoriz() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'vertical', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalHoriz() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + +function! SetUp_Test_AutoLayoutTerminalVertVert() + let s:vimspector_ui_mode = 'auto' + " Not wide enough to go horizontal, but wide enough to put the terminal and + " code vertically split + call vimspector#test#setup#PushOption( 'columns', 80 ) + call vimspector#test#setup#PushOption( 'lines', 30 ) +endfunction + +function! Test_AutoLayoutTerminalVertVert() + call s:StartDebugging() + + call vimspector#StepOver() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, 25, 1 ) + + call assert_equal( 'vertical', g:vimspector_session_windows.mode ) + call assert_equal( + \ [ 'col', [ + \ [ 'row', [ + \ [ 'leaf', g:vimspector_session_windows.variables ], + \ [ 'leaf', g:vimspector_session_windows.watches ], + \ [ 'leaf', g:vimspector_session_windows.stack_trace ], + \ ] ], + \ [ 'leaf', g:vimspector_session_windows.code ], + \ [ 'leaf', g:vimspector_session_windows.terminal ], + \ [ 'leaf', g:vimspector_session_windows.output ], + \ ] ], + \ winlayout( g:vimspector_session_windows.tabpage ) ) + + call vimspector#test#setup#Reset() + %bwipe! +endfunction + +function! TearDown_Test_AutoLayoutTerminalVertVert() + unlet s:vimspector_ui_mode + call vimspector#test#setup#PopOption( 'lines' ) + call vimspector#test#setup#PopOption( 'columns' ) +endfunction + + function! Test_CloseVariables() call s:StartDebugging() From 01ea50cb7062b8a27b8df029f5d1dd13c37b9784 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 11 Mar 2021 21:13:58 +0000 Subject: [PATCH 138/200] use --clean for minimal vimrc --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- CONTRIBUTING.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1788c04..f01a833 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -17,12 +17,12 @@ assignees: '' > Please answer the following questions -* Does your issue reproduce using `vim -Nu /path/to/vimspector/support/minimal_vimrc` ? \[Yes/No] +* Does your issue reproduce using `vim --clean -Nu /path/to/vimspector/support/minimal_vimrc` ? \[Yes/No] * If you are using Neovim, does your issue reproduce using Vim? \[Yes/No] > List of steps to reproduce: -> 1. Run `vim -Nu /path/to/vimspector/support/minimal_vimrc` +> 1. Run `vim ---clean Nu /path/to/vimspector/support/minimal_vimrc` > 2. Open _this project_... > 3. Press _this sequence of keys_ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 578fd8f..1866974 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,7 +83,7 @@ in the issue report. The minimal vimrc is in `support/test/minimal_vimrc` and can be used as follows: ``` -vim -Nu /path/to/vimspector/support/minimal_vimrc +vim --clean -Nu /path/to/vimspector/support/minimal_vimrc ``` ## Pull Requests From 2615cff97ad871de6ced52be93e72c310838543e Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 11 Mar 2021 21:14:30 +0000 Subject: [PATCH 139/200] If there isn't enough vertical space, we get vim errors (not enough room), so don't do that --- python3/vimspector/debug_session.py | 14 +++++++++++--- tests/ui.test.vim | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 4a89cdf..16f69be 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -657,8 +657,6 @@ class DebugSession( object ): mode = settings.Get( 'ui_mode' ) - self._logger.debug( 'ui_mode = %s', mode ) - if mode == 'auto': # Go vertical if there isn't enough horizontal space for at least: # the left bar width @@ -670,13 +668,23 @@ class DebugSession( object ): + 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' ) - self._logger.debug( 'min_width: %s, actual: %s - result: %s', + 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': diff --git a/tests/ui.test.vim b/tests/ui.test.vim index 1f7789e..5ba2f9c 100644 --- a/tests/ui.test.vim +++ b/tests/ui.test.vim @@ -256,7 +256,7 @@ function! SetUp_Test_AutoLayoutTerminalVertVert() " Not wide enough to go horizontal, but wide enough to put the terminal and " code vertically split call vimspector#test#setup#PushOption( 'columns', 80 ) - call vimspector#test#setup#PushOption( 'lines', 30 ) + call vimspector#test#setup#PushOption( 'lines', 50 ) endfunction function! Test_AutoLayoutTerminalVertVert() From 6d3f3e207b84432d7dd0af7c08263c5140bd3dd1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 10 Mar 2021 11:12:28 +0000 Subject: [PATCH 140/200] Fix default variable values having substitutions from the calculus --- python3/vimspector/utils.py | 8 +++++--- tests/python/Test_ExpandReferencesInDict.py | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index e7cb537..d8dd345 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -494,7 +494,6 @@ def _Substitute( template, mapping ): if mo.group( 'braceddefault' ) is not None: named = mo.group( 'defname' ) if named not in mapping: - '' raise MissingSubstitution( named, mo.group( 'default' ).replace( '\\}', '}' ) ) @@ -536,8 +535,11 @@ def ExpandReferencesInString( orig_s, if default_value is None and e.default_value is not None: try: default_value = _Substitute( e.default_value, mapping ) - except MissingSubstitution: - default_value = e.default_value + except MissingSubstitution as e2: + if e2.name in calculus: + default_value = calculus[ e2.name ]() + else: + default_value = e.default_value mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ), default_value ) diff --git a/tests/python/Test_ExpandReferencesInDict.py b/tests/python/Test_ExpandReferencesInDict.py index 4998350..15fb11b 100644 --- a/tests/python/Test_ExpandReferencesInDict.py +++ b/tests/python/Test_ExpandReferencesInDict.py @@ -35,6 +35,7 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'one': '${one}', 'two': '${one} and ${two}', 'three': '${three}', + 'three_with_default': '${three_with_default:${three\\}}', # uses calculus 'four': '${four}', 'five': '${five}', 'list': [ '*${words}' ], @@ -58,6 +59,7 @@ class TestExpandReferencesInDict( unittest.TestCase ): 'one': 'one', 'two': 'one and TWO', 'three': '3', + 'three_with_default': '3', 'four': 'typed text', 'five': '5ive!', 'list': [ 'these', 'are', 'some', 'words' ], From a53d68f04301833b30a9a8e3acf02ba793c49d82 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 10 Mar 2021 12:29:40 +0000 Subject: [PATCH 141/200] Add up and down frame mappings --- autoload/vimspector.vim | 14 ++++ plugin/vimspector.vim | 5 ++ python3/vimspector/debug_session.py | 8 ++ python3/vimspector/stack_trace.py | 40 ++++++++++ tests/stack_trace.test.vim | 114 ++++++++++++++++++++++++++++ 5 files changed, 181 insertions(+) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index e94a177..a547e5c 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -234,6 +234,20 @@ function! vimspector#GoToFrame() abort py3 _vimspector_session.ExpandFrameOrThread() endfunction +function! vimspector#UpFrame() abort + if !s:Enabled() + return + endif + py3 _vimspector_session.UpFrame() +endfunction + +function! vimspector#DownFrame() abort + if !s:Enabled() + return + endif + py3 _vimspector_session.DownFrame() +endfunction + function! vimspector#AddWatch( ... ) abort if !s:Enabled() return diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 53855ef..37509a7 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -67,6 +67,11 @@ nnoremap VimspectorBalloonEval xnoremap VimspectorBalloonEval \ :call vimspector#ShowEvalBalloon( 1 ) +nnoremap VimspectorUpFrame + \ :call vimspector#UpFrame() +nnoremap VimspectorDownFrame + \ :call vimspector#DownFrame() + if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorContinue nmap VimspectorStop diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 16f69be..4d8c816 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -571,6 +571,14 @@ class DebugSession( object ): def ExpandFrameOrThread( self ): self._stackTraceView.ExpandFrameOrThread() + @IfConnected() + def UpFrame( self ): + self._stackTraceView.UpFrame() + + @IfConnected() + def DownFrame( self ): + self._stackTraceView.DownFrame() + def ToggleLog( self ): if self._HasUI(): return self.ShowOutput( 'Vimspector' ) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index c32cead..ae14e68 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -367,6 +367,46 @@ class StackTraceView( object ): self._JumpToFrame( frame ) + + def _GetFrameOffset( self, delta ): + thread: Thread + for thread in self._threads: + if thread.id != self._current_thread: + continue + + if not thread.stacktrace: + return + + frame_idx = None + for index, frame in enumerate( thread.stacktrace ): + if frame == self._current_frame: + frame_idx = index + break + + if frame_idx is not None: + target_idx = frame_idx + delta + if target_idx >= 0 and target_idx < len( thread.stacktrace ): + return thread.stacktrace[ target_idx ] + + break + + + def UpFrame( self ): + frame = self._GetFrameOffset( 1 ) + if not frame: + utils.UserMessage( 'Top of stack' ) + else: + self._JumpToFrame( frame, 'up' ) + + + def DownFrame( self ): + frame = self._GetFrameOffset( -1 ) + if not frame: + utils.UserMessage( 'Bottom of stack' ) + else: + self._JumpToFrame( frame, 'down' ) + + def AnyThreadsRunning( self ): for thread in self._threads: if thread.state != Thread.TERMINATED: diff --git a/tests/stack_trace.test.vim b/tests/stack_trace.test.vim index 569376c..a65ea5e 100644 --- a/tests/stack_trace.test.vim +++ b/tests/stack_trace.test.vim @@ -356,3 +356,117 @@ function! Test_Multiple_Threads_Step() call vimspector#test#setup#Reset() %bwipe! endfunction + +function! Test_UpDownStack() + let fn='../support/test/python/simple_python/main.py' + exe 'edit ' . fn + call setpos( '.', [ 0, 6, 1 ] ) + + call vimspector#SetLineBreakpoint( fn, 15 ) + call vimspector#LaunchWithSettings( { 'configuration': 'run' } ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#DownFrame() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#UpFrame() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call feedkeys( "\VimspectorUpFrame", 'x' ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 23, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call feedkeys( "\VimspectorDownFrame", 'x' ) + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + call vimspector#DownFrame() + call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) + call WaitForAssert( {-> + \ AssertMatchist( + \ [ + \ '- Thread 1: MainThread (paused)', + \ ' 2: DoSomething@main.py:15', + \ ' 3: __init__@main.py:8', + \ ' 4: Main@main.py:23', + \ ' 5: @main.py:29', + \ ], + \ GetBufLine( winbufnr( g:vimspector_session_windows.stack_trace ), + \ 1, + \ '$' ) + \ ) + \ } ) + + + call vimspector#ClearBreakpoints() + call vimspector#test#setup#Reset() + %bwipe! +endfunction From 6b67d165b92d1fe858ebd427507836021e0f0623 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 12 Mar 2021 21:50:37 +0000 Subject: [PATCH 142/200] Update docs for new mappings --- README.md | 84 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 42d4765..2152a9c 100644 --- a/README.md +++ b/README.md @@ -656,18 +656,23 @@ personal and so you should work out what you like and use vim's powerful mapping features to set your own mappings. To that end, Vimspector defines the following `` mappings: -* `VimspectorContinue` -* `VimspectorStop` -* `VimspectorRestart` -* `VimspectorPause` -* `VimspectorToggleBreakpoint` -* `VimspectorToggleConditionalBreakpoint` -* `VimspectorAddFunctionBreakpoint` -* `VimspectorStepOver` -* `VimspectorStepInto` -* `VimspectorStepOut` -* `VimspectorRunToCursor` -* `VimspectorBalloonEval` +| Mapping | Function | API | +| --- | --- | --- | +| `VimspectorContinue` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | +| `VimspectorStop` | Stop debugging. | `vimspector#Stop()` | +| `VimpectorRestart` | Restart debugging with the same configuration. | `vimspector#Restart()` | +| `VimspectorPause` | Pause debuggee. | `vimspector#Pause()` | +| `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | +| `VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | +| `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | +| `VimspectorRunToCursor` | Run to Cursor | `vimspector#RunToCursor()` | +| `VimspectorStepOver` | Step Over | `vimspector#StepOver()` | +| `VimspectorStepInto` | Step Into | `vimspector#StepInto()` | +| `VimspectorStepOut` | Step out of current function scope | `vimspector#StepOut()` | +| `VimspectorUpFrame` | Move up a frame in the current call stack | `vimspector#UpFrame()` | +| `VimspectorDownFrame` | Move down a frame in the current call stack | `vimspector#DownFrame()` | +| `VimspectorBalloonEval` | Evaluate expression under cursor (or visual) in popup | *internal* | + These map roughly 1-1 with the API functions below. @@ -695,17 +700,17 @@ loading vimspector**: let g:vimspector_enable_mappings = 'VISUAL_STUDIO' ``` -| Key | Function | API | -| --- | --- | --- | -| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | -| `Shift F5` | Stop debugging. | `vimspector#Stop()` | -| `Ctrl Shift F5` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debuggee. | `vimspector#Pause()` | -| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | -| `Shift F9` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | -| `F10` | Step Over | `vimspector#StepOver()` | -| `F11` | Step Into | `vimspector#StepInto()` | -| `Shift F11` | Step out of current function scope | `vimspector#StepOut()` | +| Key | Mapping | Function +| --- | --- | --- +| `F5` | `VimspectorContinue` | When debugging, continue. Otherwise start debugging. +| `Shift F5` | `VimspectorStop` | Stop debugging. +| `Ctrl Shift F5` | `VimspectorRestart` | Restart debugging with the same configuration. +| `F6` | `VimspectorPause` | Pause debuggee. +| `F9` | `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. +| `Shift F9` | `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor +| `F10` | `VimspectorStepOver` | Step Over +| `F11` | `VimspectorStepInto` | Step Into +| `Shift F11` | `VimspectorStepOut` | Step out of current function scope ## Human Mode @@ -720,19 +725,19 @@ loading vimspector**: let g:vimspector_enable_mappings = 'HUMAN' ``` -| Key | Function | API | -| --- | --- | --- | -| `F5` | When debugging, continue. Otherwise start debugging. | `vimspector#Continue()` | -| `F3` | Stop debugging. | `vimspector#Stop()` | -| `F4` | Restart debugging with the same configuration. | `vimspector#Restart()` | -| `F6` | Pause debuggee. | `vimspector#Pause()` | -| `F9` | Toggle line breakpoint on the current line. | `vimspector#ToggleBreakpoint()` | -| `F9` | Toggle conditional line breakpoint on the current line. | `vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )` | -| `F8` | Add a function breakpoint for the expression under cursor | `vimspector#AddFunctionBreakpoint( '' )` | -| `F8` | Run to Cursor | `vimspector#RunToCursor()` | -| `F10` | Step Over | `vimspector#StepOver()` | -| `F11` | Step Into | `vimspector#StepInto()` | -| `F12` | Step out of current function scope | `vimspector#StepOut()` | +| Key | Mapping | Function +| --- | --- | --- +| `F5` | `VimspectorContinue` | When debugging, continue. Otherwise start debugging. +| `F3` | `VimspectorStop` | Stop debugging. +| `F4` | `VimspectorRestart` | Restart debugging with the same configuration. +| `F6` | `VimspectorPause` | Pause debuggee. +| `F9` | `VimspectorToggleBreakpoint` | Toggle line breakpoint on the current line. +| `F9` | `VimspectorToggleConditionalBreakpoint` | Toggle conditional line breakpoint on the current line. +| `F8` | `VimspectorAddFunctionBreakpoint` | Add a function breakpoint for the expression under cursor +| `F8` | `VimspectorRunToCursor` | Run to Cursor +| `F10` | `VimspectorStepOver` | Step Over +| `F11` | `VimspectorStepInto` | Step Into +| `F12` | `VimspectorStepOut` | Step out of current function scope In addition, I recommend adding a mapping to `VimspectorBalloonEval`, in normal and visual modes, for example: @@ -746,6 +751,13 @@ nmap di VimspectorBalloonEval xmap di VimspectorBalloonEval ``` +You may also wish to add mappings for up/down the stack, for example: + +```viml +nmap VimspectorUpFrame +nmap VimspectorDownFrame +``` + # Usage and API This section defines detailed usage instructions, organised by feature. For most From 6f88b400e1f0771d9f684ae8a2c495989f196e02 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 18 Mar 2021 13:51:32 +0000 Subject: [PATCH 143/200] Only disable mappings in the keyboard-version of the popup --- autoload/vimspector/internal/balloon.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index 32d17ab..f7ed9d7 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -69,7 +69,6 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort \ 'resize': 1, \ 'close': 'button', \ 'callback': 'vimspector#internal#balloon#CloseCallback', - \ 'mapping': 0 \ } " When ambiwidth is single, use prettier characters for the border. This @@ -86,6 +85,7 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort let config[ 'filter' ] = 'vimspector#internal#balloon#CursorFilter' let config[ 'moved' ] = 'any' let config[ 'cursorline' ] = 1 + let config[ 'mapping' ] = 0 let s:popup_win_id = popup_atcursor( body, config ) endif From b92a89f0d49611e9476d8825c7d65c700505a387 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 26 Feb 2021 19:21:40 +0000 Subject: [PATCH 144/200] Add a way to have adapter specific message handlers --- python3/vimspector/custom/java.py | 34 +++++++++++++++++++ .../vimspector/debug_adapter_connection.py | 32 ++++++++--------- python3/vimspector/debug_session.py | 16 ++++++++- python3/vimspector/gadgets.py | 3 +- support/test/java/test_project/pom.xml | 4 +-- 5 files changed, 67 insertions(+), 22 deletions(-) create mode 100644 python3/vimspector/custom/java.py diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py new file mode 100644 index 0000000..ebfec35 --- /dev/null +++ b/python3/vimspector/custom/java.py @@ -0,0 +1,34 @@ +# 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 + + +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 + if utils.Call( 'confirm', + 'Code has changed, hot reload?', + '&Yes,&No', + 1, + 'Question' ) == 1: + self.debug_session._connection.DoRequest( None, { + 'command': 'redefineClasses', + 'arguments': {}, + } ) diff --git a/python3/vimspector/debug_adapter_connection.py b/python3/vimspector/debug_adapter_connection.py index 283c40c..df2ef13 100644 --- a/python3/vimspector/debug_adapter_connection.py +++ b/python3/vimspector/debug_adapter_connection.py @@ -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() @@ -237,7 +237,7 @@ class DebugAdapterConnection( object ): def _OnMessageReceived( self, message ): - if not self._handler: + if not self._handlers: return if message[ 'type' ] == 'response': @@ -270,25 +270,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 ): diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 4d8c816..31b4342 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -21,6 +21,7 @@ import shlex import subprocess import functools import vim +import importlib from vimspector import ( breakpoints, code, @@ -888,8 +889,21 @@ 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 ) ) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index d1b6872..5c61074 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -159,7 +159,8 @@ GADGETS = { "port": "${DAPPort}", "configuration": { "cwd": "${workspaceRoot}" - } + }, + 'custom_handler': 'vimspector.custom.java.JavaDebugAdapter' } }, }, diff --git a/support/test/java/test_project/pom.xml b/support/test/java/test_project/pom.xml index 890e7e8..e6dc4d3 100644 --- a/support/test/java/test_project/pom.xml +++ b/support/test/java/test_project/pom.xml @@ -4,7 +4,7 @@ TestApplication 1 - 8 - 8 + 11 + 11 From afb912dd089a6cfbbadfad2a55531ed00226889a Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 2 Mar 2021 10:48:55 +0000 Subject: [PATCH 145/200] Print hotcodereplace messages --- python3/vimspector/custom/java.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py index ebfec35..0dfa89c 100644 --- a/python3/vimspector/custom/java.py +++ b/python3/vimspector/custom/java.py @@ -23,12 +23,18 @@ class JavaDebugAdapter( object ): def OnEvent_hotcodereplace( self, message ): # Hack for java debug server hot-code-replace - if utils.Call( 'confirm', - 'Code has changed, hot reload?', - '&Yes,&No', - 1, - 'Question' ) == 1: - self.debug_session._connection.DoRequest( None, { - 'command': 'redefineClasses', - 'arguments': {}, - } ) + body = message.get( 'body' ) or {} + + if body.get( 'type' ) != 'hotcodereplace': + return + + if body.get( 'changeType' ) == 'BUILD_COMPLETE': + if utils.AskForInput( 'Code has changed, hot reload? [Y/N] ', + 'Y' ).upper()[ 0 ] == 'Y': + self.debug_session._connection.DoRequest( None, { + 'command': 'redefineClasses', + 'arguments': {}, + } ) + elif body.get( 'message' ): + utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] ) + From 63fd3165fb48fa0c5c8dd916aa3c3ae54878d304 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 4 Mar 2021 21:44:54 +0000 Subject: [PATCH 146/200] Use popup for confirmations (note these have to be async) --- autoload/vimspector/internal/neopopup.vim | 22 ++++++++ autoload/vimspector/internal/popup.vim | 31 +++++++++++ python3/vimspector/custom/java.py | 17 +++--- python3/vimspector/debug_session.py | 63 ++++++++++++++--------- python3/vimspector/utils.py | 29 ++++++++++- 5 files changed, 129 insertions(+), 33 deletions(-) diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index fe5fe05..cc25020 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -80,6 +80,28 @@ function! vimspector#internal#neopopup#HideSplash( id ) abort unlet s:db[ a:id ] endfunction +function! vimspector#internal#neopopup#Confirm( confirm_id, + \ text, + \ default_value ) abort + let result = confirm( a:text, '&Yes &No &Default', 3 ) + + " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback + " in popup.vim) + if result == 2 + " No is represented as 0 + let result = 0 + elseif result == 0 + " User pressed ESC/ctrl-c + let result = -1 + elseif result == 3 + " Default + let result = a:default_value + 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 diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim index fc8820b..e8658ab 100644 --- a/autoload/vimspector/internal/popup.vim +++ b/autoload/vimspector/internal/popup.vim @@ -32,6 +32,37 @@ function! vimspector#internal#popup#HideSplash( id ) abort call popup_hide( a:id ) endfunction +function! s:YesNoDefaultFilter( default_value, id, key ) abort + if a:key ==# "\" || a:key ==# 'D' || a:key ==# 'd' + call popup_close( a:id, a:default_value ) + endif + + return popup_filter_yesno( a:id, a:key ) +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! vimspector#internal#popup#Confirm( + \ confirm_id, + \ text, + \ default_value ) abort + let text = a:text + if type( a:text ) != v:t_list + let text = [ a:text ] + endif + + call extend( text, [ '', '(Y)es (N)o (D)efault' ] ) + + return popup_dialog( text, { + \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), + \ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ) + \ } ) +endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py index 0dfa89c..83705c1 100644 --- a/python3/vimspector/custom/java.py +++ b/python3/vimspector/custom/java.py @@ -29,12 +29,15 @@ class JavaDebugAdapter( object ): return if body.get( 'changeType' ) == 'BUILD_COMPLETE': - if utils.AskForInput( 'Code has changed, hot reload? [Y/N] ', - 'Y' ).upper()[ 0 ] == 'Y': - self.debug_session._connection.DoRequest( None, { - 'command': 'redefineClasses', - 'arguments': {}, - } ) + def handler( result ): + if result == 1: + self.debug_session._connection.DoRequest( None, { + 'command': 'redefineClasses', + 'arguments': {}, + } ) + + utils.Confirm( self.debug_session._api_prefix, + 'Code has changed, hot reload?', + handler ) elif body.get( 'message' ): utils.UserMessage( 'Hot code replace: ' + body[ 'message' ] ) - diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 31b4342..ae16706 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -911,39 +911,52 @@ class DebugSession( object ): self._logger.info( 'Debug Adapter Started' ) def _StopDebugAdapter( self, interactive = False, callback = None ): - self._splash_screen = utils.DisplaySplash( - self._api_prefix, - self._splash_screen, - "Shutting down debug adapter..." ) + def disconnect( arguments = {} ): + 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 ) + 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 + 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 ) ) + vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format( + self._connection_type ) ) - arguments = {} - if ( interactive and - self._server_capabilities.get( 'supportTerminateDebuggee' ) ): - if self._stackTraceView.AnyThreadsRunning(): - choice = utils.AskForInput( "Terminate debuggee [Y/N/default]? ", "" ) - if choice == "Y" or choice == "y": + self._connection.DoRequest( handler, { + 'command': 'disconnect', + '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 ): + arguments = {} + if choice == 1: arguments[ 'terminateDebuggee' ] = True - elif choice == "N" or choice == 'n': + elif choice == 0: arguments[ 'terminateDebuggee' ] = False + elif choice == -1: + # Abort + return - self._connection.DoRequest( handler, { - 'command': 'disconnect', - 'arguments': arguments, - }, failure_handler = handler, timeout = 5000 ) + disconnect( arguments ) - # TODO: Use the 'tarminate' request if supportsTerminateRequest set + utils.Confirm( self._api_prefix, + "Terminate debuggee?", + handle_choice, + default_value = 3 ) def _PrepareAttach( self, adapter_config, launch_config ): diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index d8dd345..c65a184 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -375,6 +375,31 @@ def AskForInput( prompt, default_value = None, completion = None ): 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 = 1 ): + global CONFIRM_ID + CONFIRM_ID += 1 + CONFIRM[ CONFIRM_ID ] = handler + Call( f'vimspector#internal#{ api_prefix }popup#Confirm', + CONFIRM_ID, + prompt, + default_value ) + + def AppendToBuffer( buf, line_or_lines, modified=False ): line = 1 try: @@ -403,8 +428,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 ): From 85bb8594ab916358a5605c259f89b036a119d6b9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 5 Mar 2021 21:09:39 +0000 Subject: [PATCH 147/200] Allow forcing selection from the menu with F5 --- autoload/vimspector.vim | 4 ++-- plugin/vimspector.vim | 3 +++ python3/vimspector/debug_session.py | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index a547e5c..a0b6c42 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -41,11 +41,11 @@ function! s:Enabled() abort return s:enabled endfunction -function! vimspector#Launch() abort +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 diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 37509a7..75e2baa 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -35,6 +35,8 @@ let s:mappings = get( g:, 'vimspector_enable_mappings', '' ) nnoremap VimspectorContinue \ :call vimspector#Continue() +nnoremap VimspectorLaunch + \ :call vimspector#Launch( v:true ) nnoremap VimspectorStop \ :call vimspector#Stop() nnoremap VimspectorRestart @@ -84,6 +86,7 @@ if s:mappings ==# 'VISUAL_STUDIO' nmap VimspectorStepOut elseif s:mappings ==# 'HUMAN' nmap VimspectorContinue + nmap VimspectorLaunch nmap VimspectorStop nmap VimspectorRestart nmap VimspectorPause diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index ae16706..12e4563 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -100,7 +100,7 @@ class DebugSession( object ): return launch_config_file, configurations - def Start( self, launch_variables = None ): + 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: @@ -135,6 +135,11 @@ class DebugSession( object ): 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() ) ) From 6b74e584d53b284a35c72f7ab5e8f1f2095fe7ea Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 6 Mar 2021 20:24:24 +0000 Subject: [PATCH 148/200] Create a messagebox-like interface in vim --- autoload/vimspector/internal/balloon.vim | 6 +- autoload/vimspector/internal/neopopup.vim | 3 + autoload/vimspector/internal/popup.vim | 88 ++++++++++++++++++++--- python3/vimspector/utils.py | 6 +- 4 files changed, 87 insertions(+), 16 deletions(-) diff --git a/autoload/vimspector/internal/balloon.vim b/autoload/vimspector/internal/balloon.vim index f7ed9d7..b607e51 100644 --- a/autoload/vimspector/internal/balloon.vim +++ b/autoload/vimspector/internal/balloon.vim @@ -71,11 +71,7 @@ function! vimspector#internal#balloon#CreateTooltip( is_hover, ... ) abort \ 'callback': 'vimspector#internal#balloon#CloseCallback', \ } - " 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 config[ 'borderchars' ] = [ '─', '│', '─', '│', '╭', '╮', '┛', '╰' ] - endif + let config = vimspector#internal#popup#SetBorderChars( config ) if a:is_hover let config[ 'filter' ] = 'vimspector#internal#balloon#MouseFilter' diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index cc25020..189c78c 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -83,6 +83,9 @@ endfunction function! vimspector#internal#neopopup#Confirm( confirm_id, \ text, \ default_value ) 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(). let result = confirm( a:text, '&Yes &No &Default', 3 ) " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim index e8658ab..5978987 100644 --- a/autoload/vimspector/internal/popup.vim +++ b/autoload/vimspector/internal/popup.vim @@ -32,9 +32,32 @@ 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 ) + let buf = copy( s:text ) + call extend( buf, s:DrawButtons() ) + call popup_settext( a:id, buf ) +endfunction + function! s:YesNoDefaultFilter( default_value, id, key ) abort - if a:key ==# "\" || a:key ==# 'D' || a:key ==# 'd' + if a:key ==# "\" + call popup_close( a:id, s:current_selection + 1 ) + return 1 + elseif a:key ==# 'D' || a:key ==# 'd' call popup_close( a:id, a:default_value ) + return 1 + elseif index( [ "\", "\" ], a:key ) >= 0 + let s:current_selection = ( s:current_selection + 1 ) % len( s:selections ) + call s:UpdatePopup( a:id ) + return 1 + elseif index( [ "\", "\" ], 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 endif return popup_filter_yesno( a:id, a:key ) @@ -46,23 +69,68 @@ function! s:ConfirmCallback( confirm_id, id, result ) abort \ 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 ) abort - let text = a:text - if type( a:text ) != v:t_list - let text = [ a:text ] + + 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:YesNoDefaultFilter', [ a:default_value ] ), + \ 'mapping': v:false, + \ } + let config = vimspector#internal#popup#SetBorderChars( config ) + + return popup_dialog( buf, config ) +endfunction + +function! vimspector#internal#popup#SetBorderChars( config ) + " 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 - call extend( text, [ '', '(Y)es (N)o (D)efault' ] ) - - return popup_dialog( text, { - \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), - \ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ) - \ } ) + return a:config endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index c65a184..ca0b80a 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -390,13 +390,17 @@ def ConfirmCallback( confirm_id, result ): handler( result ) -def Confirm( api_prefix, prompt, handler, default_value = 1 ): +def Confirm( api_prefix, prompt, handler, default_value = 3, options = None ): global CONFIRM_ID + if not options: + options = [ '(Y)es', '(N)o', '(D)efault' ] + CONFIRM_ID += 1 CONFIRM[ CONFIRM_ID ] = handler Call( f'vimspector#internal#{ api_prefix }popup#Confirm', CONFIRM_ID, prompt, + options, default_value ) From 154e727b9693144439b37735b9e4f0aa44d58c16 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 11 Mar 2021 22:38:01 +0000 Subject: [PATCH 149/200] 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. --- autoload/vimspector/internal/neopopup.vim | 41 ++++++++++++++++++----- autoload/vimspector/internal/popup.vim | 22 ++++++++---- python3/vimspector/custom/java.py | 16 ++++++--- python3/vimspector/debug_session.py | 10 ++++-- python3/vimspector/settings.py | 5 ++- python3/vimspector/utils.py | 16 ++++++--- 6 files changed, 82 insertions(+), 28 deletions(-) diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index 189c78c..9f35914 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -82,29 +82,52 @@ endfunction function! vimspector#internal#neopopup#Confirm( confirm_id, \ text, - \ default_value ) abort + \ 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(). - let result = confirm( a:text, '&Yes &No &Default', 3 ) + let prompt = a:text + for opt in a:options + let prompt .= ' ' . opt + endfor + let prompt .= ': ' + + " 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. + try + let result = input( prompt, a:keys[ a:default_value - 1 ] ) + catch /.*/ + let result = -1 + endtry " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback " in popup.vim) - if result == 2 - " No is represented as 0 - let result = 0 - elseif result == 0 + if result == '' " User pressed ESC/ctrl-c let result = -1 - elseif result == 3 - " Default - let result = a:default_value + else + let index = 1 + for k in a:keys + if k ==? result + let result = index + break + endif + let index += 2 + 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 diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim index 5978987..db2c2fd 100644 --- a/autoload/vimspector/internal/popup.vim +++ b/autoload/vimspector/internal/popup.vim @@ -42,13 +42,10 @@ function! s:UpdatePopup( id ) call popup_settext( a:id, buf ) endfunction -function! s:YesNoDefaultFilter( default_value, id, key ) abort +function! s:ConfirmKeyFilter( keys, id, key ) abort if a:key ==# "\" call popup_close( a:id, s:current_selection + 1 ) return 1 - elseif a:key ==# 'D' || a:key ==# 'd' - call popup_close( a:id, a:default_value ) - return 1 elseif index( [ "\", "\" ], a:key ) >= 0 let s:current_selection = ( s:current_selection + 1 ) % len( s:selections ) call s:UpdatePopup( a:id ) @@ -58,9 +55,19 @@ function! s:YesNoDefaultFilter( default_value, id, key ) abort \ ? len( s:selections ) - 1: s:current_selection - 1 call s:UpdatePopup( a:id ) return 1 + elseif a:key ==# "\" || a:key ==# "\" + call popup_close( a:id, -1 ) + return 1 endif - return popup_filter_yesno( a:id, a:key ) + 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 @@ -90,7 +97,8 @@ function! vimspector#internal#popup#Confirm( \ confirm_id, \ text, \ options, - \ default_value ) abort + \ default_value, + \ keys ) abort silent! call prop_type_add( 'VimspectorSelectedItem', { \ 'highlight': 'PMenuSel' @@ -112,7 +120,7 @@ function! vimspector#internal#popup#Confirm( let config = { \ 'callback': function( 's:ConfirmCallback', [ a:confirm_id ] ), - \ 'filter': function( 's:YesNoDefaultFilter', [ a:default_value ] ), + \ 'filter': function( 's:ConfirmKeyFilter', [ a:keys ] ), \ 'mapping': v:false, \ } let config = vimspector#internal#popup#SetBorderChars( config ) diff --git a/python3/vimspector/custom/java.py b/python3/vimspector/custom/java.py index 83705c1..c2a2264 100644 --- a/python3/vimspector/custom/java.py +++ b/python3/vimspector/custom/java.py @@ -14,7 +14,7 @@ # limitations under the License. from vimspector.debug_session import DebugSession -from vimspector import utils +from vimspector import utils, settings class JavaDebugAdapter( object ): @@ -36,8 +36,16 @@ class JavaDebugAdapter( object ): 'arguments': {}, } ) - utils.Confirm( self.debug_session._api_prefix, - 'Code has changed, hot reload?', - handler ) + 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' ] ) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 12e4563..255e072 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -949,10 +949,12 @@ class DebugSession( object ): def handle_choice( choice ): arguments = {} if choice == 1: + # yes arguments[ 'terminateDebuggee' ] = True - elif choice == 0: + elif choice == 2: + # no arguments[ 'terminateDebuggee' ] = False - elif choice == -1: + else: # Abort return @@ -961,7 +963,9 @@ class DebugSession( object ): utils.Confirm( self._api_prefix, "Terminate debuggee?", handle_choice, - default_value = 3 ) + default_value = 3, + options = [ '(Y)es', '(N)o', '(D)efault' ], + keys = [ 'y', 'n', 'd' ] ) def _PrepareAttach( self, adapter_config, launch_config ): diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index e9e76ea..a060543 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -59,7 +59,10 @@ DEFAULTS = { 'expand_or_jump': [ '', '<2-LeftMouse>' ], 'focus_thread': [ '' ], } - } + }, + + # Custom + 'java_hotcodereplace_mode': 'ask', } diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index ca0b80a..53ebd3b 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -390,18 +390,26 @@ def ConfirmCallback( confirm_id, result ): handler( result ) -def Confirm( api_prefix, prompt, handler, default_value = 3, options = None ): - global CONFIRM_ID +def Confirm( api_prefix, + prompt, + handler, + default_value = 2, + options: list = None, + keys: list = None ): if not options: - options = [ '(Y)es', '(N)o', '(D)efault' ] + 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 ) + default_value, + keys ) def AppendToBuffer( buf, line_or_lines, modified=False ): From efc5c7686638efc4c047bf0f58ae58fbff0bd393 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 11 Mar 2021 22:45:59 +0000 Subject: [PATCH 150/200] Fix lints --- autoload/vimspector/internal/popup.vim | 5 +++-- python3/vimspector/utils.py | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim index db2c2fd..083fdf5 100644 --- a/autoload/vimspector/internal/popup.vim +++ b/autoload/vimspector/internal/popup.vim @@ -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 {{{ @@ -36,7 +37,7 @@ let s:current_selection = 0 let s:selections = [] let s:text = [] -function! s:UpdatePopup( id ) +function! s:UpdatePopup( id ) abort let buf = copy( s:text ) call extend( buf, s:DrawButtons() ) call popup_settext( a:id, buf ) @@ -128,7 +129,7 @@ function! vimspector#internal#popup#Confirm( return popup_dialog( buf, config ) endfunction -function! vimspector#internal#popup#SetBorderChars( config ) +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' diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 53ebd3b..5f836fc 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -378,6 +378,7 @@ def AskForInput( prompt, default_value = None, completion = None ): CONFIRM = {} CONFIRM_ID = 0 + def ConfirmCallback( confirm_id, result ): try: handler = CONFIRM.pop( confirm_id ) From c05335c79987dc3ab19f30c477ad1b435e1ab9bf Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 16 Mar 2021 19:15:56 +0000 Subject: [PATCH 151/200] Make default option work for terminate debugee --- python3/vimspector/debug_session.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 255e072..156cbfd 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -954,9 +954,10 @@ class DebugSession( object ): elif choice == 2: # no arguments[ 'terminateDebuggee' ] = False - else: + elif choice <= 0: # Abort return + # Else, use server default disconnect( arguments ) From a39017dd06869bdb2b38b30ec21f41cb684a8e8b Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 19 Mar 2021 18:23:48 +0000 Subject: [PATCH 152/200] Fix actually sending terminateDebugee, and fix neovim 1-based index reporting --- autoload/vimspector/internal/neopopup.vim | 10 ++++++---- python3/vimspector/debug_session.py | 9 +++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index 9f35914..eb5a0dc 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -103,8 +103,10 @@ function! vimspector#internal#neopopup#Confirm( confirm_id, let result = -1 endtry - " Map the results to what popup_menu_filter would return (ok s:ConfirmCallback - " in popup.vim) + " 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 @@ -115,10 +117,10 @@ function! vimspector#internal#neopopup#Confirm( confirm_id, let result = index break endif - let index += 2 + let index += 1 endfor - if index >= len( a:keys ) + if index > len( a:keys ) let result = -1 endif endif diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 156cbfd..2f132f9 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -916,7 +916,9 @@ class DebugSession( object ): self._logger.info( 'Debug Adapter Started' ) def _StopDebugAdapter( self, interactive = False, callback = None ): - def disconnect( arguments = {} ): + arguments = {} + + def disconnect(): self._splash_screen = utils.DisplaySplash( self._api_prefix, self._splash_screen, @@ -936,7 +938,7 @@ class DebugSession( object ): self._connection.DoRequest( handler, { 'command': 'disconnect', - 'arguments': {}, + 'arguments': arguments, }, failure_handler = handler, timeout = 5000 ) if not interactive: @@ -947,7 +949,6 @@ class DebugSession( object ): disconnect() else: def handle_choice( choice ): - arguments = {} if choice == 1: # yes arguments[ 'terminateDebuggee' ] = True @@ -959,7 +960,7 @@ class DebugSession( object ): return # Else, use server default - disconnect( arguments ) + disconnect() utils.Confirm( self._api_prefix, "Terminate debuggee?", From 1414f261a1700515eb67c429aa681cbd84eca4e5 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 19 Mar 2021 22:59:27 +0000 Subject: [PATCH 153/200] Documentation for hot code replace --- README.md | 18 +++++++++++++++++- autoload/vimspector/internal/neopopup.vim | 8 ++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2152a9c..952d07f 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Console autocompletion](#console-autocompletion) * [Log View](#log-view) * [Closing debugger](#closing-debugger) + * [Terminate debuggee](#terminate-debuggee) * [Debug profile configuration](#debug-profile-configuration) * [C, C , Rust, etc.](#c-c-rust-etc) * [C Remote debugging](#c-remote-debugging) @@ -76,6 +77,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Debug cli application](#debug-cli-application) * [JavaScript, TypeScript, etc.](#javascript-typescript-etc) * [Java](#java) + * [Hot code replace](#hot-code-replace) * [Usage with YouCompleteMe](#usage-with-youcompleteme) * [Other LSP clients](#other-lsp-clients) * [Lua](#lua) @@ -91,7 +93,7 @@ For detailed explanatin of the `.vimspector.json` format, see the * [Example](#example) * [FAQ](#faq) - + @@ -1591,6 +1593,20 @@ editor plugin to use Java. I recommend [YouCompleteMe][], which has full support for jdt.ls, and most importantly a trivial way to load the debug adapter and to use it with Vimspector. +### Hot code replace + +When using the [java debug server][java-debug-server], Vimspector supports the +hot code replace custom feature. By default, when the underlying class files +change, vimspector asks the user if they wish to reload these classes at +runtime. + +This behaviour can be customised: + +* `let g:ycm_java_hotcodereplace_mode = 'ask'` - the default, ask the user for + each reload. +* `let g:ycm_java_hotcodereplace_mode = 'always'` - don't ask, always reload +* `let g:ycm_java_hotcodereplace_mode = 'never'` - don't ask, never reload + ### Usage with YouCompleteMe * Set up [YCM for java][YcmJava]. diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim index eb5a0dc..a734ca3 100644 --- a/autoload/vimspector/internal/neopopup.vim +++ b/autoload/vimspector/internal/neopopup.vim @@ -87,16 +87,16 @@ function! vimspector#internal#neopopup#Confirm( confirm_id, \ 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(). + " 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 .= ': ' - " 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. try let result = input( prompt, a:keys[ a:default_value - 1 ] ) catch /.*/ From 842d9fbc2d39718943b5cf768996a0dcf1b04ffe Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 19 Mar 2021 17:50:29 +0000 Subject: [PATCH 154/200] Config for pyright language server --- .ycm_extra_conf.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index f2e32ae..6f42505 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -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: From 35e5b3d56e193ee6129eabedcd48fd17b8293b2d Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 20 Mar 2021 15:55:22 +0000 Subject: [PATCH 155/200] 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 --- .gitignore | 1 + doc/vimspector.txt | 2394 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2395 insertions(+) create mode 100644 doc/vimspector.txt diff --git a/.gitignore b/.gitignore index 77f22a9..05dc8cd 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ support/test/csharp/*.exe* configurations/ venv/ test-base/ +tags diff --git a/doc/vimspector.txt b/doc/vimspector.txt new file mode 100644 index 0000000..8def87f --- /dev/null +++ b/doc/vimspector.txt @@ -0,0 +1,2394 @@ +*vimspector* vimspector - A multi language graphical debugger for Vim + +=============================================================================== +Contents ~ + + 1. Introduction |vimspector-introduction| + 2. Features and Usage |vimspector-features-usage| + 1. Supported debugging features |vimspector-supported-debugging-features| + 2. Supported languages |vimspector-supported-languages| + 3. Other languages |vimspector-other-languages| + 3. Installation |vimspector-installation| + 1. Quick Start |vimspector-quick-start| + 2. Dependencies |vimspector-dependencies| + 3. Neovim differences |vimspector-neovim-differences| + 4. Windows differences |vimspector-windows-differences| + 5. Trying it out |vimspector-trying-it-out| + 6. Cloning the plugin |vimspector-cloning-plugin| + 7. Install some gadgets |vimspector-install-gadgets| + 1. VimspectorInstall and VimspectorUpdate commands |vimspectorinstall-vimspectorupdate-commands| + 2. install_gadget.py |vimspector-install_gadget.py| + 8. Manual gadget installation |vimspector-manual-gadget-installation| + 1. The gadget directory |vimspector-gadget-directory| + 9. Upgrade |vimspector-upgrade| + 4. About |vimspector-about| + 1. Background |vimspector-background| + 2. Status |vimspector-status| + 1. Experimental |vimspector-experimental| + 3. Motivation |vimspector-motivation| + 4. License |vimspector-license| + 5. Sponsorship |vimspector-sponsorship| + 5. Mappings |vimspector-mappings| + 1. Visual Studio / VSCode |vimspector-visual-studio-vscode| + 2. Human Mode |vimspector-human-mode| + 6. Usage and API |vimspector-usage-api| + 1. Launch and attach by PID: |vimspector-launch-attach-by-pid| + 1. Launch with options |vimspector-launch-with-options| + 2. Debug configuration selection |vimspector-debug-configuration-selection| + 3. Get configurations |vimspector-get-configurations| + 2. Breakpoints |vimspector-breakpoints| + 1. Summary |vimspector-summary| + 2. Line breakpoints |vimspector-line-breakpoints| + 3. Conditional breakpoints |vimspector-conditional-breakpoints| + 4. Exception breakpoints |vimspector-exception-breakpoints| + 5. Clear breakpoints |vimspector-clear-breakpoints| + 6. Run to Cursor |vimspector-run-to-cursor| + 3. Stepping |vimspector-stepping| + 4. Variables and scopes |vimspector-variables-scopes| + 5. Variable or selection hover evaluation |vimspector-variable-or-selection-hover-evaluation| + 6. Watches |vimspector-watches| + 1. Watch autocompletion |vimspector-watch-autocompletion| + 7. Stack Traces |vimspector-stack-traces| + 8. Program Output |vimspector-program-output| + 1. Console |vimspector-console| + 2. Console autocompletion |vimspector-console-autocompletion| + 3. Log View |vimspector-log-view| + 9. Closing debugger |vimspector-closing-debugger| + 10. Terminate debuggee |vimspector-terminate-debuggee| + 7. Debug profile configuration |vimspector-debug-profile-configuration| + 1. C, C++, Rust, etc. |vimspector-c-c-rust-etc.| + 1. C++ Remote debugging |vimspector-c-remote-debugging| + 2. C++ Remote launch and attach |vimspector-c-remote-launch-attach| + 2. Rust |vimspector-rust| + 3. Python |vimspector-python| + 1. Python Remote Debugging |vimspector-python-remote-debugging| + 2. Python Remote launch and attach |vimspector-python-remote-launch-attach| + 3. Legacy: vscode-python |vimspector-legacy-vscode-python| + 4. TCL |vimspector-tcl| + 5. C♯ |vimspector-c| + 6. Go |vimspector-go| + 7. PHP |vimspector-php| + 1. Debug web application |vimspector-debug-web-application| + 2. Debug cli application |vimspector-debug-cli-application| + 8. JavaScript, TypeScript, etc. |vimspector-javascript-typescript-etc.| + 9. Java |vimspector-java| + 1. Usage with YouCompleteMe |vimspector-usage-with-youcompleteme| + 2. Other LSP clients |vimspector-other-lsp-clients| + 10. Lua |vimspector-lua| + 11. Other servers |vimspector-other-servers| + 8. Customisation |vimspector-customisation| + 1. Changing the default signs |vimspector-changing-default-signs| + 2. Sign priority |vimspector-sign-priority| + 3. Changing the default window sizes |vimspector-changing-default-window-sizes| + 4. Changing the terminal size |vimspector-changing-terminal-size| + 5. Custom mappings while debugging |vimspector-custom-mappings-while-debugging| + 6. Advanced UI customisation |vimspector-advanced-ui-customisation| + 7. Customising the WinBar |vimspector-customising-winbar| + 8. Example |vimspector-example| + 9. FAQ |vimspector-faq| + 10. References |vimspector-references| + +=============================================================================== + *vimspector-introduction* +Introduction ~ + +For a tutorial and usage overview, take a look at the Vimspector website [1]. + +For detailed explanatin of the '.vimspector.json' format, see the reference +guide [2]. + +Image: Build (see reference [3]) Image: Gitter [4] + +- Features and Usage + + - Supported debugging features + - Supported languages + - Other languages + +- Installation + + - Quick Start + - Dependencies + - Neovim differences + - Windows differences + - Trying it out + - Cloning the plugin + - Install some gadgets + - VimspectorInstall and VimspectorUpdate commands + - install_gadget.py + - Manual gadget installation + - The gadget directory + - Upgrade + +- About + + - Background + - Status + - Experimental + - Motivation + - License + - Sponsorship + +- Mappings + + - Visual Studio / VSCode + - Human Mode + +- Usage and API + + - Launch and attach by PID: + - Launch with options + - Debug configuration selection + - Get configurations + - Breakpoints + - Summary + - Line breakpoints + - Conditional breakpoints + - Exception breakpoints + - Clear breakpoints + - Run to Cursor + - Stepping + - Variables and scopes + - Variable or selection hover evaluation + - Watches + - Watch autocompletion + - Stack Traces + - Program Output + - Console + - Console autocompletion + - Log View + - Closing debugger + +- Debug profile configuration + + - C, C , Rust, etc. + - C Remote debugging + - C Remote launch and attach + - Rust + - Python + - Python Remote Debugging + - Python Remote launch and attach + - Legacy: vscode-python + - TCL + - C♯ + - Go + - PHP + - Debug web application + - Debug cli application + - JavaScript, TypeScript, etc. + - Java + - Usage with YouCompleteMe + - Other LSP clients + - Lua + - Other servers + +- Customisation + + - Changing the default signs + - Sign priority + - Changing the default window sizes + - Changing the terminal size + - Custom mappings while debugging + - Advanced UI customisation + - Customising the WinBar + - Example + +- FAQ + +=============================================================================== + *vimspector-features-usage* +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 language that +Visual Studio Code supports (but see caveats). + +The Vimspector website [1] has an overview of the UI, along with basic +instructions for configuration and setup. + +But for now, here's a (rather old) screenshot of Vimspector debugging Vim: + + Image: vimspector-vim-screenshot (see reference [6]) + +And a couple of brief demos: + + Image: asciicast [7] + + Image: asciicast [9] + +------------------------------------------------------------------------------- + *vimspector-supported-debugging-features* +Supported debugging features ~ + +- flexible configuration syntax that can be checked in to source control +- breakpoints (function, line and exception breakpoints) +- conditional breakpoints (function, line) +- step in/out/over/up, stop, restart +- run to cursor +- launch and attach +- remote launch, remote attach +- locals and globals display +- watch expressions with autocompletion +- variable inspection tooltip on hover +- set variable value in locals, watch and hover windows +- call stack display and navigation +- hierarchical variable value display popup (see + 'VimspectorBalloonEval') +- interactive debug console with autocompletion +- launch debuggee within Vim's embedded terminal +- logging/stdout display +- simple stable API for custom tooling (e.g. integrate with language server) + +------------------------------------------------------------------------------- + *vimspector-supported-languages* +Supported languages ~ + +The following table lists the languages that are "built-in" (along with their +runtime dependencies). They are categorised by their level of support: + +- 'Tested' : Fully supported, Vimspector regression tests cover them +- '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 + +======================================================================================================================================================== +| _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 | Go, Delve [11] | +-------------------------------------------------------------------------------------------------------------------------------------------------------- +| 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) | +-------------------------------------------------------------------------------------------------------------------------------------------------------- +| 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 | +-------------------------------------------------------------------------------------------------------------------------------------------------------- + + +------------------------------------------------------------------------------- + *vimspector-other-languages* +Other languages ~ + +Vimspector should work for any debug adapter that works in Visual Studio Code. + +To use Vimspector with a language that's not "built-in", see this wiki page +[12]. + +=============================================================================== + *vimspector-installation* +Installation ~ + +------------------------------------------------------------------------------- + *vimspector-quick-start* +Quick Start ~ + +There are 2 installation methods: + +- Using a release tarball and vim packages +- Using a clone of the repo (e.g. package manager) + +Release tarballs come with debug adapters for the default languages +pre-packaged. To use a release tarball: + +1. Check the dependencies +2. Untar the release tarball for your OS into '$HOME/.vim/pack': +> + $ mkdir -p $HOME/.vim/pack + $ curl -L | tar -C $HOME/.vim/pack zxvf - +< +1. Add 'packadd! vimspector' to you '.vimrc' + +2. (optionally) Enable the default set of mappings: +> + let g:vimspector_enable_mappings = 'HUMAN' +< +1. Configure your project's debug profiles (create '.vimspector.json') + +Alternatively, you can clone the repo and select which gadgets are installed: + +1. Check the dependencies +2. Install the plugin as a Vim package. See ':help packages'. +3. Add 'packadd! vimspector' to you '.vimrc' +4. Install some 'gadgets' (debug adapters) - see ':VimspectorInstall ...' +5. Configure your project's debug profiles (create '.vimspector.json') + +If you prefer to use a plugin manager, see the plugin manager's docs. For +Vundle, use: +> + Plugin 'puremourning/vimspector' +< +The following sections expand on the above brief overview. + +------------------------------------------------------------------------------- + *vimspector-dependencies* +Dependencies ~ + +Vimspector requires: + +- One of: +- Vim 8.2 Huge build compiled with Python 3.6 or later +- Neovim 0.4.3 with Python 3.6 or later (experimental) +- One of the following operating systems: +- Linux +- macOS Mojave or later +- Windows (experimental) + +Why such a new vim ? Well 2 reasons: + +1. Because vimspector uses a lot of new Vim features +2. Because there are Vim bugs that vimspector triggers that will frustrate + you if you hit them. + +Why is neovim experimental? Because the author doesn't use neovim regularly, +and there are no regression tests for vimspector in neovim, so it may break +occasionally. Issue reports are handled on best-efforts basis, and PRs are +welcome to fix bugs. See also the next section descibing differences for neovim +vs vim. + +Why Windows support experimental? Because it's effort and it's not a priority +for the author. PRs are welcome to fix bugs. Windows will not be regularly +tested. + +Which Linux versions? I only test on Ubuntu 18.04 and later and RHEL 7. + +------------------------------------------------------------------------------- + *vimspector-neovim-differences* +Neovim differences ~ + +neovim doesn't implement some features Vimspector relies on: + +- WinBar - used for the buttons at the top of the code window and for + changing the output window's current output. + +- Prompt Buffers - used to send commands in the Console and add Watches. + (_Note_: prompt buffers are available in neovim nightly) + +- Balloons - this allows for the variable evaluation popup to be displayed + when hovering the mouse. See below for how to create a keyboard mapping + instead. + +Workarounds are in place as follows: + +- WinBar - There are mappings, ':VimspectorShowOutput' and ':VimspectorReset' + +- Prompt Buffers - There are ':VimspectorEval' and ':VimspectorWatch' + +- Balloons - There is the 'VimspectorBalloonEval' mapping. There is no + default mapping for this, so I recommend something like this to get + variable display in a popup: +> + " mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!) + + " for normal mode - the word under the cursor + nmap di VimspectorBalloonEval + " for visual mode, the visually selected text + xmap di VimspectorBalloonEval +< +------------------------------------------------------------------------------- + *vimspector-windows-differences* +Windows differences ~ + +The following features are not implemented for Windows: + +- Tailing the vimspector log in the Output Window. + +------------------------------------------------------------------------------- + *vimspector-trying-it-out* +Trying it out ~ + +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') +- Nodejs ('support/test/node/simple') +- Chrome ('support/test/chrome/') +- etc. + +To test one of these out, cd to the directory and run: +> + vim -Nu /path/to/vimspector/tests/vimrc --cmd "let g:vimspector_enable_mappings='HUMAN'" +< +Then press ''. + +There's also a C++ project in 'tests/testdata/cpp/simple/' with a 'Makefile' +which can be used to check everything is working. This is used by the +regression tests in CI so should always work, and is a good way to check if the +problem is your configuration rather than a bug. + +------------------------------------------------------------------------------- + *vimspector-cloning-plugin* +Cloning the plugin ~ + +If you're not using a release tarball, you'll need to clone this repo to the +appropriate place. + +1. Clone the plugin + +There are many Vim plugin managers, and I'm not going to state a particular +preference, so if you choose to use one, follow the plugin manager's +documentation. For example, for Vundle, use: +> + Plugin 'puremourning/vimspector' +< +If you don't use a plugin manager already, install vimspector as a Vim package +by cloning this repository into your package path, like this: +> + $ git clone https://github.com/puremourning/vimspector ~/.vim/pack/vimspector/opt/vimspector +< +1. Configure vimspector in your '.vimrc', for example to enable the standard + mapings: +> + let g:vimspector_enable_mappings = 'HUMAN' +< +1. Load vimspector at runtime. This can also be added to your '.vimrc' after + configuring vimspector: +> + packadd! vimspector +< +See support/doc/example_vimrc.vim for a minimal example. + +------------------------------------------------------------------------------- + *vimspector-install-gadgets* +Install some gadgets ~ + +Vimspector is a generic client for Debug Adapters. Debug Adapters (referred to +as 'gadgets' or 'adapters') are what actually do the work of talking to the +real debuggers. + +In order for Vimspector to be useful, you need to have some adapters installed. + +There are a few ways to do this: + +- If you downloaded a tarball, gadgets for main supported languages are + already installed for you. + +- Using ':VimspectorInstall ' (use TAB 'wildmenu' to see + the options, also accepts any 'install_gadget.py' option) + +- Using 'python3 install_gadget.py ' (use '--help' to see all options) + +- Attempting to launch a debug configuration; if the configured adapter can't + be found, vimspector will suggest installing one. + +- Using ':VimspectorUpdate' to install the latest supported versions of the + gadgets. + +Here's a demo of doing some installs and an upgrade: + + Image: asciicast [13] + +Both 'install_gadget.py' and ':VimspectorInstall' do the same set of things, +though the default behaviours are slightly different. For supported languages, +they will: + +- Download the relevant debug adapter at a version that's been tested from + the internet, either as a 'vsix' (Visusal Studio plugin), or clone from + GitHub. If you're in a corporate environment and this is a problem, you may + need to install the gadgets manually. + +- Perform any necessary post-installation actions, such as: + +- Building any binary components + +- Ensuring scripts are executable, because the VSIX packages are usually + broken in this regard. + +- Set up the 'gadgetDir' symlinks for the platform. + +For example, to install the tested debug adapter for a language, run: + +======================================================================================================================================== +| _To install_ | _Script_ | _Command_ | +======================================================================================================================================== +| '' | ':VimspectorInstall ' | +----------------------------------------------------------------------------------------- +| '', '', ... | ':VimspectorInstall ...' | +----------------------------------------------------------------------------------------- +| '' | './install_gadget.py --enable- ...' | ':VimspectorInstall --enable- ...' | +---------------------------------------------------------------------------------------------------------------------------------------- +| Supported adapters | './install_gadget.py --all' | ':VimspectorInstall --all' | +---------------------------------------------------------------------------------------------------------------------------------------- +| Supported adapters, but not TCL | './install_gadget.py --all --disable-tcl' | ':VimspectorInstall --all --disable-tcl' | +---------------------------------------------------------------------------------------------------------------------------------------- +| Supported and experimental adapters | './install_gadget.py --all --force-all' | ':VimspectorInstall --all' | +---------------------------------------------------------------------------------------------------------------------------------------- +| Adapter for specific debug config | Suggested by Vimspector when starting debugging | +----------------------------------------------------------------------------------------- + + +------------------------------------------------------------------------------- + *vimspectorinstall-vimspectorupdate-commands* +VimspectorInstall and VimspectorUpdate commands ~ + +':VimspectorInstall' runs 'install_gadget.py' in the background with some of +the options defaulted. + +':VimspectorUpdate' runs 'install_gadget.py' to re-install (i.e. update) any +gadgets already installed in your '.gadgets.json'. + +The output is minimal, to see the full output add '--verbose' to the command, +as in ':VimspectorInstall --verbose ...' or ':VimspectorUpdate --verbose ...'. + +If the installation is successful, the output window is closed (and the output +lost forever). Use a '!' to keep it open (e.g. ':VimspectorInstall! --verbose +--all' or ':VimspectorUpdate!' (etc.). + +If you know in advance which gadgets you want to install, for example so that +you can reproduce your config from source control, you can set +'g:vimspector_install_gadgets' to a list of gadgets. This will be used when: + +- Running ':VimspectorInstall' with no arguments, or +- Running ':VimspectorUpdate' + +For example: +> + let g:vimspector_install_gadgets = [ 'debugpy', 'vscode-cpptools', 'CodeLLDB' ] +< +------------------------------------------------------------------------------- + *vimspector-install_gadget.py* +install_gadget.py ~ + +By default 'install_gadget.py' will overwrite your '.gadgets.json' with the set +of adapters just installed, whereas ':VimspectorInstall' will _update_ it, +overwriting only newly changed or installed adapters. + +If you want to just add a new adapter using the script without destroying the +existing ones, add '--update-gadget-config', as in: +> + $ ./install_gadget.py --enable-tcl + $ ./install_gadget.py --enable-rust --update-gadget-config + $ ./install_gadget.py --enable-java --update-gadget-config +< +If you want to maintain 'configurations' outside of the vimspector repository +(this can be useful if you have custom gadgets or global configurations), you +can tell the installer to use a different basedir, then set +'g:vimspector_base_dir' to point to that directory, for example: +> + $ ./install_gadget.py --basedir $HOME/.vim/vimspector-config --all --force-all +< +Then add this to your '.vimrc': +> + let g:vimspector_base_dir=expand( '$HOME/.vim/vimspector-config' ) +< +When usnig ':VimspectorInstall', the 'g:vimspector_base_dir' setting is +respected unless '--basedir' is manually added (not recommended). + +See '--help' for more info on the various options. + +------------------------------------------------------------------------------- + *vimspector-manual-gadget-installation* +Manual gadget installation ~ + +If the language you want to debug is not in the supported list above, you can +probably still make it work, but it's more effort. + +You essentially need to get a working installation of the debug adapter, find +out how to start it, and configure that in an 'adapters' entry in either your +'.vimspector.json' or in '.gadgets.json'. + +The simplest way in practice is to install or start Visual Studio Code and use +its extension manager to install the relevant extension. You can then configure +the adapter manually in the 'adapters' section of your '.vimspector.json' or in +a 'gadgets.json'. + +PRs are always welcome to add supported languages (which roughly translates to +updating 'python/vimspector/gadgets.py' and testing it). + +------------------------------------------------------------------------------- + *vimspector-gadget-directory* +The gadget directory ~ + +Vimspector uses the following directory by default to look for a file named +'.gadgets.json': '/gadgets/'. + +This path is exposed as the vimspector _variable_ '${gadgetDir}'. This is +useful for configuring gadget command lines. + +Where os is one of: + +- 'macos' +- 'linux' +- 'windows' (though note: Windows is not supported) + +The format is the same as '.vimspector.json', but only the 'adapters' key is +used: + +Example: +> + { + "adapters": { + "lldb-vscode": { + "variables": { + "LLVM": { + "shell": "brew --prefix llvm" + } + }, + "attach": { + "pidProperty": "pid", + "pidSelect": "ask" + }, + "command": [ + "${LLVM}/bin/lldb-vscode" + ], + "env": { + "LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY": "YES" + }, + "name": "lldb" + }, + "vscode-cpptools": { + "attach": { + "pidProperty": "processId", + "pidSelect": "ask" + }, + "command": [ + "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" + ], + "name": "cppdbg" + }, + "vscode-python": { + "command": [ + "node", + "${gadgetDir}/vscode-python/out/client/debugger/debugAdapter/main.js" + ], + "name": "vscode-python" + } + } + } +< +The gadget file is automatically written by 'install_gadget.py' (or +':VimspectorInstall'). + +Vimspector will also load any fies matching: +'/gadgets//.gadgets.d/*.json'. These have the same +format as '.gadgets.json' but are not overwritten when running +'install_gadget.py'. + +------------------------------------------------------------------------------- + *vimspector-upgrade* +Upgrade ~ + +After updating the Vimspector code (either via 'git pull' or whatever package +manager), run ':VimspectorUpdate' to update any already-installed gadgets. + +=============================================================================== + *vimspector-about* +About ~ + +------------------------------------------------------------------------------- + *vimspector-background* +Background ~ + +The motivation is that debugging in Vim is a pretty horrible experience, +particularly if you use multiple languages. With pyclewn no more and the +built-in termdebug plugin limited to gdb, I wanted to explore options. + +While Language Server Protocol is well known, the Debug Adapter Protocol is +less well known, but achieves a similar goal: language agnostic API abstracting +debuggers from clients. + +The aim of this project is to provide a simple but effective debugging +experience in Vim for multiple languages, by leveraging the debug adapters that +are being built for Visual Studio Code. + +The ability to do remote debugging is a must. This is key to my workflow, so +baking it in to the debugging experience is a top bill goal for the project. So +vimspector has first-class support for executing programs remotely and +attaching to them. This support is unique to vimspector and on top of +(complementary to) any such support in actual debug adapters. + +------------------------------------------------------------------------------- + *vimspector-status* +Status ~ + +Vimspector is a work in progress, and any feedback/contributions are more than +welcome. + +The backlog can be viewed on Trello [15]. + +------------------------------------------------------------------------------- + *vimspector-experimental* +Experimental ~ + +The plugin is currently _experimental_. That means that any part of it can (and +probably will) change, including things like: + +- breaking changes to the configuration +- keys, layout, functionality of the UI + +However, I commit to only doing this in the most extreme cases and to annouce +such changes on Gitter well in advance. There's nothing more annoying than +stuff just breaking on you. I get that. + +------------------------------------------------------------------------------- + *vimspector-motivation* +Motivation ~ + +A message from the author about the motivation for this plugin: + +Many development environments have a built-in debugger. I spend an inordinate +amount of my time in Vim. I do all my development in Vim and I have even +customised my workflows for building code, running tests etc. + +For many years I have observed myself, friends and colleagues have been writing +'printf', 'puts', 'print', etc. debugging statements in all sorts of files +simply because there is no _easy_ way to run a debugger for _whatever_ language +we happen to be developing in. + +I truly believe that interactive, graphical debugging environments are the best +way to understand and reason about both unfamiliar and familiar code, and that +the lack of ready, simple access to a debugger is a huge hidden productivity +hole for many. + +Don't get me wrong, I know there are literally millions of developers out there +that are more than competent at developing without a graphical debugger, but I +maintain that if they had the ability to _just press a key_ and jump into the +debugger, it would be faster and more enjoyable that just cerebral code +comprehension. + +I created Vimspector because I find changing tools frustrating. 'gdb' for c++, +'pdb' for python, etc. Each has its own syntax. Each its own lexicon. Each its +own foibles. + +I designed the configuration system in such a way that the configuration can be +committed to source control so that it _just works_ for any of your colleagues, +friends, collaborators or complete strangers. + +I made remote debugging a first-class feature because that's a primary use case +for me in my job. + +With Vimspector I can _just hit ''_ in all of the languages I develop in +and debug locally or remotely using the exact same workflow, mappings and UI. I +have integrated this with my Vim in such a way that I can hit a button and _run +the test under the cursor in Vimspector_. This kind of integration has +massively improved my workflow and productivity. It's even made the process of +learning a new codebase... fun. + +- Ben Jackson, Creator. + +------------------------------------------------------------------------------- + *vimspector-license* +License ~ + +Apache 2.0 [16] + +Copyright © 2018 Ben Jackson + +------------------------------------------------------------------------------- + *vimspector-sponsorship* +Sponsorship ~ + +If you like Vimspector so much that you're wiling to part with your hard-earned +cash, please consider donating to one of the following charities, which are +meaningful to the author of Vimspector (in order of preference): + +- Greyhound Rescue Wales [17] +- Cancer Research UK [18] +- ICCF Holland [19] +- Any charity of your choosing. + +=============================================================================== + *vimspector-mappings* +Mappings ~ + +By default, vimspector does not change any of your mappings. Mappings are very +personal and so you should work out what you like and use vim's powerful +mapping features to set your own mappings. To that end, Vimspector defines the +following '' mappings: + +================================================================================================================================================================================= +| _Mapping_ | _Function_ | _API_ | +================================================================================================================================================================================= +| 'VimspectorContinue' | When debugging, continue. Otherwise start debugging. | 'vimspector#Continue()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorStop' | Stop debugging. | 'vimspector#Stop()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimpectorRestart' | Restart debugging with the same configuration. | 'vimspector#Restart()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorPause' | Pause debuggee. | 'vimspector#Pause()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorToggleBreakpoint' | Toggle line breakpoint on the current line. | 'vimspector#ToggleBreakpoint()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorToggleConditionalBreakpoint' | Toggle conditional line breakpoint on the current line. | 'vimspector#ToggleBreakpoint( { trigger expr, hit count expr } )' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorAddFunctionBreakpoint' | Add a function breakpoint for the expression under cursor | "vimspector#AddFunctionBreakpoint( '' )" | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorRunToCursor' | Run to Cursor | 'vimspector#RunToCursor()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorStepOver' | Step Over | 'vimspector#StepOver()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorStepInto' | Step Into | 'vimspector#StepInto()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorStepOut' | Step out of current function scope | 'vimspector#StepOut()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorUpFrame' | Move up a frame in the current call stack | 'vimspector#UpFrame()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorDownFrame' | Move down a frame in the current call stack | 'vimspector#DownFrame()' | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| 'VimspectorBalloonEval' | Evaluate expression under cursor (or visual) in popup | _internal_ | +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + +These map roughly 1-1 with the API functions below. + +For example, if you want '' to start/continue debugging, add this to some +appropriate place, such as your 'vimrc' (hint: run ':e $MYVIMRC'). +> + nmap VimspectorContinue +< +In addition, many users probably want to only enable certain Vimspector +mappings while debugging is active. This is also possible, though it requires +writing some vimscipt. + +That said, many people are familiar with particular debuggers, so the following +mappings can be enabled by setting 'g:vimspector_enable_mappings' to the +specified value. + +------------------------------------------------------------------------------- + *vimspector-visual-studio-vscode* +Visual Studio / VSCode ~ + +To use Visual Studio-like mappings, add the following to your 'vimrc' **before +loading vimspector**: +> + let g:vimspector_enable_mappings = 'VISUAL_STUDIO' +< +========================================================================================================================= +| _Key_ | _Mapping_ | _Function_ | +========================================================================================================================= +| 'F5' | 'VimspectorContinue' | When debugging, continue. Otherwise start debugging. | +------------------------------------------------------------------------------------------------------------------------- +| 'Shift F5' | 'VimspectorStop' | Stop debugging. | +------------------------------------------------------------------------------------------------------------------------- +| 'Ctrl Shift F5' | 'VimspectorRestart' | Restart debugging with the same configuration. | +------------------------------------------------------------------------------------------------------------------------- +| 'F6' | 'VimspectorPause' | Pause debuggee. | +------------------------------------------------------------------------------------------------------------------------- +| 'F9' | 'VimspectorToggleBreakpoint' | Toggle line breakpoint on the current line. | +------------------------------------------------------------------------------------------------------------------------- +| 'Shift F9' | 'VimspectorAddFunctionBreakpoint' | Add a function breakpoint for the expression under cursor | +------------------------------------------------------------------------------------------------------------------------- +| 'F10' | 'VimspectorStepOver' | Step Over | +------------------------------------------------------------------------------------------------------------------------- +| 'F11' | 'VimspectorStepInto' | Step Into | +------------------------------------------------------------------------------------------------------------------------- +| 'Shift F11' | 'VimspectorStepOut' | Step out of current function scope | +------------------------------------------------------------------------------------------------------------------------- + + +------------------------------------------------------------------------------- + *vimspector-human-mode* +Human Mode ~ + +If, like me, you only have 2 hands and 10 fingers, you probably don't like +Ctrl-Shift-F keys. Also, if you're running in a terminal, there's a real +possibility of terminfo being wrong for shifted-F-keys, particularly if your +'TERM' is 'screen-256color'. If these issues (number of hands, 'TERM' +variables) are unfixable, try the following mappings, by adding the following +**before loading vimspector**: +> + let g:vimspector_enable_mappings = 'HUMAN' +< +============================================================================================================================ +| _Key_ | _Mapping_ | _Function_ | +============================================================================================================================ +| 'F5' | 'VimspectorContinue' | When debugging, continue. Otherwise start debugging. | +---------------------------------------------------------------------------------------------------------------------------- +| 'F3' | 'VimspectorStop' | Stop debugging. | +---------------------------------------------------------------------------------------------------------------------------- +| 'F4' | 'VimspectorRestart' | Restart debugging with the same configuration. | +---------------------------------------------------------------------------------------------------------------------------- +| 'F6' | 'VimspectorPause' | Pause debuggee. | +---------------------------------------------------------------------------------------------------------------------------- +| 'F9' | 'VimspectorToggleBreakpoint' | Toggle line breakpoint on the current line. | +---------------------------------------------------------------------------------------------------------------------------- +| 'F9' | 'VimspectorToggleConditionalBreakpoint' | Toggle conditional line breakpoint on the current line. | +---------------------------------------------------------------------------------------------------------------------------- +| 'F8' | 'VimspectorAddFunctionBreakpoint' | Add a function breakpoint for the expression under cursor | +---------------------------------------------------------------------------------------------------------------------------- +| 'F8' | 'VimspectorRunToCursor' | Run to Cursor | +---------------------------------------------------------------------------------------------------------------------------- +| 'F10' | 'VimspectorStepOver' | Step Over | +---------------------------------------------------------------------------------------------------------------------------- +| 'F11' | 'VimspectorStepInto' | Step Into | +---------------------------------------------------------------------------------------------------------------------------- +| 'F12' | 'VimspectorStepOut' | Step out of current function scope | +---------------------------------------------------------------------------------------------------------------------------- + + +In addition, I recommend adding a mapping to 'VimspectorBalloonEval', in +normal and visual modes, for example: +> + " mnemonic 'di' = 'debug inspect' (pick your own, if you prefer!) + + " for normal mode - the word under the cursor + nmap di VimspectorBalloonEval + " for visual mode, the visually selected text + xmap di VimspectorBalloonEval +< +You may also wish to add mappings for up/down the stack, for example: +> + nmap VimspectorUpFrame + nmap VimspectorDownFrame +< +=============================================================================== + *vimspector-usage-api* +Usage and API ~ + +This section defines detailed usage instructions, organised by feature. For +most users, the mappings section contains the most common commands and default +usage. This section can be used as a reference to create your own mappings or +custom behaviours. + +------------------------------------------------------------------------------- + *vimspector-launch-attach-by-pid* +Launch and attach by PID: ~ + +- Create '.vimspector.json'. See below. +- ':call vimspector#Launch()' and select a configuration. + + Image: debug session (see reference [6]) + +------------------------------------------------------------------------------- + *vimspector-launch-with-options* +Launch with options ~ + +To launch a specific debug configuration, or specify replacement variables [20] +for the launch, you can use: + +- ':call vimspector#LaunchWithSettings( dict )' + +The argument is a 'dict' with the following keys: + +- 'configuration': (optional) Name of the debug configuration to launch +- '': (optional) Name of a variable to set + +This allows for some integration and automation. For example, if you have a +configuration named 'Run Test' that contains a replacement variable [20] named +'${Test}' you could write a mapping which ultimately executes: +> + vimspector#LaunchWithSettings( #{ configuration: 'Run Test' + \ Test: 'Name of the test' } ) +< +This would start the 'Run Test' configuration with '${Test}' set to "'Name of +the test'" and Vimspector would _not_ prompt the user to enter or confirm these +things. + +See our YouCompleteMe integration guide for another example where it can be +used to specify the port to connect the java debugger + +------------------------------------------------------------------------------- + *vimspector-debug-configuration-selection* +Debug configuration selection ~ + +Vimspector uses the following logic to choose a configuration to launch: + +1. If a configuration was specified in the launch options (as above), use + that. + +2. Otherwise if there's only one configuration and it doesn't have + 'autoselect' set to 'false', use that. + +3. Otherwise if there's exactly one configuration with 'default' set to + 'true' and without 'autoselect' set to 'false', use that. + +4. Otherwise, prompt the user to select a configuration. + +See the reference guide [21] for details. + +------------------------------------------------------------------------------- + *vimspector-get-configurations* +Get configurations ~ + +- Use 'vimspector#GetConfigurations()' to get a list of configurations + +For example, to get an array of configurations and fuzzy matching on the result +> + :call matchfuzzy(vimspector#GetConfigurations(), "test::case_1") +< +------------------------------------------------------------------------------- + *vimspector-breakpoints* +Breakpoints ~ + +See the mappings [22] section for the default mappings for working with +breakpoints. This section describes the full API in vimscript functions. + +------------------------------------------------------------------------------- + *vimspector-summary* +Summary ~ + +- Use 'vimspector#ToggleBreakpoint( { options dict } )' to set/disable/delete + a line breakpoint. The argument is optional (see below). + +- Use "vimspector#AddFunctionBreakpoint( '', { options dict} )" to add + a function breakpoint. The second argument is optional (see below). + +- Use 'vimspector#SetLineBreakpoint( file_name, line_num, { options dict } )' + to set a breakpoint at a specific file/line. The last argument is optional + (see below) + +- Use 'vimspector#ClearLineBreakpoint( file_name, line_num )' to remove a + breakpoint at a specific file/line + +- Use 'vimspector#ClearBreakpoints()' to clear all breakpoints + +Examples: + +- 'call vimspector#ToggleBreakpoint()' - toggle breakpoint on current line + +- "call vimspector#SetLineBreakpoint( 'some_file.py', 10 )" - set a + breakpoint on 'some_filepy:10' + +- "call vimspector#AddFunctionBreakpoint( 'main' )" - add a function + breakpoint on the 'main' function + +- "call vimspector#ToggleBreakpoint( { 'condition': 'i > 5' } )" - add a + breakpoint on the current line that triggers only when 'i > 5' is 'true' + +- "call vimspector#SetLineBreakpoint( 'some_file.py', 10, { 'condition': 'i > + 5' } )" - add a breakpoint at 'some_file.py:10' that triggers only when 'i + > 5' is 'true' + +- "call vimspector#ClearLineBreakpoint( 'some_file.py', 10 )" - delete the + breakpoint at 'some_file.py:10' + +- 'call vimspector#ClearBreakpoints()' - clear all breakpoints + +------------------------------------------------------------------------------- + *vimspector-line-breakpoints* +Line breakpoints ~ + +The simplest and most common form of breakpoint is a line breakpoint. Execution +is paused when the specified line is executed. + +For most debugging scenarios, users will just hit '' to create a line +breakpoint on the current line and '' to launch the application. + +------------------------------------------------------------------------------- + *vimspector-conditional-breakpoints* +Conditional breakpoints ~ + +Some debug adapters support conditional breakpoints. Note that vimspector does +not tell you if the debugger doesn't support conditional breakpoints (yet). A +conditional breakpoint is a breakpoint which only triggers if some expression +evaluates to true, or has some other constraints met. + +Some of these functions above take a single optional argument which is a +dictionary of options. The dictionary can have the following keys: + +- 'condition': An optional expression evaluated to determine if the + breakpoint should fire. Not supported by all debug adapters. For example, + to break when 'abc' is '10', enter something like 'abc == 10', depending on + the language. + +- 'hitCondition': An optional expression evaluated to determine a number of + times the breakpoint should be ignored. Should (probably?) not be used in + combination with 'condition'. Not supported by all debug adapters. For + example, to break on the 3rd time hitting this line, enter '3'. + +In both cases, the expression is evaluated by the debugger, so should be in +whatever dialect the debugger understands when evaluating expressions. + +When using the '' mapping, the user is prompted to enter these +expressions in a command line (with history). + +------------------------------------------------------------------------------- + *vimspector-exception-breakpoints* +Exception breakpoints ~ + +Exception breakpoints typically fire when an exception is throw or other error +condition occurs. Depending on the debugger, when starting debugging, you may +be asked a few questions about how to handle exceptions. These are "exception +breakpoints" and vimspector remembers your choices while Vim is still running. + +Typically you can accept the defaults (just keep pressing ''!) as most +debug adapter defaults are sane, but if you want to break on, say 'uncaught +exception' then answer 'Y' to that (for example). + +You can configure your choices in the '.vimspector.json'. See the configuration +guide [23] for details on that. + +------------------------------------------------------------------------------- + *vimspector-clear-breakpoints* +Clear breakpoints ~ + +Use 'vimspector#ClearBreakpoints()' to clear all breakpoints including the +memory of exception breakpoint choices. + +------------------------------------------------------------------------------- + *vimspector-run-to-cursor* +Run to Cursor ~ + +Use 'vimspector#RunToCursor' or '': this creates a temporary +breakpoint on the current line, then continues execution, clearing the +breakpoint when it is hit. + +------------------------------------------------------------------------------- + *vimspector-stepping* +Stepping ~ + +- Step in/out, finish, continue, pause etc. using the WinBar, or mappings. +- If you really want to, the API is 'vimspector#StepInto()' etc. + + Image: code window (see reference [24]) + +------------------------------------------------------------------------------- + *vimspector-variables-scopes* +Variables and scopes ~ + +- Current scope shows values of locals. +- Use '', or double-click with left mouse to expand/collapse (+, -). +- Set the value of the variable with '' (control + '') or + '' (if 'modifyOtherKeys' doesn't work for you) +- When changing the stack frame the locals window updates. +- While paused, hover to see values + + Image: locals window (see reference [25]) + +Scopes and variables are represented by the buffer 'vimspector.Variables'. + +------------------------------------------------------------------------------- + *vimspector-variable-or-selection-hover-evaluation* +Variable or selection hover evaluation ~ + +All rules for 'Variables and scopes' apply plus the following: + +- With mouse enabled, hover over a variable and get the value it evaluates + to. + +- Use your mouse to perform a visual selection of an expression (e.g. 'a + + b') and get its result. + +- Make a normal mode ('nmap') and visual mode ('xmap') mapping to + 'VimspectorBalloonEval' to manually trigger the popup. + +- Set the value of the variable with '' (control + '') or + '' (if 'modifyOtherKeys' doesn't work for you) + +- Use regular nagivation keys ('j', 'k') to choose the current selection; + '' (or leave the tooltip window) to close the tooltip. + + Image: variable eval hover (see reference [26]) + +------------------------------------------------------------------------------- + *vimspector-watches* +Watches ~ + +The watch window is used to inspect variables and expressions. Expressions are +evaluated in the selected stack frame which is "focussed" + +The watches window is a prompt buffer, where that's available. Enter insert +mode to add a new watch expression. + +- Add watches to the variables window by entering insert mode and typing the + expression. Commit with ''. + +- Alternatively, use ':VimspectorWatch '. Tab-completion for + expression is available in some debug adapters. + +- Expand result with '', or double-click with left mouse. + +- Set the value of the variable with '' (control + '') or + '' (if 'modifyOtherKeys' doesn't work for you) + +- Delete with ''. + + Image: watch window (see reference [27]) + +The watches are represented by the buffer 'vimspector.StackTrace'. + +------------------------------------------------------------------------------- + *vimspector-watch-autocompletion* +Watch autocompletion ~ + +The watch prompt buffer has its 'omnifunc' set to a function that will +calculate completion for the current expression. This is trivially used with +'' (see ':help ins-completion'), or integrated with your +favourite completion system. The filetype in the buffer is set to +'VimspectorPrompt'. + +For YouCompleteMe, the following config works well: +> + let g:ycm_semantic_triggers = { + \ 'VimspectorPrompt': [ '.', '->', ':', '<' ] + } +< +------------------------------------------------------------------------------- + *vimspector-stack-traces* +Stack Traces ~ + +The stack trace window shows the state of each program thread. Threads which +are stopped can be expanded to show the stack trace of that thread. + +Often, but not always, all threads are stopped when a breakpoint is hit. The +status of a thread is show in parentheses after the thread's name. Where +supported by the underlying debugger, threads can be paused and continued +individually from within the Stack Trace window. + +A particular thread, highlighted with the 'CursorLine' highlight group is the +"focussed" thread. This is the thread that receives commands like "Stop In", +"Stop Out", "Continue" and "Pause" in the code window. The focussed thread can +be changed manually to "switch to" that thread. + +- Use '', or double-click with left mouse to expand/collapse a thread + stack trace, or use the WinBar button. + +- Use '', or double-click with left mouse on a stack frame to jump to it. + +- Use the WinBar or 'vimspector#PauseContinueThread()' to individually pause + or continue the selected thread. + +- Use the "Focus" WinBar button, '' or + 'vimspector#SetCurrentThread()' 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. + + Image: stack trace (see reference [28]) + +The stack trace is represented by the buffer 'vimspector.StackTrace'. + +------------------------------------------------------------------------------- + *vimspector-program-output* +Program Output ~ + +- In the outputs window, use the WinBar to select the output channel. +- Alternatively, use ':VimspectorShowOutput '. Use command-line + completion to see the categories. +- The debuggee prints to the stdout channel. +- Other channels may be useful for debugging. + + Image: output window (see reference [29]) + +If the output window is closed, a new one can be opened with +':VimspectorShowOutput ' (use tab-completion - 'wildmenu' to see the +options). + +------------------------------------------------------------------------------- + *vimspector-console* +Console ~ + +The console window is a prompt buffer, where that's available, and can be used +as an interactive CLI for the debug adapter. Support for this varies amongst +adapters. + +- Enter insert mode to enter a command to evaluate. +- Alternatively, ':VimspectorEval '. Completion is available with + some debug adapters. +- Commit the request with '' +- The request and subsequent result are printed. + +NOTE: See also Watches above. + +If the output window is closed, a new one can be opened with +':VimspectorShowOutput Console'. + +------------------------------------------------------------------------------- + *vimspector-console-autocompletion* +Console autocompletion ~ + +The console prompt buffer has its 'omnifunc' set to a function that will +calculate completion for the current command/expression. This is trivially used +with '' (see ':help ins-completion'), or integrated with your +favourite completion system. The filetype in the buffer is set to +'VimspectorPrompt'. + +For YouCompleteMe, the following config works well: +> + let g:ycm_semantic_triggers = { + \ 'VimspectorPrompt': [ '.', '->', ':', '<' ] + } +< +------------------------------------------------------------------------------- + *vimspector-log-view* +Log View ~ + +The Vimspector log file contains a full trace of the communication between +Vimspector and the debug adapter. This is the primary source of diagnostic +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). + +------------------------------------------------------------------------------- + *vimspector-closing-debugger* +Closing debugger ~ + +To close the debugger, use: + +- 'Reset' WinBar button +- ':VimspectorReset' when the WinBar is not available. +- 'call vimspector#Reset()' + +------------------------------------------------------------------------------- + *vimspector-terminate-debuggee* +Terminate debuggee ~ + +If the debuggee is still running when stopping or resetting, then some debug +adapters allow you to specify what should happen to it when finishing +debugging. Typically, the default behaviour is sensible, and this is what +happens most of the time. These are the defaults according to DAP: + +- If the request was 'launch': terminate the debuggee +- If the request was 'attach': don't terminate the debuggee + +Some debug adapters allow you to choose what to do when disconnecting. If you +wish to control this behaviour, use ':VimspectorReset' or call +"vimspector#Reset( { 'interactive': v:true } )". If the debug adapter offers a +choice as to whether or not to terminate the debuggee, you will be prompted to +choose. The same applies for 'vimspector#Stop()' which can take an argument: +"vimspector#Stop( { 'interactive': v:true } )". + +=============================================================================== + *vimspector-debug-profile-configuration* +Debug profile configuration ~ + +For an introduction to the configuration of '.vimspector.json', take a look at +the Getting Started section of the Vimspector website [1]. + +For full explanation, including how to use variables, substitutions and how to +specify exception breakpoints, see the docs [2]. + +The JSON configuration file allows C-style comments: + +- '// comment to end of line ...' +- '/* inline comment ... */' + +Current tested with the following debug adapters. + +------------------------------------------------------------------------------- + *vimspector-c-c-rust-etc.* +C, C++, Rust, etc. ~ + +- vscode-cpptools [30] + +- On macOS, I _strongly_ recommend using CodeLLDB instead for C and C++ + projects. It's really excellent, has fewer dependencies and doesn't open + console apps in another Terminal window. + +Example '.vimspector.json' (works with both 'vscode-cpptools' and +'lldb-vscode'. For 'lldb-vscode' replace the name of the adapter with +'lldb-vscode': + +- vscode-cpptools Linux/MacOS: +> + { + "configurations": { + "Launch": { + "adapter": "vscode-cpptools", + "configuration": { + "request": "launch", + "program": "", + "args": [ ... ], + "cwd": "", + "environment": [ ... ], + "externalConsole": true, + "MIMode": "" + } + }, + "Attach": { + "adapter": "vscode-cpptools", + "configuration": { + "request": "attach", + "program": "", + "MIMode": "" + } + } + ... + } + } +< +- vscode-cpptools Windows + +**_NOTE FOR WINDOWS USERS:_** You need to install 'gdb.exe'. I recommend using +'scoop install gdb'. Vimspector cannot use the visual studio debugger due to +licensing. +> + { + "configurations": { + "Launch": { + "adapter": "vscode-cpptools", + "configuration": { + "request": "launch", + "program": "", + "stopAtEntry": true + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-c-remote-debugging* +C++ Remote debugging ~ + +The cpptools documentation describes how to attach cpptools to gdbserver using +'miDebuggerAddress'. Note that when doing this you should use the '"request": +"attach"'. + +------------------------------------------------------------------------------- + *vimspector-c-remote-launch-attach* +C++ Remote launch and attach ~ + +If you're feeling fancy, checkout the reference guide [31] for an example of +getting Vimspector to remotely launch and attach. + +- CodeLLDB (MacOS) + +CodeLLDB is superior to vscode-cpptools in a number of ways on macOS at least. + +See Rust. + +- lldb-vscode (MacOS) + +An alternative is to to use 'lldb-vscode', which comes with llvm. Here's how: + +- Install llvm (e.g. with HomeBrew: 'brew install llvm') +- Create a file named + '/path/to/vimspector/gadgets/macos/.gadgets.d/lldb-vscode.json': +> + { + "adapters": { + "lldb-vscode": { + "variables": { + "LLVM": { + "shell": "brew --prefix llvm" + } + }, + "attach": { + "pidProperty": "pid", + "pidSelect": "ask" + }, + "command": [ + "${LLVM}/bin/lldb-vscode" + ], + "env": { + "LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY": "YES" + }, + "name": "lldb" + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-rust* +Rust ~ + +Rust is supported with any gdb/lldb-based debugger. So it works fine with +'vscode-cpptools' and 'lldb-vscode' above. However, support for rust is best in +'CodeLLDB' [32]. + +- './install_gadget.py --force-enable-rust' or ':VimspectorInstall CodeLLDB' +- Example: 'support/test/rust/vimspector_test' +> + { + "configurations": { + "launch": { + "adapter": "CodeLLDB", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/target/debug/vimspector_test" + } + } + } + } +< +- Docs: https://github.com/vadimcn/vscode-lldb/blob/master/MANUAL.md + +------------------------------------------------------------------------------- + *vimspector-python* +Python ~ + +- Python: debugpy [33] + +- Install with 'install_gadget.py --enable-python' or ':VimspectorInstall + debugpy', ideally requires a working compiler and the python development + 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"'. +> + { + "configurations": { + ": Launch": { + "adapter": "debugpy", + "configuration": { + "name": ": Launch", + "type": "python", + "request": "launch", + "cwd": "", + "python": "/path/to/python/interpreter/to/use", + "stopOnEntry": true, + "console": "externalTerminal", + "debugOptions": [], + "program": "" + } + } + ... + } + } +< +------------------------------------------------------------------------------- + *vimspector-python-remote-debugging* +Python Remote Debugging ~ + +In order to use remote debugging with debugpy, you have to connect Vimspector +directly to the application that is being debugged. This is easy, but it's a +little different from how we normally configure things. Specifically, you need +to: + +- Start your application with debugpy, specifying the '--listen' argument. + See the debugpy documentation [34] for details. + +- Use the built-in "multi-session" adapter. This just asks for the host/port + to connect to. For example: +> + { + "configurations": { + "Python Attach": { + "adapter": "multi-session", + "configuration": { + "request": "attach", + "pathMappings": [ + // mappings here (optional) + ] + } + } + } + } +< +See details of the launch configuration [35] for explanation of things like +'pathMappings'. + +Additional documentation, including how to do this when the remote machine can +only be contacted via SSH are provided by debugpy [36]. + +------------------------------------------------------------------------------- + *vimspector-python-remote-launch-attach* +Python Remote launch and attach ~ + +If you're feeling fancy, checkout the reference guide [31] for an example of +getting Vimspector to remotely launch and attach. + +------------------------------------------------------------------------------- + *vimspector-legacy-vscode-python* +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 [37] +- NOTE: You must be running 'node' 10. See this issue [38] +> + { + "configurations": { + ": Launch": { + "adapter": "vscode-python", + "configuration": { + "name": ": Launch", + "type": "python", + "request": "launch", + "cwd": "", + "stopOnEntry": true, + "console": "externalTerminal", + "debugOptions": [], + "program": "" + } + } + ... + } + } +< +------------------------------------------------------------------------------- + *vimspector-tcl* +TCL ~ + +- TCL (TclProDebug) + +See my fork of TclProDebug [39] for instructions. + +------------------------------------------------------------------------------- + *vimspector-c* +C♯ ~ + +- C# - dotnet core + +Install with 'install_gadget.py --force-enable-csharp' or ':VimspectorInstall +netcoredbg' +> + { + "configurations": { + "launch - netcoredbg": { + "adapter": "netcoredbg", + "configuration": { + "request": "launch", + "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._** +> + { + "configurations": { + "launch - mono": { + "adapter": "vscode-mono-debug", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll", + "args": [], + "cwd": "${workspaceRoot}", + "runtimeExecutable": "mono", + "runtimeArgs": [], + "env": [], + "externalConsole": false, + "console": "integratedTerminal" + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-go* +Go ~ + +- Go + +Requires: + +- 'install_gadget.py --enable-go' or ':VimspectorInstall vscode-go' +- Delve [40] 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 +> + { + "configurations": { + "run": { + "adapter": "vscode-go", + "configuration": { + "request": "launch", + "program": "${fileDirname}", + "mode": "debug", + "dlvToolPath": "$HOME/go/bin/dlv" + } + } + } + } +< +See the vscode-go docs for troubleshooting information [41] + +------------------------------------------------------------------------------- + *vimspector-php* +PHP ~ + +This uses the php-debug, see +https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug + +Requires: + +- (optional) Xdebug helper for chrome https://chrome.google.com/webstore/deta + il/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc + +- 'install_gadget.py --force-enable-php' or ':VimspectorInstall + vscode-php-debug' + +- configured php xdebug extension +> + zend_extension=xdebug.so + xdebug.remote_enable=on + xdebug.remote_handler=dbgp + xdebug.remote_host=localhost + xdebug.remote_port=9000 +< + replace 'localhost' with the ip of your workstation. + +lazy alternative +> + zend_extension=xdebug.so + xdebug.remote_enable=on + xdebug.remote_handler=dbgp + xdebug.remote_connect_back=true + xdebug.remote_port=9000 +< +- .vimspector.json +> + { + "configurations": { + "Listen for XDebug": { + "adapter": "vscode-php-debug", + "configuration": { + "name": "Listen for XDebug", + "type": "php", + "request": "launch", + "port": 9000, + "stopOnEntry": false, + "pathMappings": { + "/var/www/html": "${workspaceRoot}" + } + } + }, + "Launch currently open script": { + "adapter": "vscode-php-debug", + "configuration": { + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 9000 + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-debug-web-application* +Debug web application ~ + +append 'XDEBUG_SESSION_START=xdebug' to your query string +> + curl "http://localhost?XDEBUG_SESSION_START=xdebug" +< +or use the previously mentioned Xdebug Helper extension (which sets a +'XDEBUG_SESSION' cookie) + +------------------------------------------------------------------------------- + *vimspector-debug-cli-application* +Debug cli application ~ +> + export XDEBUG_CONFIG="idekey=xdebug" + php +< +------------------------------------------------------------------------------- + *vimspector-javascript-typescript-etc.* +JavaScript, TypeScript, etc. ~ + +- Node.js + +Requires: + +- 'install_gadget.py --force-enable-node' + +- For installation, a Node.js environment that is < node 12. I believe this + is an incompatibility with gulp. Advice, use [nvm][] with 'nvm install + --lts 10; nvm use --lts 10; ./install_gadget.py --force-enable-node ...' + +- Options described here: + https://code.visualstudio.com/docs/nodejs/nodejs-debugging + +- Example: 'support/test/node/simple' +> + { + "configurations": { + "run": { + "adapter": "vscode-node", + "configuration": { + "request": "launch", + "protocol": "auto", + "stopOnEntry": true, + "console": "integratedTerminal", + "program": "${workspaceRoot}/simple.js", + "cwd": "${workspaceRoot}" + } + } + } + } +< +- Chrome + +This uses the chrome debugger, see https://marketplace.visualstudio.com/items?i +temName=msjsdiag.debugger-for-chrome. + +It allows you to debug scripts running inside chrome from within Vim. + +- './install_gadget.py --force-enable-chrome' or ':VimspectorInstall + debugger-for-chrome' +- Example: 'support/test/chrome' +> + { + "configurations": { + "launch": { + "adapter": "chrome", + "configuration": { + "request": "launch", + "url": "http://localhost:1234/", + "webRoot": "${workspaceRoot}/www" + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-java* +Java ~ + +Vimspector works well with the java debug server [42], which runs as a jdt.ls +(Java Language Server) plugin, rather than a standalone debug adapter. + +Vimspector is not in the business of running language servers, only debug +adapters, so this means that you need a compatible Language Server Protocol +editor plugin to use Java. I recommend YouCompleteMe [43], which has full +support for jdt.ls, and most importantly a trivial way to load the debug +adapter and to use it with Vimspector. + +------------------------------------------------------------------------------- + *vimspector-usage-with-youcompleteme* +Usage with YouCompleteMe ~ + +- Set up YCM for java [43]. + +- Get Vimspector to download the java debug plugin: 'install_gadget.py + --force-enable-java ' or ':VimspectorInstall + java-debug-adapter' + +- Configure Vimspector for your project using the 'vscode-java' adapter, + e.g.: +> + { + "configurations": { + "Java Attach": { + "adapter": "vscode-java", + "configuration": { + "request": "attach", + "hostName": "${host}", + "port": "${port}", + "sourcePaths": [ + "${workspaceRoot}/src/main/java", + "${workspaceRoot}/src/test/java" + ] + } + } + } + } +< +- Tell YCM to load the debugger plugin. This should be the 'gadgets/' + directory, not any specific adapter. e.g. in '.vimrc' +> + " Tell YCM where to find the plugin. Add to any existing values. + let g:ycm_java_jdtls_extension_path = [ + \ '' + \ ] +< +- Create a mapping, such as '' to start the debug server and + launch vimspector, e.g. in '~/.vim/ftplugin/java.vim': +> + let s:jdt_ls_debugger_port = 0 + function! s:StartDebugging() + if s:jdt_ls_debugger_port <= 0 + " Get the DAP port + let s:jdt_ls_debugger_port = youcompleteme#GetCommandResponse( + \ 'ExecuteCommand', + \ 'vscode.java.startDebugSession' ) + + if s:jdt_ls_debugger_port == '' + echom "Unable to get DAP port - is JDT.LS initialized?" + let s:jdt_ls_debugger_port = 0 + return + endif + endif + + " Start debugging with the DAP port + call vimspector#LaunchWithSettings( { 'DAPPort': s:jdt_ls_debugger_port } ) + endfunction + + nnoremap :call StartDebugging() +< +You can then use '' to start debugging rather than just ''. + +If you see "Unable to get DAP port - is JDT.LS initialized?", try running +':YcmCompleter ExecuteCommand vscode.java.startDebugSession' and note the +output. If you see an error like 'ResponseFailedException: Request failed: +-32601: No delegateCommandHandler for vscode.java.startDebugSession', make sure +that: _Your YCM jdt.ls is actually working, see the YCM docs [44] for +troubleshooting_ The YCM jdt.ls has had time to initialize before you start the +debugger * That 'g:ycm_java_jdtls_extension_path' is set in '.vimrc' or prior +to YCM starting + +For the launch arguments, see the vscode document [45]. + +------------------------------------------------------------------------------- + *vimspector-other-lsp-clients* +Other LSP clients ~ + +See this issue [46] for more background. + +------------------------------------------------------------------------------- + *vimspector-lua* +Lua ~ + +Lua is supported through local-lua-debugger-vscode [47]. This debugger uses +stdio to communicate with the running process, so calls to 'io.read' will cause +problems. + +- './install_gadget.py --enable-lua' or ':VimspectorInstall + local-lua-debugger-vscode' +- Examples: 'support/test/lua/simple' and 'support/test/lua/love' +> + { + "$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": "${file}" + } + } + }, + "luajit": { + "adapter": "lua-local", + "configuration": { + "request": "launch", + "type": "lua-local", + "cwd": "${workspaceFolder}", + "program": { + "lua": "luajit", + "file": "${file}" + } + } + }, + "love": { + "adapter": "lua-local", + "configuration": { + "request": "launch", + "type": "lua-local", + "cwd": "${workspaceFolder}", + "program": { + "command": "love" + }, + "args": ["${workspaceFolder}"] + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-other-servers* +Other servers ~ + +- Java - vscode-javac. This works, but is not as functional as Java Debug + Server. Take a look at this comment [48] for instructions. + +=============================================================================== + *vimspector-customisation* +Customisation ~ + +There is very limited support for customisation of the UI. + +------------------------------------------------------------------------------- + *vimspector-changing-default-signs* +Changing the default signs ~ + +Vimsector uses the following signs internally. If they are defined before +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 | +----------------------------------------------------------------------------- + + +The default symbols are the equivalent of something like the following: +> + 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 +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: +> + 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 +< +------------------------------------------------------------------------------- + *vimspector-sign-priority* +Sign priority ~ + +Many different plugins provide signs for various purposes. Examples include +diagnostic signs for code errors, etc. Vim provides only a single priority to +determine which sign should be displayed when multiple signs are placed at a +single line. If you are finding that other signs are interfering with +vimspector's (or vice-versa), you can customise the priority used by vimspector +by setting the following dictionary: +> + let g:vimspector_sign_priority = { + \ '': , + \ } +< +For example: +> + let g:vimspector_sign_priority = { + \ 'vimspectorBP': 3, + \ 'vimspectorBPCond': 2, + \ 'vimspectorBPDisabled': 1, + \ 'vimspectorPC': 999, + \ } +< +All keys are optional. If a sign is not customised, the default priority it +used (as shown above). + +See ':help sign-priority'. The default priority is 10, larger numbers override +smaller ones. + +------------------------------------------------------------------------------- + *vimspector-changing-default-window-sizes* +Changing the default window sizes ~ + +**_Please Note_**: This customisation API is **_unstable_**, meaning that it +may change at any time. I will endeavour to reduce the impact of this and +announce changes in Gitter. + +The following options control the default sizes of the UI windows (all of them +are numbers) + +- 'g:vimspector_sidebar_width' (default: 50 columns): The width in columns of + the left utility windows (variables, watches, stack trace) + +- 'g:vimspector_bottombar_height' (default 10 lines): The height in rows of + the output window below the code window. + +Example: +> + let g:vimspector_sidebar_width = 75 + let g:vimspector_bottombar_height = 15 +< +------------------------------------------------------------------------------- + *vimspector-changing-terminal-size* +Changing the terminal size ~ + +The terminal is typically created as a vertical split to the right of the code +window, and that window is re-used for subsequent terminal buffers. The +following control the sizing of the terminal window used for debuggee +input/output when using Vim's built-in terminal. + +- 'g:vimspector_code_minwidth' (default: 82 columns): Minimum number of + columns to try and maintain for the code window when splitting to create + the terminal window. + +- 'g:vimspector_terminal_maxwidth' (default: 80 columns): Maximum number of + columns to use for the terminal. + +- 'g:vimspector_terminal_minwidth' (default: 10 columns): Minimum number of + columns to use when it is not possible to fit + 'g:vimspector_terminal_maxwidth' columns for the terminal. + +That's a lot of options, but essentially we try to make sure that there are at +least 'g:vimspector_code_minwidth' columns for the main code window and that +the terminal is no wider than 'g:vimspector_terminal_maxwidth' columns. +'g:vimspector_terminal_minwidth' is there to ensure that there's a reasonable +number of columns for the terminal even when there isn't enough horizontal +space to satisfy the other constraints. + +Example: +> + let g:vimspector_code_minwidth = 90 + let g:vimspector_terminal_maxwidth = 75 + let g:vimspector_terminal_minwidth = 20 +< +------------------------------------------------------------------------------- + *vimspector-custom-mappings-while-debugging* +Custom mappings while debugging ~ + +It's useful to be able to define mappings only while debugging and remove those +mappings when debugging is complete. For this purpose, Vimspector provides 2 +'User' autocommands: + +- 'VimspectorJumpedToFrame' - triggered whenever a 'break' event happens, or + when selecting a stack from to jump to. This can be used to create (for + example) buffer-local mappings for any files opened in the code window. + +- 'VimspectorDebugEnded' - triggered when the debug session is terminated + (actually when Vimspector is fully reset) + +An example way to use this is included in 'support/custom_ui_vimrc'. In there, +these autocommands are used to create buffer-local mappings for any files +visited while debugging and to clear them when completing debugging. This is +particularly useful for commands like 'VimspectorBalloonEval' which only +make sense while debugging (and only in the code window). Check the commented +section 'Custom mappings while debugging'. + +NOTE: This is a fairly advanced feature requiring some nontrivial vimscript. +It's possible that this feature will be incorporated into Vimspector in future +as it is a common requirement. + +------------------------------------------------------------------------------- + *vimspector-advanced-ui-customisation* +Advanced UI customisation ~ + +**_Please Note_**: This customisation API is **_unstable_**, meaning that it +may change at any time. I will endeavour to reduce the impact of this and +announce changes in Gitter. + +The above customisation of window sizes is limited intentionally to keep things +simple. Vimspector also provides a way for you to customise the UI without +restrictions, by running a 'User' autocommand just after creating the UI or +opening the terminal. This requires you to write some vimscript, but allows you +to do things like: + +- Hide a particular window or windows +- Move a particular window or windows +- Resize windows +- Have multiple windows for a particular buffer (say, you want 2 watch + windows) +- etc. + +You can essentially do anything you could do manually by writing a little +vimscript code. + +The 'User' autocommand is raised with 'pattern' set with the following values: + +- 'VimspectorUICreated': Just after setting up the UI for a debug session +- 'VimspectorTerminalOpened': Just after opening the terminal window for + program input/output. + +The following global variable is set up for you to get access to the UI +elements: 'g:vimspector_session_windows'. This is a 'dict' with the following +keys: + +- 'g:vimspector_session_windows.tagpage': The tab page for the session +- 'g:vimspector_session_windows.variables': Window ID of the variables + window, containing the 'vimspector.Variables' buffer. +- 'g:vimspector_session_windows.watches': Window ID of the watches window, + containing the 'vimspector.Watches' buffer. +- 'g:vimspector_session_windows.stack_trace': Window ID of the stack trade + window containing the 'vimspector.StackTrace' buffer. +- 'g:vimspector_session_windows.code': Window ID of the code window. +- 'g:vimspector_session_windows.output': Window ID of the output window. + +In addition, the following key is added when triggering the +'VimspectorTerminalOpened' event: + +- 'g:vimspector_session_windows.terminal': Window ID of the terminal window + +------------------------------------------------------------------------------- + *vimspector-customising-winbar* +Customising the WinBar ~ + +You can even customise the WinBar buttons by simply running the usual 'menu' +(and 'unmenu') commands. + +By default, Vimspector uses something a bit like this: +> + nnoremenu WinBar.■\ Stop :call vimspector#Stop( { 'interactive': v:false } ) + nnoremenu WinBar.▶\ Cont :call vimspector#Continue() + nnoremenu WinBar.▷\ Pause :call vimspector#Pause() + nnoremenu WinBar.↷\ Next :call vimspector#StepOver() + nnoremenu WinBar.→\ Step :call vimspector#StepInto() + nnoremenu WinBar.←\ Out :call vimspector#StepOut() + nnoremenu WinBar.⟲: :call vimspector#Restart() + nnoremenu WinBar.✕ :call vimspector#Reset( { 'interactive': v:false } ) +< +If you prefer a different layout or if the unicode symbols don't render +correctly in your font, you can customise this in the 'VimspectorUICreated' +autocommand, for example: +> + func! CustomiseUI() + call win_gotoid( g:vimspector_session_windows.code ) + " Clear the existing WinBar created by Vimspector + nunmenu WinBar + " Cretae our own WinBar + nnoremenu WinBar.Kill :call vimspector#Stop( { 'interactive': v:true } ) + nnoremenu WinBar.Continue :call vimspector#Continue() + nnoremenu WinBar.Pause :call vimspector#Pause() + nnoremenu WinBar.Step\ Over :call vimspector#StepOver() + nnoremenu WinBar.Step\ In :call vimspector#StepInto() + nnoremenu WinBar.Step\ Out :call vimspector#StepOut() + nnoremenu WinBar.Restart :call vimspector#Restart() + nnoremenu WinBar.Exit :call vimspector#Reset() + endfunction + + augroup MyVimspectorUICustomistaion + autocmd! + autocmd User VimspectorUICreated call s:CustomiseUI() + augroup END +< +------------------------------------------------------------------------------- + *vimspector-example* +Example ~ + +There is some example code in 'support/custom_ui_vimrc' showing how you can use +the window IDs to modify various aspects of the UI using some basic vim +commands, primarily 'win_gotoid' function and the 'wincmd' ex command. + +To try this out 'vim -Nu support/custom_ui_vimrc '. + +Here's a rather smaller example. A simple way to use this is to drop it into a +file named 'my_vimspector_ui.vim' in '~/.vim/plugin' (or paste into your +'vimrc'): +> + " Set the basic sizes + let g:vimspector_sidebar_width = 80 + let g:vimspector_code_minwidth = 85 + let g:vimspector_terminal_minwidth = 75 + + function! s:CustomiseUI() + " Customise the basic UI... + + " Close the output window + call win_gotoid( g:vimspector_session_windows.output ) + q + endfunction + + function s:SetUpTerminal() + " Customise the terminal window size/position + " For some reasons terminal buffers in Neovim have line numbers + call win_gotoid( g:vimspector_session_windows.terminal ) + set norelativenumber nonumber + endfunction + + augroup MyVimspectorUICustomistaion + autocmd! + autocmd User VimspectorUICreated call s:CustomiseUI() + autocmd User VimspectorTerminalOpened call s:SetUpTerminal() + augroup END +< +=============================================================================== + *vimspector-faq* +FAQ ~ + +1. Q: Does it work? A: Yeah. It's a bit unpolished. + +2. Q: Does it work with _this_ language? A: Probably, but it won't + necessarily be easy to work out what to put in the '.vimspector.json'. As + you can see above, some of the servers aren't really editor agnostic, and + require very-specific unique handling. + +3. How do I stop it starting a new Terminal.app on macOS? See this comment + [49] + +4. Can I specify answers to the annoying questions about exception + breakpoints in my '.vimspector.json' ? Yes, see here [23]. + +5. Do I have to specify the file to execute in '.vimspector.json', or could + it be the current vim file? You don't need to. You can specify $file for + the current active file. See here [20] for complete list of replacements + in the configuration file. + +6. You allow comments in '.vimspector.json', but Vim highlights these as + errors, do you know how to make this not-an-error? Yes, put this in + '~/.vim/after/syntax/json.vim': +> + syn region jsonComment start="/\*" end="\*/" + hi link jsonCommentError Comment + hi link jsonComment Comment +< +1. What is the difference between a 'gadget' and an 'adapter'? A gadget is + something you install with ':VimspectorInstall' or 'install_gadget.py', + an 'adapter' is something that Vimspector talks to (actually it's the + Vimspector config describing that thing). These are _usually_ one-to-one, + but in theory a single gadget can supply multiple 'adapter' configs. + Typically this happens when a 'gadget' supplies different 'adapter' + config for, say remote debugging, or debugging in a container, etc. + +2. The signs and winbar display funny symbols. How do I fix them? See this + and this + +3. What's this telemetry stuff all about? Are you sending my data to evil + companies? 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. + +=============================================================================== + *vimspector-references* +References ~ + +[1] https://puremourning.github.io/vimspector-web/ +[2] https://puremourning.github.io/vimspector/configuration.html +[3] https://github.com/puremourning/vimspector/workflows/Build/badge.svg?branch=master +[4] https://gitter.im/vimspector/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge +[5] https://badges.gitter.im/vimspector/Lobby.svg +[6] https://puremourning.github.io/vimspector-web/img/vimspector-overview.png +[7] https://asciinema.org/a/VmptWmFHTNLPfK3DVsrR2bv8S +[8] https://asciinema.org/a/VmptWmFHTNLPfK3DVsrR2bv8S.svg +[9] https://asciinema.org/a/1wZJSoCgs3AvjkhKwetJOJhDh +[10] https://asciinema.org/a/1wZJSoCgs3AvjkhKwetJOJhDh.svg +[11] https://github.com/go-delve/delve +[12] https://github.com/puremourning/vimspector/wiki/languages +[13] https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay +[14] https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay.svg +[15] https://trello.com/b/yvAKK0rD/vimspector +[16] http://www.apache.org/licenses/LICENSE-2.0 +[17] https://greyhoundrescuewales.co.uk +[18] https://www.cancerresearchuk.org +[19] https://iccf.nl +[20] https://puremourning.github.io/vimspector/configuration.html#replacements-and-variables +[21] https://puremourning.github.io/vimspector/configuration.html#configuration-selection +[22] €mappings +[23] https://puremourning.github.io/vimspector/configuration.html#exception-breakpoints +[24] https://puremourning.github.io/vimspector-web/img/vimspector-code-window.png +[25] https://puremourning.github.io/vimspector-web/img/vimspector-locals-window.png +[26] https://puremourning.github.io/vimspector-web/img/vimspector-variable-eval-hover.png +[27] https://puremourning.github.io/vimspector-web/img/vimspector-watch-window.png +[28] https://puremourning.github.io/vimspector-web/img/vimspector-callstack-window.png +[29] https://puremourning.github.io/vimspector-web/img/vimspector-output-window.png +[30] https://github.com/Microsoft/vscode-cpptools +[31] https://puremourning.github.io/vimspector/configuration.html#remote-debugging-support +[32] https://github.com/vadimcn/vscode-lldb#features +[33] https://github.com/microsoft/debugpy +[34] https://github.com/microsoft/debugpy#debugpy-cli-usage +[35] https://github.com/microsoft/debugpy/wiki/Debug-configuration-settings +[36] https://github.com/microsoft/debugpy/wiki/Debugging-over-SSH +[37] https://github.com/Microsoft/vscode-python +[38] https://github.com/puremourning/vimspector/issues/105 +[39] https://github.com/puremourning/TclProDebug +[40] https://github.com/go-delve/delve/tree/master/Documentation/installation +[41] https://github.com/golang/vscode-go/blob/master/docs/debugging.md#troubleshooting +[42] https://github.com/Microsoft/java-debug +[43] https://github.com/ycm-core/YouCompleteMe#java-semantic-completion +[44] https://github.com/ycm-core/YouCompleteMe#troubleshooting +[45] https://code.visualstudio.com/docs/java/java-debugging +[46] https://github.com/puremourning/vimspector/issues/3 +[47] https://github.com/tomblind/local-lua-debugger-vscode +[48] https://github.com/puremourning/vimspector/issues/3#issuecomment-576916076 +[49] https://github.com/puremourning/vimspector/issues/90#issuecomment-577857322 + +vim: ft=help From 244d7d8fdfb073c8befbc777836b675459aae002 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 22 Mar 2021 14:45:21 +0000 Subject: [PATCH 156/200] Add the reference material to the vim doc too --- README.md | 2 +- doc/vimspector-ref.txt | 1085 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1086 insertions(+), 1 deletion(-) create mode 100644 doc/vimspector-ref.txt diff --git a/README.md b/README.md index 952d07f..6979e44 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ runtime dependencies). They are categorised by their level of support: | 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 | Go, [Delve][] | +| 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 | diff --git a/doc/vimspector-ref.txt b/doc/vimspector-ref.txt new file mode 100644 index 0000000..367d409 --- /dev/null +++ b/doc/vimspector-ref.txt @@ -0,0 +1,1085 @@ +*vimspector-ref* + +=============================================================================== +Contents ~ + + 1. Introduction |vimspector-ref-introduction| + 2. title: Configuration |vimspector-ref-title-configuration| + 3. Concepts |vimspector-ref-concepts| + 1. Debug adapter configuration |vimspector-ref-debug-adapter-configuration| + 2. Debug profile configuration |vimspector-ref-debug-profile-configuration| + 3. Replacements and variables |vimspector-ref-replacements-variables| + 1. The splat operator |vimspector-ref-splat-operator| + 2. Default values |vimspector-ref-default-values| + 3. Coercing Types |vimspector-ref-coercing-types| + 4. Configuration Format |vimspector-ref-configuration-format| + 5. Files and locations |vimspector-ref-files-locations| + 6. Adapter configurations |vimspector-ref-adapter-configurations| + 7. Debug configurations |vimspector-ref-debug-configurations| + 1. Configuration selection |vimspector-ref-configuration-selection| + 1. Specifying a default configuration |vimspector-ref-specifying-default-configuration| + 2. Preventing automatic selection |vimspector-ref-preventing-automatic-selection| + 2. Exception Breakpoints |vimspector-ref-exception-breakpoints| + 8. Predefined Variables |vimspector-ref-predefined-variables| + 9. Remote Debugging Support |vimspector-ref-remote-debugging-support| + 1. Python (debugpy) Example |vimspector-ref-python-example| + 2. C-family (gdbserver) Example |vimspector-ref-c-family-example| + 3. Docker Example |vimspector-ref-docker-example| + 10. Appendix: Configuration file format |vimspector-ref-appendix-configuration-file-format| + 11. Appendix: Editor configuration |vimspector-ref-appendix-editor-configuration| + 12. References |vimspector-ref-references| + +=============================================================================== + *vimspector-ref-introduction* +Introduction ~ + +=============================================================================== + *vimspector-ref-title-configuration* +title: Configuration ~ + +This document defines the supported format for project and adapter +configuration for Vimspector. + +- Concepts + + - Debug adapter configuration + - Debug profile configuration + - Replacements and variables + - The splat operator + - Default values + - Coercing Types + +- Configuration Format +- Files and locations +- Adapter configurations +- Debug configurations + + - Configuration selection + + - Specifying a default configuration + - Preventing automatic selection + + - Exception Breakpoints + +- Predefined Variables +- Remote Debugging Support + + - Python (debugpy) Example + - C-family (gdbserver) Example + - Docker Example + +- Appendix: Configuration file format +- Appendix: Editor configuration + +=============================================================================== + *vimspector-ref-concepts* +Concepts ~ + +As Vimspector supports debugging arbitrary projects, you need to tell it a few +details about what you want to debug, and how to go about doing that. + +In order to debug things, Vimspector requires a Debug Adapter which bridges +between Vimspector and the actual debugger tool. Vimspector can be used with +any debug adapter that implements the Debug Adapter Protocol [1]. + +For each debugging session, you provide a _debug configuration_ which includes +things like: + +- The debug adapter to use (and possibly how to launch and configure it). +- How to connect to the remote host, if remote debugging. +- How to launch or attach to your process. + +Along with optional additional configuration for things like: + +- Exception breakpoints + +------------------------------------------------------------------------------- + *vimspector-ref-debug-adapter-configuration* +Debug adapter configuration ~ + +The adapter to use for a particular debug session can be specified inline +within the _debug configuration_, but more usually the debug adapter is defined +separately and just referenced from the _debug configuration_. + +The adapter configuration includes things like: + +- How to launch or connect to the debug adapter +- How to configure it for PID attachment +- How to set up remote debugging, such as how to launch the process remotely + (for example, under 'gdbserver', 'ptvsd', etc.) + +------------------------------------------------------------------------------- + *vimspector-ref-debug-profile-configuration* +Debug profile configuration ~ + +Projects can have many different debug profiles. For example you might have all +of the following, for a given source tree: + +- Remotely launch c++ the process, and break on 'main' +- Locally Python test and break exception +- Remotely attach to a c++ process +- Locally launch a bash script +- Attach to a JVM listening on a port + +Each of these represents a different use case and a different _debug +configuration_. As mentioned above, a _debug configuration_ is essentially: + +- The adapter to use + +- The type of session (launch or attach), and whether or not to do it + remotely + +- The configuration to pass to the adapter in order to launch or attach to + the process. + +The bulk of the configuration is the last of these, which comprises +adapter-specific options, as the Debug Adapter Protocol does not specify any +standard for launch or attach configuration. + +------------------------------------------------------------------------------- + *vimspector-ref-replacements-variables* +Replacements and variables ~ + +Vimspector _debug configuration_ is intended to be as general as possible, and +to be committed to source control so that debugging your applications becomes a +simple, quick and pain-free habit (e.g. answering questions like "what happens +if..." with "just hit F5 and step through!"). + +Therefore it's important to abstract certain details, like runtime and +build-time paths, and to parameterise the _debug configuration_. Vimspector +provides a simple mechanism to do this with '${replacement}' style +replacements. + +The values available within the '${...}' are defined below, but in summary the +following are supported: + +- Environment variables, such as '${PATH}' +- Predefined variables, such as '${workspaceRoot}', '${file}' etc. +- Configuration-defined variables, either provided by the adapter + configuration or debug configuration, or from running a simple shell + command. +- Anything else you like - the user will be asked to provide a value. + +If the latter 2 are confusing, for now, suffice to say that they are how +Vimspector allows parameterisation of debug sessions. The [Vimspector +website][website-getting-started] has a good example of where this sort of +thing is useful: accepting the name of a test to run. + +But for now, consider the following example snippet: +> + { + "configurations": { + "example-debug-configuration": { + // This is a single-line comment explaining the purpose + "adapter": "example-adapter-name", + "variables": { + "SecretToken": { // Variables should start with upper-case letters + "shell" : [ "cat", "${HOME}/.secret_token" ] + } + }, + "configuration": { + "request": "launch" /* or it could be "attach" */, + "program": [ + "${fileBasenameNoExtension}", + "-c", "configuration_file.cfg", + "-u", "${USER}", + "--test-identifier", "${TestIdentifier}", + "--secret-token", "${SecretToken}" + ] + }, + "breakpoints": { + "exception": { + "caught": "", + "uncaught": "Y" + } + } + } + } + } +< +In this (fictitious) example the 'program' launch configuration item contains +the following variable substitutions: + +- '${fileBasenameNoExtension}' - this is a Predefined Variable, set by + Vimspector to the base name of the file that's opened in Vim, with its + extension removed ('/path/to/xyz.cc' -> 'xyz'). + +- '${USER}' - this refers to the Environment Variable 'USER'. + +- '${TestIdentifier}' - this variable is not defined, so the user is asked to + provide a value interactively when starting debugging. Vimspector remembers + what they said and provides it as the default should they debug again. + +- '${SecretToken}' - this variable is provided by the configuration's + 'variables' block. Its value is taken from the 'strip''d result of running + 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. + +------------------------------------------------------------------------------- + *vimspector-ref-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. This is why we have the replacement variables after all. + +Frequently debug adapters request command arguments as a JSON array, for +example: +> + "args": [ "one", "two three", "four" ], +< +To help with this sort of case, Vimspector supports a 'splat' operator for +replacement variables operating within lists. The syntax is: '"*${var}', which +means roughly "splice the contents of '${var}' into the list at this position". +'${var}' is parsed like a shell command (using python's 'shlex' parser) and +each word is added as a list item. + +For example: +> + "args": [ "*${CommandLineArgs}" ] +< +This would: + +- Ask the user to provide the variable 'CommandLineArgs'. Let's say they + entered 'one "two three" four' +- Split 'CommandLineArgs' like shell arguments: 'one', 'two three' and 'four' +- Set 'args' in the settings dict to: '[ "one", "two three", "four" ]' + +You can also combine with static values: +> + "args": [ "First", "*${CommandLineArgs}", "Last" ] +< +This would yield the intuitive result: '[ "First", "one", "two three", "four", +"Last" ]' + +------------------------------------------------------------------------------- + *vimspector-ref-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 +pre-populated, allowing them to just press return to accept the default. + +The syntax is '${variableName:default value}'. The default value can contain +any character, but to include a '}' you must escape it with a backslash. To +include a backslash in the JSON you must write '\\', as in: +> + { "key": "${value:default {\\} stuff}" } +< +The default value can also be a replacement variable. However, this _must_ be a +variable that's already defined, such as one of the predefined variables, or +one specified in a 'variables' block. In order to reference them, you _must_ +use '${var}' syntax and you _must_ escape the closing '}'. For example, the is +a common and useful case: +> + { + "configuration": { + "program": "${script:${file\\}}" + } + } +< +This will prompt the user to specify 'script', but it will default to the path +to the current file. + +------------------------------------------------------------------------------- + *vimspector-ref-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 +this, ensuring that the resulting JSON is valid. This is done by interpreting a +value as a JSON string and substituting the resulting JSON value in its place. + +This is easier to explain with an example. Let's say we want to offer the +ability to break on entry, as an option for the user. The launch configuration +requires 'stopOnEntry' to be a bool. This doesn't work: +> + "stopOnEntry": "${StopOnEntry}" +< +The reason is that if the user types 'true', the resulting object is: +> + "stopOnEntry": "true" +< +The problem being that is a string, not a boolean. So Vimspector allows you to +re-interpret the string as a JSON value and use that instead. To do this, add +'#json' to the key's name. You can even add a default, like this: +> + "stopOnEntry#json": "${stopOnEntry:true}" +< +If the user accepts the default, the resulting string '"true"' is coerced to a +JSON value 'true', and the suffix is stripped fom the key, resulting in the +following: +> + "stopOnEntry#json": true +< +Which is what we need. + +If you happen to have a key that already ends in '#json' (unlikely!), then you +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:_** + +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 +'env' dict), then you can do that too: +> + "env#json": "${Environment:{\\}}" +< +The default value here is '{}' (note the '}' must be escaped!). The user can +then enter something like '{ "MYVAR": "MyValue", "OTHER": "Other" }' and the +resulting object would be: +> + "env": { + "MYVAR": "MyValue", + "OTHER": "Other" + } +< +It also works for lists, though the splat operator is usually more convenient +for that. + +=============================================================================== + *vimspector-ref-configuration-format* +Configuration Format ~ + +All Vimspector configuration is defined in a JSON object. The complete +specification of this object is available in the JSON Schema [2], but the basic +format for the configuration object is: +> + { + "adapters": { }, + "configurations": { } + } +< +The 'adapters' key is actually optional, as '' can be +embedded within '', though this is not recommended usage. + +=============================================================================== + *vimspector-ref-files-locations* +Files and locations ~ + +The above configuration object is constructed from a number of configuration +files, by merging objects in a specified order. + +In a minimal sense, the only file required is a '.vimspector.json' file in the +root of your project which defines the full configuration object [2], but it is +usually useful to split the 'adapters' configuration into a separate file (or +indeed one file per debug adapter). + +The following sections describe the files that are read and use the following +abbreviations: + +- '' means the path to the Vimspector installation (such as + '$HOME/.vim/pack/vimspector/start/vimspector') + +- '' is either 'macos' or 'linux' depending on the host operating system. + +- '' is the Vim filetype. Where multiple filetypes are in effect, + typically all filetypes are checked. + +=============================================================================== + *vimspector-ref-adapter-configurations* +Adapter configurations ~ + +Vimspector reads a series of files to build the 'adapters' object. The +'adapters' objects are merged in such a way that a definition for an adapter +named 'example-adapter' in a later file _completely replaces_ a previous +definition. + +- '/gadgets//.gadgets.json' - the file written by + 'install_gadget.py' and not usually edited by users. + +- '/gadgets//.gadgets.d/*.json' (sorted alphabetically). + These files are user-supplied and override the above. + +- The first such '.gadgets.json' file found in all parent directories of the + file open in Vim. + +- The '.vimspector.json' and any filetype-specific configurations (see below) + +In all cases, the required format is: +> + { + "$schema": "https://puremourning.github.io/vimspector/schema/gadgets.schema.json#", + "adapters": { + "": { + + } + } + } +< +Each adapters block can define any number of adapters. As mentioned, if the +same adapter name exists in multiple files, the last one read takes precedence +and _completely replaces_ the previous configuration. In particular that means +you can't just override one option, you have to override the whole block. + +Adapter configurations are re-read at the start of each debug session. + +The specification for the gadget object is defined in the [gadget schema][]. + +=============================================================================== + *vimspector-ref-debug-configurations* +Debug configurations ~ + +There are two locations for debug configurations for a project: + +- '/configurations///*.json' +- '.vimspector.json' in the project source + +Typically, the debug configurations are read from '.vimspector.json'. The file +is found (like '.gadgets.json' above) by recursively searching up the directory +hierarchy from the directory of the file open in Vim. The first file found is +read and no further searching is done. + +Only a single '.vimspector.json' is read. If one is found, the location of this +file is used for '${workspaceRoot}' and other workspace-relative paths. + +In addition, users can create filetype-specific configurations in the +Vimspector installation directory. This can be useful where the parameters for +the debug session for a particular filetype are always known in advance, or can +always be entered by the user. This allows for debugging to "just work" without +any modification to the project source (no need to add a '.vimspector.json'). +In this case, the '${workspaceRoot}' and workspace-relative paths are +interpreted relative to the file open in Vim. This isn't ideal, but there is no +other obvious way to default this variable. + +As with gadgets, any debug configurations appearing within '.vimspector.json' +override any that appear in the common configuration dir. + +Debug configurations are re-read at the start of each debug session, so +modifications are picked up without any restarts of Vim. + +The specification for the gadget object is defined in the schema [2], but a +typical example looks like this: +> + { + "$schema": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json#", + "configurations": { + "": { + "adapter": "", + "configuration": { + "request": "", + + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-ref-configuration-selection* +Configuration selection ~ + +When starting debugging, you can specify which debug configuration to launch +with "call vimspector#LaunchWithSettings( #{ configuration: 'name here' } )". + +Otherwise, if there's only one configuration found, Vimspector will use that +configuration, unless it contains a key '"autoselect": false'. + +If multiple debug configurations are found, and no explicit configuration was +selected on Launch, the user is prompted to select a configuration, unless a +single debug configuration is found with a key '"default": true'. + +------------------------------------------------------------------------------- + *vimspector-ref-specifying-default-configuration* +Specifying a default configuration ~ + +As noted, you can specify a default configuration with '"default": true': +> + { + "configurations": { + "use this one": { + "default": true, + "adapter": " ... ", + "configuation": { + // ... + } + }, + "don't use this one": { + // ... + } + } + } +< +If multiple configurations are found with 'default' set to 'true', then the +user is prompted anyway. + +------------------------------------------------------------------------------- + *vimspector-ref-preventing-automatic-selection* +Preventing automatic selection ~ + +If you don't want a configuration to be selected automatically, then set +'"autoselect": false'. This particularly useful for configurations in the +central (as opposed to project-local) directory. For example: +> + "configurations": { + "Don't use this by default!": { + "autoselect": false, + "adapter": " ... ", + "configuation": { + // ... + } + } + } +< +Setting 'autoselect' to 'false' overrides setting 'default' to 'true'. + +------------------------------------------------------------------------------- + *vimspector-ref-exception-breakpoints* +Exception Breakpoints ~ + +Debug adapters have arbitrary configuration for exception breakpoints. Normally +this is presented as a series of question to the user on starting the debug +session. The question includes the name of the exception breakpoint option, the +default and the list of valid responses (usually 'Y' or 'N'). + +You can pre-configure the answers to these questions in the 'breakpoints' +section of the debug configuration. For each question, take the name provided +and configure the response 'exception' mapping in the 'breakpoints' mapping. If +the configured response is empty string, the debug adapter default will be +used. + +Referring to the above example, the following tells the debug adapter to use +the default value for 'caught' exceptions and to break on 'uncaught' exception: +> + { + "configurations": { + "example-debug-configuration": { + "adapter": "example-adapter-name", + "breakpoints": { + "exception": { + "caught": "", + "uncaught": "Y" + } + }, + ... +< +The keys in the 'exception' mapping are what Vimspector includes in the prompt. +For example, when prompted with the following: +> + cpp_throw: Break on C++: on throw (Y/N/default: Y)? +< +The exception breakpoint "type" is 'cpp_throw' and the default is 'Y'. + +Similarly: +> + cpp_catch: Break on C++: on catch (Y/N/default: N)? +< +The exception breakpoint "type" is 'cpp_catch' and the default is 'N'. + +Use the following to set the values in configuration and not get asked: +> + "configurations": { + "example-debug-configuration": { + "adapter": "example-adapter-name", + "breakpoints": { + "exception": { + "cpp_throw": "Y", + "cpp_catch": "Y" + } + }, +< +To just accept the defaults for these exception breakpoint types, don't specify +a value, as in : +> + "configurations": { + "example-debug-configuration": { + "adapter": "example-adapter-name", + "breakpoints": { + "exception": { + "cpp_throw": "", + "cpp_catch": "" + } + }, +< +=============================================================================== + *vimspector-ref-predefined-variables* +Predefined Variables ~ + +The following variables are provided: + +- '${dollar}' - has the value '$', can be used to enter a literal dollar +- '$$' - a literal dollar +- '${workspaceRoot}' - the path of the folder where '.vimspector.json' was + found +- '${workspaceFolder}' - the path of the folder where '.vimspector.json' was + found +- '${gadgetDir}' - path to the OS-specific gadget dir ('/gadgets/') +- '${file}' - the current opened file +- '${relativeFile}' - the current opened file relative to 'workspaceRoot' +- '${fileBasename}' - the current opened file's 'basename' +- '${fileBasenameNoExtension}' - the current opened file's 'basename' with no + file extension +- '${fileDirname}' - the current opened file's 'dirname' +- '${fileExtname}' - the current opened file's extension +- '${cwd}' - the current working directory of the active window on launch +- '${unusedLocalPort}' - an unused local TCP port + +=============================================================================== + *vimspector-ref-remote-debugging-support* +Remote Debugging Support ~ + +Vimspector has in-built support for executing remote debuggers (such as +'gdbserver', 'debugpy', 'llvm-server' etc.). This is useful for environments +where the development is done on one host and the runtime is some other host, +account, container, etc. + +In order for it to work, you have to set up paswordless SSH between the local +and remote machines/accounts. Then just tell Vimspector how to remotely launch +and/or attach to the app. + +This is presented as examples with commentary, as it's a fairly advanced/niche +case. If you're not already familiar with remote debugging tools (such as +gdbserver) or not familiar with ssh or such, you might need to independently +research that. + +Vimspector's tools are intended to automate your existing process for setting +this up rather than to offer batteries-included approach. Ultimately, all +Vimspector is going to do is run your commands over SSH, or docker, and +co-ordinate with the adapter. + +------------------------------------------------------------------------------- + *vimspector-ref-python-example* +Python (debugpy) Example ~ + +Here is some examples using the Vimspector built-in remote support (using SSH) +to remotely launch and attach a python application and connect to it using +debugpy. + +The usage pattern is to hit '', enter 'host' (the host where your app +runs), 'account' (the account it runs under), and 'port' (a port that will be +opened on the remote host). Vimspector also supports exec'ing into Docker run +containers with 'container' (the container name or id your app is running in). +Vimspector then orchestrates the various tools to set you up. +> + { + "adapters": { + "python-remote": { + "port": "${port}", + "host": "${host}", + "launch": { + "remote": { + "host": "${host}", // Remote host to ssh to (mandatory if not using container) + "account": "${account}", // User to connect as (optional) + + // Optional.... Manual additional arguments for ssh + // "ssh": { + // "args": [ "-o", "StrictHostKeyChecking=no" ] + // }, + + // Command to launch the debugee and attach the debugger; + // %CMD% replaced with the remote-cmdLine configured in the launch + // configuration. (mandatory) + "runCommand": [ + "python", "-m", "debugpy", + "--listen", "0.0.0.0:${port}", + "--wait-for-client", + "%CMD%" + ] + + // Optional alternative to runCommand (if you need to run multiple + // commands) + // "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": { + "host": "${host}", // Remote host to ssh to (mandatory if not using container) + "account": "${account}", // User to connect as (optional) + // Command to get the PID of the process to attach (mandatory) + "pidCommand": [ + // + // Remember taht you can use ${var} to ask for input. I use this to + // call a custom command to returm the PID for a named service, so + // here's an examle: + // + "/path/to/secret/script/GetPIDForService", "${ServiceName}" + ], + + // Command to attach the debugger; %PID% replaced with output of + // pidCommand above (mandatory) + "attachCommand": [ + "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}", + "--pid", "%PID%" + ] + + // Optional alternative to attachCommand (if you need to run multiple + // commands) + // "attachCommands": [ + // [ /* first command */ ], + // [ /* second command */ ] + // ], + + // Optional.... useful with buggy gdbservers to kill -TRAP %PID% + // "initCompleteCommand": [ + // /* optional command to run after initialized */ + // ] + + // Optional.... Manual additional arguments for ssh + // "ssh": { + // "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 + } + } + }, + "configurations": { + "remote-launch": { + "adapter": "python-remote", + + "remote-request": "launch", + "remote-cmdLine": [ + "${RemoteRoot}/${fileBasename}", "*${args}" + ], + + "configuration": { + "request": "attach", + "pathMappings": [ + { + "localRoot": "${workspaceRoot}", + "remoteRoot": "${RemoteRoot}" + } + ] + } + }, + "remote-attach": { + "variables": { + // Just an example of how to specify a variable manually rather than + // vimspector asking for input from the user + "ServiceName": "${fileBasenameNoExtention}" + }, + + "adapter": "python-remote", + "remote-request": "attach", + + "configuration": { + "request": "attach", + "pathMappings": [ + { + "localRoot": "${workspaceRoot}", + "remoteRoot": "${RemoteRoot}" + } + ] + } + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-ref-c-family-example* +C-family (gdbserver) Example ~ + +This example uses Vimspector to remotely launch or attach to a binary using +'gdbserver' and then instructs vscode-cpptools to attach to that 'gdbserver'. + +The approach is very similar to the above for python, just that we use +gdbserver and have to tell cpptools a few more options. +> + { + "adapters": { + "cpptools-remote": { + "command": [ + "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" + ], + "name": "cppdbg", + "configuration": { + "type": "cppdbg" + }, + "launch": { + "remote": { + "host": "${host}", + "account": "${account}", + "runCommand": [ + "gdbserver", + "--once", + "--no-startup-with-shell", + "--disable-randomisation", + "0.0.0.0:${port}", + "%CMD%" + } + }, + "attach": { + "remote": { + "host": "${host}", + "account": "${account}", + "pidCommand": [ + "/path/to/secret/script/GetPIDForService", "${ServiceName}" + ], + "attachCommand": [ + "gdbserver", + "--once", + "--attach", + "0.0.0.0:${port}", + "%PID%" + ], + // + // If your application is started by a wrapper script, then you might + // need the followin. GDB can't pause an application because it only + // sends the signal to the process group leader. Or something. + // Basically, if you find that everything just hangs and the + // application never attaches, try using the following to manually + // force the trap signal. + // + "initCompleteCommand": [ + "kill", + "-TRAP", + "%PID%" + ] + } + } + } + }, + "configurations": { + "remote launch": { + "adapter": "cpptools-remote", + "remote-cmdLine": [ "/path/to/the/remote/executable", "args..." ], + "remote-request": "launch", + "configuration": { + "request": "attach", // yes, attach! + + "program": "/path/to/the/local/executable", + "MIMode": "gdb", + "miDebuggerAddress": "${host}:${port}" + } + }, + "remote attach": { + "adapter": "cpptools-remote", + "remote-request": "attach", + "configuration": { + "request": "attach", + + "program": "/path/to/the/local/executable", + "MIMode": "gdb", + "miDebuggerAddress": "${host}:${port}" + } + } + } +< +------------------------------------------------------------------------------- + *vimspector-ref-docker-example* +Docker Example ~ + +This example uses Vimspector to remotely launch or attach to a docker container +port. +> + { + "adapters": { + "python-remote": { + "port": "${port}", + "launch": { + "remote": { + "container": "${container}", // Docker container id or name to exec into to. + + // Command to launch the debugee and attach the debugger; + // %CMD% replaced with the remote-cmdLine configured in the launch + // configuration. (mandatory) + "runCommand": [ + "python", "-m", "debugpy", + "--listen", "0.0.0.0:${port}", + "--wait-for-client", + "%CMD%" + ] + + // Optional alternative to runCommand (if you need to run multiple + // commands) + // "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": { + "container": "${container}", // Docker container id or name to exec into. + // Command to get the PID of the process to attach (mandatory) + // This command gets appended to "docker exec ${container}" + "pidCommand": [ + // + // Remember taht you can use ${var} to ask for input. I use this to + // call a custom command to returm the PID for a named service, so + // here's an examle: + // + "sh", "-c", "pgrep", "-f", "${filename}" + ], + + // Command to attach the debugger; %PID% replaced with output of + // pidCommand above (mandatory) + "attachCommand": [ + "sh", "-c", "python", "-m", "debugpy", "--listen", "0.0.0.0:${port}", + "--pid", "%PID%" + ] + + // Optional alternative to attachCommand (if you need to run multiple + // commands) + // "attachCommands": [ + // [ /* first command */ ], + // [ /* second command */ ] + // ], + + // Optional.... useful with buggy gdbservers to kill -TRAP %PID% + // "initCompleteCommand": [ + // /* optional command to run after initialized */ + // ] + + } + + // 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 + } + } + }, + "configurations": { + "remote-launch": { + "adapter": "python-remote", + + "remote-request": "launch", + "remote-cmdLine": [ + "${RemoteRoot}/${fileBasename}", "*${args}" + ], + + "configuration": { + "request": "attach", + "pathMappings": [ + { + "localRoot": "${workspaceRoot}", + "remoteRoot": "${RemoteRoot}" + } + ] + } + }, + "remote-attach": { + "variables": { + // Just an example of how to specify a variable manually rather than + // vimspector asking for input from the user + "FileName": "${fileName}" + }, + + "adapter": "python-remote", + "remote-request": "attach", + + "configuration": { + "request": "attach", + "pathMappings": [ + { + "localRoot": "${workspaceRoot}", + "remoteRoot": "${RemoteRoot}" + } + ] + } + } + } + } +< +=============================================================================== + *vimspector-ref-appendix-configuration-file-format* +Appendix: Configuration file format ~ + +The configuration files are text files which must be UTF-8 encoded. They +contain a single JSON object, along with optional comments. + +Comments are "c-style", i.e.: + +- '// single line comment ...' +- '/* inline comment */' + +There is much debate about whether JSON files should contain comments. I have +added them because they are useful in the context of configuration files. +Unforutnately this may mean your editor doesn't like them (they are strictly +invalid JSON) so it's up to you if you use them. + +Technically, Vimspector uses JSON minify [3] to strip comments before parsing +the JSON. + +=============================================================================== + *vimspector-ref-appendix-editor-configuration* +Appendix: Editor configuration ~ + +If you would like some assistance with writing the JSON files, and your editor +of choice has a way to use a language server, you can use the VSCode JSON +language server [4]. + +It is recommended to include the '$schema' declaration as in the above +examples, but if that isn't present, the following JSON language server +configuration [5] is recommened to load the schema from the Internet: +> + { + "json": { + "schemas": [ + { + "fileMatch": [ ".vimspector.json" ], + "url": "https://puremourning.github.io/vimspector/schema/vimspector.schema.json" + }, + { + "fileMatch": [ ".gadgets.json", ".gadgets.d/*.json" ], + "url": "https://puremourning.github.io/vimspector/schema/gadgets.schema.json" + } + ] + } + } +< +If your language server client of choice happens to be YouCompleteMe [6], then +the following '.ycm_extra_conf.py' is good enough to get you going, after +following the instructions in the lsp-examples [7] repo to get the server set +up: +> + VIMSPECTOR_HOME = '/path/to/vimspector' # TODO: Change this + + def Settings( **kwargs ): + if kwargs[ 'language' ] == 'json': + return { + 'ls': { + 'json': { + 'schemas': [ + { + 'fileMatch': [ '.vimspector.json' ], + 'url': f'file://{VIMSPECTOR_HOME}/docs/schema/vimspector.schema.json' + }, + { + 'fileMatch': [ '.gadgets.json', '.gadgets.d/*.json' ], + 'url': f'file://{VIMSPECTOR_HOME}/docs/schema/gadgets.schema.json' + } + ] + } + } + } + + return None # Or your existing Settings definition.... +< +This configuration can be adapted to any other LSP-based editor configuration +and is provided just as an example. + +=============================================================================== + *vimspector-ref-references* +References ~ + +[1] https://microsoft.github.io/debug-adapter-protocol/ +[2] http://puremourning.github.io/vimspector/schema/vimspector.schema.json +[3] https://github.com/getify/JSON.minify +[4] https://github.com/vscode-langservers/vscode-json-languageserver +[5] https://github.com/vscode-langservers/vscode-json-languageserver#settings +[6] https://github.com/ycm-core/YouCompleteMe +[7] https://github.com/ycm-core/lsp-examples + +vim: ft=help From 054ea35428e5e8d6abe12b6a535a3b0426d4874e Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 22 Mar 2021 15:13:58 +0000 Subject: [PATCH 157/200] Add a way to test with dlv directly. Currrently not ready for the big time --- support/test/go/hello_world/.vimspector.json | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/support/test/go/hello_world/.vimspector.json b/support/test/go/hello_world/.vimspector.json index 8ab5091..4613b98 100644 --- a/support/test/go/hello_world/.vimspector.json +++ b/support/test/go/hello_world/.vimspector.json @@ -1,4 +1,18 @@ { + "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", @@ -12,6 +26,21 @@ "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" From 0d9e7835a85d6b0e53faeac982d1a4599aaf6fd6 Mon Sep 17 00:00:00 2001 From: puh <-> Date: Mon, 29 Mar 2021 23:11:26 +0300 Subject: [PATCH 158/200] Update CodeLLDB --- python3/vimspector/gadgets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 528f60c..d2c280b 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -453,12 +453,12 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.5.3', + 'version': 'v1.6.1', }, 'macos': { 'file_name': 'codelldb-x86_64-darwin.vsix', 'checksum': - '7505bc1cdfcfd1cb981e2996aec62d63577440709bac31dcadb41a3b4b44631a', + 'b1c998e7421beea9f3ba21aa5706210bb2249eba93c99b809247ee831075262f', 'make_executable': [ 'adapter/codelldb', 'lldb/bin/debugserver', @@ -469,7 +469,7 @@ GADGETS = { 'linux': { 'file_name': 'codelldb-x86_64-linux.vsix', 'checksum': - 'ce7efc3e94d775368e5942a02bf5c326b6809a0b4c389f79ffa6a8f6f6b72139', + 'f2a36cb6971fd95a467cf1a7620e160914e8f11bf82929932ee0aa5afbf6ae6a', 'make_executable': [ 'adapter/codelldb', 'lldb/bin/lldb', @@ -480,7 +480,7 @@ GADGETS = { 'windows': { 'file_name': 'codelldb-x86_64-windows.vsix', 'checksum': - '', + 'ca6a6525bf7719dc95265dc630b3cc817a8c0393b756fd242b710805ffdfb940', 'make_executable': [] }, 'adapters': { From d70d51a614a11f03a64294a48aca134634053713 Mon Sep 17 00:00:00 2001 From: Tony Dwire Date: Wed, 7 Apr 2021 11:50:26 -0500 Subject: [PATCH 159/200] Updated netcoredbg to 1.2.0-761 to enable mac support of async/await --- python3/vimspector/gadgets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index d2c280b..8be7db7 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -234,11 +234,10 @@ GADGETS = { 'format': 'tar', }, 'all': { - 'version': '1.2.0-738' + 'version': '1.2.0-761' }, 'macos': { 'file_name': 'netcoredbg-osx.tar.gz', - 'version': '1.2.0-635', 'checksum': '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', }, From 7d83419a4f813aee826eee994b8e419b6ff102b0 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 7 Apr 2021 22:45:58 +0100 Subject: [PATCH 160/200] Update docs bundles --- docs/Gemfile.lock | 50 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index d2eb55f..6a18520 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.3.4) + activesupport (6.0.3.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -16,7 +16,7 @@ GEM colorator (1.1.0) commonmarker (0.17.13) ruby-enum (~> 0.5) - concurrent-ruby (1.1.7) + concurrent-ruby (1.1.8) 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.0) - ffi (1.14.2) + faraday-net_http (1.0.1) + ffi (1.15.0) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (209) - 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) @@ -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.2) + 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) @@ -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.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.23.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) @@ -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.2) + jekyll-remote-theme (0.4.3) 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.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) @@ -196,12 +196,12 @@ GEM 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.4.0) + listen (3.5.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) @@ -210,9 +210,9 @@ GEM jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.14.3) + minitest (5.14.4) multipart-post (2.1.1) - nokogiri (1.11.1) + nokogiri (1.11.3) 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 (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.23.0) - ruby-enum (0.8.0) + rexml (3.2.5) + rouge (3.26.0) + ruby-enum (0.9.0) i18n - ruby2_keywords (0.0.2) + ruby2_keywords (0.0.4) 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.1.1) + simpleidn (0.2.1) unf (~> 0.1.4) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) From 13a5a1b947825f710a0aacc0fd8167bd3d42822c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 9 Apr 2021 16:54:38 +0100 Subject: [PATCH 161/200] Fix traceback when +python3 is not availble --- autoload/vimspector.vim | 3 +++ docs/configuration.md | 2 +- plugin/vimspector.vim | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index a0b6c42..1219661 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -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 diff --git a/docs/configuration.md b/docs/configuration.md index e736985..a2864b1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -271,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. diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 75e2baa..27ce473 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -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 From 278fc3cd8c285e3e2f6abff824592a18186912bd Mon Sep 17 00:00:00 2001 From: Tony Dwire Date: Fri, 9 Apr 2021 11:29:17 -0500 Subject: [PATCH 162/200] Update sha256sum of netcoredbg --- python3/vimspector/gadgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 8be7db7..7b807b6 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -239,7 +239,7 @@ GADGETS = { 'macos': { 'file_name': 'netcoredbg-osx.tar.gz', 'checksum': - '71c773e34d358950f25119bade7e3081c4c2f9d71847bd49027ca5792e918beb', + '994e0d001f53af058c94468336dfd1f166a3f3540c9e0de4f9f45f59e6c969fe', }, 'linux': { 'file_name': 'netcoredbg-linux-bionic-amd64.tar.gz', From fa92c2a8d525972bcc97cba9579d9adfca3c859a Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 11 Apr 2021 19:23:47 +0100 Subject: [PATCH 163/200] Add a mode for debugging the extremely flaky netcoredbg --- support/test/csharp/.vimspector.json | 65 ++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/support/test/csharp/.vimspector.json b/support/test/csharp/.vimspector.json index 524ae1a..8b2c499 100644 --- a/support/test/csharp/.vimspector.json +++ b/support/test/csharp/.vimspector.json @@ -1,25 +1,52 @@ { - "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", - "console": "integratedTerminal", - "cwd": "${workspaceRoot}", - "args": [], - "env": {} - } + "command": [ + "${gadgetDir}/netcoredbg/netcoredbg", + "--interpreter=vscode", + "--engineLogging=${workspaceRoot}/netcoredbg.engine.log", + "--log=${workspaceRoot}/netcoredbg.log" + ], + "configuration": { + "cwd": "${workspaceRoot}" + }, + "name": "netcoredbg" + } + }, + "configurations": { + "launch - netcoredbg": { + "adapter": "netcoredbg", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll", + "args": [], + "stopAtEntry": true + } + }, + "launch - netcoredbg - with debug log": { + "adapter": "netcoredbg-debuglog", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll", + "args": [], + "stopAtEntry": true + } + }, + "launch - mono": { + "adapter": "vscode-mono-debug", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/Program.exe", + "console": "integratedTerminal", + "cwd": "${workspaceRoot}", + "args": [], + "env": {} } } + } } From dd88e051a408e828af1d54ce8c98e18f41c64b5d Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 13 Apr 2021 17:34:51 +0100 Subject: [PATCH 164/200] Attempt to recover from broken messages --- python3/vimspector/debug_adapter_connection.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python3/vimspector/debug_adapter_connection.py b/python3/vimspector/debug_adapter_connection.py index df2ef13..206938a 100644 --- a/python3/vimspector/debug_adapter_connection.py +++ b/python3/vimspector/debug_adapter_connection.py @@ -226,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 ) ) From a41db89523723dbdde6b3f1381e4de321e67b78c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 13 Apr 2021 18:01:10 +0100 Subject: [PATCH 165/200] Fix get_configurations test --- support/test/csharp/.vimspector.json | 5 +++++ tests/get_configurations.test.vim | 1 + 2 files changed, 6 insertions(+) diff --git a/support/test/csharp/.vimspector.json b/support/test/csharp/.vimspector.json index 8b2c499..ae796e5 100644 --- a/support/test/csharp/.vimspector.json +++ b/support/test/csharp/.vimspector.json @@ -18,6 +18,11 @@ } }, "configurations": { + // + // NOTE: + // If you add to this, you must update tests/get_configurations.test.vim + // + "launch - netcoredbg": { "adapter": "netcoredbg", "configuration": { diff --git a/tests/get_configurations.test.vim b/tests/get_configurations.test.vim index 4a37d01..33e6577 100644 --- a/tests/get_configurations.test.vim +++ b/tests/get_configurations.test.vim @@ -12,6 +12,7 @@ function Test_Get_Configurations() let configs = vimspector#GetConfigurations() call assert_equal([ \ 'launch - netcoredbg', + \ 'launch - netcoredbg - with debug log', \ 'launch - mono', \ ], configs) From 6ad9101cf27f6d07d2f68fe04762e055869ec2d7 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 15 Apr 2021 15:02:46 +0100 Subject: [PATCH 166/200] Add FAQ about json files in each project. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6979e44..ae0ef46 100644 --- a/README.md +++ b/README.md @@ -2070,6 +2070,10 @@ 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 From b4195eee93846da6c73241520751b20a25bdbab7 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 15 Apr 2021 18:02:55 +0100 Subject: [PATCH 167/200] 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. --- python3/vimspector/gadgets.py | 4 +- support/test/csharp/.gitignore | 1 + support/test/csharp/.vimspector.json | 4 +- support/test/csharp/csharp.csproj | 2 +- .../test/csharp/obj/csharp.csproj.nuget.cache | 5 - .../csharp/obj/csharp.csproj.nuget.g.props | 21 - .../csharp/obj/csharp.csproj.nuget.g.targets | 10 - support/test/csharp/obj/project.assets.json | 748 ------------------ 8 files changed, 6 insertions(+), 789 deletions(-) delete mode 100644 support/test/csharp/obj/csharp.csproj.nuget.cache delete mode 100644 support/test/csharp/obj/csharp.csproj.nuget.g.props delete mode 100644 support/test/csharp/obj/csharp.csproj.nuget.g.targets delete mode 100644 support/test/csharp/obj/project.assets.json diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 7b807b6..6b28095 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -234,12 +234,12 @@ GADGETS = { 'format': 'tar', }, 'all': { - 'version': '1.2.0-761' + 'version': '1.2.0-782' }, 'macos': { 'file_name': 'netcoredbg-osx.tar.gz', 'checksum': - '994e0d001f53af058c94468336dfd1f166a3f3540c9e0de4f9f45f59e6c969fe', + '', }, 'linux': { 'file_name': 'netcoredbg-linux-bionic-amd64.tar.gz', diff --git a/support/test/csharp/.gitignore b/support/test/csharp/.gitignore index b7d74e4..03cd7d8 100644 --- a/support/test/csharp/.gitignore +++ b/support/test/csharp/.gitignore @@ -1,2 +1,3 @@ bin/ obj/Debug +obj/ diff --git a/support/test/csharp/.vimspector.json b/support/test/csharp/.vimspector.json index ae796e5..3bfb0f3 100644 --- a/support/test/csharp/.vimspector.json +++ b/support/test/csharp/.vimspector.json @@ -27,7 +27,7 @@ "adapter": "netcoredbg", "configuration": { "request": "launch", - "program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp3.1/csharp.dll", "args": [], "stopAtEntry": true } @@ -36,7 +36,7 @@ "adapter": "netcoredbg-debuglog", "configuration": { "request": "launch", - "program": "${workspaceRoot}/bin/Debug/netcoreapp2.2/csharp.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp3.1/csharp.dll", "args": [], "stopAtEntry": true } diff --git a/support/test/csharp/csharp.csproj b/support/test/csharp/csharp.csproj index 01d5113..d453e9a 100644 --- a/support/test/csharp/csharp.csproj +++ b/support/test/csharp/csharp.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 diff --git a/support/test/csharp/obj/csharp.csproj.nuget.cache b/support/test/csharp/obj/csharp.csproj.nuget.cache deleted file mode 100644 index 3ac8d84..0000000 --- a/support/test/csharp/obj/csharp.csproj.nuget.cache +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": 1, - "dgSpecHash": "6/vdr7YprlSIoQecv/nNuLNflFpO0X7eN7jHUinZTsgian9nYpmHMWirsDWMi5l+29TH+Qy8O/QfaB/48QtjRQ==", - "success": true -} \ No newline at end of file diff --git a/support/test/csharp/obj/csharp.csproj.nuget.g.props b/support/test/csharp/obj/csharp.csproj.nuget.g.props deleted file mode 100644 index c71f0e6..0000000 --- a/support/test/csharp/obj/csharp.csproj.nuget.g.props +++ /dev/null @@ -1,21 +0,0 @@ - - - - True - NuGet - $(MSBuildThisFileDirectory)project.assets.json - /Users/ben/.nuget/packages/ - /Users/ben/.nuget/packages/;/usr/local/share/dotnet/sdk/NuGetFallbackFolder - PackageReference - 5.7.0 - - - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - \ No newline at end of file diff --git a/support/test/csharp/obj/csharp.csproj.nuget.g.targets b/support/test/csharp/obj/csharp.csproj.nuget.g.targets deleted file mode 100644 index 099158b..0000000 --- a/support/test/csharp/obj/csharp.csproj.nuget.g.targets +++ /dev/null @@ -1,10 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - - - \ No newline at end of file diff --git a/support/test/csharp/obj/project.assets.json b/support/test/csharp/obj/project.assets.json deleted file mode 100644 index bd6c0fc..0000000 --- a/support/test/csharp/obj/project.assets.json +++ /dev/null @@ -1,748 +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", - "net462", - "net47", - "net471", - "net472", - "net48" - ], - "assetTargetFallback": true, - "warn": true, - "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/3.1.402/RuntimeIdentifierGraph.json" - } - } - } -} \ No newline at end of file From f389d65a24e02137b62c939264ffeb37952c522a Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 15 Apr 2021 19:12:24 +0100 Subject: [PATCH 168/200] Add a test for csharp, run in CI --- .github/workflows/build.yaml | 5 +++ run_tests | 8 +++- support/test/csharp/.vimspector.json | 4 +- support/test/csharp/csharp.sln | 16 +++++++ tests/ci/image/Dockerfile | 6 +++ tests/language_csharp.test.vim | 65 ++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 tests/language_csharp.test.vim diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 17f9601..f4ec9bf 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -111,6 +111,11 @@ 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 + - run: vim --version name: 'Print vim version information' diff --git a/run_tests b/run_tests index 39dc7ec..441acb0 100755 --- a/run_tests +++ b/run_tests @@ -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" diff --git a/support/test/csharp/.vimspector.json b/support/test/csharp/.vimspector.json index 3bfb0f3..326739b 100644 --- a/support/test/csharp/.vimspector.json +++ b/support/test/csharp/.vimspector.json @@ -29,7 +29,7 @@ "request": "launch", "program": "${workspaceRoot}/bin/Debug/netcoreapp3.1/csharp.dll", "args": [], - "stopAtEntry": true + "stopAtEntry": false } }, "launch - netcoredbg - with debug log": { @@ -38,7 +38,7 @@ "request": "launch", "program": "${workspaceRoot}/bin/Debug/netcoreapp3.1/csharp.dll", "args": [], - "stopAtEntry": true + "stopAtEntry": false } }, "launch - mono": { diff --git a/support/test/csharp/csharp.sln b/support/test/csharp/csharp.sln index bba50e0..91f59bf 100644 --- a/support/test/csharp/csharp.sln +++ b/support/test/csharp/csharp.sln @@ -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 diff --git a/tests/ci/image/Dockerfile b/tests/ci/image/Dockerfile index a25febc..164a5a7 100644 --- a/tests/ci/image/Dockerfile +++ b/tests/ci/image/Dockerfile @@ -70,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 && \ diff --git a/tests/language_csharp.test.vim b/tests/language_csharp.test.vim new file mode 100644 index 0000000..64cf954 --- /dev/null +++ b/tests/language_csharp.test.vim @@ -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 + From bc15c9451375909c6a52cf98c9d2ce8d2a834f41 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 15 Apr 2021 21:39:38 +0100 Subject: [PATCH 169/200] Retire mono debug - never worked and seems abandoned, and vscode-python as it is serious legacy now --- README.md | 102 ++++++---------------------------- python3/vimspector/gadgets.py | 58 ------------------- 2 files changed, 18 insertions(+), 142 deletions(-) diff --git a/README.md b/README.md index ae0ef46..5e05500 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,6 @@ For detailed explanatin of the `.vimspector.json` format, see the * [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) @@ -145,23 +144,24 @@ 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) | 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 | +| 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 | ## Other languages @@ -526,13 +526,6 @@ Example: "${gadgetDir}/vscode-cpptools/debugAdapters/OpenDebugAD7" ], "name": "cppdbg" - }, - "vscode-python": { - "command": [ - "node", - "${gadgetDir}/vscode-python/out/client/debugger/debugAdapter/main.js" - ], - "name": "vscode-python" } } } @@ -1264,10 +1257,6 @@ 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": { @@ -1334,34 +1323,6 @@ 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": { - ": Launch": { - "adapter": "vscode-python", - "configuration": { - "name": ": Launch", - "type": "python", - "request": "launch", - "cwd": "", - "stopOnEntry": true, - "console": "externalTerminal", - "debugOptions": [], - "program": "" - } - } - ... - } -} -``` - ## TCL * TCL (TclProDebug) @@ -1385,35 +1346,8 @@ 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}", - "runtimeExecutable": "mono", - "runtimeArgs": [], - "env": [], - "externalConsole": false, - "console": "integratedTerminal" + "env": {} } } } diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 6b28095..2c60a1a 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -86,29 +86,6 @@ 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': { @@ -269,41 +246,6 @@ GADGETS = { }, } }, - '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.16.2', - 'checksum': - '121eca297d83daeeb1e6e1d791305d1827998dbd595c330086b3b94d33dba3b9', - }, - 'adapters': { - 'vscode-mono-debug': { - "name": "mono-debug", - "command": [ - "mono", - "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" - ], - "attach": { - "pidSelect": "none" - }, - "configuration": { - "cwd": "${workspaceRoot}", - "console": "integratedTerminal", - "args": [], - "env": {} - } - }, - } - }, 'vscode-bash-debug': { 'language': 'bash', 'download': { From 1e25313cb5efc014b66a79d84d5c92c9bded6ebf Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 15 Apr 2021 22:52:58 +0100 Subject: [PATCH 170/200] Switch to xcode 11 which apparently works with coreclr debugging https://github.com/dotnet/runtime/issues/42311#issuecomment-700718025 --- .github/workflows/build.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f4ec9bf..14f5979 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -116,6 +116,11 @@ jobs: 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' @@ -148,7 +153,7 @@ jobs: # if: failure() # with: # NGROK_AUTH_TOKEN: ${{ secrets.NGROK_AUTH_TOKEN }} - # SSH_PASS: ${{ secrets.SSH_PASS }} + # SSH_PASS: ${{ secrets.SSH_PASS }} # [V]imspector PublishRelease: runs-on: 'ubuntu-16.04' From 297c0bea56fd3afce5209f47f330880d759c8698 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 20 Apr 2021 20:52:47 +0100 Subject: [PATCH 171/200] Ensure linux tests pass on PR --- .mergify.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.mergify.yml b/.mergify.yml index 09d3d83..0f02002 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -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 From 026ac22280cc19b7dd7bb3f976968264b6b15aab Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 22 Apr 2021 03:33:02 -0700 Subject: [PATCH 172/200] Fix some typos in the readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e05500..e3a5ad5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ For a tutorial and usage overview, take a look at the [Vimspector website][website]. -For detailed explanatin of the `.vimspector.json` format, see the +For detailed explanation of the `.vimspector.json` format, see the [reference guide][vimspector-ref]. ![Build](https://github.com/puremourning/vimspector/workflows/Build/badge.svg?branch=master) [![Gitter](https://badges.gitter.im/vimspector/Lobby.svg)](https://gitter.im/vimspector/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) @@ -99,7 +99,7 @@ For detailed explanatin 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 From 0c88cc8badeeee74f9cafbf461b72769b06a15d5 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 29 Apr 2021 10:02:23 +0100 Subject: [PATCH 173/200] 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 --- autoload/vimspector/internal/neojob.vim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/autoload/vimspector/internal/neojob.vim b/autoload/vimspector/internal/neojob.vim index 0cefc63..a398afe 100644 --- a/autoload/vimspector/internal/neojob.vim +++ b/autoload/vimspector/internal/neojob.vim @@ -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' From 2b844394133343a8868e7b4044ed286d5202fc99 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 3 May 2021 14:09:14 +0100 Subject: [PATCH 174/200] Lock closed issues after 60 days --- .github/workflows/lock_old_issues.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/lock_old_issues.yaml diff --git a/.github/workflows/lock_old_issues.yaml b/.github/workflows/lock_old_issues.yaml new file mode 100644 index 0000000..d9c3bca --- /dev/null +++ b/.github/workflows/lock_old_issues.yaml @@ -0,0 +1,26 @@ +name: "Lock Old Issues" + +on: + schedule: + - cron: '0 0 * * *' + +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' From a7e8e93920cbdf41eb9334b4998c0688a00b8ef8 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 3 May 2021 14:09:56 +0100 Subject: [PATCH 175/200] Allow manual running of locker --- .github/workflows/lock_old_issues.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lock_old_issues.yaml b/.github/workflows/lock_old_issues.yaml index d9c3bca..25d65e0 100644 --- a/.github/workflows/lock_old_issues.yaml +++ b/.github/workflows/lock_old_issues.yaml @@ -3,6 +3,7 @@ name: "Lock Old Issues" on: schedule: - cron: '0 0 * * *' + workflow_dispatch: jobs: lock: From 4e04a862cb37105acebac8b6ac5b275dc7865815 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 3 May 2021 15:02:50 +0100 Subject: [PATCH 176/200] Add note about existing github issues --- CONTRIBUTING.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1866974..adec034 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 From 08679d1c3ec46edb693e934a3a0f8326280e5893 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Tue, 11 May 2021 00:55:35 +0200 Subject: [PATCH 177/200] Upgrade php-debug to v1.15.1 --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 2c60a1a..62321ae 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -323,10 +323,10 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.14.9', - 'file_name': 'php-debug.vsix', + 'version': 'v1.15.1', + 'file_name': 'php-debug-1.15.1.vsix', 'checksum': - '0c5709cbbffe26b12aa63a88142195a9a045a5d8fca7fe63d62c789fe601630d', + '10222655d4179c7d109b1f951d88034eba772b45bf6141dcdb4e9b4477d2e2ab', }, 'adapters': { 'vscode-php-debug': { From 9113dbb6989ff9e289a2d1b8d740774cc33ee024 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 4 May 2021 21:59:44 +0100 Subject: [PATCH 178/200] stack_trace: Add cursorline highlight and sign for current frame --- README.md | 42 +++++---- python3/vimspector/settings.py | 3 +- python3/vimspector/stack_trace.py | 41 +++++++-- .../cpp/simple_c_program/.ycm_extra_conf.py | 2 +- tests/stack_trace.test.vim | 89 +++++++++++++++++++ 5 files changed, 150 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index e3a5ad5..bf84d2f 100644 --- a/README.md +++ b/README.md @@ -1007,6 +1007,8 @@ 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. ![stack trace](https://puremourning.github.io/vimspector-web/img/vimspector-callstack-window.png) @@ -1700,22 +1702,26 @@ 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 | +| 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 | 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 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 ``` If the signs don't display properly, your font probably doesn't contain these @@ -1723,11 +1729,13 @@ 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 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 priority diff --git a/python3/vimspector/settings.py b/python3/vimspector/settings.py index a060543..89378af 100644 --- a/python3/vimspector/settings.py +++ b/python3/vimspector/settings.py @@ -42,7 +42,8 @@ DEFAULTS = { 'vimspectorBP': 9, 'vimspectorBPCond': 9, 'vimspectorBPDisabled': 9, - 'vimspectorCurrentThread': 200 + 'vimspectorCurrentThread': 200, + 'vimspectorCurrentFrame': 200, }, # Installer diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index ae14e68..f9540ba 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -102,7 +102,8 @@ class StackTraceView( object ): self._scratch_buffers = [] # FIXME: This ID is by group, so should be module scope - self._next_sign_id = 1 + 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 ) @@ -127,6 +128,7 @@ class StackTraceView( object ): ':call vimspector#SetCurrentThread()' ) win.options[ 'cursorline' ] = False + win.options[ 'signcolumn' ] = 'auto' if not signs.SignDefined( 'vimspectorCurrentThread' ): @@ -136,6 +138,13 @@ class StackTraceView( object ): 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 = {} @@ -157,9 +166,12 @@ class StackTraceView( object ): self._sources = {} self._requesting_threads = StackTraceView.ThreadRequestState.NO self._pending_thread_request = None - if self._next_sign_id: - signs.UnplaceSign( self._next_sign_id, 'VimspectorStackTrace' ) - self._next_sign_id = 0 + 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 ) @@ -273,10 +285,10 @@ class StackTraceView( object ): self._line_to_frame.clear() self._line_to_thread.clear() - if self._next_sign_id: - signs.UnplaceSign( self._next_sign_id, 'VimspectorStackTrace' ) + if self._current_thread_sign_id: + signs.UnplaceSign( self._current_thread_sign_id, 'VimspectorStackTrace' ) else: - self._next_sign_id = 1 + self._current_thread_sign_id = 1 with utils.ModifiableScratchBuffer( self._buf ): with utils.RestoreCursorPosition(): @@ -290,7 +302,7 @@ class StackTraceView( object ): f'({thread.State()})' ) if self._current_thread == thread.id: - signs.PlaceSign( self._next_sign_id, + signs.PlaceSign( self._current_thread_sign_id, 'VimspectorStackTrace', 'vimspectorCurrentThread', self._buf.name, @@ -421,6 +433,7 @@ class StackTraceView( object ): # 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 + self._DrawThreads() return self._session.SetCurrentFrame( self._current_frame, reason ) return False @@ -518,6 +531,11 @@ class StackTraceView( object ): if not thread.IsExpanded(): return + if self._current_frame_sign_id: + signs.UnplaceSign( self._current_frame_sign_id, 'VimspectorStackTrace' ) + else: + self._current_frame_sign_id = 2 + for frame in thread.stacktrace: if frame.get( 'source' ): source = frame[ 'source' ] @@ -542,6 +560,13 @@ class StackTraceView( object ): source[ 'name' ], frame[ 'line' ] ) ) + if 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 ): diff --git a/support/test/cpp/simple_c_program/.ycm_extra_conf.py b/support/test/cpp/simple_c_program/.ycm_extra_conf.py index 0d17586..4203b36 100644 --- a/support/test/cpp/simple_c_program/.ycm_extra_conf.py +++ b/support/test/cpp/simple_c_program/.ycm_extra_conf.py @@ -1,4 +1,4 @@ def Settings( **kwargs ): return { - 'flags': [ '-x', 'c++', '-Wall', '-Wextra' ] + 'flags': [ '-x', 'c++', '-Wall', '-Wextra', '-std=c++17' ] } diff --git a/tests/stack_trace.test.vim b/tests/stack_trace.test.vim index a65ea5e..f191201 100644 --- a/tests/stack_trace.test.vim +++ b/tests/stack_trace.test.vim @@ -379,6 +379,20 @@ function! Test_UpDownStack() \ '$' ) \ ) \ } ) + call win_gotoid( g:vimspector_session_windows.stack_trace ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 1, + \ 'vimspectorCurrentThread', + \ 200 ) } ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 2, + \ 'vimspectorCurrentFrame', + \ 200 ) } ) + wincmd w call vimspector#DownFrame() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) @@ -396,6 +410,21 @@ function! Test_UpDownStack() \ '$' ) \ ) \ } ) + call win_gotoid( g:vimspector_session_windows.stack_trace ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 1, + \ 'vimspectorCurrentThread', + \ 200 ) } ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 2, + \ 'vimspectorCurrentFrame', + \ 200 ) } ) + wincmd w + call vimspector#UpFrame() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) @@ -413,6 +442,21 @@ function! Test_UpDownStack() \ '$' ) \ ) \ } ) + call win_gotoid( g:vimspector_session_windows.stack_trace ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 1, + \ 'vimspectorCurrentThread', + \ 200 ) } ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 3, + \ 'vimspectorCurrentFrame', + \ 200 ) } ) + wincmd w + call feedkeys( "\VimspectorUpFrame", 'x' ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 23, 1 ) @@ -430,6 +474,21 @@ function! Test_UpDownStack() \ '$' ) \ ) \ } ) + call win_gotoid( g:vimspector_session_windows.stack_trace ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 1, + \ 'vimspectorCurrentThread', + \ 200 ) } ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 4, + \ 'vimspectorCurrentFrame', + \ 200 ) } ) + wincmd w + call feedkeys( "\VimspectorDownFrame", 'x' ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) @@ -447,6 +506,21 @@ function! Test_UpDownStack() \ '$' ) \ ) \ } ) + call win_gotoid( g:vimspector_session_windows.stack_trace ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 1, + \ 'vimspectorCurrentThread', + \ 200 ) } ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 3, + \ 'vimspectorCurrentFrame', + \ 200 ) } ) + wincmd w + call vimspector#DownFrame() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) @@ -464,6 +538,21 @@ function! Test_UpDownStack() \ '$' ) \ ) \ } ) + call win_gotoid( g:vimspector_session_windows.stack_trace ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 1, + \ 'vimspectorCurrentThread', + \ 200 ) } ) + call WaitForAssert( { -> + \ vimspector#test#signs#AssertSignGroupSingletonAtLine( + \ 'VimspectorStackTrace', + \ 2, + \ 'vimspectorCurrentFrame', + \ 200 ) } ) + wincmd w + call vimspector#ClearBreakpoints() From 0e9497ce8f12d481974397e7c1c7f8378b9bce69 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 15 May 2021 15:50:59 +0100 Subject: [PATCH 179/200] Add cpptools to cpp test proj --- support/test/cpp/simple_c_program/.vimspector.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/support/test/cpp/simple_c_program/.vimspector.json b/support/test/cpp/simple_c_program/.vimspector.json index 7b8c53a..fb4c958 100644 --- a/support/test/cpp/simple_c_program/.vimspector.json +++ b/support/test/cpp/simple_c_program/.vimspector.json @@ -15,6 +15,15 @@ "program": "${workspaceRoot}/test", "stopAtEntry": true } + }, + "cpptools": { + "adapter": "vscode-cpptools", + "configuration": { + "request": "launch", + "program": "${workspaceRoot}/test", + "stopOnEntry": true, + "MIMode": "lldb" + } } } } From aacd62f09feed377c35930790514b2739fa08e51 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 15 May 2021 16:03:02 +0100 Subject: [PATCH 180/200] Rename AssertMatchist -> AssertMatchList --- tests/lib/plugin/shared.vim | 2 +- tests/stack_trace.test.vim | 56 ++++++++++++++++++------------------- tests/variables.test.vim | 44 ++++++++++++++--------------- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/tests/lib/plugin/shared.vim b/tests/lib/plugin/shared.vim index 70e297e..f98b8e9 100644 --- a/tests/lib/plugin/shared.vim +++ b/tests/lib/plugin/shared.vim @@ -99,7 +99,7 @@ function! ThisTestIsFlaky() let g:test_is_flaky = v:true endfunction -function! AssertMatchist( expected, actual ) abort +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 diff --git a/tests/stack_trace.test.vim b/tests/stack_trace.test.vim index f191201..b5ed795 100644 --- a/tests/stack_trace.test.vim +++ b/tests/stack_trace.test.vim @@ -30,7 +30,7 @@ function! Test_Multiple_Threads_Continue() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call cursor( 1, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( thread_l ) @@ -45,7 +45,7 @@ function! Test_Multiple_Threads_Continue() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call cursor( 1, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( thread_l ) @@ -56,7 +56,7 @@ function! Test_Multiple_Threads_Continue() \ ) \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -70,7 +70,7 @@ function! Test_Multiple_Threads_Continue() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call cursor( 1, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( thread_l ) @@ -81,7 +81,7 @@ function! Test_Multiple_Threads_Continue() \ ) \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -95,7 +95,7 @@ function! Test_Multiple_Threads_Continue() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call cursor( 1, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( thread_l ) @@ -106,7 +106,7 @@ function! Test_Multiple_Threads_Continue() \ ) \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -121,7 +121,7 @@ function! Test_Multiple_Threads_Continue() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call cursor( 1, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( thread_l ) @@ -132,7 +132,7 @@ function! Test_Multiple_Threads_Continue() \ ) \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -146,7 +146,7 @@ function! Test_Multiple_Threads_Continue() " So we break out of the loop call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, notify_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( notify_l ) @@ -157,7 +157,7 @@ function! Test_Multiple_Threads_Continue() \ ) \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -192,7 +192,7 @@ function! Test_Multiple_Threads_Step() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread [0-9]\+: .* (paused)', \ ' .*: .*@threads.cpp:' . string( thread_l ) @@ -205,7 +205,7 @@ function! Test_Multiple_Threads_Step() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_n, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -218,7 +218,7 @@ function! Test_Multiple_Threads_Step() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ ], @@ -230,7 +230,7 @@ function! Test_Multiple_Threads_Step() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_n, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -244,7 +244,7 @@ function! Test_Multiple_Threads_Step() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -257,7 +257,7 @@ function! Test_Multiple_Threads_Step() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_n, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -273,7 +273,7 @@ function! Test_Multiple_Threads_Step() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -287,7 +287,7 @@ function! Test_Multiple_Threads_Step() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_n, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -304,7 +304,7 @@ function! Test_Multiple_Threads_Step() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -319,7 +319,7 @@ function! Test_Multiple_Threads_Step() call vimspector#StepOver() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, thread_n, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -338,7 +338,7 @@ function! Test_Multiple_Threads_Step() " So we break out of the loop call vimspector#test#signs#AssertCursorIsAtLineInBuffer( s:fn, notify_l, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '+ Thread [0-9]\+: .* (paused)', \ '+ Thread [0-9]\+: .* (paused)', @@ -366,7 +366,7 @@ function! Test_UpDownStack() call vimspector#LaunchWithSettings( { 'configuration': 'run' } ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread 1: MainThread (paused)', \ ' 2: DoSomething@main.py:15', @@ -397,7 +397,7 @@ function! Test_UpDownStack() call vimspector#DownFrame() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread 1: MainThread (paused)', \ ' 2: DoSomething@main.py:15', @@ -429,7 +429,7 @@ function! Test_UpDownStack() call vimspector#UpFrame() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread 1: MainThread (paused)', \ ' 2: DoSomething@main.py:15', @@ -461,7 +461,7 @@ function! Test_UpDownStack() call feedkeys( "\VimspectorUpFrame", 'x' ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 23, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread 1: MainThread (paused)', \ ' 2: DoSomething@main.py:15', @@ -493,7 +493,7 @@ function! Test_UpDownStack() call feedkeys( "\VimspectorDownFrame", 'x' ) call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 8, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread 1: MainThread (paused)', \ ' 2: DoSomething@main.py:15', @@ -525,7 +525,7 @@ function! Test_UpDownStack() call vimspector#DownFrame() call vimspector#test#signs#AssertCursorIsAtLineInBuffer( fn, 15, 1 ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Thread 1: MainThread (paused)', \ ' 2: DoSomething@main.py:15', diff --git a/tests/variables.test.vim b/tests/variables.test.vim index c7d373b..59ca2c0 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -211,7 +211,7 @@ function! Test_ExpandVariables() call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' \*- t (Test): {...}', @@ -229,7 +229,7 @@ function! Test_ExpandVariables() " Step - stays expanded call vimspector#StepOver() call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' - t (Test): {...}', @@ -278,7 +278,7 @@ function! Test_ExpandVariables() call setpos( '.', [ 0, 2, 1 ] ) call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' - t (Test): {...}', @@ -378,7 +378,7 @@ function! Test_ExpandWatch() call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: t', @@ -397,7 +397,7 @@ function! Test_ExpandWatch() " Step - stays expanded call vimspector#StepOver() call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: t', @@ -449,7 +449,7 @@ function! Test_ExpandWatch() call setpos( '.', [ 0, 3, 1 ] ) call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: t', @@ -607,7 +607,7 @@ function! Test_EvaluateFailure() " Add a wtch call vimspector#AddWatch( 'test' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: test', @@ -658,7 +658,7 @@ function! Test_VariableEval() \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', @@ -690,7 +690,7 @@ function! Test_VariableEval() \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', @@ -724,7 +724,7 @@ function! Test_VariableEval() \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Evaluation error', \ ], @@ -768,7 +768,7 @@ function! Test_VariableEvalExpand() \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', @@ -786,7 +786,7 @@ function! Test_VariableEvalExpand() call feedkeys( "jjjj\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', @@ -806,7 +806,7 @@ function! Test_VariableEvalExpand() call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', @@ -863,7 +863,7 @@ function! Test_SetVariableValue_Local() call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' \*- t (Test): {...}', @@ -889,7 +889,7 @@ with mock.patch( 'vimspector.utils.InputSave' ): EOF call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' \*- t (Test): {...}', @@ -908,7 +908,7 @@ EOF call vimspector#SetVariableValue( '1234' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' \*- t (Test): {...}', @@ -927,7 +927,7 @@ EOF call vimspector#SetVariableValue( 'this is invalid' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '- Scope: Locals', \ ' \*- t (Test): {...}', @@ -983,7 +983,7 @@ function! Test_SetVariableValue_Watch() call feedkeys( "\", 'xt' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: t', @@ -1012,7 +1012,7 @@ EOF call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: t', @@ -1032,7 +1032,7 @@ EOF call vimspector#SetVariableValue( '1234' ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ 'Watches: ----', \ 'Expression: t', @@ -1075,7 +1075,7 @@ function! Test_SetVariableValue_Balloon() \ } ) call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', @@ -1102,7 +1102,7 @@ with mock.patch( 'vimspector.utils.InputSave' ): EOF call WaitForAssert( {-> - \ AssertMatchist( + \ AssertMatchList( \ [ \ '{...}', \ ' - i: 0', From d43904eb57c2771c6ba05b48c47da5ff2bbb9735 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sat, 15 May 2021 17:55:01 +0100 Subject: [PATCH 181/200] Add basic VimspectorDebugInfo command --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ++++++ README.md | 2 ++ autoload/vimspector.vim | 8 +++++++ plugin/vimspector.vim | 3 +++ python3/vimspector/debug_session.py | 31 ++++++++++++++++++++++++++++ python3/vimspector/output.py | 26 ++++++++++++++++++----- 6 files changed, 71 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f01a833..828ec18 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -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` ``` diff --git a/README.md b/README.md index bf84d2f..f8db3aa 100644 --- a/README.md +++ b/README.md @@ -1070,6 +1070,8 @@ 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: diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 1219661..78c7c1b 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -557,6 +557,14 @@ 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 diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 27ce473..2668bf1 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -115,6 +115,9 @@ 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( ) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 2f132f9..36ad62b 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -1270,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 diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index c453417..8c94b44 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -64,8 +64,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' ) @@ -104,13 +107,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 From daa8865feab2ec32a60ab2fb11b6f33a0cdeadb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 May 2021 10:56:04 +0000 Subject: [PATCH 182/200] 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] --- docs/Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 6a18520..0fa7776 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -205,14 +205,14 @@ GEM rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) - mini_portile2 (2.5.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.4) multipart-post (2.1.1) - nokogiri (1.11.3) + nokogiri (1.11.5) mini_portile2 (~> 2.5.0) racc (~> 1.4) octokit (4.20.0) From a51b8b23c9b7e12c2899e423037458d46dbe196e Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 25 May 2021 14:53:29 +0100 Subject: [PATCH 183/200] Fix traceback if the current frame isn't set --- python3/vimspector/stack_trace.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index f9540ba..8b1d848 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -560,7 +560,8 @@ class StackTraceView( object ): source[ 'name' ], frame[ 'line' ] ) ) - if self._current_frame[ 'id' ] == frame[ 'id' ]: + if ( self._current_frame is not None and + self._current_frame[ 'id' ] == frame[ 'id' ] ): signs.PlaceSign( self._current_frame_sign_id, 'VimspectorStackTrace', 'vimspectorCurrentFrame', From 5ea1f0d9d49011259ecedb70df94c6ff799ead62 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Mon, 7 Jun 2021 14:10:44 +0200 Subject: [PATCH 184/200] Upgrade vscode-php-debug to 1.16.0 --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 62321ae..23a298c 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -323,10 +323,10 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.15.1', - 'file_name': 'php-debug-1.15.1.vsix', + 'version': 'v1.16.0', + 'file_name': 'php-debug-1.16.0.vsix', 'checksum': - '10222655d4179c7d109b1f951d88034eba772b45bf6141dcdb4e9b4477d2e2ab', + '62d210f7b87b21315c37ea10a1a5dbae376ff9f963b8f8cf33361e01413731be', }, 'adapters': { 'vscode-php-debug': { From 0500e41429bde17105e931d9920b3c6dbe5eabdb Mon Sep 17 00:00:00 2001 From: Paulo Date: Wed, 9 Jun 2021 19:24:37 +0200 Subject: [PATCH 185/200] FIx typo in configuration.md A small typo that wastes time for people that copy and modify the config file --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index a2864b1..3d524bf 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -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": "${fileBasenameNoExtention}" + "ServiceName": "${fileBasenameNoExtension}" }, "adapter": "python-remote", From 5075f3a11aba4e31cb7994746862a4342c8546ae Mon Sep 17 00:00:00 2001 From: Simon Drake Date: Thu, 24 Jun 2021 14:40:40 +0100 Subject: [PATCH 186/200] Add a runnable Go example --- README.md | 2 +- .../name-starts-with-vowel/.vimspector.json | 29 ++++++++++++++++ .../test/go/name-starts-with-vowel/README.md | 33 +++++++++++++++++++ .../cmd/namestartswithvowel/main.go | 20 +++++++++++ support/test/go/name-starts-with-vowel/go.mod | 3 ++ .../internal/vowels/vowels.go | 9 +++++ .../internal/vowels/vowels_test.go | 30 +++++++++++++++++ 7 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 support/test/go/name-starts-with-vowel/.vimspector.json create mode 100644 support/test/go/name-starts-with-vowel/README.md create mode 100644 support/test/go/name-starts-with-vowel/cmd/namestartswithvowel/main.go create mode 100644 support/test/go/name-starts-with-vowel/go.mod create mode 100644 support/test/go/name-starts-with-vowel/internal/vowels/vowels.go create mode 100644 support/test/go/name-starts-with-vowel/internal/vowels/vowels_test.go diff --git a/README.md b/README.md index f8db3aa..66f2720 100644 --- a/README.md +++ b/README.md @@ -290,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`) +* Go (`support/test/go/hello_world` and `support/test/go/name-starts-with-vowel`) * Nodejs (`support/test/node/simple`) * Chrome (`support/test/chrome/`) * etc. diff --git a/support/test/go/name-starts-with-vowel/.vimspector.json b/support/test/go/name-starts-with-vowel/.vimspector.json new file mode 100644 index 0000000..ffcfc93 --- /dev/null +++ b/support/test/go/name-starts-with-vowel/.vimspector.json @@ -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": [] + } + } + } +} diff --git a/support/test/go/name-starts-with-vowel/README.md b/support/test/go/name-starts-with-vowel/README.md new file mode 100644 index 0000000..fec967e --- /dev/null +++ b/support/test/go/name-starts-with-vowel/README.md @@ -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 +} +``` diff --git a/support/test/go/name-starts-with-vowel/cmd/namestartswithvowel/main.go b/support/test/go/name-starts-with-vowel/cmd/namestartswithvowel/main.go new file mode 100644 index 0000000..c160aea --- /dev/null +++ b/support/test/go/name-starts-with-vowel/cmd/namestartswithvowel/main.go @@ -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) + } +} diff --git a/support/test/go/name-starts-with-vowel/go.mod b/support/test/go/name-starts-with-vowel/go.mod new file mode 100644 index 0000000..3070734 --- /dev/null +++ b/support/test/go/name-starts-with-vowel/go.mod @@ -0,0 +1,3 @@ +module example.com + +go 1.16 diff --git a/support/test/go/name-starts-with-vowel/internal/vowels/vowels.go b/support/test/go/name-starts-with-vowel/internal/vowels/vowels.go new file mode 100644 index 0000000..4e76480 --- /dev/null +++ b/support/test/go/name-starts-with-vowel/internal/vowels/vowels.go @@ -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" +} diff --git a/support/test/go/name-starts-with-vowel/internal/vowels/vowels_test.go b/support/test/go/name-starts-with-vowel/internal/vowels/vowels_test.go new file mode 100644 index 0000000..e0d5773 --- /dev/null +++ b/support/test/go/name-starts-with-vowel/internal/vowels/vowels_test.go @@ -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) + } + }) + } +} From 21ebb22fd44c586f6b22ef393012863b6502a010 Mon Sep 17 00:00:00 2001 From: przepompownia Date: Sun, 4 Jul 2021 23:00:32 +0200 Subject: [PATCH 187/200] Upgrade vscode-php-debug to 1.16.1 --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 23a298c..240fc68 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -323,10 +323,10 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.16.0', - 'file_name': 'php-debug-1.16.0.vsix', + 'version': 'v1.16.1', + 'file_name': 'php-debug-1.16.1.vsix', 'checksum': - '62d210f7b87b21315c37ea10a1a5dbae376ff9f963b8f8cf33361e01413731be', + '2eb6ff1100b6b3d2d160f243858f3524e269078b8154e108d015882e2c0d52c4', }, 'adapters': { 'vscode-php-debug': { From 3af97f192841247a2891c021d935a2e4f15db7c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 05:43:17 +0000 Subject: [PATCH 188/200] 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] --- docs/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 0fa7776..acf20f2 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -7,7 +7,7 @@ GEM 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 From 59c9cd10ab9073b91a11ccd9b21c34d8331fa9cb Mon Sep 17 00:00:00 2001 From: przepompownia Date: Mon, 2 Aug 2021 16:11:04 +0200 Subject: [PATCH 189/200] Upgrade vscode-php-debug to 1.17.0 --- python3/vimspector/gadgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 240fc68..170956a 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -323,10 +323,10 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.16.1', - 'file_name': 'php-debug-1.16.1.vsix', + 'version': 'v1.17.0', + 'file_name': 'php-debug-1.17.0.vsix', 'checksum': - '2eb6ff1100b6b3d2d160f243858f3524e269078b8154e108d015882e2c0d52c4', + 'd0fff272503414b6696cc737bc2e18e060fdd5e5dc4bcaf38ae7373afd8d8bc9', }, 'adapters': { 'vscode-php-debug': { From f1e2c12e5bfbb0b9abd1dec75ad8d2810ecc4fc9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 2 Aug 2021 16:01:47 +0100 Subject: [PATCH 190/200] Update codelldb Add a way to checksum downloads and a little guide to updating gadgets --- python3/vimspector/gadgets.py | 8 ++++---- run_tests | 4 ++-- support/gadget_upgrade/README.md | 8 ++++++++ support/gadget_upgrade/checksum.py | 13 +++++++++++++ 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 support/gadget_upgrade/README.md create mode 100755 support/gadget_upgrade/checksum.py diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 170956a..72f13c8 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -394,12 +394,12 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.6.1', + 'version': 'v1.6.5', }, 'macos': { 'file_name': 'codelldb-x86_64-darwin.vsix', 'checksum': - 'b1c998e7421beea9f3ba21aa5706210bb2249eba93c99b809247ee831075262f', + 'e7d9f4f8ec3c3774af6d1dbf11f0568db1417c4d51038927228cd07028725594', 'make_executable': [ 'adapter/codelldb', 'lldb/bin/debugserver', @@ -410,7 +410,7 @@ GADGETS = { 'linux': { 'file_name': 'codelldb-x86_64-linux.vsix', 'checksum': - 'f2a36cb6971fd95a467cf1a7620e160914e8f11bf82929932ee0aa5afbf6ae6a', + 'eda2cd9b3089dcc0524c273e91ffb5875fe08c930bf643739a2cd1846e1f98d6', 'make_executable': [ 'adapter/codelldb', 'lldb/bin/lldb', @@ -421,7 +421,7 @@ GADGETS = { 'windows': { 'file_name': 'codelldb-x86_64-windows.vsix', 'checksum': - 'ca6a6525bf7719dc95265dc630b3cc817a8c0393b756fd242b710805ffdfb940', + '8ddebe8381a3d22dc3d95139c3797fda06b5cc34aadf300e13b1c516b9da95fe', 'make_executable': [] }, 'adapters': { diff --git a/run_tests b/run_tests index 441acb0..201ec1b 100755 --- a/run_tests +++ b/run_tests @@ -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 ;; diff --git a/support/gadget_upgrade/README.md b/support/gadget_upgrade/README.md new file mode 100644 index 0000000..9ae3d7f --- /dev/null +++ b/support/gadget_upgrade/README.md @@ -0,0 +1,8 @@ +# Manually updating shipped gadgets + +Download the gadget files manuall from their official source into this dir. +Run `./checksum.py ` to get the checksums. + +Update ../../python3/vimspector/gadgets.py with the new version and the +checksums. + diff --git a/support/gadget_upgrade/checksum.py b/support/gadget_upgrade/checksum.py new file mode 100755 index 0000000..d0c1404 --- /dev/null +++ b/support/gadget_upgrade/checksum.py @@ -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 ) }" ) From 57ce0992803fcf22c0557550fff45e3fe869f707 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 3 Aug 2021 17:29:55 +0100 Subject: [PATCH 191/200] SHow the output in the console, as this is where codelldb puts it --- python3/vimspector/output.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index 8c94b44..3f0da1e 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -32,6 +32,7 @@ class TabBuffer( object ): BUFFER_MAP = { 'console': 'Console', 'stdout': 'Console', + 'output': 'Console', 'stderr': 'stderr', 'telemetry': None, } From 7c7e3f9c3f63de7ef91e5d579662a4e16be95315 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 20 Aug 2021 11:17:05 +0100 Subject: [PATCH 192/200] Add config for bash to tests --- support/test/bash/.vimspector.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 support/test/bash/.vimspector.json diff --git a/support/test/bash/.vimspector.json b/support/test/bash/.vimspector.json new file mode 100644 index 0000000..a1be1b9 --- /dev/null +++ b/support/test/bash/.vimspector.json @@ -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}" ] + } + } + } +} From a720d0e1d56743bb1f335b2a4bcb963491e9b421 Mon Sep 17 00:00:00 2001 From: roachsinai Date: Sat, 21 Aug 2021 00:57:27 +0800 Subject: [PATCH 193/200] Fix error: E806: using Float as a String. --- support/custom_ui_vimrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support/custom_ui_vimrc b/support/custom_ui_vimrc index a8812cb..e76c6ee 100644 --- a/support/custom_ui_vimrc +++ b/support/custom_ui_vimrc @@ -54,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() From 51d78fce5f95fb10ba84b8ab66e97d44d75df010 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 7 Sep 2021 17:00:04 +0100 Subject: [PATCH 194/200] Note on using legacy vscode-dap --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 66f2720..3420d56 100644 --- a/README.md +++ b/README.md @@ -1368,6 +1368,8 @@ 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": { @@ -1385,7 +1387,7 @@ Requires: ``` See the vscode-go docs for -[troubleshooting information](https://github.com/golang/vscode-go/blob/master/docs/debugging.md#troubleshooting) +[troubleshooting information](https://github.com/golang/vscode-go/blob/master/docs/debugging-legacy.md#troubleshooting) ## PHP From 46cfdc678dbdbb162f8cb8ab4384897e1a3d3bd0 Mon Sep 17 00:00:00 2001 From: Sebastian Goth Date: Wed, 8 Sep 2021 12:19:51 +0200 Subject: [PATCH 195/200] Update vscode-cpptools from 0.27.0 to 1.6.0 --- python3/vimspector/gadgets.py | 10 +++++----- python3/vimspector/installer.py | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index 72f13c8..dda962d 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -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', 'checksum': - 'cb061e3acd7559a539e5586f8d3f535101c4ec4e8a48195856d1d39380b5cf3c', + 'ae21cde361335b350402904991cf9f746fec685449ca9bd5d50227c3dec3719b', }, 'windows': { 'file_name': 'cpptools-win32.vsix', 'checksum': - 'aa294368ed16d48c59e49c8000e146eae5a19ad07b654efed5db8ec93b24229e', + 'ef7ac5831874a3c7dbf0feb826bfda2be579aff9b6d990622fff1d0d4ede00d1', "adapters": { "vscode-cpptools": { "name": "cppdbg", diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index f0f85a4..a81db8f 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -358,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' ] From 561a5b9aa2c0c0a9f801b12af3cd7ef861fad962 Mon Sep 17 00:00:00 2001 From: Sebastian Goth Date: Wed, 8 Sep 2021 21:36:37 +0200 Subject: [PATCH 196/200] Update variables tests to expect register scope vscode-cpptools 1.6.0 now reports an additional scope 'Registers' after 'Locals'. --- tests/variables.test.vim | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/variables.test.vim b/tests/variables.test.vim index 59ca2c0..c00fb7f 100644 --- a/tests/variables.test.vim +++ b/tests/variables.test.vim @@ -194,6 +194,7 @@ function! Test_ExpandVariables() \ [ \ '- Scope: Locals', \ ' *+ t (Test): {...}', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -219,6 +220,7 @@ function! Test_ExpandVariables() \ ' \*- c (char): 0 ''\\0\{1,3}''', \ ' \*- fffff (float): 0', \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -237,6 +239,7 @@ function! Test_ExpandVariables() \ ' - c (char): 0 ''\\0\{1,3}''', \ ' - fffff (float): 0', \ ' + another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -253,6 +256,7 @@ function! Test_ExpandVariables() \ [ \ '- Scope: Locals', \ ' + t (Test): {...}', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -267,6 +271,7 @@ function! Test_ExpandVariables() \ [ \ '- Scope: Locals', \ ' + t (Test): {...}', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -286,6 +291,7 @@ function! Test_ExpandVariables() \ ' \*- c (char): 99 ''c''', \ ' \*- fffff (float): 0', \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -302,6 +308,7 @@ function! Test_ExpandVariables() \ assert_equal( \ [ \ '+ Scope: Locals', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -316,6 +323,7 @@ function! Test_ExpandVariables() \ assert_equal( \ [ \ '+ Scope: Locals', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -331,6 +339,7 @@ function! Test_ExpandVariables() \ assert_equal( \ [ \ '+ Scope: Locals', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -846,6 +855,7 @@ function! Test_SetVariableValue_Local() \ [ \ '- Scope: Locals', \ ' *+ t (Test): {...}', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -871,6 +881,7 @@ function! Test_SetVariableValue_Local() \ ' \*- c (char): 0 ''\\0\{1,3}''', \ ' \*- fffff (float): 0', \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -897,6 +908,7 @@ EOF \ ' \*- c (char): 0 ''\\0\{1,3}''', \ ' \*- fffff (float): 0', \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -916,6 +928,7 @@ EOF \ ' \*- c (char): 0 ''\\0\{1,3}''', \ ' \*- fffff (float): 0', \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, @@ -935,6 +948,7 @@ EOF \ ' \*- c (char): 0 ''\\0\{1,3}''', \ ' \*- fffff (float): 0', \ ' \*+ another_test (AnotherTest):\( {...}\)\?', + \ '+ Scope: Registers', \ ], \ getbufline( winbufnr( g:vimspector_session_windows.variables ), \ 1, From 17ca1522f8a0cca53c8ab75a680f27ea58b50de3 Mon Sep 17 00:00:00 2001 From: Sebastian Goth Date: Wed, 8 Sep 2021 23:16:47 +0200 Subject: [PATCH 197/200] Use correct spelling of MIMode in tests --- tests/testdata/cpp/simple/.vimspector.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testdata/cpp/simple/.vimspector.json b/tests/testdata/cpp/simple/.vimspector.json index 0dca061..48ce801 100644 --- a/tests/testdata/cpp/simple/.vimspector.json +++ b/tests/testdata/cpp/simple/.vimspector.json @@ -12,7 +12,7 @@ "externalConsole": false, "stopAtEntry": true, "stopOnEntry": true, - "MImode": "${VIMSPECTOR_MIMODE}" + "MIMode": "${VIMSPECTOR_MIMODE}" }, "breakpoints": { "exception": { @@ -33,7 +33,7 @@ "externalConsole": false, "stopAtEntry": false, "stopOnEntry": false, - "MImode": "${VIMSPECTOR_MIMODE}" + "MIMode": "${VIMSPECTOR_MIMODE}" }, "breakpoints": { "exception": { @@ -55,7 +55,7 @@ "externalConsole": false, "stopAtEntry": false, "stopOnEntry": false, - "MImode": "${VIMSPECTOR_MIMODE}" + "MIMode": "${VIMSPECTOR_MIMODE}" }, "breakpoints": { "exception": { @@ -82,7 +82,7 @@ "configuration": { "request": "launch", "program": "${workspaceRoot}/${fileBasenameNoExtension}", - "MImode": "${VIMSPECTOR_MIMODE}", + "MIMode": "${VIMSPECTOR_MIMODE}", "externalConsole": false, "args": [ "CALCULATED_LIST", "${CALCULATED_LIST}", From db5ed8e80228fbb5366e6fc7629e430f886d2b34 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 8 Sep 2021 22:20:33 +0100 Subject: [PATCH 198/200] Update to ubuntu 18.04 as 16.04 is deprecated --- .github/workflows/build.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 14f5979..f186f5d 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -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,7 +32,7 @@ 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 @@ -156,7 +156,7 @@ jobs: # SSH_PASS: ${{ secrets.SSH_PASS }} # [V]imspector PublishRelease: - runs-on: 'ubuntu-16.04' + runs-on: 'ubuntu-18.04' needs: - Linux - MacOS From dc862fe565a74a9810f37edaa8d0e1bb7bbdd79d Mon Sep 17 00:00:00 2001 From: Sebastian Goth Date: Thu, 9 Sep 2021 16:42:49 +0200 Subject: [PATCH 199/200] Readme: pretty printing with vscode-cpptools / gdb --- README.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3420d56..d198292 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,10 @@ 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) - * [C Remote debugging](#c-remote-debugging) - * [C Remote launch and attach](#c-remote-launch-and-attach) + * [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) * [Rust](#rust) * [Python](#python) * [Python Remote Debugging](#python-remote-debugging) @@ -1176,6 +1177,38 @@ 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": "", + ... + "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 From 7c12519b9d87f261abfff62f4f197c693a0ffb4f Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Fri, 10 Sep 2021 10:30:44 -0600 Subject: [PATCH 200/200] Modify for mac m1 --- python3/vimspector/gadgets.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py index dda962d..02eb0e7 100644 --- a/python3/vimspector/gadgets.py +++ b/python3/vimspector/gadgets.py @@ -56,9 +56,9 @@ GADGETS = { 'c25299bcfb46b22d41aa3f125df7184e6282a35ff9fb69c47def744cb4778f55', }, 'macos': { - 'file_name': 'cpptools-osx.vsix', + 'file_name': 'cpptools-osx-arm64.vsix', 'checksum': - 'ae21cde361335b350402904991cf9f746fec685449ca9bd5d50227c3dec3719b', + 'ceb3e8cdaa2b5bb45af50913ddd8402089969748af8d70f5d46480408287ba6f', }, 'windows': { 'file_name': 'cpptools-win32.vsix', @@ -394,12 +394,12 @@ GADGETS = { '${version}/${file_name}', }, 'all': { - 'version': 'v1.6.5', + 'version': 'v1.6.6', }, 'macos': { - 'file_name': 'codelldb-x86_64-darwin.vsix', + 'file_name': 'codelldb-aarch64-darwin.vsix', 'checksum': - 'e7d9f4f8ec3c3774af6d1dbf11f0568db1417c4d51038927228cd07028725594', + '5adc3b9139eabdafd825bd5efc55df4424a203fb2b6087b425cd434956e7ec58', 'make_executable': [ 'adapter/codelldb', 'lldb/bin/debugserver',