OSDN Git Service

Add Smarty syntax highlighting. (https://www.smarty.net/) (#821)
authorJun Tajima <56220423+tjmprm77@users.noreply.github.com>
Fri, 11 Jun 2021 22:35:24 +0000 (07:35 +0900)
committerGitHub <noreply@github.com>
Fri, 11 Jun 2021 22:35:24 +0000 (07:35 +0900)
- Smarty delimiters can be changed, but for now only the default delimiters "{" and "}" are supported.

Externals/crystaledit/editlib/editlib.vcxitems
Externals/crystaledit/editlib/editlib.vcxitems.filters
Externals/crystaledit/editlib/parsers/crystallineparser.cpp
Externals/crystaledit/editlib/parsers/crystallineparser.h
Externals/crystaledit/editlib/parsers/html.cpp
Externals/crystaledit/editlib/parsers/smarty.cpp [new file with mode: 0644]
Src/Merge.rc
Src/resource.h
Translations/WinMerge/StringBlacklist.txt

index e5401cc..5365b95 100644 (file)
@@ -64,6 +64,7 @@
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\sgml.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\sh.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\siod.cpp" />
+    <ClCompile Include="$(MSBuildThisFileDirectory)parsers\smarty.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\sql.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\tcl.cpp" />
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\tex.cpp" />
index 5c78ee7..bbdea65 100644 (file)
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\siod.cpp">
       <Filter>Parsers\Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="$(MSBuildThisFileDirectory)parsers\smarty.cpp">
+      <Filter>Parsers\Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="$(MSBuildThisFileDirectory)parsers\sql.cpp">
       <Filter>Parsers\Source Files</Filter>
     </ClCompile>
index 48f2353..2b773e2 100644 (file)
@@ -44,6 +44,7 @@ TextDefinition m_SourceDefs[] =
        SRC_SGML, _T ("Sgml"), _T ("sgml"), &ParseLineSgml, SRCOPT_AUTOINDENT|SRCOPT_BRACEANSI, /*2,*/ _T ("<!--"), _T ("-->"), _T (""), (DWORD)-1,
        SRC_SH, _T ("Shell"), _T ("sh;conf"), &ParseLineSh, SRCOPT_INSERTTABS|SRCOPT_AUTOINDENT|SRCOPT_EOLNUNIX, /*4,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
        SRC_SIOD, _T ("SIOD"), _T ("scm"), &ParseLineSiod, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU, /*2,*/ _T (";|"), _T ("|;"), _T (";"), (DWORD)-1,
+       SRC_SMARTY, _T("Smarty"), _T("tpl"), &ParseLineSmarty, SRCOPT_AUTOINDENT | SRCOPT_BRACEGNU, /*2,*/ _T("{*"), _T("*}"), _T(""), (DWORD)-1,
        SRC_SQL, _T ("SQL"), _T ("sql"), &ParseLineSql, SRCOPT_AUTOINDENT, /*4,*/ _T ("/*"), _T ("*/"), _T ("//"), (DWORD)-1,
        SRC_TCL, _T ("TCL"), _T ("tcl"), &ParseLineTcl, SRCOPT_AUTOINDENT|SRCOPT_BRACEGNU|SRCOPT_EOLNUNIX, /*2,*/ _T (""), _T (""), _T ("#"), (DWORD)-1,
        SRC_TEX, _T ("TEX"), _T ("tex;sty;clo;ltx;fd;dtx"), &ParseLineTex, SRCOPT_AUTOINDENT, /*4,*/ _T (""), _T (""), _T ("%"), (DWORD)-1,
index e03cc20..05b6b7e 100644 (file)
@@ -102,6 +102,7 @@ typedef enum
        SRC_SGML,\r
        SRC_SH,\r
        SRC_SIOD,\r
+       SRC_SMARTY,\r
        SRC_SQL,\r
        SRC_TCL,\r
        SRC_TEX,\r
@@ -128,7 +129,7 @@ struct TextDefinition
        unsigned encoding;\r
 };\r
 \r
-extern TextDefinition m_SourceDefs[40];\r
+extern TextDefinition m_SourceDefs[41];\r
 \r
 bool IsXKeyword(const TCHAR *pszKey, size_t nKeyLen, const TCHAR *pszKeywordList[], size_t nKeywordListCount, int(*compare)(const TCHAR *, const TCHAR *, size_t));\r
 bool IsXNumber(const TCHAR* pszChars, int nLength);\r
