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 = {}
defaultDict = {}
bindOrAlias = "bind"
from json import dumps
from copy import deepcopy
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.
# This takes all of the nested dictionaries and turns them into the right string
for key, toggles in condDict.items():
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'
if condDict != defaultDict:
# ==, and by extension !=, does in fact check
# for dictionary equality in keys and values
for key, toggles in condDict.items():
onCondPress = ';'.join(toggles["change_keys"])
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
@ -57,6 +59,22 @@ def typeOf(dictIn):
return t
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)
bindContent = bindContent.pop(bindType)
@ -80,41 +98,46 @@ def branch(keyName, bindContent):
def impulse(key, instruction):
global bindOrAlias
if isinstance(instruction, list):
instruction = ';'.join(instruction)
allInstructions = []
if isinstance(instruction, dict):
instruction = instruction["command"]
for indivCmd in instruction.split(';'):
allInstructions.append(impulseShortcuts(indivCmd))
if not isinstance(instruction, list):
instruction = instruction.split(';')
instruction = ';'.join(allInstructions)
instuction = impulseShortcuts(instruction)
instruction = ';'.join(instruction)
return f'{bindOrAlias} {key} "{instruction}"\n'
def impulseShortcuts(instruction):
splitCommand = instruction.split(' ')
cmd = splitCommand[0]
shortcuts = {
"primary": "slot1",
"secondary": "slot2",
"melee": "slot3"
}
if cmd in shortcuts:
for sc, expansion in shortcuts.items():
if cmd == sc:
splitCommand[0] = expansion
break
instruction = ' '.join(splitCommand)
def impulseShortcuts(instList):
for i, instruction in enumerate(instList):
splitCmd = instruction.split(' ')
cmd = splitCmd[0]
restOfCmd = ' '.join(splitCmd[1:])
shortcuts = {
"primary": "slot1",
"secondary": "slot2",
"melee": "slot3"
}
if cmd in shortcuts:
cmd = shortcuts[cmd]
restOfCmd = ' '.join(splitCommand[1:])
if cmd == "voice":
instruction = voice(restOfCmd)
if cmd == "voice":
cmd = "voicemenu"
restOfCmd = voice(restOfCmd)
elif cmd == "build" or cmd == "destroy":
instruction = f"{cmd} " + expandBuildings(restOfCmd)
return instruction
elif cmd == "build" or cmd == "destroy":
restOfCmd = expandBuildings(restOfCmd)
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):
keyword = keyword.lower()
@ -128,7 +151,7 @@ def voice(keyword):
for menu, voiceList in enumerate(allLists):
for selection, shortcut in enumerate(voiceList):
if keyword == shortcut:
return f'voicemenu {menu} {selection}'
return f'{menu} {selection}'
def expandBuildings(building):
buildingNums = {
@ -151,17 +174,15 @@ def simpleHold(key, instruction):
def listHold(key, options):
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' +\
f'alias -{key}_bind "{releaseStr}"\n' +\
f'{bindOrAlias} {key} "+{key}_bind"\n'
oldBindOrAlias = bindOrAlias
bindOrAlias = 'alias'
ret = impulse(f'+{key}_press', options["press"]) +\
impulse(f'-{key}_release', options["release"])
bindOrAlias = oldBindOrAlias
ret += f'{bindOrAlias} {key} "+{key}_press"\n'
return ret
@ -170,6 +191,8 @@ def toggle(key, instruction):
onStr = f'turn_{key}_on'
offStr = f'turn_{key}_off'
togStr = f'toggle_{key}'
if instruction[0] == '+':
instruction = instruction[1:]
ret = f'alias {onStr} "+{instruction}; alias {togStr} {offStr}"\n' +\
f'alias {offStr} "-{instruction}; alias {togStr} {onStr}"\n' +\
@ -184,8 +207,8 @@ def double(key, options):
mainStr = f'{key}_main'
altStr = f'{key}_alt'
pTogStr = f'+toggle_{key}'
mTogStr = f'-toggle_{key}'
pShiftStr = f'+shift_{key}'
mShiftStr = f'-shift_{key}'
global bindOrAlias
oldBindOrAlias = bindOrAlias
@ -195,28 +218,51 @@ def double(key, options):
bindOrAlias = oldBindOrAlias
ret = recursiveCode +\
f'alias {pTogStr} "{bindOrAlias} {key} {altStr}"\n' +\
f'alias {mTogStr} "{bindOrAlias} {key} {mainStr}"\n'+\
f'alias {pShiftStr} "{bindOrAlias} {key} {altStr}"\n' +\
f'alias {mShiftStr} "{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"]
global condDict
if condName in condDict:
# If the condition key (like "mouse4") already has toggles,
# 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)
changes = condDict[condName]["change_keys"]
restores = condDict[condName]["restore_keys"]
if isToggle:
# "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:
# If the condition key doesn't already exist, make it
condDict.update( {
condName: {
"plus_toggles": [ pTogStr ],
"minus_toggles": [ mTogStr ]
}
} )
if isToggle:
condDict.update( {
condName: {
"change_keys": [ toggleStr ],
"restore_keys": [ ]
}
} )
else:
condDict.update( {
condName: {
"change_keys": [ pShiftStr ],
"restore_keys": [ mShiftStr ]
}
} )
return ret

View File

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

View File

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