New alias system

main
Nicholas Hope 2022-08-15 13:41:09 -04:00
parent 40c8b4ee42
commit 90f39b2737
2 changed files with 98 additions and 73 deletions

View File

@ -2,26 +2,48 @@
# Used for the conditions in the <double> type
condDict = {}
defaultDict = {}
bindOrAlias = "bind"
from json import dumps
from copy import deepcopy
def makeCFG(cfg, default=False):
global bindOrAlias
global condDict
global defaultDict
bindOrAlias = "bind"
if default:
# Write to defaultDict instead of condDict
condDict = defaultDict
else:
condDict = deepcopy(defaultDict)
def makeCFG(cfg):
condDict.clear()
ret = ''
for key, data in cfg.items():
# I know all of these fields exist because it was verified in verify.py
bindType = firstTypeIn(data.keys())
bindContent = data[bindType]
ret += branch(key, bindContent, bindType)
isAlias = False
if "alias" in data:
isAlias = data.pop("alias")
if isAlias:
bindOrAlias = "alias"
else:
bindOrAlias = "bind"
ret += branch(key, data)
# Doubles are weird. All of the toggles got put into a dictionary.
# This takes all of the nested dictionaries and turns them into the right string
for key, toggles in condDict.items():
ret += f'alias +{key}_toggles "{toggles["plus_toggles"]}"\n' +\
f'alias -{key}_toggles "{toggles["minus_toggles"]}"\n' +\
f'bind {key} "+{key}_toggles"\n'
plusToggleStr = ';'.join(toggles["plus_toggles"])
minusToggleStr = ';'.join(toggles["minus_toggles"])
ret += f'alias +{key}_toggles "{plusToggleStr}"\n' +\
f'alias -{key}_toggles "{minusToggleStr}"\n' +\
f'{bindOrAlias} {key} "+{key}_toggles"\n'
del condDict # free deep copy
return ret
def firstTypeIn(inputList):
def typeOf(dictIn):
""" Find the first element common to both lists """
types = [
"impulse",
@ -31,10 +53,13 @@ def firstTypeIn(inputList):
"repeat"
]
for t in types:
if t in inputList:
if t in dictIn.keys():
return t
def branch(keyName, bindContent, bindType):
def branch(keyName, bindContent):
bindType = typeOf(bindContent)
bindContent = bindContent.pop(bindType)
if bindType == "impulse":
return impulse(keyName, bindContent)
@ -54,6 +79,7 @@ def branch(keyName, bindContent, bindType):
return repeat(keyName, bindContent)
def impulse(key, instruction):
global bindOrAlias
if isinstance(instruction, list):
instruction = ';'.join(instruction)
@ -64,7 +90,7 @@ def impulse(key, instruction):
instruction = ';'.join(allInstructions)
return f'bind {key} "{instruction}"\n'
return f'{bindOrAlias} {key} "{instruction}"\n'
def impulseShortcuts(instruction):
splitCommand = instruction.split(' ')
@ -116,13 +142,15 @@ def expandBuildings(building):
return num
def simpleHold(key, instruction):
global bindOrAlias
# This isn't quite right, fix later!
if instruction[0] != '+':
return f'bind {key} "+{instruction}"\n'
if instruction[0] == '+' or instruction[0] == '-':
return f'{bindOrAlias} {key} "{instruction}"\n'
else:
return f'bind {key} "{instruction}"\n'
return f'{bindOrAlias} {key} "+{instruction}"\n'
def listHold(key, options):
global bindOrAlias
pressStr = options["press"]
if isinstance(pressStr, list):
pressStr = ';'.join(pressStr)
@ -133,10 +161,12 @@ def listHold(key, options):
ret = f'alias +{key}_bind "{pressStr}"\n' +\
f'alias -{key}_bind "{releaseStr}"\n' +\
f'bind {key} "+{key}_bind"\n'
f'{bindOrAlias} {key} "+{key}_bind"\n'
return ret
def toggle(key, instruction):
global bindOrAlias
onStr = f'turn_{key}_on'
offStr = f'turn_{key}_off'
togStr = f'toggle_{key}'
@ -144,59 +174,47 @@ def toggle(key, instruction):
ret = f'alias {onStr} "+{instruction}; alias {togStr} {offStr}"\n' +\
f'alias {offStr} "-{instruction}; alias {togStr} {onStr}"\n' +\
f'alias {togStr} "{onStr}"\n' +\
f'bind {key} "{togStr}"\n'
f'{bindOrAlias} {key} "{togStr}"\n'
return ret
def double(key, options):
primaryAction = options["primary"]
pBindType = firstTypeIn(primaryAction.keys())
pBindContent = primaryAction[pBindType]
secAction = options["secondary"]
sBindType = firstTypeIn(secAction.keys())
sBindContent = secAction[sBindType]
mainStr = f'{key}_main'
altStr = f'{key}_alt'
togStr = f'toggle_{key}'
pTogStr = f'+toggle_{key}'
mTogStr = f'-toggle_{key}'
recursiveCode = branch(mainStr, pBindContent, pBindType) +\
branch(altStr, sBindContent, sBindType)
global bindOrAlias
oldBindOrAlias = bindOrAlias
bindOrAlias = "alias"
recursiveCode = branch(mainStr, primaryAction) +\
branch(altStr, secAction)
bindOrAlias = oldBindOrAlias
newcode = []
for line in recursiveCode.split('\n'):
# For every line gotten by the recursive call, change all "bind"s to "alias",
# since mainStr and altStr aren't valid bind targes
llist = line.split(' ')
for i in range(len(llist)):
alphanumChars = ''.join(c for c in llist[i] if c.isalnum())
if alphanumChars == 'bind':
if llist[i][0].isalnum():
llist[i] = 'alias'
else:
# If the first character isn't a normal character.
# Almost always because it is a double quote
llist[i] = llist[i][0] + 'alias'
newcode.append(' '.join(llist))
ret = '\n'.join(newcode) +\
f'alias +{togStr} "bind {key} {altStr}"\n' +\
f'alias -{togStr} "bind {key} {mainStr}"\n'+\
f'bind {key} "{mainStr}"\n'
ret = recursiveCode +\
f'alias {pTogStr} "{bindOrAlias} {key} {altStr}"\n' +\
f'alias {mTogStr} "{bindOrAlias} {key} {mainStr}"\n'+\
f'{bindOrAlias} {key} "{mainStr}"\n'
condName = options["condition"]
global condDict
if condName in condDict:
# If the condition key (like "mouse4") already has toggles,
# just append another toggle string (it gets encased in quotes later)
condDict[condName]["plus_toggles"] += f"; +{togStr}"
condDict[condName]["minus_toggles"] += f"; -{togStr}"
# just append another toggle string
plusToggles = condDict[condName]["plus_toggles"]
minusToggles = condDict[condName]["minus_toggles"]
if pTogStr not in plusToggles:
plusToggles.append(pTogStr)
minusToggles.append(mTogStr)
else:
# If the condition key doesn't already exist, make it with the correct values
# If the condition key doesn't already exist, make it
condDict.update( {
condName: {
"plus_toggles": f"+{togStr}",
"minus_toggles": f"-{togStr}"
"plus_toggles": [ pTogStr ],
"minus_toggles": [ mTogStr ]
}
} )