@@ -176,6 +177,8 @@ unsigned ParseLineRust(unsigned dwCookie, const TCHAR *pszChars, int nLength, TE
 unsigned ParseLineSgml(unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems);\r
 unsigned ParseLineSh(unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems);\r
 unsigned ParseLineSiod(unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems);\r
+unsigned ParseLineSmarty(unsigned dwCookie, const TCHAR* pszChars, int nLength, TEXTBLOCK* pBuf, int& nActualItems);\r
+unsigned ParseLineSmartyLanguage(unsigned dwCookie, const TCHAR* pszChars, int nLength, TEXTBLOCK* pBuf, int& nActualItems);\r
 unsigned ParseLineSql(unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems);\r
 unsigned ParseLineTcl(unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems);\r
 unsigned ParseLineTex(unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems);\r
index 4434c22..77214a8 100644 (file)
@@ -34,7 +34,7 @@ CrystalLineParser::ParseLineHtmlEx (unsigned dwCookie, const TCHAR *pszChars, in
 {
   if (nLength == 0)
     {
-      unsigned dwCookieStrChar = ((nEmbeddedLanguage == SRC_PHP) && (dwCookie & COOKIE_EXT_USER1)) ? (dwCookie & (COOKIE_STRING | COOKIE_CHAR)) : 0;
+      unsigned dwCookieStrChar = ((nEmbeddedLanguage == SRC_PHP || nEmbeddedLanguage == SRC_SMARTY) && (dwCookie & COOKIE_EXT_USER1)) ? (dwCookie & (COOKIE_STRING | COOKIE_CHAR)) : 0;
       return dwCookie & (COOKIE_EXT_COMMENT|COOKIE_EXT_USER1|COOKIE_ELEMENT|COOKIE_BLOCK_SCRIPT|COOKIE_BLOCK_STYLE|COOKIE_EXT_DEFINITION|COOKIE_EXT_VALUE|dwCookieStrChar);
     }
 
@@ -133,44 +133,81 @@ out:
             }
           else if ((dwCookie & COOKIE_EXT_USER1))
             {
-              const TCHAR *pszEnd = _tcsstr(pszChars + I, _T("?>"));
-              if (!pszEnd)
-                pszEnd = _tcsstr(pszChars + I, _T("%>"));
-              int nextI = pszEnd ? static_cast<int>(pszEnd - pszChars) : nLength;
-              unsigned (*pParseLineFunc)(unsigned, const TCHAR *, int, TEXTBLOCK *, int &);
-              switch (nEmbeddedLanguage)
-              {
-              case SRC_BASIC: pParseLineFunc = ParseLineBasic; break;
-              case SRC_PHP: pParseLineFunc = ParseLinePhpLanguage; break;
-              default: pParseLineFunc = ParseLineJavaScript; break;
-              }
-              int nActualItemsEmbedded = 0;
-              dwCookie = pParseLineFunc(dwCookie & ~COOKIE_EXT_USER1, pszChars + I, nextI - I, pBuf + nActualItems, nActualItemsEmbedded);
-              AdjustCharPosInTextBlocks(pBuf, nActualItems, nActualItems + nActualItemsEmbedded - 1, I);
-              nActualItems += nActualItemsEmbedded;
-              if (!pszEnd)
-                dwCookie |= COOKIE_EXT_USER1;
-              else if ((nEmbeddedLanguage == SRC_PHP) && (dwCookie & (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_CHAR)))
+              if (nEmbeddedLanguage != SRC_SMARTY)
                 {
-                  // A closing tag in a comment or string.
-                  if (dwCookie & COOKIE_EXT_COMMENT)
+                  const TCHAR *pszEnd = _tcsstr(pszChars + I, _T("?>"));
+                  if (!pszEnd)
+                    pszEnd = _tcsstr(pszChars + I, _T("%>"));
+                  int nextI = pszEnd ? static_cast<int>(pszEnd - pszChars) : nLength;
+                  unsigned (*pParseLineFunc)(unsigned, const TCHAR *, int, TEXTBLOCK *, int &);
+                  switch (nEmbeddedLanguage)
+                  {
+                  case SRC_BASIC: pParseLineFunc = ParseLineBasic; break;
+                  case SRC_PHP: pParseLineFunc = ParseLinePhpLanguage; break;
+                  default: pParseLineFunc = ParseLineJavaScript; break;
+                  }
+                  int nActualItemsEmbedded = 0;
+                  dwCookie = pParseLineFunc(dwCookie & ~COOKIE_EXT_USER1, pszChars + I, nextI - I, pBuf + nActualItems, nActualItemsEmbedded);
+                  AdjustCharPosInTextBlocks(pBuf, nActualItems, nActualItems + nActualItemsEmbedded - 1, I);
+                  nActualItems += nActualItemsEmbedded;
+                  if (!pszEnd)
+                    dwCookie |= COOKIE_EXT_USER1;
+                  else if ((nEmbeddedLanguage == SRC_PHP) && (dwCookie & (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_CHAR)))
                     {
-                      DEFINE_BLOCK(I, COLORINDEX_COMMENT);
+                      // A closing tag in a comment or string.
+                      if (dwCookie & COOKIE_EXT_COMMENT)
+                        {
+                           DEFINE_BLOCK(I, COLORINDEX_COMMENT);
+                        }
+                      else if (dwCookie & (COOKIE_STRING | COOKIE_CHAR))
+                        {
+                          DEFINE_BLOCK(I, COLORINDEX_STRING);
+                        }
+                      nextI += 2;    // Length of "?>"
+                      dwCookie |= COOKIE_EXT_USER1;
+                      bRedefineBlock = true;
                     }
-                  else if (dwCookie & (COOKIE_STRING | COOKIE_CHAR))
+                  else
                     {
-                      DEFINE_BLOCK(I, COLORINDEX_STRING);
+                      dwCookie = 0;
+                      bRedefineBlock = true;
                     }
-                  nextI += 2;    // Length of "?>"
-                  dwCookie |= COOKIE_EXT_USER1;
-                  bRedefineBlock = true;
+                  I = nextI - 1;
                 }
               else
                 {
-                  dwCookie = 0;
-                  bRedefineBlock = true;
+                  const TCHAR* pszEnd = _tcsstr(pszChars + I, _T("}"));
+                  int nextI = pszEnd ? static_cast<int>(pszEnd - pszChars) : nLength;
+                  int nActualItemsEmbedded = 0;
+                  int nOffset = (I > 0 && pszChars[I - 1] == '{') ? (I - 1) : I;
+                  dwCookie = ParseLineSmartyLanguage(dwCookie & ~COOKIE_EXT_USER1, pszChars + nOffset, nextI - nOffset + 1, pBuf + nActualItems, nActualItemsEmbedded);
+                  AdjustCharPosInTextBlocks(pBuf, nActualItems, nActualItems + nActualItemsEmbedded - 1, nOffset);
+                  nActualItems += nActualItemsEmbedded;
+                  if (!pszEnd)
+                      dwCookie |= COOKIE_EXT_USER1;
+                  else if (dwCookie & (COOKIE_EXT_COMMENT | COOKIE_STRING))
+                    {
+                      // A closing tag in a comment or string.
+                      if (dwCookie & COOKIE_EXT_COMMENT)
+                        {
+                          DEFINE_BLOCK(I, COLORINDEX_COMMENT);
+                        }
+                      else if (dwCookie & (COOKIE_STRING | COOKIE_CHAR))
+                        {
+                          DEFINE_BLOCK(I, COLORINDEX_STRING);
+                        }
+                      nextI += 1;    // Length of "}"
+                      dwCookie |= COOKIE_EXT_USER1;
+                      bRedefineBlock = true;
+                    }
+                  else
+                    {
+                      nextI += 1;    // Length of "}"
+                      dwCookie = 0;
+                      bRedefineBlock = true;
+                    }
+                  I = nextI - 1;
                 }
-              I = nextI - 1;
             }
           continue;
         }
@@ -245,6 +282,18 @@ out:
           continue;
         }
 
