Just, a ton of work. Aded literals
parent
0bbca21fea
commit
f0dac0d1a1
|
@ -1,3 +1,5 @@
|
|||
import re
|
||||
|
||||
validKeyList = [
|
||||
# top row
|
||||
'escape', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12',
|
||||
|
@ -18,7 +20,9 @@ validKeyList = [
|
|||
'leftarrow', 'rightarrow'
|
||||
]
|
||||
|
||||
class bind(object):
|
||||
popErrors = (AttributeError, KeyError, TypeError)
|
||||
|
||||
class Bind(object):
|
||||
'''
|
||||
Parent class for all bind types.
|
||||
Verifies key, creates local variables
|
||||
|
@ -26,18 +30,26 @@ class bind(object):
|
|||
bindTypes = []
|
||||
instances = {}
|
||||
|
||||
def __init__(self, key, fields):
|
||||
self.alias = False
|
||||
self.key = key
|
||||
self.fields = fields
|
||||
self.errors = []
|
||||
self.targetType = None
|
||||
def __init__(self, key='', fields={}, *, parent=None):
|
||||
if parent is None:
|
||||
self.alias = False
|
||||
self.key = str(key)
|
||||
self.fields = fields
|
||||
self.errors = []
|
||||
self.warnings = []
|
||||
self.TargetType = None
|
||||
else:
|
||||
self.alias = parent.alias
|
||||
self.key = parent.key
|
||||
self.fields = parent.fields
|
||||
self.errors = parent.errors
|
||||
self.warnings = parent.warnings
|
||||
|
||||
# redefined for each unique type, default just verifies key
|
||||
# and some other universal fields like alias and finds targetType
|
||||
self.verify()
|
||||
|
||||
if type(self) is bind:
|
||||
if type(self) is Bind:
|
||||
# not using isinstance(), because all subclasses are also instances
|
||||
# of bind.
|
||||
return
|
||||
|
@ -46,15 +58,15 @@ class bind(object):
|
|||
# verify function should remove all fields relavent to the bind.
|
||||
# Any extras are errors
|
||||
|
||||
self.errors.append(f'extra fields in "{self.key}":')
|
||||
self.warnings.append(f'extra fields in "{self.key}":')
|
||||
if isinstance(self.fields, str):
|
||||
# iterating over a str returns each character,
|
||||
# making meaningless error messages
|
||||
self.errors.append(f' "{self.fields}"')
|
||||
self.warnings.append(f' "{self.fields}"')
|
||||
else:
|
||||
for field in self.fields:
|
||||
self.errors.append(f' "{field}"')
|
||||
elif len(self.errors) == 0:
|
||||
self.warnings.append(f' "{field}"')
|
||||
if len(self.errors) == 0:
|
||||
# no errors, add new instance to the list of instances
|
||||
try:
|
||||
self.instances[type(self)].append(self)
|
||||
|
@ -62,20 +74,20 @@ class bind(object):
|
|||
self.instances[type(self)] = [self]
|
||||
|
||||
def verify(self):
|
||||
|
||||
try:
|
||||
self.alias = self.fields.pop('alias')
|
||||
if not isinstance(self.alias, bool):
|
||||
self.errors.append(f'alias should be "yes" or "no", not "{self.alias}"')
|
||||
self.errors.append(
|
||||
f'alias should be "yes" or "no", not "{self.alias}"'
|
||||
)
|
||||
self.alias = False
|
||||
except (KeyError, AttributeError, TypeError):
|
||||
# KeyError, if dict but no alias field;
|
||||
# AttributeError, if no pop method;
|
||||
# TypeError, if pop method won't take str() as arg
|
||||
except popErrors:
|
||||
self.alias = False
|
||||
|
||||
try:
|
||||
typeName, self.key = self.key.split(' ', 1)
|
||||
# all types start with a capital
|
||||
typeName = typeName.lower().capitalize()
|
||||
if not self.alias:
|
||||
# don't mess with alias names
|
||||
self.key = self.key.lower()
|
||||
|
@ -84,33 +96,39 @@ class bind(object):
|
|||
self.errors.append(f'could not find type in "{self.key}"')
|
||||
return
|
||||
|
||||
for type_ in self.bindTypes:
|
||||
if typeName == type_.__name__:
|
||||
self.TargetType = type_
|
||||
break
|
||||
|
||||
if self.TargetType is None:
|
||||
self.errors.append(
|
||||
f'"{typeName}" is not a valid type for "{self.key}"'
|
||||
)
|
||||
|
||||
if (not self.alias) and (self.key not in validKeyList):
|
||||
self.errors.append(f'invalid key name: "{self.key}"')
|
||||
|
||||
for type_ in self.bindTypes:
|
||||
if typeName == type_.__name__:
|
||||
self.targetType = type_
|
||||
break
|
||||
|
||||
if self.targetType is None:
|
||||
self.errors.append(f'could not find type in "{self.key}"')
|
||||
|
||||
def toTargetType(self):
|
||||
if self.targetType is None:
|
||||
if self.TargetType is None:
|
||||
# do nothing
|
||||
bind = self
|
||||
else:
|
||||
# cast to targetType, extend errors
|
||||
bind = self.targetType(self.key, self.fields)
|
||||
bind.errors.extend(self.errors)
|
||||
bind.alias = self.alias
|
||||
return self
|
||||
# cast to targetType, "inheriting" stuff from self
|
||||
bind = self.TargetType(parent=self)
|
||||
return bind
|
||||
|
||||
def err(self, message):
|
||||
self.errors.append(f'{type(self).__name__} "{self.key}" {message}')
|
||||
self.errors.append(
|
||||
f'{type(self).__name__.lower()} "{self.key}" {message}'
|
||||
)
|
||||
|
||||
def warn(self, message):
|
||||
self.warnings.append(
|
||||
f'{type(self).__name__.lower()} "{self.key}" {message}'
|
||||
)
|
||||
|
||||
|
||||
class impulse(bind):
|
||||
class Impulse(Bind):
|
||||
def verify(self):
|
||||
self.command = None
|
||||
if not isinstance(self.fields, dict):
|
||||
|
@ -118,15 +136,14 @@ class impulse(bind):
|
|||
|
||||
try:
|
||||
self.command = self.fields.pop('command')
|
||||
if isinstance(self.command, str):
|
||||
self.command = self.command.split(';')
|
||||
elif not isinstance(self.command, list):
|
||||
self.err('`command` field must be argument of string or list')
|
||||
self.command = None
|
||||
except KeyError:
|
||||
self.err('requires `command` field')
|
||||
|
||||
if isinstance(self.command, str):
|
||||
self.command = self.command.split(';')
|
||||
|
||||
elif not isinstance(self.command, list):
|
||||
self.err('`command` field must be argument of string or list')
|
||||
self.command = None
|
||||
|
||||
def toTF2(self) -> str:
|
||||
if self.alias:
|
||||
|
@ -165,7 +182,8 @@ class impulse(bind):
|
|||
elif cmd == 'build' or cmd == 'destroy':
|
||||
restOfCmd = self.expandBuildings(restOfCmd)
|
||||
|
||||
elif cmd == 'load_itempreset' and restOfCmd.isalpha():
|
||||
elif cmd == 'loadout' and restOfCmd.isalpha():
|
||||
cmd = 'load_itempreset'
|
||||
try:
|
||||
restOfCmd = restOfCmd.lower()
|
||||
restOfCmd = str(['a','b','c','d'].index(restOfCmd))
|
||||
|
@ -173,6 +191,11 @@ class impulse(bind):
|
|||
# not a load_itempreset shortcut
|
||||
pass
|
||||
|
||||
elif cmd == 'unalias':
|
||||
cmd = 'alias'
|
||||
# adding empty arg to indicate unaliasing
|
||||
restOfCmd += ' '
|
||||
|
||||
if restOfCmd != '':
|
||||
cmd += ' ' + restOfCmd
|
||||
instList[i] = cmd
|
||||
|
@ -205,7 +228,7 @@ class impulse(bind):
|
|||
return num
|
||||
|
||||
|
||||
class hold(bind):
|
||||
class Hold(Bind):
|
||||
def verify(self):
|
||||
self.press = None
|
||||
self.release = None
|
||||
|
@ -215,31 +238,32 @@ class hold(bind):
|
|||
# verify press
|
||||
try:
|
||||
self.press = self.fields.pop('press')
|
||||
if isinstance(self.press, str):
|
||||
self.press = self.press.split(';')
|
||||
elif not isinstance(self.press, list):
|
||||
self.err('`press` field must be string or list')
|
||||
self.press = None
|
||||
except KeyError:
|
||||
self.err('requires `press` field')
|
||||
|
||||
if isinstance(self.press, str):
|
||||
self.press = self.press.split(';')
|
||||
elif not isinstance(self.press, list):
|
||||
self.err('`press` field must be string or list')
|
||||
self.press = None
|
||||
if self.press is None:
|
||||
return
|
||||
|
||||
# verify release
|
||||
try:
|
||||
self.release = self.fields.pop('release')
|
||||
except KeyError:
|
||||
if isinstance(self.release, str):
|
||||
self.release = self.release.split(';')
|
||||
elif not isinstance(self.release, list):
|
||||
self.err('`release` field must be string or list')
|
||||
self.release = None
|
||||
except popErrors:
|
||||
self.warn('has no `release`, creating one')
|
||||
# no release specified, do -action for each item in press
|
||||
self.release = []
|
||||
for cmd in self.press:
|
||||
if cmd[0] == '+':
|
||||
self.release.append('-' + cmd[1:])
|
||||
|
||||
if isinstance(self.release, str):
|
||||
self.release = self.release.split(';')
|
||||
elif not isinstance(self.release, list):
|
||||
self.err('"release" field must be string or list')
|
||||
self.release = None
|
||||
|
||||
def toTF2(self) -> str:
|
||||
if self.alias:
|
||||
bindOrAlias = 'alias'
|
||||
|
@ -249,11 +273,11 @@ class hold(bind):
|
|||
|
||||
# Making impulse instances from self.press and .release
|
||||
# allows them to share the shortcuts
|
||||
pressObj = impulse(f'+{holdStr}', self.press)
|
||||
pressObj = Impulse(f'+{holdStr}', self.press)
|
||||
pressObj.alias = True
|
||||
pressStr = pressObj.toTF2()
|
||||
|
||||
releaseObj = impulse(f'-{holdStr}', self.release)
|
||||
releaseObj = Impulse(f'-{holdStr}', self.release)
|
||||
releaseObj.alias = True
|
||||
releaseStr = releaseObj.toTF2()
|
||||
|
||||
|
@ -262,10 +286,13 @@ class hold(bind):
|
|||
# and never deactivating
|
||||
self.key = '+' + self.key
|
||||
|
||||
return pressStr + releaseStr + f'{bindOrAlias} {self.key} "+{holdStr}"\n'
|
||||
return (
|
||||
pressStr + releaseStr
|
||||
+ f'{bindOrAlias} {self.key} "+{holdStr}"\n'
|
||||
)
|
||||
|
||||
|
||||
class toggle(bind):
|
||||
class Toggle(Bind):
|
||||
def verify(self):
|
||||
self.on = None
|
||||
self.off = None
|
||||
|
@ -275,31 +302,30 @@ class toggle(bind):
|
|||
# verify on
|
||||
try:
|
||||
self.on = self.fields.pop('on')
|
||||
if isinstance(self.on, str):
|
||||
self.on = self.on.split(';')
|
||||
elif not isinstance(self.on, list):
|
||||
self.err('`on` field must be string or list')
|
||||
self.on = None
|
||||
except KeyError:
|
||||
self.err('requires `on` field')
|
||||
|
||||
if isinstance(self.on, str):
|
||||
self.on = self.on.split(';')
|
||||
elif not isinstance(self.on, list):
|
||||
self.err('`on` field must be string or list')
|
||||
self.on = None
|
||||
if self.on is None:
|
||||
return
|
||||
|
||||
# verify off
|
||||
try:
|
||||
self.off = self.fields.pop('off')
|
||||
except KeyError:
|
||||
if isinstance(self.off, str):
|
||||
self.off = self.off.split(';')
|
||||
elif not isinstance(self.off, list):
|
||||
self.err('`off` field must be string or list')
|
||||
except popErrors:
|
||||
# no off specified, do -action for each item in on
|
||||
self.off = []
|
||||
for cmd in self.on:
|
||||
if cmd[0] == '+':
|
||||
self.off.append('-' + cmd[1:])
|
||||
|
||||
if isinstance(self.off, str):
|
||||
self.off = self.off.split(';')
|
||||
elif not isinstance(self.off, list):
|
||||
self.err('`off` field must be string or list')
|
||||
self.off = None
|
||||
|
||||
def toTF2(self) -> str:
|
||||
if self.alias:
|
||||
bindOrAlias = 'alias'
|
||||
|
@ -309,27 +335,28 @@ class toggle(bind):
|
|||
onStr = f'{toggleStr}_on'
|
||||
offStr = f'{toggleStr}_off'
|
||||
|
||||
onObj = impulse(onStr, self.on)
|
||||
onObj = Impulse(onStr, self.on)
|
||||
onObj.alias = True
|
||||
toggleOn = onObj.toTF2()[
|
||||
# remove trailing " and \n
|
||||
:-2
|
||||
]
|
||||
toggleOn = onObj.toTF2()
|
||||
# remove starting/trailing " and \n
|
||||
toggleOn = toggleOn[:-2]
|
||||
|
||||
offObj = impulse(offStr, self.off)
|
||||
offObj = Impulse(offStr, self.off)
|
||||
offObj.alias = True
|
||||
toggleOff = offObj.toTF2()[:-2]
|
||||
|
||||
return \
|
||||
f'{toggleOn}; alias {toggleStr} {offStr}"\n' +\
|
||||
f'{toggleOff}; alias {toggleStr} {onStr}"\n' +\
|
||||
f'alias {toggleStr} "{onStr}"\n' +\
|
||||
f'{bindOrAlias} {self.key} "{toggleStr}"\n'
|
||||
return (
|
||||
f'{toggleOn}; alias {toggleStr} {offStr}"\n'
|
||||
+ f'{toggleOff}; alias {toggleStr} {onStr}"\n'
|
||||
+ f'alias {toggleStr} "{onStr}"\n'
|
||||
+ f'{bindOrAlias} {self.key} "{toggleStr}"\n'
|
||||
)
|
||||
|
||||
|
||||
class double(bind):
|
||||
class Double(Bind):
|
||||
defaultDict = {}
|
||||
condDict = {}
|
||||
bindNames = []
|
||||
|
||||
def verify(self):
|
||||
self.primary = None
|
||||
|
@ -345,114 +372,152 @@ class double(bind):
|
|||
self.type = None
|
||||
|
||||
# either 'released' (default) or 'both'
|
||||
self.cancel = 'released'
|
||||
self.cancelBoth = False
|
||||
|
||||
# toggler
|
||||
try:
|
||||
self.condition = self.fields.pop('condition')
|
||||
if self.condition not in validKeyList:
|
||||
self.err(f'has invalid `condition` field: "{self.condition}"')
|
||||
except KeyError:
|
||||
except popErrors:
|
||||
self.err('requires `condition` field')
|
||||
|
||||
if 'toggle' in self.fields:
|
||||
try:
|
||||
self.isToggle = self.fields.pop('toggle')
|
||||
if not isinstance(self.isToggle, bool):
|
||||
self.err(f'`toggle` field should be "yes" or "no", not "{self.isToggle}"')
|
||||
self.err(
|
||||
'`toggle` field should be "yes" or "no", '
|
||||
+ f'not "{self.isToggle}"'
|
||||
)
|
||||
except popErrors:
|
||||
self.isToggle = False
|
||||
|
||||
# type
|
||||
try:
|
||||
self.type = self.fields.pop('type')
|
||||
if self.type not in [ type_.__name__ for type_ in self.bindTypes ]:
|
||||
self.type = self.fields.pop('type').lower()
|
||||
if self.type not in self.bindNames:
|
||||
# catastrophic: invalid type
|
||||
self.err(f'has invalid type: "{self.type}"')
|
||||
return
|
||||
except KeyError:
|
||||
except popErrors:
|
||||
# catastrophic: no type given
|
||||
self.err('requires `type` field')
|
||||
return
|
||||
|
||||
# cancel mode, must happend after type has been inferred
|
||||
if 'cancel' in self.fields:
|
||||
self.cancel = self.fields.pop('cancel')
|
||||
if self.cancel in ('released', 'both'):
|
||||
if self.cancel == 'both' and self.type != 'hold':
|
||||
self.err(f'`cancel` field only affects "hold", not "{self.type}"')
|
||||
elif isinstance(self.cancel, str):
|
||||
self.err(f'`cancel` field must be "released" or "both", not "{self.cancel}"')
|
||||
try:
|
||||
cancel = self.fields.pop('cancel')
|
||||
|
||||
if not isinstance(cancel, str):
|
||||
self.err(f'`cancel` field must be "released" or "both"')
|
||||
|
||||
else:
|
||||
self.err(f'`cancel` field must be argument of "released" or "both"')
|
||||
if cancel == 'both':
|
||||
if self.type == 'hold':
|
||||
self.cancelBoth = True
|
||||
else:
|
||||
self.err(
|
||||
'`cancel` field only affects "hold", '
|
||||
+ f'not "{self.type}"'
|
||||
)
|
||||
|
||||
elif cancel != 'released':
|
||||
self.err(
|
||||
'`cancel` field must be "released" '
|
||||
+ f'or "both", not "{cancel}"'
|
||||
)
|
||||
except popErrors:
|
||||
cancel = 'released'
|
||||
|
||||
# primary action
|
||||
try:
|
||||
mainSection = self.fields.pop('primary')
|
||||
mainBind = Bind(f'{self.type} {self.primStr}', mainSection)
|
||||
mainBind = mainBind.toTargetType()
|
||||
|
||||
mainAction = bind(f'{self.type} {self.primStr}', mainSection)
|
||||
self.primary = mainAction.toTargetType()
|
||||
except KeyError:
|
||||
self.errors.extend(mainBind.errors)
|
||||
self.warnings.extend(mainBind.warnings)
|
||||
self.errors.remove(f'invalid key name: "{self.primStr}"')
|
||||
self.primary = mainBind
|
||||
except popErrors:
|
||||
self.err('requires `primary` field')
|
||||
|
||||
# secondary action
|
||||
try:
|
||||
altSection = self.fields.pop('secondary')
|
||||
altBind = Bind(f'{self.type} {self.secondStr}', altSection)
|
||||
altBind = altBind.toTargetType()
|
||||
|
||||
altBind = bind(f'{self.type} {self.secondStr}', altSection)
|
||||
self.secondary = altBind.toTargetType()
|
||||
except KeyError:
|
||||
self.errors.extend(altBind.errors)
|
||||
self.warnings.extend(altBind.warnings)
|
||||
self.errors.remove(f'invalid key name: "{self.secondStr}"')
|
||||
self.secondary = altBind
|
||||
except popErrors:
|
||||
self.err('requires `secondary` field')
|
||||
|
||||
def toTF2(self) -> str:
|
||||
if self.alias:
|
||||
bindOrAlias = 'alias'
|
||||
else:
|
||||
bindOrAlias = 'bind'
|
||||
|
||||
# Get code for primary and secondary actions
|
||||
def toTF2(self) -> str:
|
||||
# Get code for primary and secondary actions.
|
||||
# alias=true so the toTF2() method aliases
|
||||
# them instead of binding them
|
||||
self.primary.alias = True
|
||||
mainCode = self.primary.toTF2()
|
||||
self.secondary.alias = True
|
||||
altCode = self.secondary.toTF2()
|
||||
|
||||
# Make code to switch between the two actions
|
||||
pShiftStr = f'+shift_{self.key}'
|
||||
mShiftStr = f'-shift_{self.key}'
|
||||
|
||||
if self.cancel == 'both':
|
||||
mainCode, altCode = self.cancelBoth(mainCode, altCode)
|
||||
if self.cancelBoth:
|
||||
mainCode, altCode = self.getCancelCode(mainCode, altCode)
|
||||
|
||||
if self.type == 'hold':
|
||||
self.primStr = '+' + self.primStr
|
||||
self.secondStr = '+' + self.secondStr
|
||||
|
||||
result = mainCode + altCode +\
|
||||
f'alias {pShiftStr} "{bindOrAlias} {self.key} {self.secondStr}"\n' +\
|
||||
f'alias {mShiftStr} "{bindOrAlias} {self.key} {self.primStr}"\n'+\
|
||||
f'{bindOrAlias} {self.key} "{self.primStr}"\n'
|
||||
shiftStr = f'shift_{self.key}'
|
||||
shiftCode = self.getChangeCode(shiftStr)
|
||||
self.addToCondDict(shiftStr)
|
||||
|
||||
try:
|
||||
# If the condition key (like 'mouse4') already has toggles,
|
||||
# just append another toggle string
|
||||
changes = self.condDict[self.condition]['change_keys']
|
||||
restores = self.condDict[self.condition]['restore_keys']
|
||||
return mainCode + altCode + shiftCode
|
||||
|
||||
if pShiftStr not in changes:
|
||||
# not already in changes
|
||||
changes.append(pShiftStr)
|
||||
restores.append(mShiftStr)
|
||||
def getChangeCode(self, shift):
|
||||
if self.alias:
|
||||
bindOrAlias = 'alias'
|
||||
else:
|
||||
bindOrAlias = 'bind'
|
||||
code = (
|
||||
f'alias +{shift} "{bindOrAlias} {self.key} {self.secondStr}"\n'
|
||||
+ f'alias -{shift} "{bindOrAlias} {self.key} {self.primStr}"\n'
|
||||
)
|
||||
|
||||
except KeyError:
|
||||
# If the condition key doesn't already exist, make it
|
||||
if self.isToggle:
|
||||
toggleObj = Toggle(shift, f'+{shift}')
|
||||
toggleObj.alias = True # so it aliases instead of binding
|
||||
code += toggleObj.toTF2()
|
||||
else:
|
||||
code += f'{bindOrAlias} {self.key} "{self.primStr}"\n'
|
||||
return code
|
||||
|
||||
def addToCondDict(self, shiftStr):
|
||||
if self.isToggle:
|
||||
changeStr = shiftStr
|
||||
else:
|
||||
changeStr = '+' + shiftStr
|
||||
restoreStr = '-' + shiftStr
|
||||
|
||||
if self.condition not in self.condDict:
|
||||
# if not already present, make dict for key
|
||||
self.condDict.update( {
|
||||
self.condition: {
|
||||
'change_keys': [ pShiftStr ],
|
||||
'restore_keys': [ mShiftStr ],
|
||||
'alias': self.alias
|
||||
'change_keys': [],
|
||||
'restore_keys': []
|
||||
}
|
||||
} )
|
||||
|
||||
return result
|
||||
self.condDict[self.condition]['change_keys'].append(changeStr)
|
||||
if self.isToggle == False:
|
||||
self.condDict[self.condition]['restore_keys'].append(restoreStr)
|
||||
|
||||
def cancelBoth(self, mainCode, altCode) -> (str, str):
|
||||
def getCancelCode(self, mainCode, altCode) -> (str, str):
|
||||
# code to cancel both if either is released
|
||||
# it copies the - statement from each to both.
|
||||
# if it just extracted the name of the - statement,
|
||||
|
@ -469,18 +534,13 @@ class double(bind):
|
|||
altMinusStr = altMinusLine.split(' ', 2)[2][1:-1]
|
||||
|
||||
# remove duplicate - actions
|
||||
mainMinusList = set(mainMinusStr.split(';'))
|
||||
altMinusList = set(altMinusStr.split(';'))
|
||||
uniqMain = mainMinusList.difference(altMinusList)
|
||||
uniqAlt = altMinusList.difference(mainMinusList)
|
||||
mainMinusSet = set(mainMinusStr.split(';'))
|
||||
altMinusSet = set(altMinusStr.split(';'))
|
||||
allCancels = mainMinusSet | altMinusSet
|
||||
allCancelStr = ';'.join(allCancels)
|
||||
|
||||
mainMinusStr = ';'.join(uniqMain)
|
||||
altMinusStr = ';'.join(uniqAlt)
|
||||
if not uniqMain.issuperset(uniqAlt):
|
||||
# main has things alt doesn't
|
||||
mainLines[1] = mainLines[1][:-1] + f';{altMinusStr}"'
|
||||
if not uniqAlt.issuperset(uniqMain):
|
||||
altLines[1] = altLines[1][:-1] + f';{mainMinusStr}"'
|
||||
altLines[1] = altLines[1][:-1] + f';{allCancelStr}"'
|
||||
mainLines[1] = mainLines[1][:-1] + f';{allCancelStr}"'
|
||||
|
||||
return (
|
||||
'\n'.join(mainLines) + '\n',
|
||||
|
@ -488,7 +548,7 @@ class double(bind):
|
|||
)
|
||||
|
||||
|
||||
class repeat(bind):
|
||||
class Repeat(Bind):
|
||||
def verify(self):
|
||||
self.interval = None
|
||||
self.command = None
|
||||
|
@ -497,25 +557,73 @@ class repeat(bind):
|
|||
intervalStr = str(self.fields.pop('interval'))
|
||||
self.interval = int(intervalStr)
|
||||
if self.interval <= 0:
|
||||
self.err('interval must be greater than 0')
|
||||
except KeyError:
|
||||
self.err('requires interval')
|
||||
self.err('`interval` must be greater than 0')
|
||||
except (KeyError, TypeError):
|
||||
self.err('requires `interval` field')
|
||||
except ValueError:
|
||||
self.err(f'has invalid number of ticks: "{self.interval}"')
|
||||
self.err(f'has invalid `interval`: "{self.interval}"')
|
||||
except AttributeError:
|
||||
self.err(f'requires `interval` field')
|
||||
|
||||
try:
|
||||
self.command = self.fields.pop('command')
|
||||
if not isinstance(self.command, (str, list)):
|
||||
self.err('command must be string or list')
|
||||
self.err('`command` must be string or list')
|
||||
self.command = None
|
||||
except KeyError:
|
||||
self.err('requires command')
|
||||
except popErrors:
|
||||
self.err('requires `command` field')
|
||||
|
||||
def toTF2(self) -> str:
|
||||
# commented-out placeholder
|
||||
return f'// repeat {self.key}\n'
|
||||
|
||||
|
||||
class Literal(Bind):
|
||||
def verify(self):
|
||||
self.text = ''
|
||||
self.run = False
|
||||
if not isinstance(self.fields, dict):
|
||||
self.fields = {'text': self.fields}
|
||||
|
||||
if not self.alias:
|
||||
try:
|
||||
# keyname should be invalid, remove the error
|
||||
self.errors.remove(
|
||||
f'invalid key name: "{self.key}"'
|
||||
)
|
||||
except ValueError:
|
||||
# if not invalid key, indicate as such
|
||||
self.warn('should not use a key as a label')
|
||||
|
||||
if 'run' in self.fields:
|
||||
self.run = self.fields.pop('run')
|
||||
if not isinstance(self.run, bool):
|
||||
self.errors.append(
|
||||
f'`run` should be "yes" or "no", not "{self.run}"'
|
||||
)
|
||||
if not self.alias:
|
||||
self.warn('`run` specified without alias')
|
||||
|
||||
try:
|
||||
self.text = self.fields.pop('text')
|
||||
except KeyError:
|
||||
self.err('requires `text` field')
|
||||
|
||||
if isinstance(self.text, str):
|
||||
self.text = self.text.split(';')
|
||||
elif not isinstance(self.text, list):
|
||||
self.err('argument must be of string or list')
|
||||
|
||||
def toTF2(self) -> str:
|
||||
result = ';'.join(self.text)
|
||||
if self.alias:
|
||||
result = f'alias {self.key} "{result}"'
|
||||
if self.run:
|
||||
result += f'\n{self.key}'
|
||||
return result + '\n'
|
||||
|
||||
# This is at the bottom because it has to happen after
|
||||
# all inheritances have been completed
|
||||
|
||||
bind.bindTypes = bind.__subclasses__()
|
||||
Bind.bindTypes = Bind.__subclasses__()
|
||||
Double.bindNames = [ bind.__name__.lower() for bind in Bind.bindTypes ]
|
Loading…
Reference in New Issue