Manipulate buffers for variables, watches and stack trace

This commit is contained in:
Ben Jackson 2020-07-11 10:13:45 +01:00
commit 5ce4147361
3 changed files with 64 additions and 54 deletions

View file

@ -39,10 +39,7 @@ class StackTraceView( object ):
utils.SetUpScratchBuffer( self._buf, 'vimspector.StackTrace' ) utils.SetUpScratchBuffer( self._buf, 'vimspector.StackTrace' )
vim.current.buffer = self._buf vim.current.buffer = self._buf
# FIXME: Remove all usage of "Windown" and just use buffers to prevent all utils.SetUpUIWindow( vim.current.window )
# the bugs around the window being closed.
self._win = vim.current.window
utils.SetUpUIWindow( self._win )
vim.command( 'nnoremap <buffer> <CR> :call vimspector#GoToFrame()<CR>' ) vim.command( 'nnoremap <buffer> <CR> :call vimspector#GoToFrame()<CR>' )
@ -311,4 +308,4 @@ class StackTraceView( object ):
def SetSyntax( self, syntax ): def SetSyntax( self, syntax ):
self._current_syntax = utils.SetSyntax( self._current_syntax, self._current_syntax = utils.SetSyntax( self._current_syntax,
syntax, syntax,
self._win ) self._buf )

View file

@ -194,6 +194,14 @@ def LetCurrentWindow( window ):
yield yield
@contextlib.contextmanager
def LetCurrentBuffer( buf ):
with RestoreCursorPosition():
with RestoreCurrentBuffer( vim.current.window ):
vim.current.buffer = buf
yield
def JumpToWindow( window ): def JumpToWindow( window ):
vim.current.tabpage = window.tabpage vim.current.tabpage = window.tabpage
vim.current.window = window vim.current.window = window
@ -555,8 +563,11 @@ def SetSyntax( current_syntax, syntax, *args ):
if current_syntax == syntax: if current_syntax == syntax:
return return
for win in args: for buf in args:
with LetCurrentWindow( win ): with LetCurrentBuffer( buf ):
# We use set syn= because just setting vim.Buffer.options[ 'syntax' ]
# doesn't actually trigger the Syntax autocommand, and i'm not sure that
# 'doautocmd Syntax' is the right solution or not
vim.command( 'set syntax={}'.format( Escape( syntax ) ) ) vim.command( 'set syntax={}'.format( Escape( syntax ) ) )
return syntax return syntax

View file

