From 1003cdc0b21f8819761cd37c5bc5e7b428dc6e79 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 26 Mar 2020 22:48:06 +0000 Subject: [PATCH] Add a splash popup while starting up Sometimes it can take quite a while to start up and initialise the debug adapter. So we use popup/float to display the status as we start up and shut down. This increases minimum Vim version to 8.2, but that's been out for ages now and I intend to agressively require latest/later vim/neovim versions. --- README.md | 8 ++- autoload/vimspector/internal/neopopup.vim | 70 +++++++++++++++++++++++ autoload/vimspector/internal/popup.vim | 38 ++++++++++++ python3/vimspector/debug_session.py | 41 ++++++++++++- python3/vimspector/utils.py | 17 ++++++ tests/ci/image/Dockerfile | 2 +- tests/tabpage.test.vim | 3 +- 7 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 autoload/vimspector/internal/neopopup.vim create mode 100644 autoload/vimspector/internal/popup.vim diff --git a/README.md b/README.md index c77b22b..ac589ca 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ Alternatively, you can clone the repo and select which gadgets are installed: Vimspector requires: -* Vim version 8.1 with at least patch 1264, or Neovim 0.4.3 +* At least Vim version 8.2, or Neovim 0.4.3 (experimental) * One of the following operating systems: * Linux * macOS Mojave or later @@ -162,6 +162,12 @@ Why such a new vim ? Well 2 reasons: 2. Because there are Vim bugs that vimspector triggers that will frustrate you if you hit them. +Why is neovim experimental? Because the author doesn't use neovim regularly, and +there are no regression tests for vimspector in neovim, so it's likely to break +frequently. Issue reports are handled on best-efforts basis, and PRs are +welcome to fix bugs. See also the next section descibing differences for neovim +vs vim. + Why Windows support experimental? Because it's effort and it's not a priority for the author. PRs are welcome to fix bugs. Windows will not be regularly tested. diff --git a/autoload/vimspector/internal/neopopup.vim b/autoload/vimspector/internal/neopopup.vim new file mode 100644 index 0000000..148107c --- /dev/null +++ b/autoload/vimspector/internal/neopopup.vim @@ -0,0 +1,70 @@ +" vimspector - A multi-language debugging system for Vim +" Copyright 2018 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. + +" Boilerplate {{{ +let s:save_cpo = &cpoptions +set cpoptions&vim +" }}} + +" Neovim's float window API, like its job/channel API is painful to use +" compared to Vim's so we have to employ more hacks + +" We can't seem to pass a Window handle back to the python, so we have to +" maintain yet another cached here +let s:db = {} +let s:next_id = 0 + +function! vimspector#internal#neopopup#DisplaySplash( message ) abort + let buf = nvim_create_buf(v:false, v:true) + call nvim_buf_set_lines(buf, 0, -1, v:true, [ a:message ] ) + + let l = len( a:message ) + + let opts = { + \ 'relative': 'editor', + \ 'width': l, + \ 'height': 1, + \ 'col': ( &columns / 2 ) - ( l / 2 ), + \ 'row': &lines / 2, + \ 'anchor': 'NW', + \ 'style': 'minimal', + \ 'focusable': v:false, + \ } + let win = nvim_open_win(buf, 0, opts) + call nvim_win_set_option(win, 'wrap', v:false) + + let id = s:next_id + let s:next_id += 1 + let s:db[ id ] = { 'win': win, 'buf': buf } + return id +endfunction + +function! vimspector#internal#neopopup#UpdateSplash( id, message ) abort + let splash = s:db[ a:id ] + call nvim_buf_set_lines(splash.buf, 0, -1, v:true, [ a:message ] ) + return a:id +endfunction + +function! vimspector#internal#neopopup#HideSplash( id ) abort + let splash = s:db[ a:id ] + call nvim_win_close( splash.win, v:true ) + unlet s:db[ a:id ] +endfunction + +" Boilerplate {{{ +let &cpoptions=s:save_cpo +unlet s:save_cpo +" }}} + diff --git a/autoload/vimspector/internal/popup.vim b/autoload/vimspector/internal/popup.vim new file mode 100644 index 0000000..fc8820b --- /dev/null +++ b/autoload/vimspector/internal/popup.vim @@ -0,0 +1,38 @@ +" vimspector - A multi-language debugging system for Vim +" Copyright 2018 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. + + +" Boilerplate {{{ +let s:save_cpo = &cpoptions +set cpoptions&vim +" }}} + +function! vimspector#internal#popup#DisplaySplash( message ) abort + return popup_dialog( a:message, {} ) +endfunction + +function! vimspector#internal#popup#UpdateSplash( id, message ) abort + call popup_settext( a:id, a:message ) + return a:id +endfunction + +function! vimspector#internal#popup#HideSplash( id ) abort + call popup_hide( a:id ) +endfunction + +" Boilerplate {{{ +let &cpoptions=s:save_cpo +unlet s:save_cpo +" }}} diff --git a/python3/vimspector/debug_session.py b/python3/vimspector/debug_session.py index fb03f41..9ad34ef 100644 --- a/python3/vimspector/debug_session.py +++ b/python3/vimspector/debug_session.py @@ -19,7 +19,6 @@ import logging import os import shlex import subprocess -import traceback import functools import vim @@ -60,6 +59,7 @@ class DebugSession( object ): self._variablesView = None self._outputView = None self._breakpoints = breakpoints.ProjectBreakpoints() + self._splash_screen = None self._run_on_server_exit = None @@ -326,9 +326,12 @@ class DebugSession( object ): def _Reset( self ): self._logger.info( "Debugging complete." ) if self._uiTab: - self._logger.debug( "Clearing down UI with stack_trace: %s", - traceback.format_stack() ) + self._logger.debug( "Clearing down UI" ) vim.current.tabpage = self._uiTab + + self._splash_screen = utils.HideSplash( self._api_prefix, + self._splash_screen ) + self._stackTraceView.Reset() self._variablesView.Reset() self._outputView.Reset() @@ -436,6 +439,7 @@ class DebugSession( object ): def GetOutputBuffers( self ): return self._outputView.GetCategories() + @IfConnected def GetCompletionsSync( self, text_line, column_in_bytes ): if not self._server_capabilities.get( 'supportsCompletionsRequest' ): return [] @@ -523,6 +527,11 @@ class DebugSession( object ): return True def _StartDebugAdapter( self ): + self._splash_screen = utils.DisplaySplash( + self._api_prefix, + self._splash_screen, + "Starting debug adapter..." ) + if self._connection: utils.UserMessage( 'The connection is already created. Please try again', persist = True ) @@ -560,6 +569,9 @@ class DebugSession( object ): " g:_vimspector_adapter_spec " ")".format( self._connection_type ) ): self._logger.error( "Unable to start debug server" ) + self._splash_screen = utils.DisplaySplash( self._api_prefix, + self._splash_screen, + "Unable to start adapter" ) else: self._connection = debug_adapter_connection.DebugAdapterConnection( self, @@ -570,6 +582,11 @@ class DebugSession( object ): self._logger.info( 'Debug Adapter Started' ) def _StopDebugAdapter( self, callback = None ): + self._splash_screen = utils.DisplaySplash( + self._api_prefix, + self._splash_screen, + "Shutting down debug adapter..." ) + def handler( *args ): if callback: self._logger.debug( "Setting server exit handler before disconnect" ) @@ -706,6 +723,11 @@ class DebugSession( object ): return [ command ] def _Initialise( self ): + self._splash_screen = utils.DisplaySplash( + self._api_prefix, + self._splash_screen, + "Initializing debug adapter..." ) + # For a good explaination as to why this sequence is the way it is, see # https://github.com/microsoft/vscode/issues/4902#issuecomment-368583522 # @@ -760,8 +782,18 @@ class DebugSession( object ): launch_config.get( 'request', 'launch' ) ) if request == "attach": + self._splash_screen = utils.DisplaySplash( + self._api_prefix, + self._splash_screen, + "Attaching to debugee..." ) + self._PrepareAttach( adapter_config, launch_config ) elif request == "launch": + self._splash_screen = utils.DisplaySplash( + self._api_prefix, + self._splash_screen, + "Launching debugee..." ) + # FIXME: This cmdLine hack is not fun. self._PrepareLaunch( self._configuration.get( 'remote-cmdLine', [] ), adapter_config, @@ -807,6 +839,9 @@ class DebugSession( object ): # leader rather than the process. The workaround is to manually SIGTRAP the # PID. # + self._splash_screen = utils.HideSplash( self._api_prefix, + self._splash_screen ) + if self._launch_complete and self._init_complete: for h in self._on_init_complete_handlers: h() diff --git a/python3/vimspector/utils.py b/python3/vimspector/utils.py index cffc425..13c43f8 100644 --- a/python3/vimspector/utils.py +++ b/python3/vimspector/utils.py @@ -546,3 +546,20 @@ def SetSyntax( current_syntax, syntax, *args ): def GetBufferFiletypes( buf ): ft = ToUnicode( vim.eval( f"getbufvar( {buf.number}, '&ft' )" ) ) return ft.split( '.' ) + + +def DisplaySplash( api_prefix, splash, text ): + if splash: + return Call( f'vimspector#internal#{api_prefix}popup#UpdateSplash', + splash, + text ) + else: + return Call( f'vimspector#internal#{api_prefix}popup#DisplaySplash', + text ) + + +def HideSplash( api_prefix, splash ): + if splash: + Call( f'vimspector#internal#{api_prefix}popup#HideSplash', splash ) + + return None diff --git a/tests/ci/image/Dockerfile b/tests/ci/image/Dockerfile index 71329b6..77e7131 100644 --- a/tests/ci/image/Dockerfile +++ b/tests/ci/image/Dockerfile @@ -27,7 +27,7 @@ RUN ln -fs /usr/share/zoneinfo/Europe/London /etc/localtime && \ ## cleanup of files from setup RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -ARG VIM_VERSION=v8.1.1270 +ARG VIM_VERSION=v8.2.0460 ENV CONF_ARGS "--with-features=huge \ --enable-python3interp \ diff --git a/tests/tabpage.test.vim b/tests/tabpage.test.vim index 2dfd4d9..356ee19 100644 --- a/tests/tabpage.test.vim +++ b/tests/tabpage.test.vim @@ -10,7 +10,7 @@ function! Test_Step_With_Different_Tabpage() lcd testdata/cpp/simple edit simple.cpp - " Add the breakpoing + " Add the breakpoint " TODO refactor FeedKeys 15 call assert_equal( 15, line( '.' ) ) @@ -47,6 +47,7 @@ function! Test_Step_With_Different_Tabpage() call vimspector#Reset() call vimspector#ClearBreakpoints() + call WaitForAssert( {-> assert_notequal( vimspector_tabnr, tabpagenr() ) } ) lcd - %bwipeout! endfunction