Merge pull request #215 from puremourning/variables-default-value

Add ability to specify defaults for variables
This commit is contained in:
mergify[bot] 2020-07-31 21:30:13 +00:00 • committed by GitHub
commit 1f270ed423
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 171 additions and 26 deletions

View file

@ -188,11 +188,15 @@ function! vimspector#EvaluateConsole( expr ) abort
py3 _vimspector_session.EvaluateConsole( vim.eval( 'a:expr' ) )
endfunction
function! vimspector#ShowOutput( category ) abort
function! vimspector#ShowOutput( ... ) abort
if !s:enabled
return
endif
py3 _vimspector_session.ShowOutput( vim.eval( 'a:category' ) )
if a:0 == 1
py3 _vimspector_session.ShowOutput( vim.eval( 'a:1' ) )
else
py3 _vimspector_session.ShowOutput( 'Console' )
endif
endfunction
function! vimspector#ShowOutputInWindow( win_id, category ) abort

View file

@ -12,6 +12,7 @@ for Vimspector.
* [Debug profile configuration](#debug-profile-configuration)
* [Replacements and variables](#replacements-and-variables)
* [The splat operator](#the-splat-operator)
* [Default values](#default-values)
* [Configuration Format](#configuration-format)
* [Files and locations](#files-and-locations)
* [Adapter configurations](#adapter-configurations)
@ -28,7 +29,7 @@ for Vimspector.
* [Appendix: Configuration file format](#appendix-configuration-file-format)
* [Appendix: Editor configuration](#appendix-editor-configuration)
<!-- Added by: ben, at: Sun 12 Jul 2020 16:46:18 BST -->
<!-- Added by: ben, at: Fri 31 Jul 2020 22:13:39 BST -->
<!--te-->
@ -204,6 +205,37 @@ You can also combine with static values:
This would yield the intuitive result:
`[ "First", "one", "two three", "four", "Last" ]`
### Default values
You can specify replacesments with default values. In this case if the user has
not specified a value, they are prompted but with the default value
pre-populated, allowing them to just press return to accept the default.
The syntax is `${variableName:default value}`. The default value can contain any
character, but to include a `}` you must escape it with a backslash. To include
a backslash in the JSON you must write `\\`, as in:
```json
{ "key": "${value:default {\\} stuff}" }
```
The default value can also be a replacement variable. However, this _must_ be a
veriable that's already defined, such as one of the [predefined
variables](#predefined-variables), or one speified in a `variables` block. In
order to reference them, you _must_ use `${var}` syntax and you _must_ escape
the closing `}`. For example, the is a common and useful case:
```json
{
"configuration": {
"program": "${script:${file\\}}"
}
}
```
This will prompt the user to specify `script`, but it will default to the path
to the current file.
## Configuration Format
All Vimspector configuration is defined in a JSON object. The complete

View file

@ -0,0 +1,25 @@
---
title: Configuration
---
This document describes how to use vimspector's `install_gadget.py` to install
custom debug adapters. This can be useful as a way to get an adapter working
that isn't officially supported by Vimspector, but otherwise can be made to work
by simply downloading the VScode extension into the gadget directory.
## Usage
```
./install_gadget.py --enable-custom=/path/to/a.json \
--enable-custom=/path/to/b.json`
```
This tells `install_gadget.py` to read `a.json` and `b.json` as _gadget
definitions_ and download/unpack the specified gadgets into the gadget dir, just
like the supported adapters.
## Gadget Definitions
A _gadget definition_ is a file containing a single JSON object definition,
describing the debug adapter and how to download and install it. This mechanism
is crude but can be effective.

View file

@ -88,7 +88,7 @@ endif
command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr
\ VimspectorWatch
\ call vimspector#AddWatch( <f-args> )
command! -bar -nargs=1 -complete=custom,vimspector#CompleteOutput
command! -bar -nargs=? -complete=custom,vimspector#CompleteOutput
\ VimspectorShowOutput
\ call vimspector#ShowOutput( <f-args> )
command! -bar -nargs=1 -complete=custom,vimspector#CompleteExpr

View file

@ -53,13 +53,13 @@ class ProjectBreakpoints( object ):
self._next_sign_id = 1
if not utils.SignDefined( 'vimspectorBP' ):
vim.command( 'sign define vimspectorBP text==> texthl=Error' )
vim.command( 'sign define vimspectorBP text=\\ ● texthl=WarningMsg' )
if not utils.SignDefined( 'vimspectorBPCond' ):
vim.command( 'sign define vimspectorBPCond text=?> texthl=Error' )
vim.command( 'sign define vimspectorBPCond text=\\ ◆ texthl=WarningMsg' )
if not utils.SignDefined( 'vimspectorBPDisabled' ):
vim.command( 'sign define vimspectorBPDisabled text=!> texthl=Warning' )
vim.command( 'sign define vimspectorBPDisabled text=\\ ● texthl=LineNr' )
def ConnectionUp( self, connection ):

View file

@ -41,17 +41,17 @@ class CodeView( object ):
}
with utils.LetCurrentWindow( self._window ):
vim.command( 'nnoremenu WinBar.Continue :call vimspector#Continue()<CR>' )
vim.command( 'nnoremenu WinBar.Next :call vimspector#StepOver()<CR>' )
vim.command( 'nnoremenu WinBar.Step :call vimspector#StepInto()<CR>' )
vim.command( 'nnoremenu WinBar.Finish :call vimspector#StepOut()<CR>' )
vim.command( 'nnoremenu WinBar.Pause :call vimspector#Pause()<CR>' )
vim.command( 'nnoremenu WinBar.Stop :call vimspector#Stop()<CR>' )
vim.command( 'nnoremenu WinBar.Restart :call vimspector#Restart()<CR>' )
vim.command( 'nnoremenu WinBar.Reset :call vimspector#Reset()<CR>' )
vim.command( 'nnoremenu WinBar.■\\ Stop :call vimspector#Stop()<CR>' )
vim.command( 'nnoremenu WinBar.▶\\ Cont :call vimspector#Continue()<CR>' )
vim.command( 'nnoremenu WinBar.▷\\ Pause :call vimspector#Pause()<CR>' )
vim.command( 'nnoremenu WinBar.↷\\ Next :call vimspector#StepOver()<CR>' )
vim.command( 'nnoremenu WinBar.→\\ Step :call vimspector#StepInto()<CR>' )
vim.command( 'nnoremenu WinBar.←\\ Out :call vimspector#StepOut()<CR>' )
vim.command( 'nnoremenu WinBar.⟲: :call vimspector#Restart()<CR>' )
vim.command( 'nnoremenu WinBar.✕ :call vimspector#Reset()<CR>' )
if not utils.SignDefined( 'vimspectorPC' ):
vim.command( 'sign define vimspectorPC text=-> texthl=Search' )
vim.command( 'sign define vimspectorPC text=\\ ▶ texthl=MatchParen' )
def SetCurrentFrame( self, frame ):

View file

@ -17,7 +17,7 @@
import sys
import os
from vimspector import install, utils
from vimspector import install, utils, installer
def SetUpDebugpy( wait=False, port=5678 ):
@ -32,7 +32,7 @@ def SetUpDebugpy( wait=False, port=5678 ):
exe = sys.executable
try:
# debugpy uses sys.executable (which is `vim`, so we hack it)
sys.executable = 'python3'
sys.executable = installer.PathToAnyWorkingPython3()
debugpy.listen( port )
finally:
sys.executable = exe

View file

@ -19,11 +19,11 @@ import os
import contextlib
import vim
import json
import string
import functools
import subprocess
import shlex
import collections
import re
LOG_FILE = os.path.expanduser( os.path.join( '~', '.vimspector.log' ) )
@ -435,6 +435,60 @@ def ExpandReferencesInObject( obj, mapping, calculus, user_choices ):
return obj
# Based on the python standard library string.Template().substitue, enhanced to
# add ${name:default} parsing, and to remove the unnecessary generality.
VAR_MATCH = re.compile(
r"""
\$(?: # A dollar, followed by...
(?P<escaped>\$) | # Another doller = escaped
(?P<named>[_a-z][_a-z0-9]*) | # or An identifier - named param
{(?P<braced>[_a-z][_a-z0-9]*)} | # or An {identifier} - braced param
{(?P<braceddefault> # or An {id:default} - default param, as
(?P<defname>[_a-z][a-z0-9]*) # an ID
: # then a colon
(?P<default>(?:[^}]|\})*) # then anything up to }, or a \}
)} | #
(?P<invalid>) # or Something else - invalid
)
""",
re.IGNORECASE | re.VERBOSE )
class MissingSubstitution( Exception ):
def __init__( self, name, default_value = None ):
self.name = name
self.default_value = default_value
def _Substitute( template, mapping ):
def convert( mo ):
# Check the most common path first.
named = mo.group( 'named' ) or mo.group( 'braced' )
if named is not None:
if named not in mapping:
raise MissingSubstitution( named )
return str( mapping[ named ] )
if mo.group( 'escaped' ) is not None:
return '$'
if mo.group( 'braceddefault' ) is not None:
named = mo.group( 'defname' )
if named not in mapping:
''
raise MissingSubstitution(
named,
mo.group( 'default' ).replace( '\\}', '}' ) )
return str( mapping[ named ] )
if mo.group( 'invalid' ) is not None:
raise ValueError( f"Invalid placeholder in string { template }" )
raise ValueError( 'Unrecognized named group in pattern', VAR_MATCH )
return VAR_MATCH.sub( convert, template )
def ExpandReferencesInString( orig_s,
mapping,
calculus,
@ -449,17 +503,23 @@ def ExpandReferencesInString( orig_s,
++bug_catcher
try:
s = string.Template( s ).substitute( mapping )
s = _Substitute( s, mapping )
break
except KeyError as e:
# HACK: This is seemingly the only way to get the key. str( e ) returns
# the key surrounded by '' for unknowable reasons.
key = e.args[ 0 ]
except MissingSubstitution as e:
key = e.name
if key in calculus:
mapping[ key ] = calculus[ key ]()
else:
default_value = user_choices.get( key, None )
default_value = user_choices.get( key )
# Allow _one_ level of additional substitution. This allows a very real
# use case of "program": ${prgram:${file\\}}
if default_value is None and e.default_value is not None:
try:
default_value = _Substitute( e.default_value, mapping )
except MissingSubstitution:
default_value = e.default_value
mapping[ key ] = AskForInput( 'Enter value for {}: '.format( key ),
default_value )

View file

@ -106,6 +106,7 @@ class Watch:
"""Holds a user watch expression (DAP request) and the result (WatchResult)"""
def __init__( self, expression: dict ):
self.result: WatchResult
self.line = None
self.expression = expression
self.result = None

View file

@ -3,6 +3,7 @@
BASEDIR=$(dirname $0)
INSTALL=0
UPDATE=0
INSTALLER_ARGS=''
RUN_VIM="vim -N --clean --not-a-term"
RUN_TEST="${RUN_VIM} -S lib/run_test.vim"
BASEDIR_CMD='py3 pass'
@ -48,6 +49,7 @@ while [ -n "$1" ]; do
# old on macOS
out_fd=3
exec 3>/dev/null
INSTALLER_ARGS="${INSTALLER_ARGS} --quiet"
;;
"--")
shift
@ -82,7 +84,10 @@ if [ "${out_fd}" = "1" ]; then
fi
if [ "$INSTALL" = "1" ] || [ "$INSTALL" = "script" ]; then
if ! python3 $(dirname $0)/install_gadget.py --basedir ${BASEDIR} --all; then
if ! python3 $(dirname $0)/install_gadget.py \
--basedir ${BASEDIR} \
${INSTALLER_ARGS} \
--all; then
echo "Script installation reported errors" >&2
exit 1
fi

View file

@ -50,6 +50,24 @@
}
}
},
"run - default": {
"adapter": "debugpy",
"configuration": {
"request": "launch",
"type": "python",
"cwd": "${workspaceRoot}",
"program": "${program:${file\\}}",
"stopOnEntry": false,
"console": "integratedTerminal"
},
"breakpoints": {
"exception": {
"raised": "N",
"uncaught": "",
"userUnhandled": ""
}
}
},
"run - main.py": {
"adapter": "debugpy",
"configuration": {