@ -16,15 +16,11 @@
import abc import abc
import vim import vim
import logging import logging
from collections import namedtuple
from functools import partial from functools import partial
import typing import typing
from vimspector import utils from vimspector import utils
View = namedtuple( 'View', [ 'win', 'lines', 'draw' ] )
class Expandable: class Expandable:
"""Base for anything which might contain a hierarchy of values represented by """Base for anything which might contain a hierarchy of values represented by
@ -104,7 +100,6 @@ class Variable( Expandable ):
self.variable = variable self.variable = variable
class Watch: class Watch:
"""Holds a user watch expression (DAP request) and the result (WatchResult)""" """Holds a user watch expression (DAP request) and the result (WatchResult)"""
def __init__( self, expression: dict ): def __init__( self, expression: dict ):
@ -114,29 +109,44 @@ class Watch:
self.result = None self.result = None
class View:
lines: typing.Dict[ int, Expandable ]
draw: typing.Callable
buf: vim.Buffer
def __init__( self, win: vim.Window, lines, draw ):
self.lines = lines
self.draw = draw
self.buf = win.buffer
utils.SetUpUIWindow( win )
class VariablesView( object ): class VariablesView( object ):
def __init__( self, connection, variables_win, watches_win ): def __init__( self, connection, variables_win, watches_win ):
self._logger = logging.getLogger( __name__ ) self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger ) utils.SetUpLogging( self._logger )
self._vars = View( variables_win, {}, self._DrawScopes )
self._watch = View( watches_win, {}, self._DrawWatches )
self._connection = connection self._connection = connection
self._current_syntax = '' self._current_syntax = ''
# Allows us to hit <CR> to expand/collapse variables # Set up the "Variables" buffer in the variables_win
with utils.LetCurrentWindow( self._vars.win ): self._scopes: typing.List[ Scope ] = []
self._vars = View( variables_win, {}, self._DrawScopes )
utils.SetUpScratchBuffer( self._vars.buf, 'vimspector.Variables' )
with utils.LetCurrentWindow( variables_win ):
vim.command( vim.command(
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' ) 'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
# List of current scopes of type Scope # Set up the "Watches" buffer in the watches_win (and create a WinBar in
self._scopes: typing.List[ 'Scope' ] = [] # there)
self._watches: typing.List[ Watch ] = []
# List of current Watches of type Watch self._watch = View( watches_win, {}, self._DrawWatches )
self._watches: typing.List[ 'Watch' ] = [] utils.SetUpPromptBuffer( self._watch.buf,
'vimspector.Watches',
# Allows us to hit <CR> to expand/collapse variables 'Expression: ',
with utils.LetCurrentWindow( self._watch.win ): 'vimspector#AddWatchPrompt' )
with utils.LetCurrentWindow( watches_win ):
vim.command( vim.command(
'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' ) 'nnoremap <buffer> <CR> :call vimspector#ExpandVariable()<CR>' )
vim.command( vim.command(
@ -149,15 +159,7 @@ class VariablesView( object ):
vim.command( 'nnoremenu 1.3 WinBar.Delete ' vim.command( 'nnoremenu 1.3 WinBar.Delete '
':call vimspector#DeleteWatch()<CR>' ) ':call vimspector#DeleteWatch()<CR>' )
utils.SetUpScratchBuffer( self._vars.win.buffer, 'vimspector.Variables' ) # Set the (global!) balloon expr if supported
utils.SetUpPromptBuffer( self._watch.win.buffer,
'vimspector.Watches',
'Expression: ',
'vimspector#AddWatchPrompt' )
utils.SetUpUIWindow( self._vars.win )
utils.SetUpUIWindow( self._watch.win )
has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) ) has_balloon = int( vim.eval( "has( 'balloon_eval' )" ) )
has_balloon_term = int( vim.eval( "has( 'balloon_eval_term' )" ) ) has_balloon_term = int( vim.eval( "has( 'balloon_eval_term' )" ) )
@ -181,10 +183,10 @@ class VariablesView( object ):
self._is_term = not bool( int( vim.eval( "has( 'gui_running' )" ) ) ) self._is_term = not bool( int( vim.eval( "has( 'gui_running' )" ) ) )
def Clear( self ): def Clear( self ):
with utils.ModifiableScratchBuffer( self._vars.win.buffer ): with utils.ModifiableScratchBuffer( self._vars.buf ):
utils.ClearBuffer( self._vars.win.buffer ) utils.ClearBuffer( self._vars.buf )
with utils.ModifiableScratchBuffer( self._watch.win.buffer ): with utils.ModifiableScratchBuffer( self._watch.buf ):
utils.ClearBuffer( self._watch.win.buffer ) utils.ClearBuffer( self._watch.buf )
self._current_syntax = '' self._current_syntax = ''
def ConnectionUp( self, connection ): def ConnectionUp( self, connection ):
@ -198,8 +200,8 @@ class VariablesView( object ):
for k, v in self._oldoptions.items(): for k, v in self._oldoptions.items():
vim.options[ k ] = v vim.options[ k ] = v
vim.command( 'bdelete! ' + str( self._watch.win.buffer.number ) ) vim.command( 'bdelete! ' + str( self._watch.buf.number ) )
vim.command( 'bdelete! ' + str( self._vars.win.buffer.number ) ) vim.command( 'bdelete! ' + str( self._vars.buf.number ) )
def LoadScopes( self, frame ): def LoadScopes( self, frame ):
def scopes_consumer( message ): def scopes_consumer( message ):
@ -256,8 +258,8 @@ class VariablesView( object ):
self.EvaluateWatches() self.EvaluateWatches()
def DeleteWatch( self ): def DeleteWatch( self ):
if vim.current.window != self._watch.win: if vim.current.buffer != self._watch.buf:
utils.UserMessage( 'Not a watch window' ) utils.UserMessage( 'Not a watch buffer' )
return return
current_line = vim.current.window.cursor[ 0 ] current_line = vim.current.window.cursor[ 0 ]
@ -305,9 +307,9 @@ class VariablesView( object ):
self._DrawWatches() self._DrawWatches()
def ExpandVariable( self ): def ExpandVariable( self ):
if vim.current.window == self._vars.win: if vim.current.buffer == self._vars.buf:
view = self._vars view = self._vars
elif vim.current.window == self._watch.win: elif vim.current.buffer == self._watch.buf:
view = self._watch view = self._watch
else: else:
return return
@ -341,7 +343,7 @@ class VariablesView( object ):
assert indent > 0 assert indent > 0
for variable in variables: for variable in variables:
line = utils.AppendToBuffer( line = utils.AppendToBuffer(
view.win.buffer, view.buf,
'{indent}{marker}{icon} {name} ({type_}): {value}'.format( '{indent}{marker}{icon} {name} ({type_}): {value}'.format(
# We borrow 1 space of indent to draw the change marker # We borrow 1 space of indent to draw the change marker
indent = ' ' * ( indent - 1 ), indent = ' ' * ( indent - 1 ),
@ -363,8 +365,8 @@ class VariablesView( object ):
# However it is pretty inefficient. # However it is pretty inefficient.
self._vars.lines.clear() self._vars.lines.clear()
with utils.RestoreCursorPosition(): with utils.RestoreCursorPosition():
with utils.ModifiableScratchBuffer( self._vars.win.buffer ): with utils.ModifiableScratchBuffer( self._vars.buf ):
utils.ClearBuffer( self._vars.win.buffer ) utils.ClearBuffer( self._vars.buf )
for scope in self._scopes: for scope in self._scopes:
self._DrawScope( 0, scope ) self._DrawScope( 0, scope )
@ -374,11 +376,11 @@ class VariablesView( object ):
# However it is pretty inefficient. # However it is pretty inefficient.
self._watch.lines.clear() self._watch.lines.clear()
with utils.RestoreCursorPosition(): with utils.RestoreCursorPosition():
with utils.ModifiableScratchBuffer( self._watch.win.buffer ): with utils.ModifiableScratchBuffer( self._watch.buf ):
utils.ClearBuffer( self._watch.win.buffer ) utils.ClearBuffer( self._watch.buf )
utils.AppendToBuffer( self._watch.win.buffer, 'Watches: ----' ) utils.AppendToBuffer( self._watch.buf, 'Watches: ----' )
for watch in self._watches: for watch in self._watches:
line = utils.AppendToBuffer( self._watch.win.buffer, line = utils.AppendToBuffer( self._watch.buf,
'Expression: ' 'Expression: '
+ watch.expression[ 'expression' ] ) + watch.expression[ 'expression' ] )
watch.line = line watch.line = line
@ -387,7 +389,7 @@ class VariablesView( object ):
def _DrawScope( self, indent, scope ): def _DrawScope( self, indent, scope ):
icon = '+' if scope.IsExpandable() and not scope.IsExpandedByUser() else '-' icon = '+' if scope.IsExpandable() and not scope.IsExpandedByUser() else '-'
line = utils.AppendToBuffer( self._vars.win.buffer, line = utils.AppendToBuffer( self._vars.buf,
'{0}{1} Scope: {2}'.format( '{0}{1} Scope: {2}'.format(
' ' * indent, ' ' * indent,
icon, icon,
@ -413,7 +415,7 @@ class VariablesView( object ):
icon = icon, icon = icon,
result = watch.result.result.get( 'result', '<unknown>' ) ) result = watch.result.result.get( 'result', '<unknown>' ) )
line = utils.AppendToBuffer( self._watch.win.buffer, line.split( '\n' ) ) line = utils.AppendToBuffer( self._watch.buf, line.split( '\n' ) )
self._watch.lines[ line ] = watch.result self._watch.lines[ line ] = watch.result
if watch.result.ShouldDrawDrillDown(): if watch.result.ShouldDrawDrillDown():
@ -495,7 +497,7 @@ class VariablesView( object ):
def SetSyntax( self, syntax ): def SetSyntax( self, syntax ):
self._current_syntax = utils.SetSyntax( self._current_syntax, self._current_syntax = utils.SetSyntax( self._current_syntax,
syntax, syntax,
self._vars.win, self._vars.buf,
self._watch.win ) self._watch.buf )
# vim: sw=2 # vim: sw=2