added new way to format files

main
Nicholas Hope 2022-08-19 21:34:45 -04:00
parent 8cd203bcb8
commit 0d64ad9b54
3 changed files with 175 additions and 100 deletions

View File

@ -4,7 +4,6 @@
condDict = {} condDict = {}
defaultDict = {} defaultDict = {}
bindOrAlias = "bind" bindOrAlias = "bind"
from json import dumps
from copy import deepcopy from copy import deepcopy
def makeCFG(cfg, default=False): def makeCFG(cfg, default=False):
@ -32,12 +31,15 @@ def makeCFG(cfg, default=False):
# 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(): if condDict != defaultDict:
plusToggleStr = ';'.join(toggles["plus_toggles"]) # ==, and by extension !=, does in fact check
minusToggleStr = ';'.join(toggles["minus_toggles"]) # for dictionary equality in keys and values
ret += f'alias +{key}_toggles "{plusToggleStr}"\n' +\ for key, toggles in condDict.items():
f'alias -{key}_toggles "{minusToggleStr}"\n' +\ onCondPress = ';'.join(toggles["change_keys"])
f'{bindOrAlias} {key} "+{key}_toggles"\n' onCondRelease = ';'.join(toggles["restore_keys"])
ret += f'alias +{key}_toggles "{onCondPress}"\n' +\
f'alias -{key}_toggles "{onCondRelease}"\n' +\
f'{bindOrAlias} {key} "+{key}_toggles"\n'
del condDict # free deep copy del condDict # free deep copy
@ -57,6 +59,22 @@ def typeOf(dictIn):
return t return t
def branch(keyName, bindContent): def branch(keyName, bindContent):
""" Using the provided keyName and content, call the correct function """
"""
Terser syntax, ex.
impulse e:
<content>
instead of
e:
impulse:
<content>
"""
splitKey = keyName.split(' ', 1)
if len(splitKey) > 1:
keyName = splitKey[1]
bindContent = {splitKey[0]: bindContent}
bindType = typeOf(bindContent) bindType = typeOf(bindContent)
bindContent = bindContent.pop(bindType) bindContent = bindContent.pop(bindType)
@ -80,41 +98,46 @@ def branch(keyName, bindContent):
def impulse(key, instruction): def impulse(key, instruction):
global bindOrAlias global bindOrAlias
if isinstance(instruction, list): if isinstance(instruction, dict):
instruction = ';'.join(instruction) instruction = instruction["command"]
allInstructions = []
for indivCmd in instruction.split(';'): if not isinstance(instruction, list):
allInstructions.append(impulseShortcuts(indivCmd)) instruction = instruction.split(';')
instruction = ';'.join(allInstructions) instuction = impulseShortcuts(instruction)
instruction = ';'.join(instruction)
return f'{bindOrAlias} {key} "{instruction}"\n' return f'{bindOrAlias} {key} "{instruction}"\n'
def impulseShortcuts(instruction): def impulseShortcuts(instList):
splitCommand = instruction.split(' ') for i, instruction in enumerate(instList):
cmd = splitCommand[0] splitCmd = instruction.split(' ')
shortcuts = { cmd = splitCmd[0]
"primary": "slot1", restOfCmd = ' '.join(splitCmd[1:])
"secondary": "slot2", shortcuts = {
"melee": "slot3" "primary": "slot1",
} "secondary": "slot2",
if cmd in shortcuts: "melee": "slot3"
for sc, expansion in shortcuts.items(): }
if cmd == sc: if cmd in shortcuts:
splitCommand[0] = expansion cmd = shortcuts[cmd]
break
instruction = ' '.join(splitCommand)
restOfCmd = ' '.join(splitCommand[1:]) if cmd == "voice":
if cmd == "voice": cmd = "voicemenu"
instruction = voice(restOfCmd) restOfCmd = voice(restOfCmd)
elif cmd == "build" or cmd == "destroy": elif cmd == "build" or cmd == "destroy":
instruction = f"{cmd} " + expandBuildings(restOfCmd) restOfCmd = expandBuildings(restOfCmd)
return instruction elif cmd == "load_itempreset" and restOfCmd.isalpha():
restOfCmd = restOfCmd.lower()
restOfCmd = ['a','b','c','d'].index(restOfCmd)
if restOfCmd != "":
cmd += ' ' + restOfCmd
instList[i] = cmd
return instList
def voice(keyword): def voice(keyword):
keyword = keyword.lower() keyword = keyword.lower()
@ -128,7 +151,7 @@ def voice(keyword):
for menu, voiceList in enumerate(allLists): for menu, voiceList in enumerate(allLists):
for selection, shortcut in enumerate(voiceList): for selection, shortcut in enumerate(voiceList):
if keyword == shortcut: if keyword == shortcut:
return f'voicemenu {menu} {selection}' return f'{menu} {selection}'
def expandBuildings(building): def expandBuildings(building):
buildingNums = { buildingNums = {
@ -151,17 +174,15 @@ def simpleHold(key, instruction):
def listHold(key, options): def listHold(key, options):
global bindOrAlias global bindOrAlias
pressStr = options["press"]
if isinstance(pressStr, list):
pressStr = ';'.join(pressStr)
releaseStr = options["release"]
if isinstance(releaseStr, list):
releaseStr = ';'.join(releaseStr)
ret = f'alias +{key}_bind "{pressStr}"\n' +\ oldBindOrAlias = bindOrAlias
f'alias -{key}_bind "{releaseStr}"\n' +\ bindOrAlias = 'alias'
f'{bindOrAlias} {key} "+{key}_bind"\n' ret = impulse(f'+{key}_press', options["press"]) +\
impulse(f'-{key}_release', options["release"])
bindOrAlias = oldBindOrAlias
ret += f'{bindOrAlias} {key} "+{key}_press"\n'
return ret return ret
@ -170,6 +191,8 @@ def toggle(key, instruction):
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}'
if instruction[0] == '+':
instruction = instruction[1:]
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' +\
@ -184,8 +207,8 @@ def double(key, options):
mainStr = f'{key}_main' mainStr = f'{key}_main'
altStr = f'{key}_alt' altStr = f'{key}_alt'
pTogStr = f'+toggle_{key}' pShiftStr = f'+shift_{key}'
mTogStr = f'-toggle_{key}' mShiftStr = f'-shift_{key}'
global bindOrAlias global bindOrAlias
oldBindOrAlias = bindOrAlias oldBindOrAlias = bindOrAlias
@ -195,28 +218,51 @@ def double(key, options):
bindOrAlias = oldBindOrAlias bindOrAlias = oldBindOrAlias
ret = recursiveCode +\ ret = recursiveCode +\
f'alias {pTogStr} "{bindOrAlias} {key} {altStr}"\n' +\ f'alias {pShiftStr} "{bindOrAlias} {key} {altStr}"\n' +\
f'alias {mTogStr} "{bindOrAlias} {key} {mainStr}"\n'+\ f'alias {mShiftStr} "{bindOrAlias} {key} {mainStr}"\n'+\
f'{bindOrAlias} {key} "{mainStr}"\n' f'{bindOrAlias} {key} "{mainStr}"\n'
isToggle = ("toggle" in options and options.pop("toggle") == True)
if isToggle:
toggleStr = toggle(key, pShiftStr)
condName = options["condition"] condName = options["condition"]
global condDict 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 # just append another toggle string
plusToggles = condDict[condName]["plus_toggles"] changes = condDict[condName]["change_keys"]
minusToggles = condDict[condName]["minus_toggles"] restores = condDict[condName]["restore_keys"]
if pTogStr not in plusToggles:
plusToggles.append(pTogStr) if isToggle:
minusToggles.append(mTogStr) # "toggle: true" specified, add the toggle string
if toggleStr not in changes:
changes.append(toggleStr)
if pShiftStr in changes:
# If key already has normal shift, remove it
changes.remove(pShiftStr)
changes.remove(mShiftStr)
elif pShiftStr not in changes:
# not toggle, not already in changes
changes.append(pShiftStr)
restores.append(mShiftStr)
else: else:
# If the condition key doesn't already exist, make it # If the condition key doesn't already exist, make it
condDict.update( { if isToggle:
condName: { condDict.update( {
"plus_toggles": [ pTogStr ], condName: {
"minus_toggles": [ mTogStr ] "change_keys": [ toggleStr ],
} "restore_keys": [ ]
} ) }
} )
else:
condDict.update( {
condName: {
"change_keys": [ pShiftStr ],
"restore_keys": [ mShiftStr ]
}
} )
return ret return ret

View File

@ -11,7 +11,7 @@ __copyright__ = "Copyright © 2022 Nicholas Hope. See LICENSE for details."
# Standard libraries # Standard libraries
from sys import stderr from sys import stderr
from os import mkdir from os import mkdir, sep as dirsep
from os.path import isdir, expanduser, normpath from os.path import isdir, expanduser, normpath
import argparse import argparse
from warnings import warn from warnings import warn
@ -134,20 +134,12 @@ def main() -> int:
systemName = GetOSName() systemName = GetOSName()
if args.directory is not None: if args.directory is not None:
targetDir = normpath(args.directory) targetDir = normpath(args.directory) + dirsep
if systemName == "Windows":
targetDir += '\\'
else:
targetDir += '/'
else: else:
targetDir = getTargetDir(systemName) targetDir = getTargetDir(systemName)
if targetDir is not None: if targetDir is not None:
# Supported OS: add steamapps path # Supported OS: add steamapps path
targetDir += normpath("/steamapps/common/Team Fortress 2/tf/cfg") targetDir += normpath("/steamapps/common/Team Fortress 2/tf/cfg") + dirsep
if systemName == "Windows":
targetDir += '\\'
else:
targetDir += '/'
elif args.force: elif args.force:
# Unsupported OS but -f specified # Unsupported OS but -f specified
if args.debug: if args.debug:

View File

@ -1,4 +1,6 @@
"""Verify all the things that could go wrong.""" """Verify all the things that could go wrong."""
from copy import deepcopy
def verifyConfig(cfg: dict) -> (dict, dict): def verifyConfig(cfg: dict) -> (dict, dict):
verifiedConfig = {} verifiedConfig = {}
@ -76,7 +78,7 @@ def verifyConfig(cfg: dict) -> (dict, dict):
globalErrors.append(f'Conflicting names for section: "{remainingClass}" and "{otherName}"') globalErrors.append(f'Conflicting names for section: "{remainingClass}" and "{otherName}"')
if len(globalErrors) > 0: if len(globalErrors) > 0:
errors.update( {"file": globalErrors} ) errors.update({"file": globalErrors})
if len(errors) > 0: if len(errors) > 0:
verifiedConfig.update({"errors": errors}) verifiedConfig.update({"errors": errors})
@ -86,15 +88,17 @@ def verifyConfig(cfg: dict) -> (dict, dict):
def validBind(key, data, alias = False) -> list: def validBind(key, data, alias = False) -> list:
"""Check for valid key and valid binding""" """Check for valid key and valid binding"""
ret = [] ret = []
splitKey = key.split(' ')
if len(splitKey) > 1:
key = splitKey[1]
data = {splitKey[0]: data}
if (not alias and not validKey(key)): if (not alias and not validKey(key)):
ret.append(f'Invalid key "{key}"') ret.append(f'Invalid key "{key}"')
# The values passed to validBindType get mutilated, so a copy must be made # The values passed to validBindType get mutilated, so a copy must be made
dataCopy = data.copy() dataCopy, errMsgs = validBindType(key, data)
dataCopy, errMsgs = validBindType(key, dataCopy) ret.extend(errMsgs)
if len(errMsgs) > 0:
for msg in errMsgs:
ret.append(msg)
extras = dataCopy.keys() extras = dataCopy.keys()
if len(extras) > 0: if len(extras) > 0:
@ -140,33 +144,65 @@ def validBindType(key, data: dict):
for potentialType in data.keys(): for potentialType in data.keys():
if potentialType in types: if potentialType in types:
validType = True validType = True
data, errMsgs = removeRelaventFields(data, potentialType)
break break
if not validType: if validType:
expandSpaceFields(data)
dataCopy = deepcopy(data)
dataCopy, errMsgs = removeRelaventFields(key, dataCopy, potentialType)
else:
errMsgs.append(f'Key "{key}" has no known bind type') errMsgs.append(f'Key "{key}" has no known bind type')
return data, errMsgs return dataCopy, errMsgs
def removeRelaventFields(data, bindType): def expandSpaceFields(data):
keys = list(data.keys())
for field in keys:
# if you change a key of a dict, while looping
# over the dict, it causes a RuntimeError.
# Looping as list avoids this
splitField = field.split(' ', 1)
if len(splitField) > 1:
newContent = {splitField[0]: data.pop(field)}
data.update({splitField[1]: newContent})
field = splitField[1]
content = data[field]
if isinstance(content, dict):
expandSpaceFields(content)
def removeRelaventFields(key, data, bindType):
errMsgs = [] errMsgs = []
if "alias" in data: data.pop("alias") content = data.pop(bindType)
# These types are simple, just the bind type and argument if "alias" in data:
if bindType in ["impulse", "toggle"]: # alias is universal
data.pop(bindType) data.pop("alias")
if bindType == "impulse":
if isinstance(content, dict):
if "command" not in content:
errMsgs.append('impulse requires `command` argument')
else:
content.pop("command")
elif bindType == "toggle":
if isinstance(content, dict):
if "begin" not in content:
errMsgs.append("toggle requires `begin` argument")
if "end" not in content:
errMsgs.append("toggle requires `end` argument")
elif not isinstance(content, str):
errMsgs.append(f"toggle must be either single action or begin and end")
elif bindType == "hold": elif bindType == "hold":
content = data.pop("hold")
if isinstance(content, dict): if isinstance(content, dict):
if "press" not in content: if "press" not in content:
errMsgs.append("If hold is not a single argument, it requires a `press` argument") errMsgs.append("hold requires `press` argument")
elif "release" not in content: if "release" not in content:
errMsgs.append("If hold is not a single argument, it requires a `release` argument") errMsgs.append("hold requires `release` argument")
elif not isinstance(content, str): elif not isinstance(content, str):
errMsgs.append(f"Hold must be either single action or press and release") errMsgs.append(f"Hold must be either single action or press and release")
elif bindType == "double": elif bindType == "double":
content = data.pop("double")
if "primary" not in content: if "primary" not in content:
errMsgs.append("Double requires primary action") errMsgs.append("Double requires primary action")
else: else:
@ -174,28 +210,29 @@ def removeRelaventFields(data, bindType):
# It takes advantage of `alias = True` not verifying the key, # It takes advantage of `alias = True` not verifying the key,
# but it isn't an alias, I'm just lazy. # but it isn't an alias, I'm just lazy.
errMessages = validBind("primary", content["primary"], alias = True) errMessages = validBind("primary", content["primary"], alias = True)
if len(errMessages) > 0: errMsgs.extend(errMessages)
errMsgs += errMessages
if "secondary" not in content: if "secondary" not in content:
errMsgs.append("Double requires secondary action") errMsgs.append("Double requires secondary action")
else: else:
# Same logic as above # Same logic as above
errMessages = validBind("secondary", content["secondary"], alias = True) errMessages = validBind("secondary", content["secondary"], alias = True)
if len(errMessages) > 0: errMsgs.extend(errMessages)
errMsgs += errMessages
if "condition" not in content: if "condition" not in content:
errMsgs.append("Double requires condition to toggle") errMsgs.append("Double requires condition to toggle")
else: else:
# Validate the toggler # Validate the toggler
key = content["condition"] condition = content["condition"]
if not validKey(key): if not validKey(condition):
errMsgs.append(f'Invalid condition to toggle "{key}"') errMsgs.append(f'Invalid condition to toggle "{condition}"')
if "cancel both" in content:
cancelBoth = content["cancel both"]
if not isinstance(cancelBoth, bool):
errMsgs.append(f'"cancel both" field in "{key}" makes no sense: "{cancelBoth}"')
elif bindType == "repeat": elif bindType == "repeat":
content = data.pop("repeat")
unit = "s" unit = "s"
if "unit" in content: if "unit" in content:
# Set unit if provided # Set unit if provided