+      if (nEmbeddedLanguage == SRC_SMARTY)
+        {
+          // In Smarty templates, the { and } braces will be ignored so long as they are surrounded by white space.
+          bool bLeftDelim = ((I < nLength&& pszChars[I] == '{') && ((I > 0 && (!xisspace(pszChars[I - 1]))) || (I + 1 < nLength && (!xisspace(pszChars[I + 1])))));
+          if (bLeftDelim)
+            {
+              dwCookie |= COOKIE_EXT_USER1;
+              nIdentBegin = -1;
+              continue;
+            }
+        }
+
       if (pBuf == nullptr)
         continue;               //  We don't need to extract keywords,
       //  for faster parsing skip the rest of loop
@@ -263,10 +312,13 @@ out:
                   if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
                     {
                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
-                      if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<script"), sizeof("<script") - 1) == 0)
-                        dwCookie |= COOKIE_BLOCK_SCRIPT;
-                      else if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<style"), sizeof("<style") - 1) == 0)
-                        dwCookie |= COOKIE_BLOCK_STYLE;
+                      if (nEmbeddedLanguage != SRC_SMARTY)
+                        {
+                          if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<script"), sizeof("<script") - 1) == 0)
+                            dwCookie |= COOKIE_BLOCK_SCRIPT;
+                          else if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<style"), sizeof("<style") - 1) == 0)
+                            dwCookie |= COOKIE_BLOCK_STYLE;
+                        }
                     }
                   else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
                     {
@@ -348,10 +400,13 @@ next:
       if (IsHtmlKeyword (pszChars + nIdentBegin, I - nIdentBegin) && (pszChars[nIdentBegin - 1] == _T ('<') || pszChars[nIdentBegin - 1] == _T ('/')))
         {
           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
-          if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<script"), sizeof("<script") - 1) == 0)
-            dwCookie |= COOKIE_BLOCK_SCRIPT;
-          else if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<style"), sizeof("<style") - 1) == 0)
-            dwCookie |= COOKIE_BLOCK_STYLE;
+          if (nEmbeddedLanguage != SRC_SMARTY)
+            {
+              if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<script"), sizeof("<script") - 1) == 0)
+                dwCookie |= COOKIE_BLOCK_SCRIPT;
+              else if (nIdentBegin > 0 && _tcsnicmp(pszChars + nIdentBegin - 1, _T("<style"), sizeof("<style") - 1) == 0)
+                dwCookie |= COOKIE_BLOCK_STYLE;
+            }
         }
       else if (IsHtmlUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
         {
@@ -367,7 +422,7 @@ next:
         }
     }
 
-  unsigned dwCookieChar = ((nEmbeddedLanguage == SRC_PHP) && (dwCookie & COOKIE_EXT_USER1)) ? (dwCookie & COOKIE_CHAR) : 0;
+  unsigned dwCookieChar = ((nEmbeddedLanguage == SRC_PHP || nEmbeddedLanguage == SRC_SMARTY) && (dwCookie & COOKIE_EXT_USER1)) ? (dwCookie & COOKIE_CHAR) : 0;
   dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_ELEMENT | COOKIE_EXT_USER1 | COOKIE_BLOCK_SCRIPT | COOKIE_BLOCK_STYLE | COOKIE_EXT_DEFINITION | COOKIE_EXT_VALUE | dwCookieChar);
   return dwCookie;
 }
