/// <summary> /// Does the actual work. /// </summary> internal void FormatExInternal(CustomFormatInfo info) { if (info.Current == null && info.Arguments.Length >= 1) { info.Current = info.Arguments[0]; } // We need to store the Format and the Current items and keep them in this context string format = info.Format; object current = info.Current; // ' Here is the regular expression to use for parsing the Format string: // Static R As New Regex( _ // "{ ([0-9A-Za-z_.\[\]()]*) (?: : ( (?: (?<open>{) | (?<nest-open>}) | [^{}]+ )*? ) (?(open)(?!)) )? }" _ // , RegexOptions.IgnorePatternWhitespace Or RegexOptions.Compiled) // { ( Selectors ) (Optnl : { Nested } or Format ) } int lastAppendedIndex = 0; PlaceholderInfo placeholder = null; while (NextPlaceholder(format, lastAppendedIndex, format.Length, ref placeholder)) { // Write the text in-between placeholders: info.WriteRegularText(format, lastAppendedIndex, (placeholder.placeholderStart - lastAppendedIndex)); lastAppendedIndex = placeholder.placeholderStart + placeholder.placeholderLength; // Evaluate the source by evaluating each argSelector: info.Current = current; // Restore the current scope //bool isFirstSelector = true; // TODO: Remove this variable if it never gets used again int selectorIndex = -1; foreach (string selector in placeholder.selectors) { selectorIndex++; info.SetSelector(selector, selectorIndex); // Raise the ExtendCustomSource event to allow custom source evaluation: OnExtendSourceEvent(new ExtendSourceEventArgs(info)); // Make sure that the selector has been handled: if (!info.Handled) { break; } //isFirstSelector = false; } // Handle errors: if (!info.Handled) { // If the ExtendCustomSource event wasn't handled, // then the Selector could not be evaluated. if (!OnInvalidSelector(format, info, placeholder)) { continue; } } string argFormat = format.Substring(placeholder.formatStart, placeholder.formatLength); info.SetFormat(argFormat, placeholder.hasNested); try { // Raise the ExtendCustomFormat event to allow custom formatting: OnExtendFormatEvent(new ExtendFormatEventArgs(info)); } catch (Exception ex) { // Handle errors: OnInvalidFormat(format, info, placeholder, ex); } } // Write the substring between the last bracket and the end of the string: info.WriteRegularText(format, lastAppendedIndex, (format.Length - lastAppendedIndex)); }
private static void FormatConditional(object sender, ExtendFormatEventArgs e) { CustomFormatInfo info = e.FormatInfo; // See if the format string contains un-nested "|": string[] parameters = Core.ParsingServices.SplitNested(info.Format, '|'); if (parameters.Length == 1) { return; // There are no splits. } int paramCount = parameters.Length; int paramIndex = 0; // Determines which parameter to use in the result // See if there are any (optional) conditions: bool conditionResult = false; if (info.CurrentIsNumber && TryEvaluateCondition(ref parameters[0], info.Current, ref conditionResult)) { // parameters(0) contained a "conditional statement" // If the conditional statement was False, then // we will move on to the next parameters while (!conditionResult) { if (paramIndex == parameters.Length - 1) { break; } paramIndex += 1; if (!TryEvaluateCondition(ref parameters[paramIndex], info.Current, ref conditionResult)) { // (couldn't evaluate the conditional statement, which means it's an "else" statement break; } } } else { // Determine the Current item's Type: if (info.CurrentIsNumber) { // Number: Neg|Zero|One|Many or Zero|One|Many/Neg or One|Many/Neg/Zero var arg = Convert.ToDecimal(info.Current); if (arg < 0m) { paramIndex = -4; } else if (arg == 0m) { paramIndex = -3; } else if (0m < arg && arg <= 1m) { paramIndex = -2; } else { paramIndex = -1; } paramIndex = paramIndex + paramCount; if (paramIndex < 0) { paramIndex = paramCount - 1; } } else if (info.CurrentIsBoolean) { // Bool: True|False bool arg = (bool)info.Current; if (!arg) { paramIndex = 1; } } else if (info.CurrentIsDate) { // Date: Past|Present|Future or Past/Present|Future System.DateTime arg = (DateTime)info.Current; if (paramCount == 3 && arg.Date == DateTime.Today) { paramIndex = 1; } else if (arg > DateTime.Now) { paramIndex = paramCount - 1; } } else if (info.CurrentIsTimeSpan) { // TimeSpan: Negative|Zero|Positive or Negative/Zero|Positive TimeSpan arg = (TimeSpan)info.Current; if (paramCount == 3 && arg == TimeSpan.Zero) { paramIndex = 1; } else if (arg.CompareTo(TimeSpan.Zero) == 1) { paramIndex = paramCount - 1; } } else if (info.CurrentIsString) { // String: Value|NullOrEmpty var arg = (string)info.Current; if (string.IsNullOrEmpty(arg)) { paramIndex = 1; } } else { // Object: Something|Nothing object arg = info.Current; if (arg == null) { paramIndex = 1; } } } // Now, output the selected parameter: if (parameters[paramIndex].Contains("{")) { // The format has nested items, so let's evaluate those now: info.SetFormat(parameters[paramIndex], true); info.CustomFormatNested(); } else { // The format doesn't have nested items so let's just write the selected parameter: info.Write(parameters[paramIndex]); } }
private void DoArrayFormatting(object sender, ExtendFormatEventArgs e) { CustomFormatInfo info = e.FormatInfo; // This method needs the Highest priority so that it comes before Strings.Format.Conditional.vb ICollection items = info.Current as ICollection; if (items == null) { return; } // The SplitString function is in the file Strings.Format.Conditional.vb: string[] split = Core.ParsingServices.SplitNested(info.Format, '|', 3); string format = split[0]; string spacer = null, lastSpacer = null; if (split.Length >= 2) { spacer = split[1]; } else { spacer = " "; // At least put a space between items by default } if (split.Length >= 3) { lastSpacer = split[2]; } if (!info.HasNested) { format = "{:" + format + "}"; } int itemCount = -1; if (lastSpacer != null) { itemCount = items.Count; } int oldCollectionIndex = CollectionIndex; // In case we have nested arrays, we might need to restore the CollectionIndex CollectionIndex = -1; foreach (object item in items) { CollectionIndex += 1; // Keep track of the index // If it isn't the first item, then write the spacer: if (CollectionIndex > 0) { // Write either the spacer or lastSpacer: if (itemCount == -1 || CollectionIndex < itemCount - 1) { info.Write(spacer); } else { info.Write(lastSpacer); } } // Write the format for this item: info.Current = item; info.SetFormat(format, info.HasNested); info.CustomFormatNested(); } CollectionIndex = oldCollectionIndex; // Restore the CollectionIndex }