text: ///////////////////////////////////////////////////////////////////////////
  //
  //  Copyright:  Ferdinand Prantl, portions by Stcherbatchenko Andrei
  //  E-mail:     prantl@ff.cuni.cz
  //
  //  Python syntax highlighing definition
  //
  //  You are free to use or modify this code to the following restrictions:
  //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
  //  will be enough. If you can't (or don't want to), contact me personally.
  //  - LEAVE THIS HEADER INTACT
  ////////////////////////////////////////////////////////////////////////////
  
  #include <coolprj/pch.h>
  #pragma hdrstop
  
  #include <coolprj/cooledit.h>
  
  using namespace owl;
  
  //  C++ keywords (MSVC5.0 + POET5.0)
  static LPCTSTR s_apszPythonKeywordList[] =
    {
      _T ("access"),
      _T ("and"),
      _T ("break"),
      _T ("class"),
      _T ("continue"),
      _T ("def"),
      _T ("del"),
      _T ("elif"),
      _T ("else"),
      _T ("except"),
      _T ("exec"),
      _T ("finally"),
      _T ("for"),
      _T ("from"),
      _T ("global"),
      _T ("if"),
      _T ("import"),
      _T ("in"),
      _T ("is"),
      _T ("lambda"),
      _T ("not"),
      _T ("or"),
      _T ("pass"),
      _T ("print"),
      _T ("raise"),
      _T ("return"),
      _T ("try"),
      _T ("while"),
      NULL
    };
  
  static LPCTSTR s_apszUser1KeywordList[] =
    {
      _T ("argv"),
      _T ("builtin_module_names"),
      _T ("exc_type"),
      _T ("exc_value"),
      _T ("exc_traceback"),
      _T ("exit"),
      _T ("exitfunc"),
      _T ("last_type"),
      _T ("last_value"),
      _T ("last_traceback"),
      _T ("modules"),
      _T ("path"),
      _T ("ps1"),
      _T ("ps2"),
      _T ("settrace"),
      _T ("setprofile"),
      _T ("stdin"),
      _T ("stdout"),
      _T ("stderr"),
      _T ("tracebacklimit"),
      _T ("AttributeError"),
      _T ("EOFError"),
      _T ("IOError"),
      _T ("ImportError"),
      _T ("IndexError"),
      _T ("KeyError"),
      _T ("KeyboardInterrupt"),
      _T ("MemoryError"),
      _T ("NameError"),
      _T ("OverflowError"),
      _T ("RuntimeError"),
      _T ("SyntaxError"),
      _T ("SystemError"),
      _T ("SystemExit"),
      _T ("TypeError"),
      _T ("ValueError"),
      _T ("ZeroDivisionError"),
      NULL
    };
  
  static LPCTSTR s_apszUser2KeywordList[] =
    {
      _T ("id"),
      _T ("__init__"),
      _T ("__del__"),
      _T ("__repr__"),
      _T ("__str__"),
      _T ("__cmp__"),
      _T ("__hash__"),
      _T ("__dict__"),
      _T ("__methods__"),
      _T ("__members__"),
      _T ("__class__"),
      _T ("__bases__"),
      _T ("__add__"),
      _T ("__mul__"),
      _T ("__mod__"),
      _T ("__sub__"),
      _T ("__div__"),
      _T ("divmod"),
      _T ("__divmod__"),
      _T ("pow"),
      _T ("__pow__"),
      _T ("__and__"),
      _T ("__xor__"),
      _T ("__or__"),
      _T ("__lshift__"),
      _T ("__rshift__"),
      _T ("nonzero"),
      _T ("__nonzero__"),
      _T ("coerce"),
      _T ("__coerce__"),
      _T ("__neg__"),
      _T ("__pos__"),
      _T ("abs"),
      _T ("__abs__"),
      _T ("__invert__"),
      _T ("int"),
      _T ("__int__"),
      _T ("float"),
      _T ("__float__"),
      _T ("long"),
      _T ("__long__"),
      _T ("float"),
      _T ("__float__"),
      _T ("oct"),
      _T ("__oct__"),
      _T ("hex"),
      _T ("__hex__"),
      _T ("range"),
      _T ("round"),
      _T ("xrange"),
      _T ("len"),
      _T ("__len__"),
      _T ("__getitem__"),
      NULL
    };
  
  static BOOL
  IsXKeyword (LPCTSTR apszKeywords[], LPCTSTR pszChars, int nLength)
  {
    for (int L = 0; apszKeywords[L] != NULL; L++)
      {
        if (_tcsncmp (apszKeywords[L], pszChars, nLength) == 0
              && apszKeywords[L][nLength] == 0)
          return TRUE;
      }
    return FALSE;
  }
  
  static BOOL
  IsPythonKeyword (LPCTSTR pszChars, int nLength)
  {
    return IsXKeyword (s_apszPythonKeywordList, pszChars, nLength);
  }
  
  static BOOL
  IsUser1Keyword (LPCTSTR pszChars, int nLength)
  {
    return IsXKeyword (s_apszUser1KeywordList, pszChars, nLength);
  }
  
  static BOOL
  IsUser2Keyword (LPCTSTR pszChars, int nLength)
  {
    return IsXKeyword (s_apszUser2KeywordList, pszChars, nLength);
  }
  
  static BOOL
  IsPythonNumber (LPCTSTR pszChars, int nLength)
  {
    if (nLength > 2 && pszChars[0] == '0' && pszChars[1] == 'x')
      {
        for (int I = 2; I < nLength; I++)
          {
            if (_istdigit (pszChars[I]) || (pszChars[I] >= 'A' && pszChars[I] <= 'F') ||
                  (pszChars[I] >= 'a' && pszChars[I] <= 'f'))
              continue;
            return FALSE;
          }
        return TRUE;
      }
    if (!_istdigit (pszChars[0]))
      return FALSE;
    for (int I = 1; I < nLength; I++)
      {
        if (!_istdigit (pszChars[I]) && pszChars[I] != '+' &&
              pszChars[I] != '-' && pszChars[I] != '.' && pszChars[I] != 'e' &&
              pszChars[I] != 'E')
          return FALSE;
      }
    return TRUE;
  }
  
  #define DEFINE_BLOCK(pos, syntaxindex)  \
    CHECK((pos) >= 0 && (pos) <= nLength);\
    if (pBuf != NULL){\
      if (nActualItems == 0 || pBuf[nActualItems - 1].CharPos <= (pos)){\
        pBuf[nActualItems].CharPos     = (pos);\
        pBuf[nActualItems].SyntaxIndex = (syntaxindex);\
        nActualItems++;\
      }\
    }
  
  #define COOKIE_COMMENT          0x0001
  #define COOKIE_PREPROCESSOR     0x0002
  #define COOKIE_EXT_COMMENT      0x0004
  #define COOKIE_STRING           0x0008
  #define COOKIE_CHAR             0x0010
  
  //
  //
  //
  struct TPythonSyntaxParser: public TSyntaxParser {
    public:
      TPythonSyntaxParser(TCoolTextWnd* parent):TSyntaxParser(parent){}
      uint32 ParseLine(uint32 cookie, int index, TCoolTextWnd::TTextBlock* buf, int& items);
  };
  //
  _COOLEDFUNC(TSyntaxParser*) PythonParserCreator(TCoolTextWnd* parent)
  {
    return  new TPythonSyntaxParser(parent);
  }
  //
  uint32 TPythonSyntaxParser::ParseLine(uint32 dwCookie, int nLineIndex,
                                         TCoolTextWnd::TTextBlock* pBuf, int& nActualItems)
  {
    int nLength = Parent->GetLineLength (nLineIndex);
    if (nLength <= 1)
      return dwCookie & COOKIE_EXT_COMMENT;
  
    LPCTSTR pszChars = GetLineText (nLineIndex);
    BOOL bFirstChar = (dwCookie & ~COOKIE_EXT_COMMENT) == 0;
    BOOL bRedefineBlock = TRUE;
    BOOL bDecIndex = FALSE;
    int nIdentBegin = -1;
    int I;
    for (I = 0;; I++)
      {
        if (bRedefineBlock)
          {
            int nPos = I;
            if (bDecIndex)
              nPos--;
            if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))
              {
                DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);
              }
            else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING))
              {
                DEFINE_BLOCK (nPos, COLORINDEX_STRING);
              }
            else
              {
                if (xisalnum (pszChars[nPos]) ||
                  (
                    nPos > 0 &&
                    pszChars[nPos] == '.' &&
                    !xisalpha (pszChars[nPos - 1]) &&
                    xisalpha (pszChars[nPos + 1])
                  ))
                  {
                    DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
                  }
                else
                  {
                    DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
                    bRedefineBlock = TRUE;
                    bDecIndex = TRUE;
                    goto out;
                  }
              }
            bRedefineBlock = FALSE;
            bDecIndex = FALSE;
          }
  out:
  
        if (I == nLength)
          break;
  
        if (dwCookie & COOKIE_COMMENT)
          {
            DEFINE_BLOCK (I, COLORINDEX_COMMENT);
            dwCookie |= COOKIE_COMMENT;
            break;
          }
  
        //  String constant "...."
        if (dwCookie & COOKIE_STRING)
          {
            if (pszChars[I] == '"' &&
              (
                I == 0 || // "...
                (I >= 1 && pszChars[I - 1] != '\\') || // ...?"...
                (I >= 2 && pszChars[I - 1] == '\\' && pszChars[I - 2] == '\\') // ...\\"...
                // TODO: What about ...\\\"...?
              ))
              {
                dwCookie &= ~COOKIE_STRING;
                bRedefineBlock = TRUE;
              }
            continue;
          }
  
        //  Char constant '..'
        if (dwCookie & COOKIE_CHAR)
          {
            if (pszChars[I] == '\'' &&
              (
                I == 0 || // '...
                (I >= 1 && pszChars[I - 1] != '\\') || // ...?'...
                (I >= 2 && pszChars[I - 1] == '\\' && pszChars[I - 2] == '\\') // ...\\'...
                // TODO: What about ...\\\'...?
              ))
              {
                dwCookie &= ~COOKIE_CHAR;
                bRedefineBlock = TRUE;
              }
            continue;
          }
  
        if (pszChars[I] == '#')
          {
            DEFINE_BLOCK (I, COLORINDEX_COMMENT);
            dwCookie |= COOKIE_COMMENT;
            break;
          }
  
        //  Normal text
        if (pszChars[I] == '"')
          {
            DEFINE_BLOCK (I, COLORINDEX_STRING);
            dwCookie |= COOKIE_STRING;
            continue;
          }
        if (pszChars[I] == '\'')
          {
            DEFINE_BLOCK (I, COLORINDEX_STRING);
            dwCookie |= COOKIE_CHAR;
            continue;
          }
  
        if (bFirstChar)
          {
            if (!isspace (pszChars[I]))
              bFirstChar = FALSE;
          }
  
        if (pBuf == NULL)
          continue;               //  We don't need to extract keywords,
        //  for faster parsing skip the rest of loop
  
        if (xisalnum (pszChars[I]) ||
          (
            I > 0 &&
            pszChars[I] == '.' &&
            !xisalpha (pszChars[I - 1]) &&
            !xisalpha (pszChars[I + 1])
          ))
          {
            if (nIdentBegin == -1)
              nIdentBegin = I;
          }
        else
          {
            if (nIdentBegin >= 0)
              {
                if (IsPythonKeyword (pszChars + nIdentBegin, I - nIdentBegin))
                  {
                    DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
                  }
                else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
                  {
                    DEFINE_BLOCK (nIdentBegin, COLORINDEX_CUSTOM0);
                  }
                else if (IsUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
                  {
                    DEFINE_BLOCK (nIdentBegin, COLORINDEX_CUSTOM1);
                  }
                else if (IsPythonNumber (pszChars + nIdentBegin, I - nIdentBegin))
                  {
                    DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
                  }
                else
                  {
                    bool bFunction = FALSE;
  
                    for (int j = I; j < nLength; j++)
                      {
                        if (!isspace (pszChars[j]))
                          {
                            if (pszChars[j] == '(')
                              {
                                bFunction = TRUE;
                              }
                            break;
                          }
                      }
                    if (bFunction)
                      {
                        DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
                      }
                  }
                bRedefineBlock = TRUE;
                bDecIndex = TRUE;
                nIdentBegin = -1;
              }
          }
      }
  
    if (nIdentBegin >= 0)
      {
        if (IsPythonKeyword (pszChars + nIdentBegin, I - nIdentBegin))
          {
            DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
          }
        else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
          {
            DEFINE_BLOCK (nIdentBegin, COLORINDEX_CUSTOM0);
          }
        else if (IsUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
          {
            DEFINE_BLOCK (nIdentBegin, COLORINDEX_CUSTOM1);
          }
        else if (IsPythonNumber (pszChars + nIdentBegin, I - nIdentBegin))
          {
            DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
          }
        else
          {
            bool bFunction = FALSE;
  
            for (int j = I; j < nLength; j++)
              {
                if (!isspace (pszChars[j]))
                  {
                    if (pszChars[j] == '(')
                      {
                        bFunction = TRUE;
                      }
                    break;
                  }
              }
            if (bFunction)
              {
                DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
              }
          }
      }
  
    if (pszChars[nLength - 1] != '\\')
      dwCookie &= COOKIE_EXT_COMMENT;
    return dwCookie;
  }
  