@Override
    protected void processIndexTemplate(
            final Configuration cfg,
            final List<DocWorkUnit> workUnitList,
            final List<Map<String, String>> groupMaps
    ) throws IOException {
        // Create a root map for all the work units so we can access all the info we need:
        final Map<String, Object> propertiesMap = new HashMap<>();
        workUnits.stream().forEach( workUnit -> propertiesMap.put(workUnit.getName(), workUnit.getRootMap()) );

        // Add everything into a nice package that we can iterate over
        // while exposing the command line program names as keys:
        final Map<String, Object> rootMap = new HashMap<>();
        rootMap.put("tools", propertiesMap);

        // Add the caller script options into another top-level tree node:
        final Map<String, Object> callerScriptOptionsMap = new HashMap<>();
        callerScriptOptionsMap.put("callerScriptName", callerScriptName);

        callerScriptOptionsMap.put("callerScriptPrefixLegalArgs", callerScriptPrefixLegalArgs);
        callerScriptOptionsMap.put("callerScriptPrefixArgValueTypes", callerScriptPrefixArgValueTypes);
        callerScriptOptionsMap.put("callerScriptPrefixMutexArgs", callerScriptPrefixMutexArgs);
        callerScriptOptionsMap.put("callerScriptPrefixAliasArgs", callerScriptPrefixAliasArgs);
        callerScriptOptionsMap.put("callerScriptPrefixMinOccurrences", callerScriptPrefixMinOccurrences);
        callerScriptOptionsMap.put("callerScriptPrefixMaxOccurrences", callerScriptPrefixMaxOccurrences);

        callerScriptOptionsMap.put("callerScriptPostfixLegalArgs", callerScriptPostfixLegalArgs);
        callerScriptOptionsMap.put("callerScriptPostfixArgValueTypes", callerScriptPostfixArgValueTypes);
        callerScriptOptionsMap.put("callerScriptPostfixMutexArgs", callerScriptPostfixMutexArgs);
        callerScriptOptionsMap.put("callerScriptPostfixAliasArgs", callerScriptPostfixAliasArgs);
        callerScriptOptionsMap.put("callerScriptPostfixMinOccurrences", callerScriptPostfixMinOccurrences);
        callerScriptOptionsMap.put("callerScriptPostfixMaxOccurrences", callerScriptPostfixMaxOccurrences);
        if ( hasCallerScriptPostfixArgs ) {
            callerScriptOptionsMap.put("hasCallerScriptPostfixArgs", "true");
        }
        else {
            callerScriptOptionsMap.put("hasCallerScriptPostfixArgs", "false");
        }

        rootMap.put("callerScriptOptions", callerScriptOptionsMap);

        // Get or create a template
        final Template template = cfg.getTemplate(getIndexTemplateName());

        // Create the output file
        final File indexFile = new File(getDestinationDir(),
                getIndexBaseFileName() + "." + getIndexFileExtension()
        );

        // Run the template and merge in the data
        try (final FileOutputStream fileOutStream = new FileOutputStream(indexFile);
             final OutputStreamWriter outWriter = new OutputStreamWriter(fileOutStream)) {
            template.process(rootMap, outWriter);
        } catch (TemplateException e) {
            throw new DocException("Freemarker Template Exception during documentation index creation", e);
        }
    }
