/// <summary>Parses all the keywords/macros in a string and replaces them recursively</summary>
      /// <param name="text">Source text to parse</param>
      /// <param name="depth">Debugging output depth</param>
      /// <returns>Fully parsed text</returns>
      /// <exception cref="Logic::FileFormatException">Macro contains wrong number of parameters</exception>
      /// <exception cref="Logic::Language::RegularExpressionException">RegEx error</exception>
      wstring  DescriptionParser::Parse(wstring text, int depth) const 
      {
         UINT Position;
         wsmatch match;
         wstring r;
         
         try
         {
#ifdef PRINT_CONSOLE
            Console << Cons::Cyan << Indent(depth) << "Parsing: " << Cons::White << text << ENDL;
#endif

            // Find/Replace all macros:  {AAAA:bbb}, {AAAA:bbb,ccc}, {AAAA:bbb,ccc,ddd} ...
            for (Position = 0; regex_search(text.cbegin()+Position, text.cend(), match, MatchMacro); ) //  Manually track position for in-place replacement + avoid infinite loop
            {
               // Recursively generate replacement text
               r = onMatchMacro(match, depth);

#ifdef PRINT_CONSOLE
               Console << Indent(depth) << "Replacing text: " << Cons::Yellow << match[0].str() << Cons::White << " with " << Cons::Green << r << ENDL;
#endif

               // Advance position to beyond inserted text, and insert text
               Position = (match[0].first - text.cbegin()) + r.length();
               text.replace(match[0].first, match[0].second, r);
            }

            // Find/Replace all keywords:  {AAAAA}, AAAAA
            for (Position = 0; regex_search(text.cbegin()+Position, text.cend(), match, MatchKeyword); )  
            {
               // Recursively generate replacement text
               r = onMatchKeyword(match, depth);

#ifdef PRINT_CONSOLE
               Console << Indent(depth) << "Replacing text: " << Cons::Yellow << match[0].str() << Cons::White << " with " << Cons::Green << r << ENDL;
#endif

               // Advance position to beyond inserted text, and insert text
               Position = (match[0].first - text.cbegin()) + r.length();
               text.replace(match[0].first, match[0].second, r);
            }

            return text;
         }
         catch (regex_error& e) {
            throw RegularExpressionException(HERE, e);
         }
      }
      /// <summary>Populates the parameters markers within the description source text.</summary>
      /// <param name="src">source text.</param>
      /// <param name="cmd">command syntax.</param>
      /// <returns></returns>
      wstring  DescriptionParser::Populate(wstring src, CommandSyntaxRef cmd)
      {
         wsmatch match;
         wstring r;
         
         // Replace all {aaa,bbb} markers.  Manually track position for in-place replacement + avoid infinite loop
         for (int Position = 0; regex_search(src.cbegin()+Position, src.cend(), match, MartchParameterMarker); )
         {
            r = onParameterMarker(match, cmd);

#ifdef PRINT_CONSOLE            
            Console << "  Replace: " << Cons::Yellow << match[0].str() << Cons::White << " with " << Cons::Green << r << ENDL;
#endif
            // Advance position + perform replacement
            Position = (match[0].first - src.cbegin()) + r.length();
            src.replace(match[0].first, match[0].second, r);
         }

         return src;
      }
bool ConnectedShortcut::startsWith(const wstring& tested, const wstring& prefix)
{
	return (tested.length() >= prefix.length()) &&
		(std::mismatch(prefix.cbegin(), prefix.cend(), tested.cbegin()).first == prefix.cend());
}