diff --git a/files/con4m/params.nim b/files/con4m/params.nim index 15b08da..4e89180 100644 --- a/files/con4m/params.nim +++ b/files/con4m/params.nim @@ -12,11 +12,20 @@ proc validateParameter*(state: ConfigState, param: ParameterInfo): err = unpack[string](boxOpt.get()) if err != "": - return some(text(err)) + return some(color("error: ", "red") + text(err)) return none(Rope) +proc setAndValidateParameter(state: ConfigState, param: ParameterInfo, + value: Option[Box]): bool = + param.value = value + let err = state.validateParameter(param) + if err.isSome(): + print(err.get()) + return false + return true + proc basicConfigureOneParam(state: ConfigState, component: ComponentInfo, param: ParameterInfo) = @@ -31,6 +40,23 @@ proc basicConfigureOneParam(state: ConfigState, elif param.defaultCb.isSome(): boxOpt = state.sCall(param.defaultCb.get(), @[]) + if not param.prompt: + if boxOpt.isNone(): + print(atom("Non-prompting parameter ") + em(param.name) + + text(" does not define a default value either as literal or callback. ") + + text("Please manually provide value:")) + boxOpt = none(Box) + else: + if state.setAndValidateParameter(param, boxOpt): + return + else: + # if the default is invalid, even though its non-prompting param + # fallback to manual user input to allow to fix the value + print(color("error: ", "red") + text("Non-prompting parameter ") + + em(param.name) + text(" does not have valid default value. ") + + text("Please manually fix it:")) + boxOpt = none(Box) + if boxOpt.isSome(): default = h2(atom("Default is: ") + fgColor(param.defaultType.oneArgToString(boxOpt.get()), @@ -65,15 +91,9 @@ proc basicConfigureOneParam(state: ConfigState, let f = float(unpack[int](box)) boxOpt = some(pack(f)) - param.value = boxOpt - - let err = state.validateParameter(param) - - if err.isNone(): + if state.setAndValidateParameter(param, boxOpt): break - print(err.get()) - proc basicConfigureParameters*(state: ConfigState, component: ComponentInfo, componentList: seq[ComponentInfo], diff --git a/files/con4m/treecheck.nim b/files/con4m/treecheck.nim index 1ec5088..93aa861 100644 --- a/files/con4m/treecheck.nim +++ b/files/con4m/treecheck.nim @@ -1038,7 +1038,7 @@ proc checkNode(node: Con4mNode, s: ConfigState) = # aren't going to be interpreted in the way they are in any other # part of a program. const - validParamProps = ["doc", "shortdoc", "validator", "default"] + validParamProps = ["doc", "shortdoc", "validator", "default", "prompt"] var foundProps: seq[string] @@ -1078,6 +1078,10 @@ proc checkNode(node: Con4mNode, s: ConfigState) = if allowedCallbackType.unify(kid.children[1].typeInfo).isBottom(): fatal("Callback must be a function that takes no arguments and " & "Returns a value of the proper type.") + of "prompt": + if kid.children[1].kind != NodeSimpLit or + boolType.unify(kid.children[1].typeInfo).isBottom(): + fatal("Prompt must be a boolean") of "validator": let allowedValidatorType = "(`x) -> string".toCon4mType() if kid.children[1].kind != NodeCallbackLit or @@ -1117,7 +1121,7 @@ proc checkNode(node: Con4mNode, s: ConfigState) = s.waitingForTypeInfo = true var - paramObj = ParameterInfo(name: name, defaultType: newTypeVar()) + paramObj = ParameterInfo(name: name, defaultType: newTypeVar(), prompt: true) assnNodes: seq[Con4mNode] if len(node.children) > 1: @@ -1140,6 +1144,13 @@ proc checkNode(node: Con4mNode, s: ConfigState) = if paramobj.defaultType.unify(callback.tInfo.params[0]).isBottom(): fatal2Type("Validator parameter does not match inferred type", assignNode, paramObj.defaultType, callback.tInfo) + of "prompt": + let defType = assignNode.children[1].typeInfo + if defType.kind == TypeBool: + paramObj.prompt = unpack[bool](assignNode.children[1].value) + else: + fatal2Type("Prompt value needs to be a boolean", + assignNode, paramObj.defaultType, defType) of "default": let defType = assignNode.children[1].typeInfo diff --git a/files/con4m/types.nim b/files/con4m/types.nim index 21fad72..04b7671 100644 --- a/files/con4m/types.nim +++ b/files/con4m/types.nim @@ -320,6 +320,7 @@ type defaultType*: Con4mType defaultCb*: Option[CallbackObj] value*: Option[Box] + prompt*: bool # wheter to prompt user for the value or use default only let # These are just shared instances for types that aren't