@ Override protected void processIndexTemplate ( final Configuration cfg , final List < DocWorkUnit > workUnitList , final List < Map < String , String > > groupMaps ) throws IOException { final Map < String , Object > propertiesMap = new HashMap < > ( ) ; workUnits . stream ( ) . forEach ( workUnit -> propertiesMap . put ( workUnit . getName ( ) , workUnit . getRootMap ( ) ) ) ; final Map < String , Object > rootMap = new HashMap < > ( ) ; rootMap . put ( "tools" , propertiesMap ) ; final Map < String , Object > callerScriptOptionsMap = new HashMap < > ( ) ; callerScriptOptionsMap . put ( "callerScriptName" , callerScriptName ) ; callerScriptOptionsMap . put ( "callerScriptPrefixLegalArgs" , callerScriptPrefixLegalArgs ) ; callerScriptOptionsMap . put ( "callerScriptPrefixArgValueTypes" , callerScriptPrefixArgValueTypes ) ; callerScriptOptionsMap . put ( "callerScriptPrefixMutexArgs" , callerScriptPrefixMutexArgs ) ; callerScriptOptionsMap . put ( "callerScriptPrefixAliasArgs" , callerScriptPrefixAliasArgs ) ; callerScriptOptionsMap . put ( "callerScriptPrefixMinOccurrences" , callerScriptPrefixMinOccurrences ) ; callerScriptOptionsMap . put ( "callerScriptPrefixMaxOccurrences" , callerScriptPrefixMaxOccurrences ) ; callerScriptOptionsMap . put ( "callerScriptPostfixLegalArgs" , callerScriptPostfixLegalArgs ) ; callerScriptOptionsMap . put ( "callerScriptPostfixArgValueTypes" , callerScriptPostfixArgValueTypes ) ; callerScriptOptionsMap . put ( "callerScriptPostfixMutexArgs" , callerScriptPostfixMutexArgs ) ; callerScriptOptionsMap . put ( "callerScriptPostfixAliasArgs" , callerScriptPostfixAliasArgs ) ; callerScriptOptionsMap . put ( "callerScriptPostfixMinOccurrences" , callerScriptPostfixMinOccurrences ) ; callerScriptOptionsMap . put ( "callerScriptPostfixMaxOccurrences" , callerScriptPostfixMaxOccurrences ) ; if ( hasCallerScriptPostfixArgs ) { callerScriptOptionsMap . put ( "hasCallerScriptPostfixArgs" , "true" ) ; } else { callerScriptOptionsMap . put ( "hasCallerScriptPostfixArgs" , "false" ) ; } rootMap . put ( "callerScriptOptions" , callerScriptOptionsMap ) ; final Template template = cfg . getTemplate ( getIndexTemplateName ( ) ) ; final File indexFile = new File ( getDestinationDir ( ) , getIndexBaseFileName ( ) + "." + getIndexFileExtension ( ) ) ; try ( final FileOutputStream fileOutStream = new FileOutputStream ( indexFile ) ; final OutputStreamWriter outWriter = new OutputStreamWriter ( fileOutStream ) ) { template . process ( rootMap , outWriter ) ; } catch ( TemplateException e ) { throw new DocException ( "Freemarker Template Exception during documentation index creation" , e ) ; } }
The Index file in the Bash Completion Doclet is what generates the actual tab-completion script.

This will actually write out the shell completion output file.
The Freemarker instance will see a top-level map that has two keys in it.

The first key is for caller script options:

SimpleMap callerScriptOptions = SimpleMap {

"callerScriptName"                 : caller script name

"callerScriptPrefixLegalArgs"      : caller Script Prefix Legal Args
"callerScriptPrefixArgValueTypes"  : caller Script Prefix Arg Value Types
"callerScriptPrefixMutexArgs"      : caller Script Prefix Mutex Args
"callerScriptPrefixAliasArgs"      : caller Script Prefix Alias Args
"callerScriptPrefixMinOccurrences" : caller Script Prefix Min Occurrences
"callerScriptPrefixMaxOccurrences" : caller Script Prefix Max Occurrences
"hasCallerScriptPrefixArgs"        : has Caller Script Prefix Args

"callerScriptPostfixLegalArgs"      : caller Script Postfix Legal Args
"callerScriptPostfixArgValueTypes"  : caller Script Postfix Arg Value Types
"callerScriptPostfixMutexArgs"      : caller Script Postfix Mutex Args
"callerScriptPostfixAliasArgs"      : caller Script Postfix Alias Args
"callerScriptPostfixMinOccurrences" : caller Script Postfix Min Occurrences
"callerScriptPostfixMaxOccurrences" : caller Script Postfix Max Occurrences
"hasCallerScriptPostfixArgs"        : has Caller Script Postfix Args

}

The second key is for tool options:

SimpleMap tools = SimpleMap { ToolName : MasterPropertiesMap }

where

MasterPropertiesMap is a map containing the following Keys:
all
common
positional
hidden
advanced
deprecated
optional
dependent
required

Each of those keys maps to a List&lt;SimpleMap&gt; representing each property.
These property maps each contain the following keys:

kind
name
summary
fulltext
otherArgumentRequired
synonyms
exclusiveOf
type
options
attributes
required
minRecValue
maxRecValue
minValue
maxValue
defaultValue
minElements
maxElements

@param cfg
@param workUnitList
@param groupMaps
@throws IOException