diff --git a/Externals/crystaledit/editlib/parsers/smarty.cpp b/Externals/crystaledit/editlib/parsers/smarty.cpp
new file mode 100644 (file)
index 0000000..50b159c
--- /dev/null
@@ -0,0 +1,452 @@
+///////////////////////////////////////////////////////////////////////////
+//  File:    smarty.cpp
+//  Version: 1.0.0.0
+//  Updated: 11-Jun-2021
+//
+//  Copyright:  Ferdinand Prantl, portions by Stcherbatchenko Andrei
+//  E-mail:     prantl@ff.cuni.cz
+//
+//  Smarty 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 "StdAfx.h"
+#include "crystallineparser.h"
+#include "../SyntaxColors.h"
+#include "../utils/string_util.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+// See https://www.smarty.net/docs/en/
+
+// Chapter7
+// Built-in Functions
+static const TCHAR * s_apszBuiltInFunctionList[] =
+  {
+    _T ("append"),
+    _T ("as"),            // This is used with "foreach".
+    _T ("assign"),
+    _T ("block"),
+    _T ("break"),
+    _T ("call"),
+    _T ("capture"),
+    _T ("config_load"),
+    _T ("continue"),
+    _T ("debug"),
+    _T ("else"),
+    _T ("elseif"),
+    _T ("extends"),
+    _T ("for"),
+    _T ("foreach"),
+    _T ("foreachelse"),
+    _T ("forelse"),
+    _T ("function"),
+    _T ("if"),
+    _T ("include"),
+    _T ("include_php"),
+    _T ("insert"),
+    _T ("ldelim"),
+    _T ("literal"),
+    _T ("nocache"),
+    _T ("php"),
+    _T ("rdelim"),
+    _T ("section"),
+    _T ("sectionelse"),
+    _T ("setfilter"),
+    _T ("step"),      // This is used with "for".
+    _T ("strip"),
+    _T ("to"),        // This is used with "for".
+    _T ("while"),
+  };
+
+// Operators
+static const TCHAR * s_apszOperatorList[] =
+  {
+    _T ("by"),
+    _T ("div"),
+    _T ("eq"),
+    _T ("even"),
+    _T ("ge"),
+    _T ("gt"),
+    _T ("gte"),
+    _T ("is"),
+    _T ("le"),
+    _T ("lt"),
+    _T ("lte"),
+    _T ("mod"),
+    _T ("ne"),
+    _T ("neq"),
+    _T ("not"),
+    _T ("odd"),
+  };
+
+// Chapter8
+// Custom Functions
+static const TCHAR * s_apszCustomFunctionList[] =
+  {
+    _T ("counter"),
+    _T ("cycle"),
+    _T ("eval"),
+    _T ("fetch"),
+    _T ("html_checkboxes"),
+    _T ("html_image"),
+    _T ("html_options"),
+    _T ("html_radios"),
+    _T ("html_select_date"),
+    _T ("html_select_time"),
+    _T ("html_table"),
+    _T ("mailto"),
+    _T ("math"),
+    _T ("textformat"),
+  };
+
+// Chapter5
+// Variable Modifiers
+static const TCHAR * s_apszVariableModifierList[] =
+  {
+    _T ("capitalize"),
+    _T ("cat"),
+    _T ("count_characters"),
+    _T ("count_paragraphs"),
+    _T ("count_sentences"),
+    _T ("count_words"),
+    _T ("date_format"),
+    _T ("default"),
+    _T ("escape"),
+    _T ("from_charset"),
+    _T ("indent"),
+    _T ("lower"),
+    _T ("nl2br"),
+    _T ("regex_replace"),
+    _T ("replace"),
+    _T ("spacify"),
+    _T ("string_format"),
+//  _T ("strip"),             // This is also defined as a build-in function, so comment it out.
+    _T ("strip_tags"),
+    _T ("to_charset"),
+    _T ("truncate"),
+    _T ("unescape"),
+    _T ("upper"),
+    _T ("wordwrap"),
+  };
+
+
+static bool
+IsSmartyKeyword (const TCHAR *pszChars, int nLength)
+{
+  return ISXKEYWORDI (s_apszBuiltInFunctionList, pszChars, nLength);
+}
+
+static bool
+IsOperatorKeyword(const TCHAR* pszChars, int nLength)
+{
+    return ISXKEYWORDI(s_apszOperatorList, pszChars, nLength);
+}
+
+static bool
+IsUser1Keyword (const TCHAR *pszChars, int nLength)
+{
+  return ISXKEYWORDI (s_apszCustomFunctionList, pszChars, nLength);
+}
+
+static bool
+IsUser2Keyword (const TCHAR *pszChars, int nLength)
+{
+  return ISXKEYWORDI (s_apszVariableModifierList, pszChars, nLength);
+}
+
+unsigned
+CrystalLineParser::ParseLineSmarty(unsigned dwCookie, const TCHAR* pszChars, int nLength, TEXTBLOCK* pBuf, int& nActualItems)
+{
+  return ParseLineHtmlEx(dwCookie, pszChars, nLength, pBuf, nActualItems, SRC_SMARTY);
+}
+
+unsigned
+CrystalLineParser::ParseLineSmartyLanguage (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)
+{
+  if (nLength == 0)
+    return dwCookie & (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_CHAR);
+
+  const TCHAR *pszCommentBegin = nullptr;
+  const TCHAR *pszCommentEnd = nullptr;
+  bool bRedefineBlock = true;
+  bool bDecIndex = false;
+  int nIdentBegin = -1;
+  int nPrevI = -1;
+  int I=0;
+  for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))
+    {
+      if (I == nPrevI)
+        {
+          // CharNext did not advance, so we're at the end of the string
+          // and we already handled this character, so stop
+          break;
+        }
+
+      if (bRedefineBlock)
+        {
+          int nPos = I;
+          if (bDecIndex)
+            nPos = nPrevI;
+          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 (dwCookie & COOKIE_USER1)         // Config???
+            {
+              DEFINE_BLOCK(nPos, COLORINDEX_USER1);
+            }
+          else if (dwCookie & COOKIE_PREPROCESSOR)
+            {
+              DEFINE_BLOCK (nPos, COLORINDEX_PREPROCESSOR);
+            }
+          else
+            {
+              if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.')
+                {
+                  DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);
+                }
+              else
+                {
+                  DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);
+                  bRedefineBlock = true;
+                  bDecIndex = true;
+                  goto out;
+                }
+            }
+          bRedefineBlock = false;
+          bDecIndex = false;
+        }
+out:
+
+      // Can be bigger than length if there is binary data
+      // See bug #1474782 Crash when comparing SQL with with binary data
+      if (I >= nLength || pszChars[I] == 0)
+        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[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
+            {
+              dwCookie &= ~COOKIE_STRING;
+              bRedefineBlock = true;
+            }
+          continue;
+        }
+
+      //  Char constant '..'
+      if (dwCookie & COOKIE_CHAR)
+        {
+          if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
+            {
+              dwCookie &= ~COOKIE_CHAR;
+              bRedefineBlock = true;
+            }
+          continue;
+        }
+
+      //  Variables loaded from config files #....#
+      if (dwCookie & COOKIE_USER1)
+        {
+          if (pszChars[I] == '#' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))
+            {
+              dwCookie &= ~COOKIE_USER1;
+              bRedefineBlock = true;
+            }
+          continue;
+        }
+
+      //  Comment
+      if (dwCookie & COOKIE_EXT_COMMENT)
+        {
+          if ((pszCommentBegin < pszChars + I) && (I > 0 && pszChars[I] == '}' && pszChars[nPrevI] == '*'))
+            {
+              dwCookie &= ~COOKIE_EXT_COMMENT;
+              bRedefineBlock = true;
+              pszCommentEnd = pszChars + I + 1;
+            }
+          continue;
+        }
+
+      //  Normal text
+      if (pszChars[I] == '"')
+        {
+          DEFINE_BLOCK (I, COLORINDEX_STRING);
+          dwCookie |= COOKIE_STRING;
+          continue;
+        }
+
+      if (pszChars[I] == '\'')
+        {
+          // if (I + 1 < nLength && pszChars[I + 1] == '\'' || I + 2 < nLength && pszChars[I + 1] != '\\' && pszChars[I + 2] == '\'' || I + 3 < nLength && pszChars[I + 1] == '\\' && pszChars[I + 3] == '\'')
+          if (!I || !xisalnum (pszChars[nPrevI]))
+            {
+              DEFINE_BLOCK (I, COLORINDEX_STRING);
+              dwCookie |= COOKIE_CHAR;
+              continue;
+            }
+        }
+
+      if (pszChars[I] == '#')
+        {
+          DEFINE_BLOCK(I, COLORINDEX_USER1);
+          dwCookie |= COOKIE_USER1;
+          continue;
+        }
+
+      if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '{'))
+        {
+          DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);
+          dwCookie |= COOKIE_EXT_COMMENT;
+          pszCommentBegin = pszChars + I + 1;
+          continue;
+        }
+
+      if (pBuf == nullptr)
+        continue;               //  We don't need to extract keywords,
+      //  for faster parsing skip the rest of loop
+
+      if (xisalnum (pszChars[I]) || pszChars[I] == '.')
+        {
+          if (nIdentBegin == -1)
+            nIdentBegin = I;
+        }
+      else
+        {
+          if (nIdentBegin >= 0)
+            {
+              if (dwCookie & COOKIE_USER2)
+                {
+                  DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);
+                }
+              if (IsSmartyKeyword (pszChars + nIdentBegin, I - nIdentBegin))
+                {
+                  DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
+                }
+              else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
+                {
+                  DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
+                }
+              else if (IsUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
+                {
+                  DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
+                }
+              else if (IsOperatorKeyword(pszChars + nIdentBegin, I - nIdentBegin))
+                {
+                  DEFINE_BLOCK(nIdentBegin, COLORINDEX_OPERATOR);
+                }
+              else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
+                {
+                  DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
+                }
+              else
+                {
+                  bool bFunction = false;
+
+                  for (int j = I; j < nLength; j++)
+                    {
+                      if (!xisspace (pszChars[j]))
+                        {
+                          if (pszChars[j] == '(')
+                            {
+                              bFunction = true;
+                            }
+                          break;
+                        }
+                    }
+                  if (bFunction)
+                    {
+                      DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
+                    }
+                }
+              bRedefineBlock = true;
+              bDecIndex = true;
+              nIdentBegin = -1;
+            }
+
+          //  Preprocessor start: $
+          if (pszChars[I] == '$')
+            {
+              dwCookie |= COOKIE_USER2;
+              nIdentBegin = -1;
+              continue;
+            }
+
+          //  Preprocessor end: ...
+          if (dwCookie & COOKIE_USER2)
+            {
+              if (!xisalnum (pszChars[I]))
+                {
+                  dwCookie &= ~COOKIE_USER2;
+                  nIdentBegin = -1;
+                  continue;
+                }
+            }
+        }
+    }
+
+  if (nIdentBegin >= 0)
+    {
+      if (IsSmartyKeyword (pszChars + nIdentBegin, I - nIdentBegin))
+        {
+          DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);
+        }
+      else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))
+        {
+          DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
+        }
+      else if (IsUser2Keyword (pszChars + nIdentBegin, I - nIdentBegin))
+        {
+          DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER2);
+        }
+      else if (IsOperatorKeyword(pszChars + nIdentBegin, I - nIdentBegin))
+        {
+          DEFINE_BLOCK(nIdentBegin, COLORINDEX_OPERATOR);
+        }
+      else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))
+        {
+          DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);
+        }
+      else
+        {
+          bool bFunction = false;
+
+          for (int j = I; j < nLength; j++)
+            {
+              if (!xisspace (pszChars[j]))
+                {
+                  if (pszChars[j] == '(')
+                    {
+                      bFunction = true;
+                    }
+                  break;
+                }
+            }
+          if (bFunction)
+            {
+              DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);
+            }
+        }
+    }
+
+  dwCookie &= (COOKIE_EXT_COMMENT | COOKIE_STRING | COOKIE_CHAR);
+  return dwCookie;
+}
index dc43279..5e2740d 100644 (file)
@@ -3539,6 +3539,7 @@ BEGIN
     IDS_COLORSCHEME_SGML    "SGML"\r
     IDS_COLORSCHEME_SH      "Shell"\r
     IDS_COLORSCHEME_SIOD    "SIOD"\r
