OSDN Git Service

Commit DialogBox compile Okay
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexPython.cxx
diff --git a/ext/scintilla/src/LexPython.cxx b/ext/scintilla/src/LexPython.cxx
new file mode 100644 (file)
index 0000000..3ac0b75
--- /dev/null
@@ -0,0 +1,461 @@
+// Scintilla source code edit control\r
+/** @file LexPython.cxx\r
+ ** Lexer for Python.\r
+ **/\r
+// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>\r
+// The License.txt file describes the conditions under which this software may be distributed.\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <ctype.h>\r
+#include <stdio.h>\r
+#include <stdarg.h>\r
+\r
+#include "Platform.h"\r
+\r
+#include "PropSet.h"\r
+#include "Accessor.h"\r
+#include "StyleContext.h"\r
+#include "KeyWords.h"\r
+#include "Scintilla.h"\r
+#include "SciLexer.h"\r
+\r
+#ifdef SCI_NAMESPACE\r
+using namespace Scintilla;\r
+#endif\r
+\r
+enum kwType { kwOther, kwClass, kwDef, kwImport };\r
+static const int indicatorWhitespace = 1;\r
+\r
+static bool IsPyComment(Accessor &styler, int pos, int len) {\r
+       return len > 0 && styler[pos] == '#';\r
+}\r
+\r
+static bool IsPyStringStart(int ch, int chNext, int chNext2) {\r
+       if (ch == '\'' || ch == '"')\r
+               return true;\r
+       if (ch == 'u' || ch == 'U') {\r
+               if (chNext == '"' || chNext == '\'')\r
+                       return true;\r
+               if ((chNext == 'r' || chNext == 'R') && (chNext2 == '"' || chNext2 == '\''))\r
+                       return true;\r
+       }\r
+       if ((ch == 'r' || ch == 'R') && (chNext == '"' || chNext == '\''))\r
+               return true;\r
+\r
+       return false;\r
+}\r
+\r
+/* Return the state to use for the string starting at i; *nextIndex will be set to the first index following the quote(s) */\r
+static int GetPyStringState(Accessor &styler, int i, unsigned int *nextIndex) {\r
+       char ch = styler.SafeGetCharAt(i);\r
+       char chNext = styler.SafeGetCharAt(i + 1);\r
+\r
+       // Advance beyond r, u, or ur prefix, but bail if there are any unexpected chars\r
+       if (ch == 'r' || ch == 'R') {\r
+               i++;\r
+               ch = styler.SafeGetCharAt(i);\r
+               chNext = styler.SafeGetCharAt(i + 1);\r
+       } else if (ch == 'u' || ch == 'U') {\r
+               if (chNext == 'r' || chNext == 'R')\r
+                       i += 2;\r
+               else\r
+                       i += 1;\r
+               ch = styler.SafeGetCharAt(i);\r
+               chNext = styler.SafeGetCharAt(i + 1);\r
+       }\r
+\r
+       if (ch != '"' && ch != '\'') {\r
+               *nextIndex = i + 1;\r
+               return SCE_P_DEFAULT;\r
+       }\r
+\r
+       if (ch == chNext && ch == styler.SafeGetCharAt(i + 2)) {\r
+               *nextIndex = i + 3;\r
+\r
+               if (ch == '"')\r
+                       return SCE_P_TRIPLEDOUBLE;\r
+               else\r
+                       return SCE_P_TRIPLE;\r
+       } else {\r
+               *nextIndex = i + 1;\r
+\r
+               if (ch == '"')\r
+                       return SCE_P_STRING;\r
+               else\r
+                       return SCE_P_CHARACTER;\r
+       }\r
+}\r
+\r
+static inline bool IsAWordChar(int ch) {\r
+       return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');\r
+}\r
+\r
+static inline bool IsAWordStart(int ch) {\r
+       return (ch < 0x80) && (isalnum(ch) || ch == '_');\r
+}\r
+\r
+static void ColourisePyDoc(unsigned int startPos, int length, int initStyle,\r
+                           WordList *keywordlists[], Accessor &styler) {\r
+\r
+       int endPos = startPos + length;\r
+\r
+       // Backtrack to previous line in case need to fix its tab whinging\r
+       int lineCurrent = styler.GetLine(startPos);\r
+       if (startPos > 0) {\r
+               if (lineCurrent > 0) {\r
+                       lineCurrent--;\r
+                       startPos = styler.LineStart(lineCurrent);\r
+                       if (startPos == 0)\r
+                               initStyle = SCE_P_DEFAULT;\r
+                       else\r
+                               initStyle = styler.StyleAt(startPos - 1);\r
+               }\r
+       }\r
+\r
+       WordList &keywords = *keywordlists[0];\r
+       WordList &keywords2 = *keywordlists[1];\r
+\r
+       const int whingeLevel = styler.GetPropertyInt("tab.timmy.whinge.level");\r
+\r
+       initStyle = initStyle & 31;\r
+       if (initStyle == SCE_P_STRINGEOL) {\r
+               initStyle = SCE_P_DEFAULT;\r
+       }\r
+\r
+       kwType kwLast = kwOther;\r
+       int spaceFlags = 0;\r
+       styler.IndentAmount(lineCurrent, &spaceFlags, IsPyComment);\r
+       bool hexadecimal = false;\r
+\r
+       StyleContext sc(startPos, endPos - startPos, initStyle, styler);\r
+\r
+       bool indentGood = true;\r
+       int startIndicator = sc.currentPos;\r
+\r
+       for (; sc.More(); sc.Forward()) {\r
+\r
+               if (sc.atLineStart) {\r
+                       styler.IndentAmount(lineCurrent, &spaceFlags, IsPyComment);\r
+                       indentGood = true;\r
+                       if (whingeLevel == 1) {\r
+                               indentGood = (spaceFlags & wsInconsistent) == 0;\r
+                       } else if (whingeLevel == 2) {\r
+                               indentGood = (spaceFlags & wsSpaceTab) == 0;\r
+                       } else if (whingeLevel == 3) {\r
+                               indentGood = (spaceFlags & wsSpace) == 0;\r
+                       } else if (whingeLevel == 4) {\r
+                               indentGood = (spaceFlags & wsTab) == 0;\r
+                       }\r
+                       if (!indentGood) {\r
+                               styler.IndicatorFill(startIndicator, sc.currentPos, indicatorWhitespace, 0);\r
+                               startIndicator = sc.currentPos;\r
+                       }\r
+               }\r
+\r
+               if (sc.atLineEnd) {\r
+                       if ((sc.state == SCE_P_DEFAULT) ||\r
+                               (sc.state == SCE_P_TRIPLE) ||\r
+                               (sc.state == SCE_P_TRIPLEDOUBLE)) {\r
+                               // Perform colourisation of white space and triple quoted strings at end of each line to allow\r
+                               // tab marking to work inside white space and triple quoted strings\r
+                               sc.SetState(sc.state);\r
+                       }\r
+                       lineCurrent++;\r
+                       if ((sc.state == SCE_P_STRING) || (sc.state == SCE_P_CHARACTER)) {\r
+                               sc.ChangeState(SCE_P_STRINGEOL);\r
+                               sc.ForwardSetState(SCE_P_DEFAULT);\r
+                       }\r
+                       if (!sc.More())\r
+                               break;\r
+               }\r
+\r
+               bool needEOLCheck = false;\r
+\r
+               // Check for a state end\r
+               if (sc.state == SCE_P_OPERATOR) {\r
+                       kwLast = kwOther;\r
+                       sc.SetState(SCE_P_DEFAULT);\r
+               } else if (sc.state == SCE_P_NUMBER) {\r
+                       if (!IsAWordChar(sc.ch) &&\r
+                               !(!hexadecimal && ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) {\r
+                               sc.SetState(SCE_P_DEFAULT);\r
+                       }\r
+               } else if (sc.state == SCE_P_IDENTIFIER) {\r
+                       if ((sc.ch == '.') || (!IsAWordChar(sc.ch))) {\r
+                               char s[100];\r
+                               sc.GetCurrent(s, sizeof(s));\r
+                               int style = SCE_P_IDENTIFIER;\r
+                               if ((kwLast == kwImport) && (strcmp(s, "as") == 0)) {\r
+                                       style = SCE_P_WORD;\r
+                               } else if (keywords.InList(s)) {\r
+                                       style = SCE_P_WORD;\r
+                               } else if (kwLast == kwClass) {\r
+                                       style = SCE_P_CLASSNAME;\r
+                               } else if (kwLast == kwDef) {\r
+                                       style = SCE_P_DEFNAME;\r
+                               } else if (keywords2.InList(s)) {\r
+                                       style = SCE_P_WORD2;\r
+                               }\r
+                               sc.ChangeState(style);\r
+                               sc.SetState(SCE_P_DEFAULT);\r
+                               if (style == SCE_P_WORD) {\r
+                                       if (0 == strcmp(s, "class"))\r
+                                               kwLast = kwClass;\r
+                                       else if (0 == strcmp(s, "def"))\r
+                                               kwLast = kwDef;\r
+                                       else if (0 == strcmp(s, "import"))\r
+                                               kwLast = kwImport;\r
+                                       else\r
+                                               kwLast = kwOther;\r
+                               } else {\r
+                                       kwLast = kwOther;\r
+                               }\r
+                       }\r
+               } else if ((sc.state == SCE_P_COMMENTLINE) || (sc.state == SCE_P_COMMENTBLOCK)) {\r
+                       if (sc.ch == '\r' || sc.ch == '\n') {\r
+                               sc.SetState(SCE_P_DEFAULT);\r
+                       }\r
+               } else if (sc.state == SCE_P_DECORATOR) {\r
+                       if (!IsAWordChar(sc.ch)) {\r
+                               sc.SetState(SCE_P_DEFAULT);\r
+                       }\r
+               } else if ((sc.state == SCE_P_STRING) || (sc.state == SCE_P_CHARACTER)) {\r
+                       if (sc.ch == '\\') {\r
+                               if ((sc.chNext == '\r') && (sc.GetRelative(2) == '\n')) {\r
+                                       sc.Forward();\r
+                               }\r
+                               sc.Forward();\r
+                       } else if ((sc.state == SCE_P_STRING) && (sc.ch == '\"')) {\r
+                               sc.ForwardSetState(SCE_P_DEFAULT);\r
+                               needEOLCheck = true;\r
+                       } else if ((sc.state == SCE_P_CHARACTER) && (sc.ch == '\'')) {\r
+                               sc.ForwardSetState(SCE_P_DEFAULT);\r
+                               needEOLCheck = true;\r
+                       }\r
+               } else if (sc.state == SCE_P_TRIPLE) {\r
+                       if (sc.ch == '\\') {\r
+                               sc.Forward();\r
+                       } else if (sc.Match("\'\'\'")) {\r
+                               sc.Forward();\r
+                               sc.Forward();\r
+                               sc.ForwardSetState(SCE_P_DEFAULT);\r
+                               needEOLCheck = true;\r
+                       }\r
+               } else if (sc.state == SCE_P_TRIPLEDOUBLE) {\r
+                       if (sc.ch == '\\') {\r
+                               sc.Forward();\r
+                       } else if (sc.Match("\"\"\"")) {\r
+                               sc.Forward();\r
+                               sc.Forward();\r
+                               sc.ForwardSetState(SCE_P_DEFAULT);\r
+                               needEOLCheck = true;\r
+                       }\r
+               }\r
+\r
+               if (!indentGood && !IsASpaceOrTab(sc.ch)) {\r
+                       styler.IndicatorFill(startIndicator, sc.currentPos, indicatorWhitespace, 1);\r
+                       startIndicator = sc.currentPos;\r
+                       indentGood = true;\r
+               }\r
+\r
+               // State exit code may have moved on to end of line\r
+               if (needEOLCheck && sc.atLineEnd) {\r
+                       lineCurrent++;\r
+                       styler.IndentAmount(lineCurrent, &spaceFlags, IsPyComment);\r
+                       if (!sc.More())\r
+                               break;\r
+               }\r
+\r
+               // Check for a new state starting character\r
+               if (sc.state == SCE_P_DEFAULT) {\r
+                       if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {\r
+                               if (sc.ch == '0' && (sc.chNext == 'x' || sc.chNext == 'X')) {\r
+                                       hexadecimal = true;\r
+                               } else {\r
+                                       hexadecimal = false;\r
+                               }\r
+                               sc.SetState(SCE_P_NUMBER);\r
+                       } else if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch)) || sc.ch == '`') {\r
+                               sc.SetState(SCE_P_OPERATOR);\r
+                       } else if (sc.ch == '#') {\r
+                               sc.SetState(sc.chNext == '#' ? SCE_P_COMMENTBLOCK : SCE_P_COMMENTLINE);\r
+                       } else if (sc.ch == '@') {\r
+                               sc.SetState(SCE_P_DECORATOR);\r
+                       } else if (IsPyStringStart(sc.ch, sc.chNext, sc.GetRelative(2))) {\r
+                               unsigned int nextIndex = 0;\r
+                               sc.SetState(GetPyStringState(styler, sc.currentPos, &nextIndex));\r
+                               while (nextIndex > (sc.currentPos + 1) && sc.More()) {\r
+                                       sc.Forward();\r
+                               }\r
+                       } else if (IsAWordStart(sc.ch)) {\r
+                               sc.SetState(SCE_P_IDENTIFIER);\r
+                       }\r
+               }\r
+       }\r
+       styler.IndicatorFill(startIndicator, sc.currentPos, indicatorWhitespace, 0);\r
+       sc.Complete();\r
+}\r
+\r
+static bool IsCommentLine(int line, Accessor &styler) {\r
+       int pos = styler.LineStart(line);\r
+       int eol_pos = styler.LineStart(line + 1) - 1;\r
+       for (int i = pos; i < eol_pos; i++) {\r
+               char ch = styler[i];\r
+               if (ch == '#')\r
+                       return true;\r
+               else if (ch != ' ' && ch != '\t')\r
+                       return false;\r
+       }\r
+       return false;\r
+}\r
+\r
+static bool IsQuoteLine(int line, Accessor &styler) {\r
+       int style = styler.StyleAt(styler.LineStart(line)) & 31;\r
+       return ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE));\r
+}\r
+\r
+\r
+static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unused*/,\r
+                      WordList *[], Accessor &styler) {\r
+       const int maxPos = startPos + length;\r
+       const int maxLines = styler.GetLine(maxPos - 1);             // Requested last line\r
+       const int docLines = styler.GetLine(styler.Length() - 1);  // Available last line\r
+       const bool foldComment = styler.GetPropertyInt("fold.comment.python") != 0;\r
+       const bool foldQuotes = styler.GetPropertyInt("fold.quotes.python") != 0;\r
+\r
+       // Backtrack to previous non-blank line so we can determine indent level\r
+       // for any white space lines (needed esp. within triple quoted strings)\r
+       // and so we can fix any preceding fold level (which is why we go back\r
+       // at least one line in all cases)\r
+       int spaceFlags = 0;\r
+       int lineCurrent = styler.GetLine(startPos);\r
+       int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);\r
+       while (lineCurrent > 0) {\r
+               lineCurrent--;\r
+               indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);\r
+               if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) &&\r
+                       (!IsCommentLine(lineCurrent, styler)) &&\r
+                       (!IsQuoteLine(lineCurrent, styler)))\r
+                       break;\r
+       }\r
+       int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;\r
+\r
+       // Set up initial loop state\r
+       startPos = styler.LineStart(lineCurrent);\r
+       int prev_state = SCE_P_DEFAULT & 31;\r
+       if (lineCurrent >= 1)\r
+               prev_state = styler.StyleAt(startPos - 1) & 31;\r
+       int prevQuote = foldQuotes && ((prev_state == SCE_P_TRIPLE) || (prev_state == SCE_P_TRIPLEDOUBLE));\r
+       int prevComment = 0;\r
+       if (lineCurrent >= 1)\r
+               prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler);\r
+\r
+       // Process all characters to end of requested range or end of any triple quote\r
+       // or comment that hangs over the end of the range.  Cap processing in all cases\r
+       // to end of document (in case of unclosed quote or comment at end).\r
+       while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevQuote || prevComment)) {\r
+\r
+               // Gather info\r
+               int lev = indentCurrent;\r
+               int lineNext = lineCurrent + 1;\r
+               int indentNext = indentCurrent;\r
+               int quote = false;\r
+               if (lineNext <= docLines) {\r
+                       // Information about next line is only available if not at end of document\r
+                       indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);\r
+                       int style = styler.StyleAt(styler.LineStart(lineNext)) & 31;\r
+                       quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE));\r
+               }\r
+               const int quote_start = (quote && !prevQuote);\r
+               const int quote_continue = (quote && prevQuote);\r
+               const int comment = foldComment && IsCommentLine(lineCurrent, styler);\r
+               const int comment_start = (comment && !prevComment && (lineNext <= docLines) &&\r
+                                          IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE));\r
+               const int comment_continue = (comment && prevComment);\r
+               if ((!quote || !prevQuote) && !comment)\r
+                       indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;\r
+               if (quote)\r
+                       indentNext = indentCurrentLevel;\r
+               if (indentNext & SC_FOLDLEVELWHITEFLAG)\r
+                       indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;\r
+\r
+               if (quote_start) {\r
+                       // Place fold point at start of triple quoted string\r
+                       lev |= SC_FOLDLEVELHEADERFLAG;\r
+               } else if (quote_continue || prevQuote) {\r
+                       // Add level to rest of lines in the string\r
+                       lev = lev + 1;\r
+               } else if (comment_start) {\r
+                       // Place fold point at start of a block of comments\r
+                       lev |= SC_FOLDLEVELHEADERFLAG;\r
+               } else if (comment_continue) {\r
+                       // Add level to rest of lines in the block\r
+                       lev = lev + 1;\r
+               }\r
+\r
+               // Skip past any blank lines for next indent level info; we skip also\r
+               // comments (all comments, not just those starting in column 0)\r
+               // which effectively folds them into surrounding code rather\r
+               // than screwing up folding.\r
+\r
+               while (!quote &&\r
+                       (lineNext < docLines) &&\r
+                       ((indentNext & SC_FOLDLEVELWHITEFLAG) ||\r
+                        (lineNext <= docLines && IsCommentLine(lineNext, styler)))) {\r
+\r
+                       lineNext++;\r
+                       indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);\r
+               }\r
+\r
+               const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK;\r
+               const int levelBeforeComments = Platform::Maximum(indentCurrentLevel,levelAfterComments);\r
+\r
+               // Now set all the indent levels on the lines we skipped\r
+               // Do this from end to start.  Once we encounter one line\r
+               // which is indented more than the line after the end of\r
+               // the comment-block, use the level of the block before\r
+\r
+               int skipLine = lineNext;\r
+               int skipLevel = levelAfterComments;\r
+\r
+               while (--skipLine > lineCurrent) {\r
+                       int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL);\r
+\r
+                       if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments)\r
+                               skipLevel = levelBeforeComments;\r
+\r
+                       int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;\r
+\r
+                       styler.SetLevel(skipLine, skipLevel | whiteFlag);\r
+               }\r
+\r
+               // Set fold header on non-quote/non-comment line\r
+               if (!quote && !comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) {\r
+                       if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))\r
+                               lev |= SC_FOLDLEVELHEADERFLAG;\r
+               }\r
+\r
+               // Keep track of triple quote and block comment state of previous line\r
+               prevQuote = quote;\r
+               prevComment = comment_start || comment_continue;\r
+\r
+               // Set fold level for this line and move to next line\r
+               styler.SetLevel(lineCurrent, lev);\r
+               indentCurrent = indentNext;\r
+               lineCurrent = lineNext;\r
+       }\r
+\r
+       // NOTE: Cannot set level of last line here because indentCurrent doesn't have\r
+       // header flag set; the loop above is crafted to take care of this case!\r
+       //styler.SetLevel(lineCurrent, indentCurrent);\r
+}\r
+\r
+static const char * const pythonWordListDesc[] = {\r
+       "Keywords",\r
+       "Highlighted identifiers",\r
+       0\r
+};\r
+\r
+LexerModule lmPython(SCLEX_PYTHON, ColourisePyDoc, "python", FoldPyDoc,\r
+                                        pythonWordListDesc);\r