From d3fd0a38f097e0259c1fa0d4db45e72798cf24e9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 27 May 2020 21:15:00 +0100 Subject: [PATCH 01/23] Refactor installer fully into installer module --- install_gadget.py | 646 +------------------------------- python3/vimspector/gadgets.py | 490 ++++++++++++++++++++++++ python3/vimspector/installer.py | 207 +++++++++- 3 files changed, 692 insertions(+), 651 deletions(-) create mode 100644 python3/vimspector/gadgets.py diff --git a/install_gadget.py b/install_gadget.py index f805e80..af2794e 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -23,9 +23,6 @@ if sys.version_info.major < 3: import argparse import os -import string -import subprocess -import traceback import json import functools import operator @@ -35,628 +32,9 @@ import glob sys.path.insert( 1, os.path.join( os.path.dirname( __file__ ), 'python3' ) ) -from vimspector import install, installer +from vimspector import install, installer, gadgets from vimspector.vendor.json_minify import minify -GADGETS = { - '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" - } - }, - }, - }, - }, - 'vscode-python': { - 'language': 'python.legacy', - 'enabled': False, - 'download': { - 'url': 'https://github.com/Microsoft/vscode-python/releases/download/' - '${version}/${file_name}', - }, - 'all': { - 'version': '2019.11.50794', - 'file_name': 'ms-python-release.vsix', - 'checksum': - '6a9edf9ecabed14aac424e6007858068204a3638bf3bb4f235bd6035d823acc6', - }, - 'adapters': { - "vscode-python": { - "name": "vscode-python", - "command": [ - "node", - "${gadgetDir}/vscode-python/out/client/debugger/debugAdapter/main.js", - ], - } - }, - }, - 'debugpy': { - 'language': 'python', - 'download': { - 'url': 'https://github.com/microsoft/debugpy/archive/${file_name}' - }, - 'all': { - 'version': '1.0.0b12', - 'file_name': 'v1.0.0b12.zip', - 'checksum': - '210632bba2221fbb841c9785a615258819ceec401d1abdbeb5f2326f12cc72a1' - }, - 'do': lambda name, root, gadget: InstallDebugpy( name, root, gadget ), - 'adapters': { - 'debugpy': { - "command": [ - sys.executable, - "${gadgetDir}/debugpy/build/lib/debugpy/adapter" - ], - "name": "debugpy", - "configuration": { - "python": sys.executable, - # 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}", - } - }, - }, - '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': 'master' - }, - '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", - ] - } - } - }, - }, - 'netcoredbg': { - 'language': 'csharp', - 'enabled': False, - 'download': { - 'url': 'https://github.com/Samsung/netcoredbg/releases/download/latest/' - '${file_name}', - 'format': 'tar', - }, - 'all': { - 'version': 'master' - }, - 'macos': { - 'file_name': 'netcoredbg-osx-master.tar.gz', - 'checksum': - 'c1dc6ed58c3f5b0473cfb4985a96552999360ceb9795e42d9c9be64af054f821', - }, - 'linux': { - 'file_name': 'netcoredbg-linux-master.tar.gz', - 'checksum': '', - }, - 'windows': { - 'file_name': 'netcoredbg-win64-master.zip', - 'checksum': '', - }, - 'do': lambda name, root, gadget: installer.MakeSymlink( - gadget_dir, - name, - os.path.join( root, 'netcoredbg' ) ), - 'adapters': { - 'netcoredbg': { - "name": "netcoredbg", - "command": [ - "${gadgetDir}/netcoredbg/netcoredbg", - "--interpreter=vscode" - ], - "attach": { - "pidProperty": "processId", - "pidSelect": "ask" - }, - }, - } - }, - 'vscode-mono-debug': { - 'language': 'csharp', - 'enabled': False, - 'download': { - 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' - 'publishers/ms-vscode/vsextensions/mono-debug/${version}/' - 'vspackage', - 'target': 'vscode-mono-debug.vsix.gz', - 'format': 'zip.gz', - }, - 'all': { - 'file_name': 'vscode-mono-debug.vsix', - 'version': '0.15.8', - 'checksum': - '723eb2b621b99d65a24f215cb64b45f5fe694105613a900a03c859a62a810470', - }, - 'adapters': { - 'vscode-mono-debug': { - "name": "mono-debug", - "command": [ - "mono", - "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" - ], - "attach": { - "pidSelect": "none" - }, - }, - } - }, - '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", - } - } - } - }, - 'vscode-go': { - 'language': 'go', - 'download': { - 'url': 'https://github.com/microsoft/vscode-go/releases/download/' - '${version}/${file_name}' - }, - 'all': { - 'version': '0.11.4', - 'file_name': 'Go-0.11.4.vsix', - 'checksum': - 'ff7d7b944da5448974cb3a0086f4a2fd48e2086742d9c013d6964283d416027e' - }, - 'adapters': { - 'vscode-go': { - 'name': 'delve', - 'command': [ - 'node', - '${gadgetDir}/vscode-go/out/src/debugAdapter/goDebug.js' - ], - }, - }, - }, - '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", - ] - } - } - }, - 'vscode-node-debug2': { - 'language': 'node', - 'enabled': False, - 'repo': { - 'url': 'https://github.com/microsoft/vscode-node-debug2', - 'ref': 'v1.42.0', - }, - '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' - ] - }, - }, - }, - '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.0.vsix.gz', - 'format': 'zip.gz', - }, - 'all': { - 'version': '4.12.0', - 'file_name': 'msjsdiag.debugger-for-chrome-4.12.0.vsix', - 'checksum': - '0df2fe96d059a002ebb0936b0003e6569e5a5c35260dc3791e1657d27d82ccf5' - }, - 'adapters': { - 'chrome': { - 'name': 'debugger-for-chrome', - 'type': 'chrome', - 'command': [ - 'node', - '${gadgetDir}/debugger-for-chrome/out/src/chromeDebug.js' - ], - }, - }, - }, - 'CodeLLDB': { - 'language': 'rust', - 'enabled': False, - '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", - } - }, - }, - }, -} - - -def InstallGeneric( name, root, gadget ): - extension = os.path.join( root, 'extension' ) - for f in gadget.get( 'make_executable', [] ): - installer.MakeExecutable( os.path.join( extension, f ) ) - - installer.MakeExtensionSymlink( vimspector_base, 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. - 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( vimspector_base, name, root ) - - -def InstallBashDebug( name, root, gadget ): - installer.MakeExecutable( os.path.join( root, - 'extension', - 'bashdb_dir', - 'bashdb' ) ) - installer.MakeExtensionSymlink( vimspector_base, name, root ) - - -def InstallDebugpy( name, root, gadget ): - wd = os.getcwd() - root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) ) - os.chdir( root ) - try: - subprocess.check_call( [ sys.executable, 'setup.py', 'build' ] ) - finally: - os.chdir( wd ) - - installer.MakeSymlink( gadget_dir, name, root ) - - -def InstallTclProDebug( name, root, gadget ): - configure = [ './configure' ] - - if OS == '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' ) ): - subprocess.check_call( configure ) - subprocess.check_call( [ 'make' ] ) - - installer.MakeSymlink( gadget_dir, name, root ) - - -def InstallNodeDebug( name, root, gadget ): - node_version = subprocess.check_output( [ 'node', '--version' ], - universal_newlines=True ).strip() - print( "Node.js version: {}".format( node_version ) ) - if list( map( int, node_version[ 1: ].split( '.' ) ) ) >= [ 12, 0, 0 ]: - print( "Can't install vscode-debug-node2:" ) - print( "Sorry, you appear to be running node 12 or later. That's not " - "compatible with the build system for this extension, and as far as " - "we know, there isn't a pre-built independent package." ) - print( "My advice is to install nvm, then do:" ) - print( " $ nvm install --lts 10" ) - print( " $ nvm use --lts 10" ) - print( " $ ./install_gadget.py --enable-node ..." ) - raise RuntimeError( 'Invalid node environent for node debugger' ) - - with installer.CurrentWorkingDir( root ): - subprocess.check_call( [ 'npm', 'install' ] ) - subprocess.check_call( [ 'npm', 'run', 'build' ] ) - installer.MakeSymlink( gadget_dir, name, root ) - - -def InstallGagdet( name, gadget, failed, all_adapters ): - try: - v = {} - v.update( gadget.get( 'all', {} ) ) - v.update( gadget.get( OS, {} ) ) - - if 'download' in gadget: - if 'file_name' not in v: - raise RuntimeError( "Unsupported OS {} for gadget {}".format( OS, - name ) ) - - destination = os.path.join( gadget_dir, 'download', name, v[ 'version' ] ) - - url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( v ) - - file_path = installer.DownloadFileTo( - url, - destination, - file_name = gadget[ 'download' ].get( 'target' ), - checksum = v.get( 'checksum' ), - check_certificate = not args.no_check_certificate ) - - root = os.path.join( destination, 'root' ) - installer.ExtractZipTo( - file_path, - root, - format = gadget[ 'download' ].get( 'format', 'zip' ) ) - elif 'repo' in gadget: - url = string.Template( gadget[ 'repo' ][ 'url' ] ).substitute( v ) - ref = string.Template( gadget[ 'repo' ][ 'ref' ] ).substitute( v ) - - destination = os.path.join( gadget_dir, 'download', name ) - installer.CloneRepoTo( url, ref, destination ) - root = destination - - if 'do' in gadget: - gadget[ 'do' ]( name, root, v ) - else: - InstallGeneric( name, root, v ) - - # Allow per-OS adapter overrides. v already did that for us... - all_adapters.update( v.get( 'adapters', {} ) ) - # Add any other "all" adapters - all_adapters.update( gadget.get( 'adapters', {} ) ) - - print( "Done installing {}".format( name ) ) - except Exception as e: - traceback.print_exc() - failed.append( name ) - print( "FAILED installing {}: {}".format( name, e ) ) - - # ------------------------------------------------------------------------------ # Entry point # ------------------------------------------------------------------------------ @@ -723,7 +101,7 @@ parser.add_argument( '--sudo', "run this as root via sudo, pass this flag." ) done_languages = set() -for name, gadget in GADGETS.items(): +for name, gadget in gadgets.GADGETS.items(): lang = gadget[ 'language' ] if lang in done_languages: continue @@ -766,12 +144,8 @@ if args.basedir: vimspector_base = os.path.abspath( args.basedir ) install.MakeInstallDirs( vimspector_base ) - -OS = install.GetOS() -gadget_dir = install.GetGadgetDir( vimspector_base, OS ) - -print( 'OS = ' + OS ) -print( 'gadget_dir = ' + gadget_dir ) +installer.Configure( vimspector_base = vimspector_base, + no_check_certificate = args.no_check_certificate ) if args.force_all and not args.all: args.all = True @@ -803,7 +177,7 @@ all_adapters.update( { }, } ) -for name, gadget in 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' ] ) ): @@ -814,14 +188,14 @@ for name, gadget in GADGETS.items(): if getattr( args, 'disable_' + gadget[ 'language' ] ): continue - InstallGagdet( name, - gadget, - failed, - all_adapters ) + installer.InstallGagdet( name, + gadget, + failed, + all_adapters ) for name, gadget in CUSTOM_GADGETS.items(): - InstallGagdet( name, gadget, failed, all_adapters ) + installer.InstallGagdet( name, gadget, failed, all_adapters ) adapter_config = json.dumps ( { 'adapters': all_adapters }, indent=2, diff --git a/python3/vimspector/gadgets.py b/python3/vimspector/gadgets.py new file mode 100644 index 0000000..a96c9f5 --- /dev/null +++ b/python3/vimspector/gadgets.py @@ -0,0 +1,490 @@ +# 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 installer +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" + } + }, + }, + }, + }, + 'vscode-python': { + 'language': 'python.legacy', + 'enabled': False, + 'download': { + 'url': 'https://github.com/Microsoft/vscode-python/releases/download/' + '${version}/${file_name}', + }, + 'all': { + 'version': '2019.11.50794', + 'file_name': 'ms-python-release.vsix', + 'checksum': + '6a9edf9ecabed14aac424e6007858068204a3638bf3bb4f235bd6035d823acc6', + }, + 'adapters': { + "vscode-python": { + "name": "vscode-python", + "command": [ + "node", + "${gadgetDir}/vscode-python/out/client/debugger/debugAdapter/main.js", + ], + } + }, + }, + 'debugpy': { + 'language': 'python', + 'download': { + 'url': 'https://github.com/microsoft/debugpy/archive/${file_name}' + }, + 'all': { + 'version': '1.0.0b12', + 'file_name': 'v1.0.0b12.zip', + '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}", + } + }, + }, + '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': 'master' + }, + '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/latest/' + '${file_name}', + 'format': 'tar', + }, + 'all': { + 'version': 'master' + }, + 'macos': { + 'file_name': 'netcoredbg-osx-master.tar.gz', + 'checksum': + 'c1dc6ed58c3f5b0473cfb4985a96552999360ceb9795e42d9c9be64af054f821', + }, + 'linux': { + 'file_name': 'netcoredbg-linux-master.tar.gz', + 'checksum': '', + }, + 'windows': { + 'file_name': 'netcoredbg-win64-master.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" + }, + }, + } + }, + 'vscode-mono-debug': { + 'language': 'csharp', + 'enabled': False, + 'download': { + 'url': 'https://marketplace.visualstudio.com/_apis/public/gallery/' + 'publishers/ms-vscode/vsextensions/mono-debug/${version}/' + 'vspackage', + 'target': 'vscode-mono-debug.vsix.gz', + 'format': 'zip.gz', + }, + 'all': { + 'file_name': 'vscode-mono-debug.vsix', + 'version': '0.15.8', + 'checksum': + '723eb2b621b99d65a24f215cb64b45f5fe694105613a900a03c859a62a810470', + }, + 'adapters': { + 'vscode-mono-debug': { + "name": "mono-debug", + "command": [ + "mono", + "${gadgetDir}/vscode-mono-debug/bin/Release/mono-debug.exe" + ], + "attach": { + "pidSelect": "none" + }, + }, + } + }, + '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", + } + } + } + }, + 'vscode-go': { + 'language': 'go', + 'download': { + 'url': 'https://github.com/microsoft/vscode-go/releases/download/' + '${version}/${file_name}' + }, + 'all': { + 'version': '0.11.4', + 'file_name': 'Go-0.11.4.vsix', + 'checksum': + 'ff7d7b944da5448974cb3a0086f4a2fd48e2086742d9c013d6964283d416027e' + }, + 'adapters': { + 'vscode-go': { + 'name': 'delve', + 'command': [ + 'node', + '${gadgetDir}/vscode-go/out/src/debugAdapter/goDebug.js' + ], + }, + }, + }, + '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", + ] + } + } + }, + 'vscode-node-debug2': { + 'language': 'node', + 'enabled': False, + 'repo': { + 'url': 'https://github.com/microsoft/vscode-node-debug2', + 'ref': 'v1.42.0', + }, + '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' + ] + }, + }, + }, + '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.0.vsix.gz', + 'format': 'zip.gz', + }, + 'all': { + 'version': '4.12.0', + 'file_name': 'msjsdiag.debugger-for-chrome-4.12.0.vsix', + 'checksum': + '0df2fe96d059a002ebb0936b0003e6569e5a5c35260dc3791e1657d27d82ccf5' + }, + 'adapters': { + 'chrome': { + 'name': 'debugger-for-chrome', + 'type': 'chrome', + 'command': [ + 'node', + '${gadgetDir}/debugger-for-chrome/out/src/chromeDebug.js' + ], + }, + }, + }, + 'CodeLLDB': { + 'language': 'rust', + 'enabled': False, + '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/installer.py b/python3/vimspector/installer.py index 1afea27..c767aa5 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -16,22 +16,195 @@ # limitations under the License. from urllib import request -import io import contextlib -import zipfile -import gzip -import shutil -import tarfile -import hashlib -import time -import ssl -import subprocess import functools +import gzip +import hashlib +import io import os +import shutil +import ssl +import string +import subprocess import sys +import tarfile +import time +import traceback +import zipfile +import json from vimspector import install +class Options: + vimspector_base = None + no_check_certificate = False + + +options = Options() + + +def Configure( **kwargs ): + for k, v in kwargs.items(): + setattr( options, k, v ) + + +def InstallGeneric( name, root, gadget ): + extension = os.path.join( root, 'extension' ) + for f in gadget.get( 'make_executable', [] ): + MakeExecutable( os.path.join( extension, f ) ) + + 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() + root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) ) + os.chdir( root ) + try: + subprocess.check_call( [ sys.executable, 'setup.py', 'build' ] ) + finally: + os.chdir( wd ) + + MakeSymlink( name, root ) + + +def InstallTclProDebug( name, root, gadget ): + configure = [ './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' ) ): + subprocess.check_call( configure ) + subprocess.check_call( [ 'make' ] ) + + MakeSymlink( name, root ) + + +def InstallNodeDebug( name, root, gadget ): + node_version = subprocess.check_output( [ 'node', '--version' ], + universal_newlines=True ).strip() + print( "Node.js version: {}".format( node_version ) ) + if list( map( int, node_version[ 1: ].split( '.' ) ) ) >= [ 12, 0, 0 ]: + print( "Can't install vscode-debug-node2:" ) + print( "Sorry, you appear to be running node 12 or later. That's not " + "compatible with the build system for this extension, and as far as " + "we know, there isn't a pre-built independent package." ) + print( "My advice is to install nvm, then do:" ) + print( " $ nvm install --lts 10" ) + print( " $ nvm use --lts 10" ) + print( " $ ./install_gadget.py --enable-node ..." ) + raise RuntimeError( 'Invalid node environent for node debugger' ) + + with CurrentWorkingDir( root ): + subprocess.check_call( [ 'npm', 'install' ] ) + subprocess.check_call( [ 'npm', 'run', 'build' ] ) + MakeSymlink( name, root ) + + +def InstallGagdet( name, gadget, failed, all_adapters ): + try: + v = {} + v.update( gadget.get( 'all', {} ) ) + v.update( gadget.get( install.GetOS(), {} ) ) + + if 'download' in gadget: + if 'file_name' not in v: + raise RuntimeError( "Unsupported OS {} for gadget {}".format( + install.GetOS(), + name ) ) + + destination = os.path.join( _GetGadgetDir(), + 'download', + name, v[ 'version' ] ) + + url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( v ) + + file_path = DownloadFileTo( + url, + destination, + file_name = gadget[ 'download' ].get( 'target' ), + checksum = v.get( 'checksum' ), + check_certificate = not options.no_check_certificate ) + + root = os.path.join( destination, 'root' ) + ExtractZipTo( + file_path, + root, + format = gadget[ 'download' ].get( 'format', 'zip' ) ) + elif 'repo' in gadget: + url = string.Template( gadget[ 'repo' ][ 'url' ] ).substitute( v ) + ref = string.Template( gadget[ 'repo' ][ 'ref' ] ).substitute( v ) + + destination = os.path.join( _GetGadgetDir(), 'download', name ) + CloneRepoTo( url, ref, destination ) + root = destination + + if 'do' in gadget: + gadget[ 'do' ]( name, root, v ) + else: + InstallGeneric( name, root, v ) + + # Allow per-OS adapter overrides. v already did that for us... + all_adapters.update( v.get( 'adapters', {} ) ) + # Add any other "all" adapters + all_adapters.update( gadget.get( 'adapters', {} ) ) + + print( "Done installing {}".format( name ) ) + except Exception as e: + traceback.print_exc() + failed.append( name ) + print( "FAILED installing {}: {}".format( name, e ) ) + @contextlib.contextmanager def CurrentWorkingDir( d ): @@ -212,14 +385,18 @@ def ExtractZipTo( file_path, destination, format ): subprocess.check_call( [ 'tar', 'zxvf', file_path ] ) -def MakeExtensionSymlink( vimspector_base, name, root ): - MakeSymlink( install.GetGadgetDir( vimspector_base, - install.GetOS() ), - name, - os.path.join( root, 'extension' ) ), +def _GetGadgetDir(): + return install.GetGadgetDir( options.vimspector_base, install.GetOS() ) -def MakeSymlink( in_folder, link, pointing_to ): +def MakeExtensionSymlink( name, root ): + MakeSymlink( name, os.path.join( root, 'extension' ) ), + + +def MakeSymlink( link, pointing_to, in_folder = None ): + if not in_folder: + in_folder = _GetGadgetDir() + RemoveIfExists( os.path.join( in_folder, link ) ) in_folder = os.path.abspath( in_folder ) From 6b89df173fe84c6f8a6663ebb57c7f124aa32c59 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 27 May 2020 21:22:08 +0100 Subject: [PATCH 02/23] Remove pointless calls to GetOS() everywhere --- python3/vimspector/debug_session.py | 7 +++---- python3/vimspector/developer.py | 3 +-- python3/vimspector/install.py | 10 ++++------ python3/vimspector/installer.py | 19 ++++++++++--------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 9ff680a..bd32cf1 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -51,8 +51,7 @@ class DebugSession( object ): self._logger.info( "API is: {}".format( api_prefix ) ) self._logger.info( 'VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME ) self._logger.info( 'gadgetDir = %s', - install.GetGadgetDir( VIMSPECTOR_HOME, - install.GetOS() ) ) + install.GetGadgetDir( VIMSPECTOR_HOME ) ) self._uiTab = None self._stackTraceView = None @@ -91,7 +90,7 @@ class DebugSession( object ): configurations = {} adapters = {} - glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ) ) + glob.glob( install.GetGadgetDir( VIMSPECTOR_HOME ) ) for gadget_config_file in PathsToAllGadgetConfigs( VIMSPECTOR_HOME, current_file ): self._logger.debug( f'Reading gadget config: {gadget_config_file}' ) @@ -192,7 +191,7 @@ class DebugSession( object ): 'dollar': '$', # HACK. Hote '$$' also works. 'workspaceRoot': self._workspace_root, 'workspaceFolder': self._workspace_root, - 'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME, install.GetOS() ), + 'gadgetDir': install.GetGadgetDir( VIMSPECTOR_HOME ), 'file': current_file, } diff --git a/python3/vimspector/developer.py b/python3/vimspector/developer.py index 4945e6a..49e96c3 100644 --- a/python3/vimspector/developer.py +++ b/python3/vimspector/developer.py @@ -23,8 +23,7 @@ from vimspector import install, utils def SetUpDebugpy( wait=False, port=5678 ): sys.path.insert( 1, - os.path.join( install.GetGadgetDir( utils.GetVimspectorBase(), - install.GetOS() ), + os.path.join( install.GetGadgetDir( utils.GetVimspectorBase() ), 'debugpy', 'build', 'lib' ) ) diff --git a/python3/vimspector/install.py b/python3/vimspector/install.py index 4726a5b..7dc0897 100644 --- a/python3/vimspector/install.py +++ b/python3/vimspector/install.py @@ -38,18 +38,16 @@ def MakeInstallDirs( vimspector_base ): mkdirs( GetConfigDirForFiletype( vimspector_base, '_all' ) ) -def GetGadgetDir( vimspector_base, OS ): - return os.path.join( os.path.abspath( vimspector_base ), 'gadgets', OS ) +def GetGadgetDir( vimspector_base ): + return os.path.join( os.path.abspath( vimspector_base ), 'gadgets', GetOS() ) def GetGadgetConfigFile( vimspector_base ): - return os.path.join( GetGadgetDir( vimspector_base, GetOS() ), - '.gadgets.json' ) + return os.path.join( GetGadgetDir( vimspector_base ), '.gadgets.json' ) def GetGadgetConfigDir( vimspector_base ): - return os.path.join( GetGadgetDir( vimspector_base, GetOS() ), - '.gadgets.d' ) + return os.path.join( GetGadgetDir( vimspector_base ), '.gadgets.d' ) def GetConfigDirForFiletype( vimspector_base, filetype ): diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index c767aa5..9e42fee 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -163,9 +163,11 @@ def InstallGagdet( name, gadget, failed, all_adapters ): install.GetOS(), name ) ) - destination = os.path.join( _GetGadgetDir(), - 'download', - name, v[ 'version' ] ) + destination = os.path.join( + install.GetGadgetDir( options.vimspector_base ), + 'download', + name, + v[ 'version' ] ) url = string.Template( gadget[ 'download' ][ 'url' ] ).substitute( v ) @@ -185,7 +187,10 @@ def InstallGagdet( name, gadget, failed, all_adapters ): url = string.Template( gadget[ 'repo' ][ 'url' ] ).substitute( v ) ref = string.Template( gadget[ 'repo' ][ 'ref' ] ).substitute( v ) - destination = os.path.join( _GetGadgetDir(), 'download', name ) + destination = os.path.join( + install.GetGadgetDir( options.vimspector_base ), + 'download', + name ) CloneRepoTo( url, ref, destination ) root = destination @@ -385,17 +390,13 @@ def ExtractZipTo( file_path, destination, format ): subprocess.check_call( [ 'tar', 'zxvf', file_path ] ) -def _GetGadgetDir(): - return install.GetGadgetDir( options.vimspector_base, install.GetOS() ) - - def MakeExtensionSymlink( name, root ): MakeSymlink( name, os.path.join( root, 'extension' ) ), def MakeSymlink( link, pointing_to, in_folder = None ): if not in_folder: - in_folder = _GetGadgetDir() + in_folder = install.GetGadgetDir( options.vimspector_base ) RemoveIfExists( os.path.join( in_folder, link ) ) From 8f3de079bcc09222b6cf39ebe5d4da2dfaf40efa Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 27 May 2020 21:25:17 +0100 Subject: [PATCH 03/23] Use --install to run_tests instead of manually running the installer --- azure-pipelines.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5fb2b08..d5e36a2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,20 +45,17 @@ stages: - task: CacheBeta@0 inputs: - key: v1 | gadgets | $(Agent.OS) | install_gadget.py + key: v2 | gadgets | $(Agent.OS) | python3/vimspector/installer.py path: gadgets/linux/download displayName: Cache gadgets - - bash: python3 install_gadget.py --all - displayName: 'Install gadgets - python3' - - bash: vim --version displayName: 'Print vim version information' - bash: | eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) export GOPATH=$HOME/go - ./run_tests --report messages --quiet + ./run_tests --install --report messages --quiet displayName: 'Run the tests' env: VIMSPECTOR_MIMODE: gdb @@ -92,17 +89,14 @@ stages: - task: CacheBeta@0 inputs: - key: v1 | gadgets | $(Agent.OS) | install_gadget.py + key: v2 | gadgets | $(Agent.OS) | python3/vimspector/installer.py path: gadgets/macos/download displayName: Cache gadgets - - bash: python3 install_gadget.py --all - displayName: 'Install gadgets - python3' - - bash: vim --version displayName: 'Print vim version information' - - bash: ./run_tests --report messages --quiet + - bash: ./run_tests --install --report messages --quiet displayName: 'Run the tests' env: VIMSPECTOR_MIMODE: lldb From f945dbcfdda670b0a6009da30b773b02566840ec Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 27 May 2020 21:47:17 +0100 Subject: [PATCH 04/23] Move gadget config file writing too --- install_gadget.py | 24 ++++-------------------- python3/vimspector/installer.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/install_gadget.py b/install_gadget.py index af2794e..5cfc395 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -163,19 +163,8 @@ for custom_file_name in functools.reduce( operator.add, failed = [] -if args.update_gadget_config: - with open( install.GetGadgetConfigFile( vimspector_base ), 'r' ) as f: - all_adapters = json.load( f ).get( 'adapters', {} ) -else: - all_adapters = {} - -# Include "built-in" adapter for multi-session mode -all_adapters.update( { - 'multi-session': { - 'port': '${port}', - 'host': '${host}' - }, -} ) +all_adapters = installer.ReadAdapters( + read_existing = args.update_gadget_config ) for name, gadget in gadgets.GADGETS.items(): if not gadget.get( 'enabled', True ): @@ -197,17 +186,12 @@ for name, gadget in gadgets.GADGETS.items(): for name, gadget in CUSTOM_GADGETS.items(): installer.InstallGagdet( name, gadget, failed, all_adapters ) -adapter_config = json.dumps ( { 'adapters': all_adapters }, - indent=2, - sort_keys=True ) - if args.no_gadget_config: print( "" ) print( "Would write the following gadgets: " ) - print( adapter_config ) + installer.WriteAdapters( all_adapters, to_file = sys.stdout ) else: - with open( install.GetGadgetConfigFile( vimspector_base ), 'w' ) as f: - f.write( adapter_config ) + installer.WriteAdapters( all_adapters ) if failed: raise RuntimeError( 'Failed to install gadgets: {}'.format( diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 9e42fee..8bf78b0 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -211,6 +211,38 @@ def InstallGagdet( name, gadget, failed, all_adapters ): print( "FAILED installing {}: {}".format( name, e ) ) +def ReadAdapters( read_existing = True ): + if read_existing: + with open( install.GetGadgetConfigFile( options.vimspector_base ), + 'r' ) as f: + all_adapters = json.load( f ).get( 'adapters', {} ) + else: + all_adapters = {} + + # Include "built-in" adapter for multi-session mode + all_adapters.update( { + 'multi-session': { + 'port': '${port}', + 'host': '${host}' + }, + } ) + + return all_adapters + + +def WriteAdapters( all_adapters, to_file=None ): + adapter_config = json.dumps ( { 'adapters': all_adapters }, + indent=2, + sort_keys=True ) + + if to_file: + to_file.write( adapter_config ) + else: + with open( install.GetGadgetConfigFile( options.vimspector_base ), + 'w' ) as f: + f.write( adapter_config ) + + @contextlib.contextmanager def CurrentWorkingDir( d ): cur_d = os.getcwd() From 025d193493f864d97f88ac0e58796625ab0213ea Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 3 Jul 2020 18:47:48 +0100 Subject: [PATCH 05/23] Add VimspectorInstall command with sort-of completion --- autoload/vimspector.vim | 46 +++++++++++++++++++++++++++++++++ plugin/vimspector.vim | 5 ++++ python3/vimspector/installer.py | 33 ++++++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index a7c6e4b..3d0ea05 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -150,6 +150,52 @@ function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort \ "\n" ) endfunction +function! vimspector#Install( ... ) abort + if a:0 < 1 + return + endif + + let gadgets = a:000 + let force = a:1 ==# '--force' + if force + let gadgets = a:000[ 1: ] + endif + + py3 << EOF +from vimspector import installer as vimspector_installer +from vimspector import utils as vimspector_utils +vimspector_installer.Configure( + vimspector_base = vimspector_utils.GetVimspectorBase() ) +vimspector_installer.Install( vim.eval( 'gadgets'), vim.eval( 'force' ) ) +EOF +endfunction + +function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort + let words = split( a:CmdLine ) + let done_options = v:false + for word in words + if ! word =~# '^--' + let done_options = v:true + break + endif + endfor + + let options = [] + + if !done_options + call extend( options, [ '--force' ] ) + endif + + py3 from vimspector import installer as vimspector_installer + call extend( options, [ 'all' ] ) + call extend( + \ options, + \ py3eval( + \ '[ g[ "language" ] for g in vimspector_installer.GADGETS.values() ]' ) ) + + return join( options, "\n" ) +endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index fa8312c..5a31021 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -97,6 +97,11 @@ command! -bar \ VimspectorReset \ call vimspector#Reset() +" Installer commands +command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall + \ VimspectorInstall + \ call vimspector#Install( ) + " Dummy autocommands so that we can call this whenever augroup VimspectorUserAutoCmds au! diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 8bf78b0..89844d3 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -15,6 +15,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# TODO: Chnage `print` to some other mechanism that can be displayed in a vim +# buffer? + from urllib import request import contextlib import functools @@ -33,7 +36,8 @@ import traceback import zipfile import json -from vimspector import install +from vimspector import install, gadgets + class Options: vimspector_base = None @@ -48,6 +52,33 @@ def Configure( **kwargs ): setattr( options, k, v ) +def Install( languages, force ): + all_enabled = 'all' in languages + force_all = all_enabled and force + + install.MakeInstallDirs( options.vimspector_base ) + all_adapters = ReadAdapters() + failed = [] + + for name, gadget in gadgets.GADGETS.items(): + if not gadget.get( 'enabled', True ): + if ( not force_all + and not ( force and gadget[ 'language' ] in languages ) ): + continue + else: + if not all_enabled and not gadget[ 'language' ] in languages: + continue + + InstallGagdet( name, + gadget, + failed, + all_adapters ) + + WriteAdapters( all_adapters ) + + return failed + + def InstallGeneric( name, root, gadget ): extension = os.path.join( root, 'extension' ) for f in gadget.get( 'make_executable', [] ): From 23e5f6bbf4f18623c53c2343080f82123ef25859 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 21 Jul 2020 16:43:39 +0100 Subject: [PATCH 06/23] Switch to running the actual install_gadget.py This re-uses the OutputView code to run the installer script. Refactor to remove connection from the base OutputView (and other places, it wasn't used - only used after ConnectionUp). This also consolidates the stdout and stderr buffers for running jobs. The distinction was always arbitrary and probably an error, based on the fact that they were separate in the APIs not based on usability. --- autoload/vimspector.vim | 47 ++------- autoload/vimspector/internal/job.vim | 13 +-- autoload/vimspector/internal/neojob.vim | 12 +-- autoload/vimspector/internal/state.vim | 15 +-- install_gadget.py | 15 ++- plugin/vimspector.vim | 3 +- python3/vimspector/debug_session.py | 9 +- python3/vimspector/installer.py | 106 ++++++++++++++++---- python3/vimspector/output.py | 128 ++++++++++++++---------- python3/vimspector/stack_trace.py | 4 +- python3/vimspector/utils.py | 47 +++++---- python3/vimspector/variables.py | 4 +- 12 files changed, 236 insertions(+), 167 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 3d0ea05..4e96968 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -132,6 +132,14 @@ function! vimspector#ShowOutput( category ) abort py3 _vimspector_session.ShowOutput( vim.eval( 'a:category' ) ) endfunction +function! vimspector#ShowOutputInWindow( win_id, category ) abort + py3 <:p:h:h' ) let s:mappings = get( g:, 'vimspector_enable_mappings', '' ) @@ -98,7 +99,7 @@ command! -bar \ call vimspector#Reset() " Installer commands -command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall +command! -bar -nargs=* \ VimspectorInstall \ call vimspector#Install( ) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index bd32cf1..17d6303 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -528,7 +528,6 @@ class DebugSession( object ): stack_trace_window = vim.current.window one_third = int( vim.eval( 'winheight( 0 )' ) ) / 3 self._stackTraceView = stack_trace.StackTraceView( self, - self._connection, stack_trace_window ) # Watches @@ -546,17 +545,15 @@ class DebugSession( object ): with utils.LetCurrentWindow( stack_trace_window ): vim.command( f'{ one_third }wincmd _' ) - self._variablesView = variables.VariablesView( self._connection, - vars_window, + self._variablesView = variables.VariablesView( vars_window, watch_window ) # Output/logging vim.current.window = code_window vim.command( f'rightbelow { settings.Int( "bottombar_height", 10 ) }new' ) output_window = vim.current.window - self._outputView = output.OutputView( self._connection, - output_window, - self._api_prefix ) + 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 diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 89844d3..29ae91f 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -36,7 +36,9 @@ import traceback import zipfile import json -from vimspector import install, gadgets +from vimspector import install + +OUTPUT_VIEW = None class Options: @@ -52,31 +54,94 @@ def Configure( **kwargs ): setattr( options, k, v ) -def Install( languages, force ): - all_enabled = 'all' in languages - force_all = all_enabled and force +def PathToAnyWorkingPython3(): + # We can't rely on sys.executable because it's usually 'vim' (fixme, not with + # neovim?) + paths = os.environ[ 'PATH' ].split( os.pathsep ) - install.MakeInstallDirs( options.vimspector_base ) - all_adapters = ReadAdapters() - failed = [] + if install.GetOS() == 'windows': + paths.insert( 0, os.getcwd() ) + candidates = [ os.path.join( sys.exec_prefix, 'python.exe' ), + 'python.exe' ] + else: + candidates = [ os.path.join( sys.exec_prefix, 'bin', 'python3' ), + 'python3', + 'python' ] - for name, gadget in gadgets.GADGETS.items(): - if not gadget.get( 'enabled', True ): - if ( not force_all - and not ( force and gadget[ 'language' ] in languages ) ): + for candidate in candidates: + for path in paths: + filename = os.path.abspath( os.path.join( path, candidate ) ) + if not os.path.isfile( filename ): continue - else: - if not all_enabled and not gadget[ 'language' ] in languages: + if not os.access( filename, os.F_OK | os.X_OK ): continue - InstallGagdet( name, - gadget, - failed, - all_adapters ) + return filename - WriteAdapters( all_adapters ) + raise RuntimeError( "Unable to find a working python3" ) + + +def RunInstaller( api_prefix, *args ): + from vimspector import utils, output, settings + import vim + + vimspector_home = utils.GetVimString( vim.vars, 'vimspector_home' ) + vimspector_base_dir = utils.GetVimspectorBase() + + # TODO: Translate the arguments to something more user-friendly than -- args + global OUTPUT_VIEW + + if OUTPUT_VIEW: + OUTPUT_VIEW.Reset() + OUTPUT_VIEW = None + + with utils.RestoreCurrentWindow(): + vim.command( f'botright { settings.Int( "bottombar_height", 10 ) }new' ) + win = vim.current.window + OUTPUT_VIEW = output.OutputView( win, api_prefix ) + + cmd = [ + PathToAnyWorkingPython3(), + '-u', + os.path.join( vimspector_home, 'install_gadget.py' ), + '--update-gadget-config', + ] + if not vimspector_base_dir == vimspector_home: + cmd.extend( '--basedir', vimspector_base_dir ) + cmd.extend( args ) + + OUTPUT_VIEW.RunJobWithOutput( 'Installer', cmd ) + OUTPUT_VIEW.ShowOutput( 'Installer' ) + + +# def Install( languages, force ): +# all_enabled = 'all' in languages +# force_all = all_enabled and force +# +# install.MakeInstallDirs( options.vimspector_base ) +# all_adapters = ReadAdapters() +# succeeded = [] +# failed = [] +# +# for name, gadget in gadgets.GADGETS.items(): +# if not gadget.get( 'enabled', True ): +# if ( not force_all +# and not ( force and gadget[ 'language' ] in languages ) ): +# continue +# else: +# if not all_enabled and not gadget[ 'language' ] in languages: +# continue +# +# InstallGagdet( name, +# gadget, +# succeeded, +# failed, +# all_adapters ) +# +# WriteAdapters( all_adapters ) +# +# return succeeded, failed - return failed def InstallGeneric( name, root, gadget ): @@ -182,7 +247,7 @@ def InstallNodeDebug( name, root, gadget ): MakeSymlink( name, root ) -def InstallGagdet( name, gadget, failed, all_adapters ): +def InstallGagdet( name, gadget, succeeded, failed, all_adapters ): try: v = {} v.update( gadget.get( 'all', {} ) ) @@ -235,6 +300,7 @@ def InstallGagdet( name, gadget, failed, all_adapters ): # Add any other "all" adapters all_adapters.update( gadget.get( 'adapters', {} ) ) + succeeded.append( name ) print( "Done installing {}".format( name ) ) except Exception as e: traceback.print_exc() diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index a359448..2e2412b 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -25,7 +25,6 @@ class TabBuffer( object ): self.index = index self.flag = False self.is_job = False - self.job_category = None BUFFER_MAP = { @@ -40,18 +39,24 @@ def CategoryToBuffer( category ): return BUFFER_MAP.get( category, category ) +VIEWS = set() + + +def ShowOutputInWindow( win_id, category ): + for view in VIEWS: + if view._window.valid and utils.WindowID( view._window ) == win_id: + view.ShowOutput( category ) + return + + raise ValueError( f'Unable to find output object for win id {win_id}!' ) + + class OutputView( object ): - def __init__( self, connection, window, api_prefix ): + def __init__( self, window, api_prefix ): self._window = window - self._connection = connection self._buffers = {} self._api_prefix = api_prefix - - for b in set( BUFFER_MAP.values() ): - self._CreateBuffer( b ) - - self._CreateBuffer( 'Vimspector', file_name = utils.LOG_FILE ) - self._ShowOutput( 'Console' ) + VIEWS.add( self ) def Print( self, categroy, text ): self._Print( 'server', text.splitlines() ) @@ -82,22 +87,23 @@ class OutputView( object ): with utils.RestoreCurrentBuffer( self._window ): self._ShowOutput( category ) - def ConnectionUp( self, connection ): - self._connection = connection - - def ConnectionClosed( self ): - # Don't clear because output is probably still useful - self._connection = None - def Reset( self ): self.Clear() + VIEWS.remove( self ) + + + def _CleanUpBuffer( self, category, tab_buffer = None ): + if tab_buffer is None: + tab_buffer = self._buffers[ category ] + + if tab_buffer.is_job: + utils.CleanUpCommand( category, self._api_prefix ) + utils.CleanUpHiddenBuffer( tab_buffer.buf ) + def Clear( self ): for category, tab_buffer in self._buffers.items(): - if tab_buffer.is_job: - utils.CleanUpCommand( tab_buffer.job_category or category, - self._api_prefix ) - utils.CleanUpHiddenBuffer( tab_buffer.buf ) + self._CleanUpBuffer( category, tab_buffer ) # FIXME: nunmenu the WinBar ? self._buffers = {} @@ -125,28 +131,6 @@ class OutputView( object ): self._ToggleFlag( category, False ) self._ShowOutput( category ) - def Evaluate( self, frame, expression ): - self._Print( 'Console', [ 'Evaluating: ' + expression ] ) - - def print_result( message ): - result = message[ 'body' ][ 'result' ] - if result is None: - result = '' - self._Print( 'Console', f' Result: { result }' ) - - request = { - 'command': 'evaluate', - 'arguments': { - 'expression': expression, - 'context': 'repl', - } - } - - if frame: - request[ 'arguments' ][ 'frameId' ] = frame[ 'id' ] - - self._connection.DoRequest( print_result, request ) - def _ToggleFlag( self, category, flag ): if self._buffers[ category ].flag != flag: self._buffers[ category ].flag = flag @@ -178,16 +162,10 @@ class OutputView( object ): cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ] if cmd is not None: - out, err = utils.SetUpCommandBuffer( cmd, category, self._api_prefix ) - self._buffers[ category + '-out' ] = TabBuffer( out, - len( self._buffers ) ) - self._buffers[ category + '-out' ].is_job = True - self._buffers[ category + '-out' ].job_category = category - self._buffers[ category + '-err' ] = TabBuffer( err, - len( self._buffers ) ) - self._buffers[ category + '-err' ].is_job = False - self._RenderWinBar( category + '-out' ) - self._RenderWinBar( category + '-err' ) + out = utils.SetUpCommandBuffer( cmd, category, self._api_prefix ) + self._buffers[ category ] = TabBuffer( out, len( self._buffers ) ) + self._buffers[ category ].is_job = True + self._RenderWinBar( category ) else: vim.command( 'enew' ) tab_buffer = TabBuffer( vim.current.buffer, len( self._buffers ) ) @@ -218,10 +196,52 @@ class OutputView( object ): raise vim.command( "nnoremenu 1.{0} WinBar.{1}{2} " - ":call vimspector#ShowOutput( '{1}' )".format( + ":call vimspector#ShowOutputInWindow( {3}, '{1}' )".format( tab_buffer.index, utils.Escape( category ), - '*' if tab_buffer.flag else '' ) ) + '*' if tab_buffer.flag else '', + utils.WindowID( self._window ) ) ) def GetCategories( self ): return list( self._buffers.keys() ) + + +class DAPOutputView( OutputView ): + def __init__( self, *args ): + super().__init__( *args ) + + self._connection = None + for b in set( BUFFER_MAP.values() ): + self._CreateBuffer( b ) + + self._CreateBuffer( 'Vimspector', file_name = utils.LOG_FILE ) + self._ShowOutput( 'Console' ) + + def ConnectionUp( self, connection ): + self._connection = connection + + def ConnectionClosed( self ): + # Don't clear because output is probably still useful + self._connection = None + + def Evaluate( self, frame, expression ): + self._Print( 'Console', [ 'Evaluating: ' + expression ] ) + + def print_result( message ): + result = message[ 'body' ][ 'result' ] + if result is None: + result = '' + self._Print( 'Console', f' Result: { result }' ) + + request = { + 'command': 'evaluate', + 'arguments': { + 'expression': expression, + 'context': 'repl', + } + } + + if frame: + request[ 'arguments' ][ 'frameId' ] = frame[ 'id' ] + + self._connection.DoRequest( print_result, request ) diff --git a/python3/vimspector/stack_trace.py b/python3/vimspector/stack_trace.py index d5ea0b5..6caccc8 100644 --- a/python3/vimspector/stack_trace.py +++ b/python3/vimspector/stack_trace.py @@ -21,13 +21,13 @@ from vimspector import utils class StackTraceView( object ): - def __init__( self, session, connection, win ): + def __init__( self, session, win ): self._logger = logging.getLogger( __name__ ) utils.SetUpLogging( self._logger ) self._buf = win.buffer self._session = session - self._connection = connection + self._connection = None self._current_thread = None self._current_frame = None diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index bfdddcc..ab6f733 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -72,20 +72,18 @@ def OpenFileInCurrentWindow( file_name ): def SetUpCommandBuffer( cmd, name, api_prefix ): - bufs = vim.eval( - 'vimspector#internal#{}job#StartCommandWithLog( {}, "{}" )'.format( - api_prefix, - json.dumps( cmd ), - name ) ) + buf = Call( f'vimspector#internal#{api_prefix}job#StartCommandWithLog', + cmd, + name ) - if bufs is None: + if buf is None: raise RuntimeError( "Unable to start job {}: {}".format( cmd, name ) ) - elif not all( int( b ) > 0 for b in bufs ): + elif int( buf ) <= 0: raise RuntimeError( "Unable to get all streams for job {}: {}".format( name, cmd ) ) - return [ vim.buffers[ int( b ) ] for b in bufs ] + return vim.buffers[ int( buf ) ] def CleanUpCommand( name, api_prefix ): @@ -558,7 +556,6 @@ def Call( vimscript_function, *args ): call += 'g:' + arg_name call += ')' - _logger.debug( 'Calling: {}'.format( call ) ) return vim.eval( call ) @@ -633,16 +630,26 @@ def HideSplash( api_prefix, splash ): return None +def GetVimString( vim_dict, name, default=None ): + + # FIXME: use 'encoding' ? + try: + value = vim_dict[ name ] + except KeyError: + return default + + if isinstance( value, bytes ): + return value.decode( 'utf-8' ) + return value + + def GetVimspectorBase(): - base = vim.vars.get( 'vimspector_base_dir' ) - if base is None: - return os.path.abspath( os.path.join( os.path.dirname( __file__ ), - '..', - '..' ) ) - elif isinstance( base, bytes ): - return base.decode( 'utf-8' ) - else: - return base + return GetVimString( vim.vars, + 'vimspector_base_dir', + os.path.abspath( + os.path.join( os.path.dirname( __file__ ), + '..', + '..' ) ) ) def GetUnusedLocalPort(): @@ -655,5 +662,7 @@ def GetUnusedLocalPort(): return port -def WindowID( window, tab ): +def WindowID( window, tab=None ): + if tab is None: + tab = window.tabpage return int( Call( 'win_getid', window.number, tab.number ) ) diff --git a/python3/vimspector/variables.py b/python3/vimspector/variables.py index f6df06c..ffd641d 100644 --- a/python3/vimspector/variables.py +++ b/python3/vimspector/variables.py @@ -124,11 +124,11 @@ class View: class VariablesView( object ): - def __init__( self, connection, variables_win, watches_win ): + def __init__( self, variables_win, watches_win ): self._logger = logging.getLogger( __name__ ) utils.SetUpLogging( self._logger ) - self._connection = connection + self._connection = None self._current_syntax = '' # Set up the "Variables" buffer in the variables_win From 0140a607b1b6f6abd43eb87edcf55eac84166b92 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 21 Jul 2020 19:11:31 +0100 Subject: [PATCH 07/23] Raise autocommand when installer completes. use this in testing --- autoload/vimspector/internal/job.vim | 11 ++++++++++ python3/vimspector/installer.py | 28 ++++++++++++++++++------- python3/vimspector/output.py | 31 +++++++++++++++------------- python3/vimspector/utils.py | 15 +++++++++++++- run_tests | 23 +++++++++++++++++++-- 5 files changed, 84 insertions(+), 24 deletions(-) diff --git a/autoload/vimspector/internal/job.vim b/autoload/vimspector/internal/job.vim index 834f83c..51ed137 100644 --- a/autoload/vimspector/internal/job.vim +++ b/autoload/vimspector/internal/job.vim @@ -146,6 +146,14 @@ function! vimspector#internal#job#Reset() abort call vimspector#internal#job#StopDebugSession() endfunction +function! s:_OnCommandExit( category, ch, code ) abort + py3 << EOF +from vimspector import utils as vimspector_utils +vimspector_utils.OnCommandWithLogComplete( vim.eval( 'a:category' ), + int( vim.eval( 'a:code' ) ) ) +EOF +endfunction + function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort if ! exists( 's:commands' ) let s:commands = {} @@ -165,8 +173,11 @@ function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort \ 'out_io': 'buffer', \ 'in_io': 'null', \ 'err_io': 'buffer', + \ 'out_msg': 0, + \ 'err_msg': 0, \ 'out_name': buf, \ 'err_name': buf, + \ 'exit_cb': funcref( 's:_OnCommandExit', [ a:category ] ), \ 'out_modifiable': 0, \ 'err_modifiable': 0, \ 'stoponexit': 'kill' diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 29ae91f..eefbd80 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -107,10 +107,22 @@ def RunInstaller( api_prefix, *args ): '--update-gadget-config', ] if not vimspector_base_dir == vimspector_home: - cmd.extend( '--basedir', vimspector_base_dir ) + cmd.extend( [ '--basedir', vimspector_base_dir ] ) cmd.extend( args ) - OUTPUT_VIEW.RunJobWithOutput( 'Installer', cmd ) + def handler( exit_code ): + if exit_code == 0: + utils.UserMessage( "Vimspector installation complete!" ) + vim.command( 'doautocmd User VimspectorInstallSuccess' ) + else: + utils.UserMessage( 'Vimspector installation reported errors', + error = True ) + vim.command( 'silent doautocmd User VimspectorInstallFailed' ) + + + OUTPUT_VIEW.RunJobWithOutput( 'Installer', + cmd, + completion_handler = handler ) OUTPUT_VIEW.ShowOutput( 'Installer' ) @@ -309,12 +321,14 @@ def InstallGagdet( name, gadget, succeeded, failed, all_adapters ): def ReadAdapters( read_existing = True ): + all_adapters = {} if read_existing: - with open( install.GetGadgetConfigFile( options.vimspector_base ), - 'r' ) as f: - all_adapters = json.load( f ).get( 'adapters', {} ) - else: - all_adapters = {} + try: + with open( install.GetGadgetConfigFile( options.vimspector_base ), + 'r' ) as f: + all_adapters = json.load( f ).get( 'adapters', {} ) + except OSError: + pass # Include "built-in" adapter for multi-session mode all_adapters.update( { diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index 2e2412b..4b89d95 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -92,18 +92,11 @@ class OutputView( object ): VIEWS.remove( self ) - def _CleanUpBuffer( self, category, tab_buffer = None ): - if tab_buffer is None: - tab_buffer = self._buffers[ category ] - - if tab_buffer.is_job: - utils.CleanUpCommand( category, self._api_prefix ) - utils.CleanUpHiddenBuffer( tab_buffer.buf ) - - def Clear( self ): for category, tab_buffer in self._buffers.items(): - self._CleanUpBuffer( category, tab_buffer ) + if tab_buffer.is_job: + utils.CleanUpCommand( category, self._api_prefix ) + utils.CleanUpHiddenBuffer( tab_buffer.buf ) # FIXME: nunmenu the WinBar ? self._buffers = {} @@ -140,11 +133,17 @@ class OutputView( object ): self._RenderWinBar( category ) - def RunJobWithOutput( self, category, cmd ): - self._CreateBuffer( category, cmd = cmd ) + def RunJobWithOutput( self, category, cmd, completion_handler = None ): + self._CreateBuffer( category, + cmd = cmd, + completion_handler = completion_handler ) - def _CreateBuffer( self, category, file_name = None, cmd = None ): + def _CreateBuffer( self, + category, + file_name = None, + cmd = None, + completion_handler = None ): win = self._window if not win.valid: # We need to borrow the current window @@ -162,7 +161,11 @@ class OutputView( object ): cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ] if cmd is not None: - out = utils.SetUpCommandBuffer( cmd, category, self._api_prefix ) + out = utils.SetUpCommandBuffer( + cmd, + category, + self._api_prefix, + completion_handler = completion_handler ) self._buffers[ category ] = TabBuffer( out, len( self._buffers ) ) self._buffers[ category ].is_job = True self._RenderWinBar( category ) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index ab6f733..cf4a69d 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -71,7 +71,20 @@ def OpenFileInCurrentWindow( file_name ): return vim.buffers[ buffer_number ] -def SetUpCommandBuffer( cmd, name, api_prefix ): +COMMAND_HANDLERS = {} + + +def OnCommandWithLogComplete( name, exit_code ): + cb = COMMAND_HANDLERS.get( name ) + if cb: + cb( exit_code ) + else: + UserMessage( f'Job complete: { name } (exit status: { exit_code })' ) + + +def SetUpCommandBuffer( cmd, name, api_prefix, completion_handler = None ): + COMMAND_HANDLERS[ name ] = completion_handler + buf = Call( f'vimspector#internal#{api_prefix}job#StartCommandWithLog', cmd, name ) diff --git a/run_tests b/run_tests index c03c7b9..3c327bb 100755 --- a/run_tests +++ b/run_tests @@ -25,6 +25,11 @@ while [ -n "$1" ]; do INSTALL=1 shift ;; + "--install-method") + shift + INSTALL=$1 + shift + ;; "--report") shift VIMSPECTOR_TEST_STDOUT=$1 @@ -71,8 +76,22 @@ if [ "${out_fd}" = "1" ]; then exec 3>&1 fi -if [ $INSTALL = 1 ]; then - python3 $(dirname $0)/install_gadget.py --basedir ${BASEDIR} --all +if [ "$INSTALL" = "1" ] || [ "$INSTALL" = "script" ]; then + if ! python3 $(dirname $0)/install_gadget.py --basedir ${BASEDIR} --all; then + echo "Script installation reported errors" >&2 + exit 1 + fi +fi + +if [ "$INSTALL" = "1" ] || [ "$INSTALL" = "vim" ]; then + if ! $RUN_VIM -u $(dirname $0)/tests/vimrc \ + --cmd "${BASEDIR_CMD}" \ + -c 'autocmd User VimspectorInstallSuccess qa!' \ + -c 'autocmd User VimspectorInstallFailed cquit!' \ + -c "VimspectorInstall --all"; then + echo "Vim installation reported errors" >&2 + exit 1 + fi fi if [ -z "$VIMSPECTOR_MIMODE" ]; then From ca4ab52f8d1fe56005b0c5573a1efc532e952449 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 21 Jul 2020 19:23:38 +0100 Subject: [PATCH 08/23] Fix regression: Don't render winbar if the window isn't valid --- python3/vimspector/output.py | 3 +++ python3/vimspector/utils.py | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index 4b89d95..4cd7c64 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -186,6 +186,9 @@ class OutputView( object ): self._RenderWinBar( category ) def _RenderWinBar( self, category ): + if not self._window.valid: + return + tab_buffer = self._buffers[ category ] try: diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index cf4a69d..d2870c6 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -195,9 +195,8 @@ def RestoreCurrentWindow(): try: yield finally: - if old_tabpage.valid: + if old_tabpage.valid and old_window.valid: vim.current.tabpage = old_tabpage - if old_window.valid: vim.current.window = old_window From 05bbafd60c18529902abfdde05722df04593ea05 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 21 Jul 2020 21:55:31 +0100 Subject: [PATCH 09/23] Close the intaller output when complete --- autoload/vimspector.vim | 24 ++++++++++++++--------- plugin/vimspector.vim | 3 ++- python3/vimspector/installer.py | 34 +++++++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 4e96968..1dd22f1 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -133,11 +133,10 @@ function! vimspector#ShowOutput( category ) abort endfunction function! vimspector#ShowOutputInWindow( win_id, category ) abort - py3 < ) + " Dummy autocommands so that we can call this whenever augroup VimspectorUserAutoCmds au! diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index eefbd80..33a6a76 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -85,12 +85,13 @@ def RunInstaller( api_prefix, *args ): from vimspector import utils, output, settings import vim + args = GadgetListToInstallerArgs( *args ) + vimspector_home = utils.GetVimString( vim.vars, 'vimspector_home' ) vimspector_base_dir = utils.GetVimspectorBase() # TODO: Translate the arguments to something more user-friendly than -- args global OUTPUT_VIEW - if OUTPUT_VIEW: OUTPUT_VIEW.Reset() OUTPUT_VIEW = None @@ -112,10 +113,14 @@ def RunInstaller( api_prefix, *args ): def handler( exit_code ): if exit_code == 0: - utils.UserMessage( "Vimspector installation complete!" ) - vim.command( 'doautocmd User VimspectorInstallSuccess' ) + global OUTPUT_VIEW + if OUTPUT_VIEW: + OUTPUT_VIEW.Reset() + OUTPUT_VIEW = None + utils.UserMessage( "Vimspector gadget installation complete!" ) + vim.command( 'silent doautocmd User VimspectorInstallSuccess' ) else: - utils.UserMessage( 'Vimspector installation reported errors', + utils.UserMessage( 'Vimspector gadget installation reported errors', error = True ) vim.command( 'silent doautocmd User VimspectorInstallFailed' ) @@ -126,6 +131,27 @@ def RunInstaller( api_prefix, *args ): OUTPUT_VIEW.ShowOutput( 'Installer' ) +def GadgetListToInstallerArgs( *gadget_list ): + installer_args = [] + from vimspector import gadgets + for name in gadget_list: + if name.startswith( '-' ): + installer_args.append( name ) + continue + + try: + gadget = gadgets.GADGETS[ name ] + except KeyError: + continue + + if not gadget.get( 'enabled', True ): + installer_args.append( f'--force-enable-{ gadget[ "language" ] }' ) + else: + installer_args.append( f'--enable-{ gadget[ "language" ] }' ) + + return installer_args + + # def Install( languages, force ): # all_enabled = 'all' in languages # force_all = all_enabled and force From cd5ca37ce1b1da2b10e462785b75d1c6f7151a4c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 21 Jul 2020 22:48:26 +0100 Subject: [PATCH 10/23] Neovim support --- autoload/vimspector/internal/job.vim | 9 +- autoload/vimspector/internal/neojob.vim | 112 +++++++++++++----------- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/autoload/vimspector/internal/job.vim b/autoload/vimspector/internal/job.vim index 51ed137..474eb7c 100644 --- a/autoload/vimspector/internal/job.vim +++ b/autoload/vimspector/internal/job.vim @@ -147,11 +147,10 @@ function! vimspector#internal#job#Reset() abort endfunction function! s:_OnCommandExit( category, ch, code ) abort - py3 << EOF -from vimspector import utils as vimspector_utils -vimspector_utils.OnCommandWithLogComplete( vim.eval( 'a:category' ), - int( vim.eval( 'a:code' ) ) ) -EOF + py3 __import__( "vimspector", + \ fromlist = [ "utils" ] ).utils.OnCommandWithLogComplete( + \ vim.eval( 'a:category' ), + \ int( vim.eval( 'a:code' ) ) ) endfunction function! vimspector#internal#job#StartCommandWithLog( cmd, category ) abort diff --git a/autoload/vimspector/internal/neojob.vim b/autoload/vimspector/internal/neojob.vim index 9d0f79f..0cefc63 100644 --- a/autoload/vimspector/internal/neojob.vim +++ b/autoload/vimspector/internal/neojob.vim @@ -116,58 +116,65 @@ function! s:_OnCommandEvent( category, id, data, event ) abort return endif - if a:data == [''] - return - endif - - if !has_key( s:commands, a:category ) - return - endif - - if !has_key( s:commands[ a:category ], a:id ) - return - endif - - if a:event ==# 'stdout' - let buffer = s:commands[ a:category ][ a:id ].stdout - elseif a:event ==# 'stderr' - let buffer = s:commands[ a:category ][ a:id ].stderr - endif - - try - call bufload( buffer ) - catch /E325/ - " Ignore E325/ATTENTION - endtry - - - let numlines = py3eval( "len( vim.buffers[ int( vim.eval( 'buffer' ) ) ] )" ) - let last_line = getbufline( buffer, '$' )[ 0 ] - - call s:MakeBufferWritable( buffer ) - try - if numlines == 1 && last_line ==# '' - call setbufline( buffer, 1, a:data[ 0 ] ) - else - call setbufline( buffer, '$', last_line . a:data[ 0 ] ) + if a:event ==# 'stdout' || a:event ==# 'stderr' + if a:data == [''] + return endif - call appendbufline( buffer, '$', a:data[ 1: ] ) - finally - call s:MakeBufferReadOnly( buffer ) - call setbufvar( buffer, '&modified', 0 ) - endtry + if !has_key( s:commands, a:category ) + return + endif + + if !has_key( s:commands[ a:category ], a:id ) + return + endif + + if a:event ==# 'stdout' + let buffer = s:commands[ a:category ][ a:id ].stdout + elseif a:event ==# 'stderr' + let buffer = s:commands[ a:category ][ a:id ].stderr + endif - " if the buffer is visible, scroll it - let w = bufwinnr( buffer ) - if w > 0 - let cw = winnr() try - execute w . 'wincmd w' - normal! Gz. - finally - execute cw . 'wincmd w' + call bufload( buffer ) + catch /E325/ + " Ignore E325/ATTENTION endtry + + + let numlines = py3eval( "len( vim.buffers[ int( vim.eval( 'buffer' ) ) ] )" ) + let last_line = getbufline( buffer, '$' )[ 0 ] + + call s:MakeBufferWritable( buffer ) + try + if numlines == 1 && last_line ==# '' + call setbufline( buffer, 1, a:data[ 0 ] ) + else + call setbufline( buffer, '$', last_line . a:data[ 0 ] ) + endif + + call appendbufline( buffer, '$', a:data[ 1: ] ) + finally + call s:MakeBufferReadOnly( buffer ) + call setbufvar( buffer, '&modified', 0 ) + endtry + + " if the buffer is visible, scroll it + let w = bufwinnr( buffer ) + if w > 0 + let cw = winnr() + try + execute w . 'wincmd w' + normal! Gz- + finally + execute cw . 'wincmd w' + endtry + endif + elseif a:event ==# 'exit' + py3 __import__( "vimspector", + \ fromlist = [ "utils" ] ).utils.OnCommandWithLogComplete( + \ vim.eval( 'a:category' ), + \ int( vim.eval( 'a:data' ) ) ) endif endfunction @@ -210,7 +217,9 @@ function! vimspector#internal#neojob#StartCommandWithLog( cmd, category ) abort \ 'on_stdout': funcref( 's:_OnCommandEvent', \ [ a:category ] ), \ 'on_stderr': funcref( 's:_OnCommandEvent', - \ [ a:category ] ) + \ [ a:category ] ), + \ 'on_exit': funcref( 's:_OnCommandEvent', + \ [ a:category ] ), \ } ) let s:commands[ a:category ][ id ] = { @@ -227,8 +236,11 @@ function! vimspector#internal#neojob#CleanUpCommand( category ) abort endif for id in keys( s:commands[ a:category ] ) - call jobstop( str2nr( id ) ) - call jobwait( [ str2nr( id ) ] ) + let id = str2nr( id ) + if jobwait( [ id ], 0 )[ 0 ] == -1 + call jobstop( id ) + endif + call jobwait( [ id ], -1 ) endfor unlet! s:commands[ a:category ] endfunction From 375ff4aa2727b4c529c16a8f333e8a01d2d5f690 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 21 Jul 2020 23:18:07 +0100 Subject: [PATCH 11/23] Suggest installing gadget if possible --- python3/vimspector/debug_session.py | 21 ++++++++++++- python3/vimspector/installer.py | 48 +++++++++++------------------ 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index 17d6303..cc23a47 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -30,7 +30,8 @@ from vimspector import ( breakpoints, stack_trace, utils, variables, - settings ) + settings, + installer ) from vimspector.vendor.json_minify import minify # We cache this once, and don't allow it to change (FIXME?) @@ -151,6 +152,24 @@ class DebugSession( object ): adapter_dict = adapters.get( adapter ) if adapter_dict is None: + suggested_gadgets = installer.FindGadgetForAdapter( adapter ) + if suggested_gadgets: + response = utils.AskForInput( + f"The specified adapter '{adapter}' is not " + "installed. Would you like to install the following gadgets? ", + ' '.join( suggested_gadgets ) ) + if response: + new_launch_variables = dict( launch_variables ) + new_launch_variables[ 'configuration' ] = configuration_name + + installer.RunInstaller( + self._api_prefix, + *shlex.split( response ), + then = lambda: self.Start( new_launch_variables ) ) + return + elif response is None: + return + utils.UserMessage( f"The specified adapter '{adapter}' is not " "available. Did you forget to run " "'install_gadget.py'?", diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 33a6a76..e287adc 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -36,7 +36,7 @@ import traceback import zipfile import json -from vimspector import install +from vimspector import install, gadgets OUTPUT_VIEW = None @@ -81,7 +81,7 @@ def PathToAnyWorkingPython3(): raise RuntimeError( "Unable to find a working python3" ) -def RunInstaller( api_prefix, *args ): +def RunInstaller( api_prefix, *args, **kwargs ): from vimspector import utils, output, settings import vim @@ -119,6 +119,8 @@ def RunInstaller( api_prefix, *args ): OUTPUT_VIEW = None utils.UserMessage( "Vimspector gadget installation complete!" ) vim.command( 'silent doautocmd User VimspectorInstallSuccess' ) + if 'then' in kwargs: + kwargs[ 'then' ]() else: utils.UserMessage( 'Vimspector gadget installation reported errors', error = True ) @@ -133,7 +135,6 @@ def RunInstaller( api_prefix, *args ): def GadgetListToInstallerArgs( *gadget_list ): installer_args = [] - from vimspector import gadgets for name in gadget_list: if name.startswith( '-' ): installer_args.append( name ) @@ -152,34 +153,21 @@ def GadgetListToInstallerArgs( *gadget_list ): return installer_args -# def Install( languages, force ): -# all_enabled = 'all' in languages -# force_all = all_enabled and force -# -# install.MakeInstallDirs( options.vimspector_base ) -# all_adapters = ReadAdapters() -# succeeded = [] -# failed = [] -# -# for name, gadget in gadgets.GADGETS.items(): -# if not gadget.get( 'enabled', True ): -# if ( not force_all -# and not ( force and gadget[ 'language' ] in languages ) ): -# continue -# else: -# if not all_enabled and not gadget[ 'language' ] in languages: -# continue -# -# InstallGagdet( name, -# gadget, -# succeeded, -# failed, -# all_adapters ) -# -# WriteAdapters( all_adapters ) -# -# return succeeded, failed +def FindGadgetForAdapter( adapter_name ): + candidates = [] + for name, gadget in gadgets.GADGETS.items(): + v = {} + v.update( gadget.get( 'all', {} ) ) + v.update( gadget.get( install.GetOS(), {} ) ) + adapters = {} + adapters.update( v.get( 'adapters', {} ) ) + adapters.update( gadget.get( 'adapters', {} ) ) + + if adapter_name in adapters: + candidates.append( name ) + + return candidates def InstallGeneric( name, root, gadget ): From 98bef3db030d056f80d4a8939822d63fc6bf7cd1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 09:36:32 +0100 Subject: [PATCH 12/23] Fix - don't switch windows/buffers to create a new hidden buffer --- autoload/vimspector.vim | 83 +++++++++++++++++++- autoload/vimspector/internal/state.vim | 20 +++-- python3/vimspector/installer.py | 1 - python3/vimspector/output.py | 102 ++++++++++++------------- python3/vimspector/utils.py | 7 ++ 5 files changed, 155 insertions(+), 58 deletions(-) diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 1dd22f1..8ad19e2 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -20,29 +20,47 @@ set cpoptions&vim " }}} -call vimspector#internal#state#Reset() +let s:enabled = vimspector#internal#state#Reset() function! vimspector#Launch() abort + if !s:enabled + return + endif py3 _vimspector_session.Start() endfunction function! vimspector#LaunchWithSettings( settings ) abort + if !s:enabled + return + endif py3 _vimspector_session.Start( launch_variables = vim.eval( 'a:settings' ) ) endfunction function! vimspector#Reset() abort + if !s:enabled + return + endif py3 _vimspector_session.Reset() endfunction function! vimspector#Restart() abort + if !s:enabled + return + endif py3 _vimspector_session.Restart() endfunction function! vimspector#ClearBreakpoints() abort + if !s:enabled + return + endif py3 _vimspector_session.ClearBreakpoints() endfunction function! vimspector#ToggleBreakpoint( ... ) abort + if !s:enabled + return + endif if a:0 == 0 let options = {} else @@ -52,6 +70,9 @@ function! vimspector#ToggleBreakpoint( ... ) abort endfunction function! vimspector#AddFunctionBreakpoint( function, ... ) abort + if !s:enabled + return + endif if a:0 == 0 let options = {} else @@ -62,42 +83,72 @@ function! vimspector#AddFunctionBreakpoint( function, ... ) abort endfunction function! vimspector#StepOver() abort + if !s:enabled + return + endif py3 _vimspector_session.StepOver() endfunction function! vimspector#StepInto() abort + if !s:enabled + return + endif py3 _vimspector_session.StepInto() endfunction function! vimspector#StepOut() abort + if !s:enabled + return + endif py3 _vimspector_session.StepOut() endfunction function! vimspector#Continue() abort + if !s:enabled + return + endif py3 _vimspector_session.Continue() endfunction function! vimspector#Pause() abort + if !s:enabled + return + endif py3 _vimspector_session.Pause() endfunction function! vimspector#Stop() abort + if !s:enabled + return + endif py3 _vimspector_session.Stop() endfunction function! vimspector#ExpandVariable() abort + if !s:enabled + return + endif py3 _vimspector_session.ExpandVariable() endfunction function! vimspector#DeleteWatch() abort + if !s:enabled + return + endif py3 _vimspector_session.DeleteWatch() endfunction function! vimspector#GoToFrame() abort + if !s:enabled + return + endif py3 _vimspector_session.ExpandFrameOrThread() endfunction function! vimspector#AddWatch( ... ) abort + if !s:enabled + return + endif if a:0 == 0 let expr = input( 'Enter watch expression: ' ) else @@ -112,27 +163,42 @@ function! vimspector#AddWatch( ... ) abort endfunction function! vimspector#AddWatchPrompt( expr ) abort + if !s:enabled + return + endif stopinsert setlocal nomodified call vimspector#AddWatch( a:expr ) endfunction function! vimspector#Evaluate( expr ) abort + if !s:enabled + return + endif py3 _vimspector_session.ShowOutput( 'Console' ) py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) ) endfunction function! vimspector#EvaluateConsole( expr ) abort + if !s:enabled + return + endif stopinsert setlocal nomodified py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) ) endfunction function! vimspector#ShowOutput( category ) abort + if !s:enabled + return + endif py3 _vimspector_session.ShowOutput( vim.eval( 'a:category' ) ) endfunction function! vimspector#ShowOutputInWindow( win_id, category ) abort + if !s:enabled + return + endif py3 __import__( 'vimspector', \ fromlist = [ 'output' ] ).output.ShowOutputInWindow( \ int( vim.eval( 'a:win_id' ) ), @@ -140,16 +206,25 @@ function! vimspector#ShowOutputInWindow( win_id, category ) abort endfunction function! vimspector#ListBreakpoints() abort + if !s:enabled + return + endif py3 _vimspector_session.ListBreakpoints() endfunction function! vimspector#CompleteOutput( ArgLead, CmdLine, CursorPos ) abort + if !s:enabled + return + endif let buffers = py3eval( '_vimspector_session.GetOutputBuffers() ' \ . ' if _vimspector_session else []' ) return join( buffers, "\n" ) endfunction function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort + if !s:enabled + return + endif return join( py3eval( '_vimspector_session.GetCompletionsSync( ' \.' vim.eval( "a:CmdLine" ),' \.' int( vim.eval( "a:CursorPos" ) ) )' @@ -158,6 +233,9 @@ function! vimspector#CompleteExpr( ArgLead, CmdLine, CursorPos ) abort endfunction function! vimspector#Install( ... ) abort + if !s:enabled + return + endif if a:0 < 1 return endif @@ -169,6 +247,9 @@ function! vimspector#Install( ... ) abort endfunction function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort + if !s:enabled + return + endif return py3eval( '"\n".join(' \ . '__import__( "vimspector", fromlist = [ "gadgets" ] )' \ . '.gadgets.GADGETS.keys() ' diff --git a/autoload/vimspector/internal/state.vim b/autoload/vimspector/internal/state.vim index a03d9a3..b4f18aa 100644 --- a/autoload/vimspector/internal/state.vim +++ b/autoload/vimspector/internal/state.vim @@ -25,11 +25,21 @@ if has( 'nvim' ) endif function! vimspector#internal#state#Reset() abort - py3 << EOF -import vim -from vimspector import debug_session -_vimspector_session = debug_session.DebugSession( vim.eval( 's:prefix' ) ) -EOF + try + py3 import vim + py3 _vimspector_session = __import__( + \ "vimspector", + \ fromlist=[ "debug_session" ] ).debug_session.DebugSession( + \ vim.eval( 's:prefix' ) ) + catch /.*/ + echohl WarningMsg + echom 'Exception while loading vimspector:' v:exception + echom 'Vimspector unavailable: Requires Vim compiled with Python 3.6' + echohl None + return v:false + endtry + + return v:true endfunction function! vimspector#internal#state#GetAPIPrefix() abort diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index e287adc..f52d667 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -90,7 +90,6 @@ def RunInstaller( api_prefix, *args, **kwargs ): vimspector_home = utils.GetVimString( vim.vars, 'vimspector_home' ) vimspector_base_dir = utils.GetVimspectorBase() - # TODO: Translate the arguments to something more user-friendly than -- args global OUTPUT_VIEW if OUTPUT_VIEW: OUTPUT_VIEW.Reset() diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index 4cd7c64..3a2d5cb 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -52,6 +52,8 @@ def ShowOutputInWindow( win_id, category ): class OutputView( object ): + """Container for a 'tabbed' window of buffers that can be used to display + files or the output of commands.""" def __init__( self, window, api_prefix ): self._window = window self._buffers = {} @@ -144,75 +146,73 @@ class OutputView( object ): file_name = None, cmd = None, completion_handler = None ): - win = self._window - if not win.valid: - # We need to borrow the current window - win = vim.current.window + if file_name is not None: + assert cmd is None + if install.GetOS() == "windows": + # FIXME: Can't display fiels in windows (yet?) + return - with utils.LetCurrentWindow( win ): - with utils.RestoreCurrentBuffer( win ): + cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ] - if file_name is not None: - assert cmd is None - if install.GetOS() == "windows": - # FIXME: Can't display fiels in windows (yet?) - return + if cmd is not None: + out = utils.SetUpCommandBuffer( + cmd, + category, + self._api_prefix, + completion_handler = completion_handler ) + self._buffers[ category ] = TabBuffer( out, len( self._buffers ) ) + self._buffers[ category ].is_job = True + self._RenderWinBar( category ) + else: + if category == 'Console': + name = 'vimspector.Console' + else: + name = 'vimspector.Output:{0}'.format( category ) - cmd = [ 'tail', '-F', '-n', '+1', '--', file_name ] + tab_buffer = TabBuffer( utils.NewEmptyBuffer(), len( self._buffers ) ) + self._buffers[ category ] = tab_buffer - if cmd is not None: - out = utils.SetUpCommandBuffer( - cmd, - category, - self._api_prefix, - completion_handler = completion_handler ) - self._buffers[ category ] = TabBuffer( out, len( self._buffers ) ) - self._buffers[ category ].is_job = True - self._RenderWinBar( category ) - else: - vim.command( 'enew' ) - tab_buffer = TabBuffer( vim.current.buffer, len( self._buffers ) ) - self._buffers[ category ] = tab_buffer - if category == 'Console': - utils.SetUpPromptBuffer( tab_buffer.buf, - 'vimspector.Console', - '> ', - 'vimspector#EvaluateConsole' ) - else: - utils.SetUpHiddenBuffer( - tab_buffer.buf, - 'vimspector.Output:{0}'.format( category ) ) + if category == 'Console': + utils.SetUpPromptBuffer( tab_buffer.buf, + name, + '> ', + 'vimspector#EvaluateConsole' ) + else: + utils.SetUpHiddenBuffer( tab_buffer.buf, name ) - self._RenderWinBar( category ) + self._RenderWinBar( category ) def _RenderWinBar( self, category ): if not self._window.valid: return - tab_buffer = self._buffers[ category ] + with utils.LetCurrentWindow( self._window ): + tab_buffer = self._buffers[ category ] - try: - if tab_buffer.flag: - vim.command( 'nunmenu WinBar.{}'.format( utils.Escape( category ) ) ) - else: - vim.command( 'nunmenu WinBar.{}*'.format( utils.Escape( category ) ) ) - except vim.error as e: - # E329 means the menu doesn't exist; ignore that. - if 'E329' not in str( e ): - raise + try: + if tab_buffer.flag: + vim.command( 'nunmenu WinBar.{}'.format( utils.Escape( category ) ) ) + else: + vim.command( 'nunmenu WinBar.{}*'.format( utils.Escape( category ) ) ) + except vim.error as e: + # E329 means the menu doesn't exist; ignore that. + if 'E329' not in str( e ): + raise - vim.command( "nnoremenu 1.{0} WinBar.{1}{2} " - ":call vimspector#ShowOutputInWindow( {3}, '{1}' )".format( - tab_buffer.index, - utils.Escape( category ), - '*' if tab_buffer.flag else '', - utils.WindowID( self._window ) ) ) + vim.command( + "nnoremenu 1.{0} WinBar.{1}{2} " + ":call vimspector#ShowOutputInWindow( {3}, '{1}' )".format( + tab_buffer.index, + utils.Escape( category ), + '*' if tab_buffer.flag else '', + utils.WindowID( self._window ) ) ) def GetCategories( self ): return list( self._buffers.keys() ) class DAPOutputView( OutputView ): + """Specialised OutputView which adds the DAP Console (REPL)""" def __init__( self, *args ): super().__init__( *args ) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index d2870c6..fe11631 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -52,6 +52,12 @@ def BufferForFile( file_name ): return vim.buffers[ BufferNumberForFile( file_name ) ] +def NewEmptyBuffer(): + bufnr = int( vim.eval( 'bufadd("")' ) ) + Call( 'bufload', bufnr ) + return vim.buffers[ bufnr ] + + def WindowForBuffer( buf ): for w in vim.current.tabpage.windows: if w.buffer == buf: @@ -353,6 +359,7 @@ def AskForInput( prompt, default_value = None ): def AppendToBuffer( buf, line_or_lines, modified=False ): + line = 1 try: # After clearing the buffer (using buf[:] = None) there is always a single # empty line in the buffer object and no "is empty" method. From 8275d2fafb130c3c189aca28c2cb80edd575a66c Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 11:53:51 +0100 Subject: [PATCH 13/23] README updates --- README.md | 188 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 84 deletions(-) diff --git a/README.md b/README.md index f70f537..3fc4722 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,12 @@ For a tutorial and usage overview, take a look at the * [Features and Usage](#features-and-usage) * [Supported debugging features](#supported-debugging-features) - * [Supported languages:](#supported-languages) - * [Languages known to work](#languages-known-to-work) - * [Languages known not to work](#languages-known-not-to-work) + * [Supported languages](#supported-languages) * [Other languages](#other-languages) * [Installation](#installation) * [Dependencies](#dependencies) * [Neovim differences](#neovim-differences) * [Windows differences](#windows-differences) - * [Language dependencies](#language-dependencies) * [Clone the plugin](#clone-the-plugin) * [Install some gadgets](#install-some-gadgets) * [Manual gadget installation](#manual-gadget-installation) @@ -66,7 +63,7 @@ For a tutorial and usage overview, take a look at the * [Customisation](#customisation) * [Changing the default signs](#changing-the-default-signs) * [Changing the default window sizes](#changing-the-default-window-sizes) - * [Changing the terminal size](#changing-the-terminal-size) + * [Changing the terminal size](#changing-the-terminal-size) * [Advanced UI customisation](#advanced-ui-customisation) * [Example](#example) * [FAQ](#faq) @@ -74,7 +71,7 @@ For a tutorial and usage overview, take a look at the * [License](#license) * [Sponsorship](#sponsorship) - + @@ -91,6 +88,12 @@ But for now, here's a (rather old) screenshot of Vimsepctor debugging Vim: ![vimspector-vim-screenshot](https://puremourning.github.io/vimspector-web/img/vimspector-overview.png) +And a couple of brief demos: + +[![asciicast](https://asciinema.org/a/VmptWmFHTNLPfK3DVsrR2bv8S.svg)](https://asciinema.org/a/VmptWmFHTNLPfK3DVsrR2bv8S) + +[![asciicast](https://asciinema.org/a/1wZJSoCgs3AvjkhKwetJOJhDh.svg)](https://asciinema.org/a/1wZJSoCgs3AvjkhKwetJOJhDh) + ## Supported debugging features - flexible configuration syntax that can be checked in to source control @@ -108,31 +111,32 @@ But for now, here's a (rather old) screenshot of Vimsepctor debugging Vim: - logging/stdout display - simple stable API for custom tooling (e.g. integrate with language server) -## Supported languages: +For other languages, you'll need some other way to install the gadget. -The following languages are used frequently by the author and are known to work -with little effort, and are supported as first-class languages. +## Supported languages -- C, C++, etc. (languages supported by gdb or lldb) -- Python 2 and Python 3 -- TCL -- Bash scripts -- Java +The following table lists the languages that are "built-in" (along with their +runtime dependencies). They are categorised by their level of support: -## Languages known to work +* `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 -The following languages are used frequently by the author, but require some sort -of hackery that makes it challenging to support generally. These languages are -on a best-efforts basis: - -- C# (c-sharp) using dotnet core -- Go (requires separate installation of [Delve][]) -- Node.js (requires node <12 for installation) -- Anything running in chrome (i.e. javascript). - -## Languages known not to work - -- C# (c-sharp) using mono debug adapter (vimspector unable to set breakpoints) +| Language | Status | Switch (for `install_gadget.py`) | Adapter (for `:VimspectorInstall`) | Dependencies | +|------------------|--------------|----------------------------------|------------------------------------|--------------------------------------------| +| C, C++, etc. | Tested | `--all` or `--enable-c` | vscode-cpptools | mono-core | +| 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?? | +| 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 | +| Rust (CodeLLDB) | Experimental | `--force-enable-rust` | CodeLLDB | Python 3 | +| Python.legacy | Legacy | `--force-enable-python.legacy` | vscode-python | Node 10, Python 2.7 or Python 3 | ## Other languages @@ -224,33 +228,6 @@ The following features are not implemented for Windows: * Tailing the vimspector log in the Output Window. -## Language dependencies - -The debug adapters themselves have certain runtime dependencies. They are -categorised as follows: - -* `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 | Adapter | Dependencies | -|------------------|--------------|--------------------------------|---------------------|--------------------------------------------| -| C, C++, etc. | Tested | `--all` or `--enable-c` | vscode-cpptools | mono-core | -| 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?? | -| 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 | -| Rust (CodeLLDB) | Experimental | `--force-enable-rust` | CodeLLDB | Python 3 | -| Python.legacy | Legacy | `--force-enable-python.legacy` | vscode-python | Node 10, Python 2.7 or Python 3 | - -For other languages, you'll need some other way to install the gadget. - ## Clone the plugin There are many Vim plugin managers, and I'm not going to state a particular @@ -281,10 +258,27 @@ See support/doc/example_vimrc.vim. ## Install some gadgets -There are a couple of ways of doing this, but ***using `install_gadget.py` is -highly recommended*** where that's an option. +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. -For supported languages, `install_gadget.py` will: +In order for Vimspector to be useful, you need to have some adapters installed. + +There are a few ways to do this: + +* 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) +* When attempting to launch a debug configuration, if the configured adapter + can't be found, vimspector might suggest installing one. + +Here's a demo: + +[![asciicast](https://asciinema.org/a/M3kShmfAZ8I5YewTCCKezzrr9.svg)](https://asciinema.org/a/M3kShmfAZ8I5YewTCCKezzrr9) + +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 @@ -298,25 +292,29 @@ For supported languages, `install_gadget.py` will: To install the tested debug adapter for a language, run: -``` -./install_gadget.py --enable- -``` +| 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 | -Or to install all supported gagtets: +`"VimspectorInstall` runs `install_gadget.py` in the background with some of +the options defaulted. -``` -./install_gadget.py --all -``` +Here's a demo: -To install everything other than TCL (because TCL is sadly not as popular as it -should be): +[![asciicast](https://asciinema.org/a/mJQmMAuQG4rOp5DWq1IhDvQty.svg)](https://asciinema.org/a/mJQmMAuQG4rOp5DWq1IhDvQty) -``` -./install_gadget.py --all --disable-tcl -``` +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 without destroying the exisitng ones, add -`--update-gadget-config`, as in: +If you want to just add a new adapter using the script without destroying the +exisitng ones, add `--update-gadget-config`, as in: ```bash $ ./install_gadget.py --enable-tcl @@ -339,10 +337,16 @@ Then add this to your `.vimrc`: let g:vimspector_base_dir=expand( '$HOME/.vim/vimspector-config' ) ``` -See `--help` for more info. +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. ## 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`. @@ -352,7 +356,9 @@ 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 configuration to do this to `install_gadget.py`. +PRs are always welcome to add supported languages (which roughly translates to +updating `python/vimspector/gadgets.py` and testing it). + ### The gadget directory @@ -415,7 +421,8 @@ Example: } ``` -The gadget file is automatically written by `install_gadget.py`. +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 @@ -865,9 +872,9 @@ an example of getting Vimspector to remotely launch and attach. ## Python * Python: [debugpy][] -* Requires `install_gadget.py --enable-python`, ideally requires a working - compiler and the python development headers/libs to build a C python extension - for performance. +* 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 @@ -978,7 +985,8 @@ See [my fork of TclProDebug](https://github.com/puremourning/TclProDebug) for in * C# - dotnet core -Requires `install_gadget.py --force-enable-csharp` +Install with `install_gadget.py --force-enable-csharp` or `:VimspectorInstall +netcoredbg` ```json { @@ -998,7 +1006,8 @@ Requires `install_gadget.py --force-enable-csharp` * C# - mono -Requires `install_gadget.py --force-enable-csharp`. +Install with `install_gadget.py --force-enable-csharp` or `:VimspectorInstall +vscode-mono-debug`. ***Known not to work.*** @@ -1029,7 +1038,7 @@ Requires `install_gadget.py --force-enable-csharp`. Requires: -* `install_gadget.py --enable-go` +* `install_gadget.py --enable-go` or `:VimspectorInstall vscode-go` * [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 @@ -1057,7 +1066,8 @@ https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug Requires: * (optional) Xdebug helper for chrome https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc -* `install_gadget.py --force-enable-php` +* `install_gadget.py --force-enable-php` or `:VimspectorInstall + vscode-php-debug` * configured php xdebug extension ```ini zend_extension=xdebug.so @@ -1161,7 +1171,8 @@ https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome It allows you to debug scripts running inside chrome from within Vim. -* `./install_gadget.py --force-enable-chrome` +* `./install_gadget.py --force-enable-chrome` or `:VimspectorInstall + debugger-for-chrome` * Example: `support/test/chrome` ```json @@ -1195,7 +1206,8 @@ use it with Vimspector. * Set up [YCM for java][YcmJava]. * Get Vimspector to download the java debug plugin: - `install_gadget.py --force-enable-java ` + `install_gadget.py --force-enable-java ` or + `:VimspectorInstall java-debug-adapter` * Configure Vimspector for your project using the `vscode-java` adapter, e.g.: ```json @@ -1266,7 +1278,7 @@ 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`](https://github.com/vadimcn/vscode-lldb#features). -* `./install_gadget.py --force-enable-rust` +* `./install_gadget.py --force-enable-rust` or `:VimspectorInstall CodeLLDB` * Example: `support/test/rust/vimspector_test` ```json @@ -1478,6 +1490,14 @@ hi link jsonCommentError Comment 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 + `adapter` is something that Vimspector talks to (actually it's the Vimsepctor + 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. + # Motivation A message from the author about the motivation for this plugin: From 4144631d0367e43f99d436c8f5872a4484ce7994 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 12:50:44 +0100 Subject: [PATCH 14/23] Add :VimspectorUpdate --- README.md | 5 +++++ autoload/vimspector.vim | 11 +++++++++++ plugin/vimspector.vim | 4 ++++ python3/vimspector/installer.py | 13 +++++++++++++ 4 files changed, 33 insertions(+) diff --git a/README.md b/README.md index 3fc4722..4bd72c9 100644 --- a/README.md +++ b/README.md @@ -453,6 +453,11 @@ 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. +## Upgrade + +After updating the Vimspector code (either via `git pull` or whatever pacakge +manager), run `:VimspectorUpdate` to update any already-installed gadets. + # About ## Background diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 8ad19e2..791c262 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -256,6 +256,17 @@ function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort \ . ')' ) endfunction +function! vimspector#Update() abort + if !s:enabled + return + endif + + let prefix = vimspector#internal#state#GetAPIPrefix() + py3 __import__( 'vimspector', + \ fromlist = [ 'installer' ] ).installer.RunUpdate( + \ vim.eval( 'prefix' ) ) +endfunction + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index 338d034..be51c27 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -102,6 +102,10 @@ command! -bar command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall \ VimspectorInstall \ call vimspector#Install( ) +command! -bar -nargs=0 + \ VimspectorUpdate + \ call vimspector#Update() + " Dummy autocommands so that we can call this whenever diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index f52d667..53a48a6 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -132,6 +132,19 @@ def RunInstaller( api_prefix, *args, **kwargs ): OUTPUT_VIEW.ShowOutput( 'Installer' ) +def RunUpdate( api_prefix ): + from vimspector import utils + Configure( vimspector_base = utils.GetVimspectorBase() ) + + current_adapters = ReadAdapters( read_existing = True ) + adapters = [] + for adapter_name in current_adapters.keys(): + adapters.extend( FindGadgetForAdapter( adapter_name ) ) + + if adapters: + RunInstaller( api_prefix, *adapters ) + + def GadgetListToInstallerArgs( *gadget_list ): installer_args = [] for name in gadget_list: From 000f7a923220deea4aa98300413fc289743a0b9f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 14:40:23 +0100 Subject: [PATCH 15/23] Prettify the output with some syntax and quiet option --- README.md | 13 ++- autoload/vimspector.vim | 15 +++- install_gadget.py | 18 ++++- plugin/vimspector.vim | 7 +- python3/vimspector/installer.py | 139 +++++++++++++++++++------------- python3/vimspector/output.py | 16 ++-- python3/vimspector/utils.py | 3 +- syntax/vimspector-installer.vim | 13 +++ 8 files changed, 146 insertions(+), 78 deletions(-) create mode 100644 syntax/vimspector-installer.vim diff --git a/README.md b/README.md index 4bd72c9..d20f046 100644 --- a/README.md +++ b/README.md @@ -268,13 +268,16 @@ There are a few ways to do this: * 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) +* Alternatively, using `python3 install_gadget.py ` (use `--help` to see + all options) * When attempting to launch a debug configuration, if the configured adapter can't be found, vimspector might suggest installing one. +* Use `:VimspectorUpdate` to install the latest supported versions of the + gadgets. -Here's a demo: +Here's a demo of doing somee installs and an upgrade: -[![asciicast](https://asciinema.org/a/M3kShmfAZ8I5YewTCCKezzrr9.svg)](https://asciinema.org/a/M3kShmfAZ8I5YewTCCKezzrr9) +[![asciicast](https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay.svg)](https://asciinema.org/a/Hfu4ZvuyTZun8THNen9FQbTay) Both `install_gadget.py` and `:VimspectorInstall` do the same set of things, though the default behaviours are slightly different. For supported languages, @@ -305,10 +308,6 @@ To install the tested debug adapter for a language, run: `"VimspectorInstall` runs `install_gadget.py` in the background with some of the options defaulted. -Here's a demo: - -[![asciicast](https://asciinema.org/a/mJQmMAuQG4rOp5DWq1IhDvQty.svg)](https://asciinema.org/a/mJQmMAuQG4rOp5DWq1IhDvQty) - 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. diff --git a/autoload/vimspector.vim b/autoload/vimspector.vim index 791c262..1ada223 100644 --- a/autoload/vimspector.vim +++ b/autoload/vimspector.vim @@ -256,7 +256,7 @@ function! vimspector#CompleteInstall( ArgLead, CmdLine, CursorPos ) abort \ . ')' ) endfunction -function! vimspector#Update() abort +function! vimspector#Update( ... ) abort if !s:enabled return endif @@ -264,9 +264,20 @@ function! vimspector#Update() abort let prefix = vimspector#internal#state#GetAPIPrefix() py3 __import__( 'vimspector', \ fromlist = [ 'installer' ] ).installer.RunUpdate( - \ vim.eval( 'prefix' ) ) + \ vim.eval( 'prefix' ), + \ *vim.eval( 'a:000' ) ) endfunction +function! vimspector#AbortInstall() abort + if !s:enabled + return + endif + + let prefix = vimspector#internal#state#GetAPIPrefix() + py3 __import__( 'vimspector', fromlist = [ 'installer' ] ).installer.Abort() +endfunction + + " Boilerplate {{{ let &cpoptions=s:save_cpo unlet s:save_cpo diff --git a/install_gadget.py b/install_gadget.py index c030699..44dbfe4 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -69,6 +69,14 @@ parser.add_argument( '--force-all', action = 'store_true', help = 'Enable all unsupported completers' ) +parser.add_argument( '--quiet', + action = 'store_true', + help = 'Suppress installation output' ) + +parser.add_argument( '--verbose', + action = 'store_true', + help = 'Force installation output' ) + parser.add_argument( '--basedir', action = 'store', help = 'Advanced option. ' @@ -145,6 +153,7 @@ if args.basedir: install.MakeInstallDirs( vimspector_base ) installer.Configure( vimspector_base = vimspector_base, + quiet = args.quiet and not args.verbose, no_check_certificate = args.no_check_certificate ) if args.force_all and not args.all: @@ -202,8 +211,11 @@ if args.basedir: "let g:vimspector_base_dir='" + vimspector_base + "'" ) if succeeded: - print( "The following adapters were installed successfully: {}".format( - ','.join( succeeded ) ) ) + print( "Done. The following adapters were installed successfully:\n - {}".format( + '\n - '.join( succeeded ) ) ) if failed: - sys.exit( 'Failed to install adapters: {}'.format( ','.join( failed ) ) ) + sys.exit( 'Failed to install adapters:\n * {}{}'.format( + '\n * '.join( failed ), + "\nRe-run with --verbose for more info on failures" + if args.quiet and not args.verbose else '' ) ) diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index be51c27..afc1c08 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -102,9 +102,12 @@ command! -bar command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall \ VimspectorInstall \ call vimspector#Install( ) -command! -bar -nargs=0 +command! -bar -nargs=* \ VimspectorUpdate - \ call vimspector#Update() + \ call vimspector#Update( ) +command! -bar -nargs=* + \ VimspectorAbortInstall + \ call vimspector#AbortInstall( ) diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 53a48a6..28624af 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -44,6 +44,7 @@ OUTPUT_VIEW = None class Options: vimspector_base = None no_check_certificate = False + quiet = False options = Options() @@ -54,6 +55,23 @@ def Configure( **kwargs ): setattr( options, k, v ) +def Print( *args, **kwargs ): + if not options.quiet: + print( *args, **kwargs ) + + +def CheckCall( *args, **kwargs ): + if options.quiet: + out = subprocess.PIPE + else: + out = sys.stdout + + kwargs[ 'stdout' ] = out + kwargs[ 'stderr' ] = subprocess.STDOUT + + subprocess.check_call( *args, **kwargs ) + + def PathToAnyWorkingPython3(): # We can't rely on sys.executable because it's usually 'vim' (fixme, not with # neovim?) @@ -91,9 +109,7 @@ def RunInstaller( api_prefix, *args, **kwargs ): vimspector_base_dir = utils.GetVimspectorBase() global OUTPUT_VIEW - if OUTPUT_VIEW: - OUTPUT_VIEW.Reset() - OUTPUT_VIEW = None + _ResetInstaller() with utils.RestoreCurrentWindow(): vim.command( f'botright { settings.Int( "bottombar_height", 10 ) }new' ) @@ -104,6 +120,7 @@ def RunInstaller( api_prefix, *args, **kwargs ): PathToAnyWorkingPython3(), '-u', os.path.join( vimspector_home, 'install_gadget.py' ), + '--quiet', '--update-gadget-config', ] if not vimspector_base_dir == vimspector_home: @@ -112,10 +129,7 @@ def RunInstaller( api_prefix, *args, **kwargs ): def handler( exit_code ): if exit_code == 0: - global OUTPUT_VIEW - if OUTPUT_VIEW: - OUTPUT_VIEW.Reset() - OUTPUT_VIEW = None + _ResetInstaller() utils.UserMessage( "Vimspector gadget installation complete!" ) vim.command( 'silent doautocmd User VimspectorInstallSuccess' ) if 'then' in kwargs: @@ -128,21 +142,37 @@ def RunInstaller( api_prefix, *args, **kwargs ): OUTPUT_VIEW.RunJobWithOutput( 'Installer', cmd, - completion_handler = handler ) + completion_handler = handler, + syntax = 'vimspector-installer' ) OUTPUT_VIEW.ShowOutput( 'Installer' ) -def RunUpdate( api_prefix ): +def RunUpdate( api_prefix, *args ): from vimspector import utils Configure( vimspector_base = utils.GetVimspectorBase() ) + args = list( args ) current_adapters = ReadAdapters( read_existing = True ) - adapters = [] for adapter_name in current_adapters.keys(): - adapters.extend( FindGadgetForAdapter( adapter_name ) ) + args.extend( FindGadgetForAdapter( adapter_name ) ) - if adapters: - RunInstaller( api_prefix, *adapters ) + if args: + RunInstaller( api_prefix, *args ) + + +def _ResetInstaller(): + global OUTPUT_VIEW + if OUTPUT_VIEW: + OUTPUT_VIEW.Reset() + OUTPUT_VIEW = None + + +def Abort(): + _ResetInstaller() + from vimspector import utils + utils.UserMessage( 'Vimspector installation aborted', + persist = True, + error = True ) def GadgetListToInstallerArgs( *gadget_list ): @@ -222,7 +252,7 @@ def InstallDebugpy( name, root, gadget ): root = os.path.join( root, 'debugpy-{}'.format( gadget[ 'version' ] ) ) os.chdir( root ) try: - subprocess.check_call( [ sys.executable, 'setup.py', 'build' ] ) + CheckCall( [ sys.executable, 'setup.py', 'build' ] ) finally: os.chdir( wd ) @@ -258,8 +288,8 @@ def InstallTclProDebug( name, root, gadget ): with CurrentWorkingDir( os.path.join( root, 'lib', 'tclparser' ) ): - subprocess.check_call( configure ) - subprocess.check_call( [ 'make' ] ) + CheckCall( configure ) + CheckCall( [ 'make' ] ) MakeSymlink( name, root ) @@ -267,26 +297,27 @@ def InstallTclProDebug( name, root, gadget ): def InstallNodeDebug( name, root, gadget ): node_version = subprocess.check_output( [ 'node', '--version' ], universal_newlines=True ).strip() - print( "Node.js version: {}".format( node_version ) ) + Print( "Node.js version: {}".format( node_version ) ) if list( map( int, node_version[ 1: ].split( '.' ) ) ) >= [ 12, 0, 0 ]: - print( "Can't install vscode-debug-node2:" ) - print( "Sorry, you appear to be running node 12 or later. That's not " + Print( "Can't install vscode-debug-node2:" ) + Print( "Sorry, you appear to be running node 12 or later. That's not " "compatible with the build system for this extension, and as far as " "we know, there isn't a pre-built independent package." ) - print( "My advice is to install nvm, then do:" ) - print( " $ nvm install --lts 10" ) - print( " $ nvm use --lts 10" ) - print( " $ ./install_gadget.py --enable-node ..." ) - raise RuntimeError( 'Invalid node environent for node debugger' ) + Print( "My advice is to install nvm, then do:" ) + Print( " $ nvm install --lts 10" ) + Print( " $ nvm use --lts 10" ) + Print( " $ ./install_gadget.py --enable-node ..." ) + raise RuntimeError( 'Node 10 is required to install node debugger (sadly)' ) with CurrentWorkingDir( root ): - subprocess.check_call( [ 'npm', 'install' ] ) - subprocess.check_call( [ 'npm', 'run', 'build' ] ) + CheckCall( [ 'npm', 'install' ] ) + CheckCall( [ 'npm', 'run', 'build' ] ) MakeSymlink( name, root ) def InstallGagdet( name, gadget, succeeded, failed, all_adapters ): try: + print( f"Installing {name}..." ) v = {} v.update( gadget.get( 'all', {} ) ) v.update( gadget.get( install.GetOS(), {} ) ) @@ -339,11 +370,12 @@ def InstallGagdet( name, gadget, succeeded, failed, all_adapters ): all_adapters.update( gadget.get( 'adapters', {} ) ) succeeded.append( name ) - print( "Done installing {}".format( name ) ) + print( f" - Done installing {name}" ) except Exception as e: - traceback.print_exc() + if not options.quiet: + traceback.print_exc() failed.append( name ) - print( "FAILED installing {}: {}".format( name, e ) ) + print( f" - FAILED installing {name}: {e}".format( name, e ) ) def ReadAdapters( read_existing = True ): @@ -392,7 +424,7 @@ def CurrentWorkingDir( d ): def MakeExecutable( file_path ): # TODO: import stat and use them by _just_ adding the X bit. - print( 'Making executable: {}'.format( file_path ) ) + Print( 'Making executable: {}'.format( file_path ) ) os.chmod( file_path, 0o755 ) @@ -409,7 +441,7 @@ def WithRetry( f ): return f( *args, **kwargs ) except Exception as e: thrown = e - print( "Failed - {}, will retry in {} seconds".format( e, timeout ) ) + Print( "Failed - {}, will retry in {} seconds".format( e, timeout ) ) time.sleep( timeout ) raise thrown @@ -437,13 +469,13 @@ def DownloadFileTo( url, if os.path.exists( file_path ): if checksum: if ValidateCheckSumSHA256( file_path, checksum ): - print( "Checksum matches for {}, using it".format( file_path ) ) + Print( "Checksum matches for {}, using it".format( file_path ) ) return file_path else: - print( "Checksum doesn't match for {}, removing it".format( + Print( "Checksum doesn't match for {}, removing it".format( file_path ) ) - print( "Removing existing {}".format( file_path ) ) + Print( "Removing existing {}".format( file_path ) ) os.remove( file_path ) r = request.Request( url, headers = { 'User-Agent': 'Vimspector' } ) @@ -470,7 +502,7 @@ def DownloadFileTo( url, GetChecksumSHA254( file_path ), checksum ) ) else: - print( "Checksum for {}: {}".format( file_path, + Print( "Checksum for {}: {}".format( file_path, GetChecksumSHA254( file_path ) ) ) return file_path @@ -488,7 +520,7 @@ def ValidateCheckSumSHA256( file_path, checksum ): def RemoveIfExists( destination ): if os.path.islink( destination ): - print( "Removing file {}".format( destination ) ) + Print( "Removing file {}".format( destination ) ) os.remove( destination ) return @@ -499,21 +531,21 @@ def RemoveIfExists( destination ): return "{}.{}".format( destination, N ) while os.path.isdir( BackupDir() ): - print( "Removing old dir {}".format( BackupDir() ) ) + Print( "Removing old dir {}".format( BackupDir() ) ) try: shutil.rmtree( BackupDir() ) - print ( "OK, removed it" ) + Print ( "OK, removed it" ) break except OSError: - print ( "FAILED" ) + Print ( "FAILED" ) N = N + 1 if os.path.exists( destination ): - print( "Removing dir {}".format( destination ) ) + Print( "Removing dir {}".format( destination ) ) try: shutil.rmtree( destination ) except OSError: - print( "FAILED, moving {} to dir {}".format( destination, BackupDir() ) ) + Print( "FAILED, moving {} to dir {}".format( destination, BackupDir() ) ) os.rename( destination, BackupDir() ) @@ -534,7 +566,7 @@ class ModePreservingZipFile( zipfile.ZipFile ): def ExtractZipTo( file_path, destination, format ): - print( "Extracting {} to {}".format( file_path, destination ) ) + Print( "Extracting {} to {}".format( file_path, destination ) ) RemoveIfExists( destination ) if format == 'zip': @@ -556,7 +588,7 @@ def ExtractZipTo( file_path, destination, format ): # windows-generated tar files os.makedirs( destination ) with CurrentWorkingDir( destination ): - subprocess.check_call( [ 'tar', 'zxvf', file_path ] ) + CheckCall( [ 'tar', 'zxvf', file_path ] ) def MakeExtensionSymlink( name, root ): @@ -580,12 +612,7 @@ def MakeSymlink( link, pointing_to, in_folder = None ): link_path = os.path.abspath( link_path ) if os.path.isdir( link_path ): os.rmdir( link_path ) - subprocess.check_call( [ 'cmd.exe', - '/c', - 'mklink', - '/J', - link_path, - pointing_to ] ) + CheckCall( [ 'cmd.exe', '/c', 'mklink', '/J', link_path, pointing_to ] ) else: os.symlink( pointing_to_relative, link_path ) @@ -593,13 +620,10 @@ def MakeSymlink( link, pointing_to, in_folder = None ): def CloneRepoTo( url, ref, destination ): RemoveIfExists( destination ) git_in_repo = [ 'git', '-C', destination ] - subprocess.check_call( [ 'git', 'clone', url, destination ] ) - subprocess.check_call( git_in_repo + [ 'checkout', ref ] ) - subprocess.check_call( git_in_repo + [ 'submodule', 'sync', '--recursive' ] ) - subprocess.check_call( git_in_repo + [ 'submodule', - 'update', - '--init', - '--recursive' ] ) + CheckCall( [ 'git', 'clone', url, destination ] ) + CheckCall( git_in_repo + [ 'checkout', ref ] ) + CheckCall( git_in_repo + [ 'submodule', 'sync', '--recursive' ] ) + CheckCall( git_in_repo + [ 'submodule', 'update', '--init', '--recursive' ] ) def AbortIfSUperUser( force_sudo ): @@ -613,4 +637,5 @@ def AbortIfSUperUser( force_sudo ): print( "*** RUNNING AS SUPER USER DUE TO force_sudo! " " All bets are off. ***" ) else: - sys.exit( "This script should *not* be run as super user. Aborting." ) + raise RuntimeError( + "This script should *not* be run as super user. Aborting." ) diff --git a/python3/vimspector/output.py b/python3/vimspector/output.py index 3a2d5cb..1d349aa 100644 --- a/python3/vimspector/output.py +++ b/python3/vimspector/output.py @@ -25,6 +25,7 @@ class TabBuffer( object ): self.index = index self.flag = False self.is_job = False + self.syntax = None BUFFER_MAP = { @@ -135,17 +136,16 @@ class OutputView( object ): self._RenderWinBar( category ) - def RunJobWithOutput( self, category, cmd, completion_handler = None ): - self._CreateBuffer( category, - cmd = cmd, - completion_handler = completion_handler ) + def RunJobWithOutput( self, category, cmd, **kwargs ): + self._CreateBuffer( category, cmd = cmd, **kwargs ) def _CreateBuffer( self, category, file_name = None, cmd = None, - completion_handler = None ): + completion_handler = None, + syntax = None ): if file_name is not None: assert cmd is None if install.GetOS() == "windows": @@ -182,6 +182,12 @@ class OutputView( object ): self._RenderWinBar( category ) + self._buffers[ category ].syntax = utils.SetSyntax( + self._buffers[ category ].syntax, + syntax, + self._buffers[ category ].buf ) + + def _RenderWinBar( self, category ): if not self._window.valid: return diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index fe11631..21ac3ff 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -621,8 +621,7 @@ def SetSyntax( current_syntax, syntax, *args ): # doesn't actually trigger the Syntax autocommand, and i'm not sure that # 'doautocmd Syntax' is the right solution or not for buf in args: - with AnyWindowForBuffer( buf ): - vim.command( 'set syntax={}'.format( Escape( syntax ) ) ) + Call( 'setbufvar', buf.number, '&syntax', syntax ) return syntax diff --git a/syntax/vimspector-installer.vim b/syntax/vimspector-installer.vim new file mode 100644 index 0000000..98ea48b --- /dev/null +++ b/syntax/vimspector-installer.vim @@ -0,0 +1,13 @@ +if exists( 'b:current_syntax' ) + finish +endif + +let b:current_syntax = 'vimspector-installer' + +syn keyword VimspectorInstalling Installing +syn keyword VimspectorDone Done +syn keyword VimspectorError Failed FAILED + +hi default link VimspectorInstalling Constant +hi default link VimspectorDone DiffAdd +hi default link VimspectorError WarningMsg From 625da3fcbeb86a5f3718b1d6a4ddc83581810e81 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 14:57:26 +0100 Subject: [PATCH 16/23] Tarballs still require no installation --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d20f046..37b05c5 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,8 @@ 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 + installed for you. * Using `:VimspectorInstall ` (use TAB `wildmenu` to see the options, also accepts any `install_gadget.py` option) * Alternatively, using `python3 install_gadget.py ` (use `--help` to see From d7eff46e0b902ff32839efd14121d01a5be1b8a3 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 14:59:54 +0100 Subject: [PATCH 17/23] Vint the syntax file too --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d5e36a2..24932f2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,7 +28,7 @@ stages: - bash: pip3 install -r dev_requirements.txt displayName: "Install requirements" - - bash: $HOME/.local/bin/vint autoload/ compiler/ plugin/ tests/ + - bash: $HOME/.local/bin/vint autoload/ compiler/ plugin/ tests/ syntax/ displayName: "Run vint" - job: 'linux' From 2d6cada5a9ecddc13845caf45c492d070c7b7267 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 15:04:37 +0100 Subject: [PATCH 18/23] Azure - check gadgets.py --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 24932f2..6584cf9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,7 +45,7 @@ stages: - task: CacheBeta@0 inputs: - key: v2 | gadgets | $(Agent.OS) | python3/vimspector/installer.py + key: v2 | gadgets | $(Agent.OS) | python3/vimspector/gagdets.py path: gadgets/linux/download displayName: Cache gadgets @@ -89,7 +89,7 @@ stages: - task: CacheBeta@0 inputs: - key: v2 | gadgets | $(Agent.OS) | python3/vimspector/installer.py + key: v2 | gadgets | $(Agent.OS) | python3/vimspector/gagdets.py path: gadgets/macos/download displayName: Cache gadgets From 8a6d56d3e1ac3439f1906cd6878ceb542c509728 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 15:04:48 +0100 Subject: [PATCH 19/23] Run the upate in CI too --- azure-pipelines.yml | 4 ++-- run_tests | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6584cf9..0c4d9e6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -55,7 +55,7 @@ stages: - bash: | eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) export GOPATH=$HOME/go - ./run_tests --install --report messages --quiet + ./run_tests --install --update --report messages --quiet displayName: 'Run the tests' env: VIMSPECTOR_MIMODE: gdb @@ -96,7 +96,7 @@ stages: - bash: vim --version displayName: 'Print vim version information' - - bash: ./run_tests --install --report messages --quiet + - bash: ./run_tests --install --update --report messages --quiet displayName: 'Run the tests' env: VIMSPECTOR_MIMODE: lldb diff --git a/run_tests b/run_tests index 3c327bb..44e09f3 100755 --- a/run_tests +++ b/run_tests @@ -2,6 +2,7 @@ BASEDIR=$(dirname $0) INSTALL=0 +UPDATE=0 RUN_VIM="vim -N --clean --not-a-term" RUN_TEST="${RUN_VIM} -S lib/run_test.vim" BASEDIR_CMD='py3 pass' @@ -30,6 +31,10 @@ while [ -n "$1" ]; do INSTALL=$1 shift ;; + "--update") + UPDATE=1 + shift + ;; "--report") shift VIMSPECTOR_TEST_STDOUT=$1 @@ -94,6 +99,18 @@ if [ "$INSTALL" = "1" ] || [ "$INSTALL" = "vim" ]; then fi fi +if [ "$UPDATE" = "1" ]; then + if ! $RUN_VIM -u $(dirname $0)/tests/vimrc \ + --cmd "${BASEDIR_CMD}" \ + -c 'autocmd User VimspectorInstallSuccess qa!' \ + -c 'autocmd User VimspectorInstallFailed cquit!' \ + -c "VimspectorUpdate"; then + echo "Vim update reported errors" >&2 + exit 1 + fi +fi + + if [ -z "$VIMSPECTOR_MIMODE" ]; then if which lldb >/dev/null 2>&1; then export VIMSPECTOR_MIMODE=lldb From e603520860a216899a3b0135086221cfa4dbc7ca Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 15:14:59 +0100 Subject: [PATCH 20/23] FixUp: Flake8 --- install_gadget.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install_gadget.py b/install_gadget.py index 44dbfe4..4b42984 100755 --- a/install_gadget.py +++ b/install_gadget.py @@ -211,7 +211,8 @@ if args.basedir: "let g:vimspector_base_dir='" + vimspector_base + "'" ) if succeeded: - print( "Done. The following adapters were installed successfully:\n - {}".format( + print( "Done" ) + print( "The following adapters were installed successfully:\n - {}".format( '\n - '.join( succeeded ) ) ) if failed: From 8d1c723b283669d49bf1c218f18f7b121dcfc446 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 15:16:09 +0100 Subject: [PATCH 21/23] FixUp: Azure --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0c4d9e6..ade040c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,7 +45,7 @@ stages: - task: CacheBeta@0 inputs: - key: v2 | gadgets | $(Agent.OS) | python3/vimspector/gagdets.py + key: v2 | gadgets | $(Agent.OS) | python3/vimspector/gadgets.py path: gadgets/linux/download displayName: Cache gadgets @@ -89,7 +89,7 @@ stages: - task: CacheBeta@0 inputs: - key: v2 | gadgets | $(Agent.OS) | python3/vimspector/gagdets.py + key: v2 | gadgets | $(Agent.OS) | python3/vimspector/gadgets.py path: gadgets/macos/download displayName: Cache gadgets From 2ea112ded9845bacac5fda3e0c2bb97c1df9af12 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 15:48:16 +0100 Subject: [PATCH 22/23] No args for VimspectorAbortInstall --- plugin/vimspector.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/vimspector.vim b/plugin/vimspector.vim index afc1c08..3e937da 100644 --- a/plugin/vimspector.vim +++ b/plugin/vimspector.vim @@ -105,9 +105,9 @@ command! -bar -nargs=* -complete=custom,vimspector#CompleteInstall command! -bar -nargs=* \ VimspectorUpdate \ call vimspector#Update( ) -command! -bar -nargs=* +command! -bar -nargs=0 \ VimspectorAbortInstall - \ call vimspector#AbortInstall( ) + \ call vimspector#AbortInstall() From c50c99ef342181de7558b3173b082239552b4bae Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Jul 2020 16:01:44 +0100 Subject: [PATCH 23/23] Don't spam echo when jobs finish, revert sudo exit --- python3/vimspector/installer.py | 6 +----- python3/vimspector/utils.py | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/python3/vimspector/installer.py b/python3/vimspector/installer.py index 28624af..e610fe4 100644 --- a/python3/vimspector/installer.py +++ b/python3/vimspector/installer.py @@ -15,9 +15,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# TODO: Chnage `print` to some other mechanism that can be displayed in a vim -# buffer? - from urllib import request import contextlib import functools @@ -637,5 +634,4 @@ def AbortIfSUperUser( force_sudo ): print( "*** RUNNING AS SUPER USER DUE TO force_sudo! " " All bets are off. ***" ) else: - raise RuntimeError( - "This script should *not* be run as super user. Aborting." ) + sys.exit( "This script should *not* be run as super user. Aborting." ) diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index 21ac3ff..ad5bc9a 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -84,8 +84,6 @@ def OnCommandWithLogComplete( name, exit_code ): cb = COMMAND_HANDLERS.get( name ) if cb: cb( exit_code ) - else: - UserMessage( f'Job complete: { name } (exit status: { exit_code })' ) def SetUpCommandBuffer( cmd, name, api_prefix, completion_handler = None ):