+    IDS_COLORSCHEME_SMARTY  "Smarty"\r
     IDS_COLORSCHEME_SQL     "SQL"\r
     IDS_COLORSCHEME_TCL     "TCL"\r
 END\r
index cdb1e8a..c470cb5 100644 (file)
 #define IDS_COLORSCHEME_SGML            33183\r
 #define IDS_COLORSCHEME_SH              33184\r
 #define IDS_COLORSCHEME_SIOD            33185\r
-#define IDS_COLORSCHEME_SQL             33186\r
-#define IDS_COLORSCHEME_TCL             33187\r
-#define IDS_COLORSCHEME_TEX             33188\r
-#define IDS_COLORSCHEME_VERILOG         33189\r
-#define IDS_COLORSCHEME_VHDL            33190\r
-#define IDS_COLORSCHEME_XML             33191\r
-#define ID_COLORSCHEME_LAST             33191 // = IDS_COLORSCHEME_XML\r
+#define IDS_COLORSCHEME_SMARTY          33186\r
+#define IDS_COLORSCHEME_SQL             33187\r
+#define IDS_COLORSCHEME_TCL             33188\r
+#define IDS_COLORSCHEME_TEX             33189\r
+#define IDS_COLORSCHEME_VERILOG         33190\r
+#define IDS_COLORSCHEME_VHDL            33191\r
+#define IDS_COLORSCHEME_XML             33192\r
+#define ID_COLORSCHEME_LAST             33192 // = IDS_COLORSCHEME_XML\r
 #define ID_TOOLBAR_NONE                 33194\r
 #define ID_TOOLBAR_SMALL                33195\r
 #define ID_TOOLBAR_BIG                  33196\r