def _SetUpUI( self ): vim.command( 'tab split' ) self._uiTab = vim.current.tabpage # Code window code_window = vim.current.window self._codeView = code.CodeView( code_window, self._api_prefix ) # Call stack vim.command( f'topleft vertical { settings.Int( "sidebar_width", 50 ) }new' ) 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 vim.command( 'leftabove new' ) watch_window = vim.current.window # Variables vim.command( 'leftabove new' ) vars_window = vim.current.window with utils.LetCurrentWindow( vars_window ): vim.command( f'{ one_third }wincmd _' ) with utils.LetCurrentWindow( watch_window ): vim.command( f'{ one_third }wincmd _' ) with utils.LetCurrentWindow( stack_trace_window ): vim.command( f'{ one_third }wincmd _' ) self._variablesView = variables.VariablesView( self._connection, 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 ) # TODO: If/when we support multiple sessions, we'll need some way to # indicate which tab was created and store all the tabs vim.vars[ 'vimspector_session_windows' ] = { 'tabpage': self._uiTab.number, 'code': utils.WindowID( code_window, self._uiTab ), 'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ), 'variables': utils.WindowID( vars_window, self._uiTab ), 'watches': utils.WindowID( watch_window, self._uiTab ), 'output': utils.WindowID( output_window, self._uiTab ), } with utils.RestoreCursorPosition(): with utils.RestoreCurrentWindow(): with utils.RestoreCurrentBuffer( vim.current.window ): vim.command( 'doautocmd User VimspectorUICreated' )
def _SetUpUIVertical( self ): # Code window code_window = vim.current.window self._codeView = code.CodeView( code_window, self._api_prefix ) # Call stack vim.command( f'topleft { settings.Int( "topbar_height" ) }new' ) stack_trace_window = vim.current.window one_third = int( vim.eval( 'winwidth( 0 )' ) ) / 3 self._stackTraceView = stack_trace.StackTraceView( self, stack_trace_window ) # Watches vim.command( 'leftabove vertical new' ) watch_window = vim.current.window # Variables vim.command( 'leftabove vertical new' ) vars_window = vim.current.window with utils.LetCurrentWindow( vars_window ): vim.command( f'{ one_third }wincmd |' ) with utils.LetCurrentWindow( watch_window ): vim.command( f'{ one_third }wincmd |' ) with utils.LetCurrentWindow( stack_trace_window ): vim.command( f'{ one_third }wincmd |' ) self._variablesView = variables.VariablesView( vars_window, watch_window ) # Output/logging vim.current.window = code_window vim.command( f'rightbelow { settings.Int( "bottombar_height" ) }new' ) output_window = vim.current.window self._outputView = output.DAPOutputView( output_window, self._api_prefix ) # TODO: If/when we support multiple sessions, we'll need some way to # indicate which tab was created and store all the tabs vim.vars[ 'vimspector_session_windows' ] = { 'mode': 'vertical', 'tabpage': self._uiTab.number, 'code': utils.WindowID( code_window, self._uiTab ), 'stack_trace': utils.WindowID( stack_trace_window, self._uiTab ), 'variables': utils.WindowID( vars_window, self._uiTab ), 'watches': utils.WindowID( watch_window, self._uiTab ), 'output': utils.WindowID( output_window, self._uiTab ), 'eval': None # this is going to be updated every time eval popup is opened } with utils.RestoreCursorPosition(): with utils.RestoreCurrentWindow(): with utils.RestoreCurrentBuffer( vim.current.window ): vim.command( 'doautocmd User VimspectorUICreated' )
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}!')
def _RenderWinBar(self, category): if not utils.UseWinBar(): return if not self._window.valid: return 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 vim.command( "nnoremenu <silent> 1.{0} WinBar.{1}{2} " ":call vimspector#ShowOutputInWindow( {3}, '{1}' )<CR>".format( tab_buffer.index, utils.Escape(category), '*' if tab_buffer.flag else '', utils.WindowID(self._window)))
def ShowOutput(self, category): if not self._outputView.WindowIsValid(): # TODO: The UI code is too scattered. Re-organise into a UI class that # just deals with these thigns like window layout and custmisattion. # currently, this class and the CodeView share some responsiblity for this # and poking into each View class to check its window is valid also feels # wrong. with utils.LetCurrentTabpage(self._uiTab): vim.command( f'botright { settings.Int( "bottombar_height" ) }new') self._outputView.UseWindow(vim.current.window) vim.vars['vimspector_session_windows'][ 'output'] = utils.WindowID(vim.current.window, self._uiTab) self._outputView.ShowOutput(category)
def _UpdateView( self, breakpoint_list, show=True ): if show and not self._HasWindow(): vim.command( f'botright { settings.Int( "bottombar_height" ) }new' ) self._win = vim.current.window if self._HasBuffer(): with utils.NoAutocommands(): vim.current.buffer = self._buffer else: self._buffer = vim.current.buffer mappings = settings.Dict( 'mappings' )[ 'breakpoints' ] groups = { 'toggle': 'ToggleBreakpointViewBreakpoint', 'toggle_all': 'ToggleAllBreakpointsViewBreakpoint', 'delete': 'DeleteBreakpointViewBreakpoint', 'jump_to': 'JumpToBreakpointViewBreakpoint', 'add_line': 'SetAdvancedLineBreakpoint', 'add_func': 'AddAdvancedFunctionBreakpoint' } for key, func in groups.items(): for mapping in utils.GetVimList( mappings, key ): vim.command( f'nnoremap <silent> <buffer> { mapping } ' ':<C-u>call ' f'vimspector#{ func }()<CR>' ) utils.SetUpHiddenBuffer( self._buffer, "vimspector.Breakpoints" ) utils.UpdateSessionWindows( { 'breakpoints': utils.WindowID( self._win ) } ) # set highlighting vim.eval( "matchadd( 'WarningMsg', 'ENABLED', 100 )" ) vim.eval( "matchadd( 'WarningMsg', 'VERIFIED', 100 )" ) vim.eval( "matchadd( 'LineNr', 'DISABLED', 100 )" ) vim.eval( "matchadd( 'LineNr', 'PENDING', 100 )" ) vim.eval( "matchadd( 'Title', '\\v^\\S+:{0,}', 100 )" ) if utils.UseWinBar(): vim.command( 'nnoremenu <silent> 1.1 WinBar.Delete ' ':call vimspector#DeleteBreakpointViewBreakpoint()<CR>' ) vim.command( 'nnoremenu <silent> 1.2 WinBar.Toggle ' ':call vimspector#ToggleBreakpointViewBreakpoint()<CR>' ) vim.command( 'nnoremenu <silent> 1.2 WinBar.*Toggle ' ':call' ' vimspector#ToggleAllBreakpointsViewBreakpoint()<CR>' ) vim.command( 'nnoremenu <silent> 1.3 WinBar.Jump\\ To ' ':call vimspector#JumpToBreakpointViewBreakpoint()<CR>' ) # TODO: Add tests for this function vim.command( 'nnoremenu <silent> 1.4 WinBar.+Line ' ':call vimspector#SetAdvancedLineBreakpoint()<CR>' ) vim.command( 'nnoremenu <silent> 1.4 WinBar.+Function ' ':call vimspector#AddAdvancedFunctionBreakpoint()<CR>' ) vim.command( 'nnoremenu <silent> 1.4 WinBar.Clear ' ':call vimspector#ClearBreakpoints()<CR>' ) vim.command( 'nnoremenu <silent> 1.4 WinBar.Save ' ':call vimspector#WriteSessionFile()<CR>' ) vim.command( 'nnoremenu <silent> 1.4 WinBar.Load ' ':call vimspector#ReadSessionFile()<CR>' ) # we want to maintain the height of the window self._win.options[ "winfixheight" ] = True self._breakpoint_list = breakpoint_list def FormatEntry( el ): prefix = '' if el.get( 'type' ) == 'L': prefix = '{}:{} '.format( os.path.basename( el.get( 'filename' ) ), el.get( 'lnum' ) ) return '{}{}'.format( prefix, el.get( 'text' ) ) if self._HasBuffer(): with utils.ModifiableScratchBuffer( self._buffer ): with utils.RestoreCursorPosition(): utils.SetBufferContents( self._buffer, list( map( FormatEntry, breakpoint_list ) ) )
def LaunchTerminal(api_prefix, params, window_for_start, existing_term): if not existing_term: term = Terminal() else: term = existing_term cwd = params['cwd'] args = params['args'] env = params.get('env', {}) term_options = { 'vertical': 1, 'norestore': 1, 'cwd': cwd, 'env': env, } if not window_for_start or not window_for_start.valid: # TOOD: Where? Maybe we should just use botright vertical ... window_for_start = vim.current.window if term.window is not None and term.window.valid: assert term.buffer_number window_for_start = term.window if (term.window.buffer.number == term.buffer_number and int( utils.Call( 'vimspector#internal#{}term#IsFinished'.format(api_prefix), term.buffer_number))): term_options['curwin'] = 1 else: term_options['vertical'] = 0 buffer_number = None terminal_window = None with utils.LetCurrentWindow(window_for_start): # If we're making a vertical split from the code window, make it no more # than 80 columns and no fewer than 10. Also try and keep the code window # at least 82 columns if term_options['vertical'] and not term_options.get('curwin', 0): term_options['term_cols'] = max( min( int(vim.eval('winwidth( 0 )')) - settings.Int('code_minwidth'), settings.Int('terminal_maxwidth')), settings.Int('terminal_minwidth')) buffer_number = int( utils.Call('vimspector#internal#{}term#Start'.format(api_prefix), args, term_options)) terminal_window = vim.current.window if buffer_number is None or buffer_number <= 0: # TODO: Do something better like reject the request? raise ValueError("Unable to start terminal") term.window = terminal_window term.buffer_number = buffer_number vim.vars['vimspector_session_windows']['terminal'] = utils.WindowID( term.window, vim.current.tabpage) with utils.RestoreCursorPosition(): with utils.RestoreCurrentWindow(): with utils.RestoreCurrentBuffer(vim.current.window): vim.command('doautocmd User VimspectorTerminalOpened') return term
def LaunchTerminal(api_prefix, params, window_for_start, existing_term): if not existing_term: term = Terminal() else: term = existing_term cwd = params['cwd'] or os.getcwd() args = params['args'] or [] env = params.get('env') or {} term_options = { 'norestore': 1, 'cwd': cwd, 'env': env, } if settings.Get('ui_mode') == 'horizontal': # force-horizontal term_options['vertical'] = 1 elif utils.GetVimValue(vim.vars['vimspector_session_windows'], 'mode') == 'horizontal': # horizontal, which means that we should have enough space for: # - sidebar # - code min # - term min width # - + 2 vertical spaders # - + 3 columns for signs term_options['vertical'] = 1 # if we don't have enough space for terminal_maxwidth, then see if we have # enough vertically for terminal_maxheight, in which case, # that seems a better fit term_horiz_max = (settings.Int('sidebar_width') + 1 + 2 + 3 + settings.Int('code_minwidth') + 1 + settings.Int('terminal_maxwidth')) term_vert_max = (settings.Int('bottombar_height') + 1 + settings.Int('code_minheight') + 1 + settings.Int('terminal_minheight')) if (vim.options['columns'] < term_horiz_max and vim.options['lines'] >= term_vert_max): # Looks like it, let's try that layout term_options['vertical'] = 0 else: # vertical - we need enough space horizontally for the code+terminal, but we # may fit better with code above terminal term_options['vertical'] = 0 term_horiz_max = (settings.Int('code_minwidth') + 3 + settings.Int('terminal_maxwidth') + 1) if vim.options['columns'] > term_horiz_max: term_options['vertical'] = 1 if not window_for_start or not window_for_start.valid: # TOOD: Where? Maybe we should just use botright vertical ... window_for_start = vim.current.window if term.window is not None and term.window.valid: assert term.buffer_number window_for_start = term.window if (term.window.buffer.number == term.buffer_number and int( utils.Call( 'vimspector#internal#{}term#IsFinished'.format(api_prefix), term.buffer_number))): term_options['curwin'] = 1 else: term_options['vertical'] = 0 buffer_number = None terminal_window = None with utils.LetCurrentWindow(window_for_start): # If we're making a vertical split from the code window, make it no more # than 80 columns and no fewer than 10. Also try and keep the code window # at least 82 columns if term_options.get('curwin', 0): pass elif term_options['vertical']: term_options['term_cols'] = max( min( int(vim.eval('winwidth( 0 )')) - settings.Int('code_minwidth'), settings.Int('terminal_maxwidth')), settings.Int('terminal_minwidth')) else: term_options['term_rows'] = max( min( int(vim.eval('winheight( 0 )')) - settings.Int('code_minheight'), settings.Int('terminal_maxheight')), settings.Int('terminal_minheight')) buffer_number = int( utils.Call('vimspector#internal#{}term#Start'.format(api_prefix), args, term_options)) terminal_window = vim.current.window if buffer_number is None or buffer_number <= 0: # TODO: Do something better like reject the request? raise ValueError("Unable to start terminal") term.window = terminal_window term.buffer_number = buffer_number utils.UpdateSessionWindows( {'terminal': utils.WindowID(term.window, vim.current.tabpage)}) with utils.RestoreCursorPosition(): with utils.RestoreCurrentWindow(): with utils.RestoreCurrentBuffer(vim.current.window): vim.command('doautocmd User VimspectorTerminalOpened') return term