in CSharp/Library/Microsoft.Bot.Builder/FormFlow/IPrompt.cs [452:692]
private string ExpandTemplate(string template, string currentChoice, string noValue, T state, IField<T> field, object[] args, ref IList<DescribeAttribute> buttons)
{
bool foundUnspecified = false;
int last = 0;
int numeric;
var response = new StringBuilder();
foreach (Match match in _args.Matches(template))
{
var expr = match.Groups[1].Value.Trim();
var substitute = string.Empty;
if (expr.StartsWith("&"))
{
var name = expr.Substring(1);
if (name == string.Empty && field != null) name = field.Name;
var pathField = _fields.Field(name);
substitute = Language.Normalize(pathField == null ? field.Name : pathField.FieldDescription.Description, _annotation.FieldCase);
}
else if (expr == "||")
{
var builder = new StringBuilder();
var values = _recognizer.ValueDescriptions();
var useButtons = !field.AllowsMultiple
&& (_annotation.ChoiceStyle == ChoiceStyleOptions.Auto
|| _annotation.ChoiceStyle == ChoiceStyleOptions.Buttons
|| _annotation.ChoiceStyle == ChoiceStyleOptions.Carousel);
if (values.Any() && _annotation.AllowDefault != BoolDefault.False && field.Optional)
{
values = values.Concat(new DescribeAttribute[] { new DescribeAttribute(Language.Normalize(noValue, _annotation.ChoiceCase)) });
}
string current = null;
if (_annotation.AllowDefault != BoolDefault.False)
{
if (!field.Optional)
{
if (!field.IsUnknown(state))
{
current = ExpandTemplate(currentChoice, null, noValue, state, field, args, ref buttons);
}
}
else
{
current = ExpandTemplate(currentChoice, null, noValue, state, field, args, ref buttons);
}
}
if (values.Any())
{
if (useButtons)
{
foreach (var value in values)
{
buttons.Add(value);
}
}
else
{
// Buttons do not support multiple selection so we fall back to text
if (((_annotation.ChoiceStyle == ChoiceStyleOptions.Auto || _annotation.ChoiceStyle == ChoiceStyleOptions.AutoText)
&& values.Count() < 4)
|| (_annotation.ChoiceStyle == ChoiceStyleOptions.Inline))
{
// Inline choices
if (_annotation.ChoiceParens == BoolDefault.True) builder.Append('(');
var choices = new List<string>();
var i = 1;
foreach (var value in values)
{
choices.Add(string.Format(_annotation.ChoiceFormat, i, Language.Normalize(value.Description, _annotation.ChoiceCase)));
++i;
}
builder.Append(Language.BuildList(choices, _annotation.ChoiceSeparator, _annotation.ChoiceLastSeparator));
if (_annotation.ChoiceParens == BoolDefault.True) builder.Append(')');
if (current != null)
{
builder.Append(" ");
builder.Append(current);
}
}
else
{
// Separate line choices
if (current != null)
{
builder.Append(current);
builder.Append(" ");
}
var i = 1;
foreach (var value in values)
{
builder.AppendLine();
builder.Append(" ");
if (!_annotation.AllowNumbers)
{
builder.Append("* ");
}
builder.AppendFormat(_annotation.ChoiceFormat, i, Language.Normalize(value.Description, _annotation.ChoiceCase));
++i;
}
}
}
}
else if (current != null)
{
builder.Append(" ");
builder.Append(current);
}
substitute = builder.ToString();
}
else if (expr.StartsWith("*"))
{
// Status display of active results
var filled = expr.ToLower().Trim().EndsWith("filled");
var builder = new StringBuilder();
if (match.Index > 0)
{
builder.AppendLine();
}
foreach (var entry in (from step in _fields where (!filled || !step.IsUnknown(state)) && step.Role == FieldRole.Value && step.Active(state) select step))
{
var format = new Prompter<T>(Template(entry, TemplateUsage.StatusFormat), _form, null);
builder.Append("* ").AppendLine(format.Prompt(state, entry).Prompt);
}
substitute = builder.ToString();
}
else if (expr.StartsWith("[") && expr.EndsWith("]"))
{
// Generate a list from multiple fields
var paths = expr.Substring(1, expr.Length - 2).Split(' ');
var values = new List<Tuple<IField<T>, object, string>>();
foreach (var spec in paths)
{
if (!spec.StartsWith("{") || !spec.EndsWith("}"))
{
throw new ArgumentException("Only {<field>} references are allowed in lists.");
}
var formatArgs = spec.Substring(1, spec.Length - 2).Trim().Split(':');
var name = formatArgs[0];
if (name == string.Empty && field != null) name = field.Name;
var format = (formatArgs.Length > 1 ? "0:" + formatArgs[1] : "0");
var eltDesc = _fields.Field(name);
if (!eltDesc.IsUnknown(state))
{
var value = eltDesc.GetValue(state);
if (value.GetType() != typeof(string) && value.GetType().IsIEnumerable())
{
var eltValues = (value as System.Collections.IEnumerable);
foreach (var elt in eltValues)
{
values.Add(Tuple.Create(eltDesc, elt, format));
}
}
else
{
values.Add(Tuple.Create(eltDesc, eltDesc.GetValue(state), format));
}
}
}
if (values.Count() > 0)
{
var elements = (from elt in values
select Language.Normalize(ValueDescription(elt.Item1, elt.Item2, elt.Item3), _annotation.ValueCase)).ToArray();
substitute = Language.BuildList(elements, _annotation.Separator, _annotation.LastSeparator);
}
}
else if (expr.StartsWith("?"))
{
// Conditional template
var subValue = ExpandTemplate(expr.Substring(1), currentChoice, null, state, field, args, ref buttons);
if (subValue == null)
{
substitute = string.Empty;
}
else
{
substitute = subValue;
}
}
else if (TryParseFormat(expr, out numeric))
{
// Process ad hoc arg
if (numeric < args.Length && args[numeric] != null)
{
substitute = string.Format("{" + expr + "}", args);
}
else
{
foundUnspecified = true;
break;
}
}
else
{
var formatArgs = expr.Split(':');
var name = formatArgs[0];
if (name == string.Empty && field != null) name = field.Name;
var pathDesc = _fields.Field(name);
if (pathDesc.IsUnknown(state))
{
if (noValue == null)
{
foundUnspecified = true;
break;
}
substitute = noValue;
}
else
{
var value = pathDesc.GetValue(state);
if (value.GetType() != typeof(string) && value.GetType().IsIEnumerable())
{
if (value.GetType().IsAttachmentCollection())
{
var locTemplate = this._form.Configuration.Template(TemplateUsage.AttachmentCollectionDescription);
substitute = string.Format(locTemplate.Pattern(), (value as IEnumerable<AwaitableAttachment>).Count());
}
else
{
var values = (value as System.Collections.IEnumerable);
substitute = Language.BuildList(from elt in values.Cast<object>()
select Language.Normalize(ValueDescription(pathDesc, elt, "0"), _annotation.ValueCase),
_annotation.Separator, _annotation.LastSeparator);
}
}
else if (value.GetType().IsAttachmentType())
{
var attachment = (value as AwaitableAttachment).Attachment;
var locTemplate = this._form.Configuration.Template(TemplateUsage.AttachmentFieldDescription);
substitute = string.Format(locTemplate.Pattern(), attachment.Name, attachment.ContentType);
}
else
{
var format = (formatArgs.Length > 1 ? "0:" + formatArgs[1] : "0");
substitute = ValueDescription(pathDesc, value, format);
}
}
}
response.Append(template.Substring(last, match.Index - last)).Append(substitute);
last = match.Index + match.Length;
}
return (foundUnspecified ? null : response.Append(template.Substring(last, template.Length - last)).ToString());
}