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

View File

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