cmdr-spec-flow - Cmdr - Runtime Processing Flow
Welcome to the Cmdr project, written by Andreas Kupries.
For availability please read Cmdr - How To Get The Sources.
This document is for users of the cmdr framework. If you have not read Cmdr - Introduction to the Specification Language and the related documents yet, please do so. The explanations how the framework processes a command line at runtime guided by a specified command hierarchy presuppose knowledge of command-hierarchy specifications.
The first phase determines the cmdr::private instance to use. To this end it processes words from the command line and uses them to navigate the tree of cmdr::officer instances until a private is reached.
Each word of the command line is treated as the name of the cmdr::officer instance to descend into. An error will be thrown when encountering a name for which there is no known actor (officer or private), and the current officer has no default declared for it.
On the converse, when reaching the end of the command line but not reaching a private the framework will not throw an error. It will start an interactive command line shell instead. This main shell provides access to exactly the commands of the cmdr::officer instance which was reached, plus two pseudo-commands to either exit this shell or gain help.
Execution of the command tree specification, i.e. the generation of the in-memory command tree and the actor instances bound in it, is intertwined with this descent through the command tree. I.e. instead of processing the entire specification immediately in full it is lazily unfolded on demand, ignoring all parts which are not needed. Note that the generated data structures are not destroyed after Execution, but kept, avoiding the need to re-parse the parts of the specification already used at least once when an interactive command line shell is active.
This is the most complex phase internally, as it has to assign the left-over words to the parameters of the chosen cmdr::private instance, taking into account the kind of parameters, their requiredness, listness, and other attributes.
Generally processing the words from left to right options are detected in all positions, through their flags (primary, aliases, and all unique prefixes), followed by their (string) value to assign.
When a word cannot be the flag for an option the positional inputs are considered, in order of their declarations. For a mandatory input the word is simply assigned as its string value and processing continues with the next word, and the next input, if any. Operation becomes more complex when the input under consideration is optional. Now it is necessary to truly decide if the word should be assigned to this input or the following.
The standard method for this decision is to count words and compare to the count of mandatory inputs left. If there are more words available than required to satisfy all mandatory inputs, then we can and do assign the current word to the optional input. Otherwise the current input is skipped and we consider the next. A set of condensed examples can be found in section Example for Handling optional Inputs by Threshold. They demonstrate how a various numbers of argument words are assigned to a specific set of inputs, optional and non. This is called the threshold algorithm.
The non-triviality in the above description is in the phrase to count words. We cannot simply count all words left on the command line. To get a proper count we have discard/ignore all words belonging to options. At this point the processor essentially works ahead, processing and removing all flags/options and their arguments from the command line before performing the comparison and making its decision.
The whole behaviour however can be changed via test (See section General control of Cmdr - Parameter Specification Language). Instead of counting words the current word is run through the validation type of the current input. On acceptance the value is assigned to it, otherwise that input is skipped and the next one put under consideration.
After all of the above the system will process any options found after the last word assigned to the last input to consider.
Errors are thrown if we either find more words than inputs to assign to, or encounter an unknown option flag. Note that not having enough words for all required inputs is not an error unless the framework is not allowed to start an interactive shell. In this mini shell all parameters are mapped to shell commands taking a single argument, the string value of parameter to assign. Additional five pseudo commands are available to either abort, or commit to the action, or gain help (.ok, .run, .exit, .cancel, and .help).
Parameters marked as list-valued also trigger special behaviours. For options the assigned values get accumulated instead of each new value overwriting the last. For inputs only one such parameter can exist, and will be the last of the private. The processor now takes all remaining words and assign them to this parameter. If the list is also optional then options may be processed ahead or not, depending on the chosen decision mode, as described for regular inputs above.
Then are the boolean and presence options modifying the handling of flags and flag arguments. The details of this were already explained in section Validation of Cmdr - Parameter Specification Language.
The examples in this section demonstrate how the threshold algorithm assigns a various number of argument words to a specific set of inputs, optional and non.
Parameter | A? | B | C? | D? | E #Required | 2| | 1| 1| --------------+----+---+----+----+---- 2 arguments: | | a | | | b 3 arguments: | a | b | | | c 4 arguments: | a | b | c | | d 5 arguments: | a | b | c | d | e
This phase is reached when all words of the command line have been processed and no error was thrown by the preceding phases. At this point we know the cmdr::private instance to use, and its parameters may have a string representation.
All immediate-mode parameters are now given their internal representation. The parameters marked as defered are ignored here and will get theirs on first access by the backend.
This completion of parameters is done in their order of declaration within the enclosing private command. Note that when parameters have dependencies between them, i.e. the calculation of their internal representation requires the internal representation of another parameter, then this order may be violated as the requesting parameter triggers completion in the requested one on access. If this is behaviour not wanted then it is the responsibility of the user specifying the private to place the parameters into an order where all parameters access only previously completed parameters during their own completion.
The last phase is also the most simple.
It only invokes the Tcl command prefix associated with the chosen cmdr::private instance, providing it with the cmdr::config instance holding the parameter information extracted from the command line as its single argument.
For an example of very simple action implementations see section Simple backend of Cmdr - Introduction to the Specification Language.
All parameters declared for a private are made accessible through individual methods associated with each. As example, a parameter with system name P is mapped to the method @P, with all instance methods provided by the cmdr::parameter class accessible as sub-methods. This general access to all methods may be removed in the future, restricting actions and callbacks to a safe subset.
Another place providing information to actions is the root and other actors of the command hierarchy itself, via common blocks whose value is managed by the system. Currently we have
This block is read-only, and only found in the root actor. Its value is managed by the framework. It is a boolean flag indicating if an interactive shell is currently active (true) or not (false). This can be used to modulate command messages and other context-dependent things.
Note that the block will not exist until after the first shell was active. This means that a missing *in-shell* block should be treated like false.
This block is read-only, and only found in the root actor. Its value is managed by the framework, specifically by privates.
It is a command name, i.e. object handle, to the active instance of cmdr::config. For regular parameters that is the same handle given to them in their various callbacks. For a global parameter however the active config object is what the parameter is currently used by, whereas the callback argument is where it was defined in and inherited from.
This distinction is important when the global parameter has to look at and work with non-global parameters of the active private. These can only be found in the active context.
This block is read-only and found in the private actor for the currently executing action command prefix, accessible through the cmdr::config instance method context. Its value is managed by the framework. It is a list of the command names used to reach the private instance. This is not the logical path in the command hierarchy, but the actual path taken, which may be through aliases.
Calling @P without arguments is a shorthand for calling ``@P value'', i.e. the retrieval of the parameter's internal representation. Which may calculate the value if the call is the first access and the parameter specified as defered.
Both the package(s) and this documentation will undoubtedly contain bugs and other problems. Please report such at Cmdr Tickets.
Please also report any ideas you may have for enhancements of either package(s) and/or documentation.
arguments, command hierarchy, command line completion, command line handling, command tree, editing command line, help for command line, hierarchy of commands, interactive command shell, optional arguments, options, parameters, processing command line, tree of commands
Copyright © 2013-2016 Andreas Kupries
Copyright © 2013-2016 Documentation, Andreas Kupries