View File

@ -3,18 +3,22 @@ def verifyConfig(cfg: dict) -> (dict, dict):
verifiedConfig = {}
# Do defaults first
aliasErrors = []
errors = {}
defaults = None
if "default" in cfg:
defaults = cfg.pop("default")
errMessages = []
for key, data in defaults.items():
isAlias = ("alias" in data and data["alias"] == True)
errMessages = validBind(key, data, alias = isAlias)
if len(errMessages) > 0:
for msg in errMessages:
aliasErrors.append(f"Error in defaults: {msg}")
isAlias = False
if "alias" in data:
isAlias = data["alias"]
if not isinstance(isAlias, bool):
errMessages.append(f'"alias" field in "{key}" makes no sense: "{isAlias}"')
errMessages.extend(validBind(key, data, alias = isAlias) )
if len(errMessages) > 0:
errors.update( {"default": errMessages} )
classList = [
"scout",
@ -28,9 +32,6 @@ def verifyConfig(cfg: dict) -> (dict, dict):
"spy"
]
errors = aliasErrors.copy()
for cclass in classList:
classCFG = None
className = cclass
@ -47,33 +48,35 @@ def verifyConfig(cfg: dict) -> (dict, dict):
# It may be less efficient this way, but
# it makes for more descriptive error messages
continue
errMessages = []
for key, data in classCFG.items():
errMessages = []
isAlias = False
if "alias" in data:
isAlias = data["alias"]
if not isinstance(isAlias, bool):
errMessages.append(f'Key "{key}" has alias not set to true or false. Did you accidentally put it in quotes?')
errMessages.append(f'"alias" field in "{key}" makes no sense: "{isAlias}"')
errMessages.extend( validBind(key, data, alias = isAlias) )
if len(errMessages) > 0:
for msg in errMessages:
errors.append(f"Error in {cclass}: {msg}")
if len(errMessages) > 0:
errors.update( {className: errMessages} )
verifiedConfig.update({className: classCFG})
# Turn list into only strings by expanding tuples
for i, clss in enumerate(classList):
if isinstance(clss, tuple):
classList.insert(i+1, clss[0])
classList.insert(i+1, clss[1])
classList.insert(i+1, clss[0])
classList.pop(i)
globalErrors = []
for remainingClass in cfg:
if remainingClass not in classList:
errors.append(f'Error in {remainingClass}: "{remainingClass}" is not a valid class')
globalErrors.append(f'"{remainingClass}" is not a valid class')
else:
otherName = findTwin(remainingClass)
if otherName is not None:
errors.append(f'Error in {remainingClass}: conflicting names for section: "{remainingClass}" and "{otherName}"')
globalErrors.append(f'Conflicting names for section: "{remainingClass}" and "{otherName}"')
if len(globalErrors) > 0:
errors.update( {"file": globalErrors} )
if len(errors) > 0:
verifiedConfig.update({"errors": errors})
@ -95,8 +98,8 @@ def validBind(key, data, alias = False) -> list:
extras = dataCopy.keys()
if len(extras) > 0:
extrasString = "\n\t".join(extras)
ret.append(f'Unused fields in "{key}":\n\t{extrasString}')
extrasString = "\n ".join(extras)
ret.append(f'Unused fields in "{key}":\n {extrasString}')
return ret
@ -108,7 +111,10 @@ validKeyList = [
'u', 'v', 'w', 'x', 'y', 'z',
'mouse1', 'mouse2', 'mouse3', 'mouse4', 'mouse5',
'shift', 'capslock', 'ctrl', 'semicolon', 'space', 'enter',
'backspace'
'backspace',
'scrolllock', 'numlock',
'ins', 'home', 'pgup',
'del', 'end', 'pgdn'
]
def validKey(key):
@ -144,6 +150,7 @@ def validBindType(key, data: dict):
def removeRelaventFields(data, bindType):
errMsgs = []
if "alias" in data: data.pop("alias")
# These types are simple, just the bind type and argument
if bindType in ["impulse", "toggle"]:
data.pop(bindType)