]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexPython.cxx
221859035e353cca2f3e6377be2c48fadf5bc8c2
   1 // Scintilla source code edit control 
   2 /** @file LexPython.cxx 
   5 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> 
   6 // The License.txt file describes the conditions under which this software may be distributed. 
  18 #include "StyleContext.h" 
  20 #include "Scintilla.h" 
  23 enum kwType 
{ kwOther
, kwClass
, kwDef
, kwImport 
}; 
  25 static bool IsPyComment(Accessor 
&styler
, int pos
, int len
) { 
  26         return len
>0 && styler
[pos
]=='#'; 
  29 static bool IsPyStringStart(int ch
, int chNext
, int chNext2
) { 
  30         if (ch 
== '\'' || ch 
== '"') 
  32         if (ch 
== 'u' || ch 
== 'U') { 
  33                 if (chNext 
== '"' || chNext 
== '\'') 
  35                 if ((chNext 
== 'r' || chNext 
== 'R') && (chNext2 
== '"' || chNext2 
== '\'')) 
  38         if ((ch 
== 'r' || ch 
== 'R') && (chNext 
== '"' || chNext 
== '\'')) 
  44 /* Return the state to use for the string starting at i; *nextIndex will be set to the first index following the quote(s) */ 
  45 static int GetPyStringState(Accessor 
&styler
, int i
, int *nextIndex
) { 
  46         char ch 
= styler
.SafeGetCharAt(i
); 
  47         char chNext 
= styler
.SafeGetCharAt(i 
+ 1); 
  49         // Advance beyond r, u, or ur prefix, but bail if there are any unexpected chars 
  50         if (ch 
== 'r' || ch 
== 'R') { 
  52                 ch 
= styler
.SafeGetCharAt(i
); 
  53                 chNext 
= styler
.SafeGetCharAt(i 
+ 1); 
  55         else if (ch 
== 'u' || ch 
== 'U') { 
  56                 if (chNext 
== 'r' || chNext 
== 'R') 
  60                 ch 
= styler
.SafeGetCharAt(i
); 
  61                 chNext 
= styler
.SafeGetCharAt(i 
+ 1); 
  64         if (ch 
!= '"' && ch 
!= '\'') { 
  69         if (ch 
== chNext 
&& ch 
== styler
.SafeGetCharAt(i 
+ 2)) { 
  73                         return SCE_P_TRIPLEDOUBLE
; 
  82                         return SCE_P_CHARACTER
; 
  86 inline bool IsAWordChar(int  ch
) { 
  87         return (ch 
< 0x80) && (isalnum(ch
) || ch 
== '.' || ch 
== '_'); 
  90 inline bool IsAWordStart(int ch
) { 
  91         return (ch 
< 0x80) && (isalnum(ch
) || ch 
== '_'); 
  94 static void ColourisePyDoc(unsigned int startPos
, int length
, int initStyle
, 
  95                                                    WordList 
*keywordlists
[], Accessor 
&styler
) { 
  97         int endPos 
= startPos 
+ length
; 
  99         // Backtrack to previous line in case need to fix its tab whinging 
 100         int lineCurrent 
= styler
.GetLine(startPos
); 
 102                 if (lineCurrent 
> 0) { 
 103                         startPos 
= styler
.LineStart(lineCurrent
-1); 
 105                                 initStyle 
= SCE_P_DEFAULT
; 
 107                                 initStyle 
= styler
.StyleAt(startPos
-1); 
 111         WordList 
&keywords 
= *keywordlists
[0]; 
 113         const int whingeLevel 
= styler
.GetPropertyInt("tab.timmy.whinge.level"); 
 115         initStyle 
= initStyle 
& 31; 
 116         if (initStyle 
== SCE_P_STRINGEOL
) { 
 117                 initStyle 
= SCE_P_DEFAULT
; 
 120         kwType kwLast 
= kwOther
; 
 122         styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsPyComment
); 
 124         // Python uses a different mask because bad indentation is marked by oring with 32 
 125         StyleContext 
sc(startPos
, endPos
-startPos
, initStyle
, styler
, 0x7f); 
 127         for (; sc
.More(); sc
.Forward()) { 
 129                 if (sc
.atLineStart
) { 
 130                         const char chBad 
= static_cast<char>(64); 
 131                         const char chGood 
= static_cast<char>(0); 
 132                         char chFlags 
= chGood
; 
 133                         if (whingeLevel 
== 1) { 
 134                                 chFlags 
= (spaceFlags 
& wsInconsistent
) ? chBad 
: chGood
; 
 135                         } else if (whingeLevel 
== 2) { 
 136                                 chFlags 
= (spaceFlags 
& wsSpaceTab
) ? chBad 
: chGood
; 
 137                         } else if (whingeLevel 
== 3) { 
 138                                 chFlags 
= (spaceFlags 
& wsSpace
) ? chBad 
: chGood
; 
 139                         } else if (whingeLevel 
== 4) { 
 140                                 chFlags 
= (spaceFlags 
& wsTab
) ? chBad 
: chGood
; 
 142                         styler
.SetFlags(chFlags
, static_cast<char>(sc
.state
)); 
 146                         if ((sc
.state 
== SCE_P_DEFAULT
) ||  
 147                                 (sc
.state 
== SCE_P_TRIPLE
) ||  
 148                                 (sc
.state 
== SCE_P_TRIPLEDOUBLE
)) { 
 149                                 // Perform colourisation of white space and triple quoted strings at end of each line to allow 
 150                                 // tab marking to work inside white space and triple quoted strings 
 151                                 sc
.ForwardSetState(sc
.state
); 
 154                         styler
.IndentAmount(lineCurrent
, &spaceFlags
, IsPyComment
); 
 155                         if ((sc
.state 
== SCE_P_STRING
) || (sc
.state 
== SCE_P_CHARACTER
)) { 
 156                                 sc
.ChangeState(SCE_P_STRINGEOL
); 
 157                                 sc
.ForwardSetState(SCE_P_DEFAULT
); 
 161                 // Check for a state end 
 162                 if (sc
.state 
== SCE_P_OPERATOR
) { 
 164                         sc
.SetState(SCE_C_DEFAULT
); 
 165                 } else if (sc
.state 
== SCE_P_NUMBER
) { 
 166                         if (!IsAWordChar(sc
.ch
)) { 
 167                                 sc
.SetState(SCE_P_DEFAULT
); 
 169                 } else if (sc
.state 
== SCE_P_WORD
) { 
 170                         if ((sc
.ch 
== '.') || (!IsAWordChar(sc
.ch
))) { 
 172                                 sc
.GetCurrent(s
, sizeof(s
)); 
 173                                 int style 
= SCE_P_IDENTIFIER
; 
 174                                 if ((kwLast 
== kwImport
) && (strcmp(s
, "as") == 0)) { 
 176                                 } else if (keywords
.InList(s
)) { 
 178                                 } else if (kwLast 
== kwClass
) { 
 179                                         style 
= SCE_P_CLASSNAME
; 
 180                                 } else if (kwLast 
== kwDef
) { 
 181                                         style 
= SCE_P_DEFNAME
; 
 183                                 sc
.ChangeState(style
); 
 184                                 sc
.SetState(SCE_P_DEFAULT
); 
 185                                 if (style 
== SCE_P_WORD
) { 
 186                                         if (0 == strcmp(s
, "class")) 
 188                                         else if (0 == strcmp(s
, "def")) 
 190                                         else if (0 == strcmp(s
, "import")) 
 194                                 } else if (style 
== SCE_P_CLASSNAME
) { 
 196                                 } else if (style 
== SCE_P_DEFNAME
) { 
 200                 } else if ((sc
.state 
== SCE_P_COMMENTLINE
) || (sc
.state 
== SCE_P_COMMENTBLOCK
)) { 
 201                         if (sc
.ch 
== '\r' || sc
.ch 
== '\n') { 
 202                                 sc
.SetState(SCE_P_DEFAULT
); 
 204                 } else if ((sc
.state 
== SCE_P_STRING
) || (sc
.state 
== SCE_P_CHARACTER
)) { 
 206                                 if ((sc
.chNext 
== '\r') && (sc
.GetRelative(2) == '\n')) { 
 210                         } else if ((sc
.state 
== SCE_P_STRING
) && (sc
.ch 
== '\"')) { 
 211                                 sc
.ForwardSetState(SCE_P_DEFAULT
); 
 212                         } else if ((sc
.state 
== SCE_P_CHARACTER
) && (sc
.ch 
== '\'')) { 
 213                                 sc
.ForwardSetState(SCE_P_DEFAULT
); 
 215                 } else if (sc
.state 
== SCE_P_TRIPLE
) { 
 218                         } else if (sc
.Match("\'\'\'")) { 
 221                                 sc
.ForwardSetState(SCE_P_DEFAULT
); 
 223                 } else if (sc
.state 
== SCE_P_TRIPLEDOUBLE
) { 
 226                         } else if (sc
.Match("\"\"\"")) { 
 229                                 sc
.ForwardSetState(SCE_P_DEFAULT
); 
 233                 // Check for a new state starting character 
 234                 if (sc
.state 
== SCE_P_DEFAULT
) { 
 235                         if (isascii(sc
.ch
) && isoperator(static_cast<char>(sc
.ch
)) || sc
.ch 
== '`') { 
 236                                 sc
.SetState(SCE_P_OPERATOR
); 
 237                         } else if (sc
.ch 
== '#') { 
 238                                 sc
.SetState(sc
.chNext 
== '#' ? SCE_P_COMMENTBLOCK 
: SCE_P_COMMENTLINE
); 
 239                         } else if (IsADigit(sc
.ch
) || (sc
.ch 
== '.' && IsADigit(sc
.chNext
))) { 
 240                                 sc
.SetState(SCE_P_NUMBER
); 
 241                         } else if (IsPyStringStart(sc
.ch
, sc
.chNext
, sc
.GetRelative(2))) { 
 243                                 sc
.SetState(GetPyStringState(styler
, sc
.currentPos
, &nextIndex
)); 
 244                                 while (nextIndex 
> (sc
.currentPos
+1)) { 
 247                         } else if (IsAWordStart(sc
.ch
)) { 
 248                                 sc
.SetState(SCE_P_WORD
); 
 255 static bool IsCommentLine(int line
, Accessor 
&styler
) { 
 256         int pos 
= styler
.LineStart(line
); 
 257         int eol_pos 
= styler
.LineStart(line
+1) - 1; 
 258         for (int i 
= pos
; i 
< eol_pos
; i
++) { 
 262                 else if (ch 
!= ' ' && ch 
!= '\t') 
 268 static bool IsQuoteLine(int line
, Accessor 
&styler
) { 
 269         int style 
= styler
.StyleAt(styler
.LineStart(line
)) & 31; 
 270         return ((style 
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
)); 
 274 static void FoldPyDoc(unsigned int startPos
, int length
, int /*initStyle - unused*/, 
 275                                         WordList 
*[], Accessor 
&styler
) { 
 276         const int maxPos 
= startPos 
+ length
; 
 277         const int maxLines 
= styler
.GetLine(maxPos
-1);             // Requested last line 
 278         const int docLines 
= styler
.GetLine(styler
.Length() - 1);  // Available last line 
 279         const bool foldComment 
= styler
.GetPropertyInt("fold.comment.python"); 
 280         const bool foldQuotes 
= styler
.GetPropertyInt("fold.quotes.python"); 
 282         // Backtrack to previous non-blank line so we can determine indent level 
 283         // for any white space lines (needed esp. within triple quoted strings) 
 284         // and so we can fix any preceding fold level (which is why we go back 
 285         // at least one line in all cases) 
 287         int lineCurrent 
= styler
.GetLine(startPos
); 
 288         int indentCurrent 
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
); 
 289         while (lineCurrent 
> 0) { 
 291                 indentCurrent 
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
); 
 292                 if (!(indentCurrent 
& SC_FOLDLEVELWHITEFLAG
) && 
 293                         (!IsCommentLine(lineCurrent
, styler
)) && 
 294                         (!IsQuoteLine(lineCurrent
, styler
))) 
 297         int indentCurrentLevel 
= indentCurrent 
& SC_FOLDLEVELNUMBERMASK
; 
 299         // Set up initial loop state 
 300         startPos 
= styler
.LineStart(lineCurrent
); 
 301         int prev_state 
= SCE_P_DEFAULT 
& 31; 
 302         if (lineCurrent 
>= 1) 
 303                 prev_state 
= styler
.StyleAt(startPos
-1) & 31; 
 304         int prevQuote 
= foldQuotes 
&& ((prev_state 
== SCE_P_TRIPLE
) || (prev_state 
== SCE_P_TRIPLEDOUBLE
)); 
 306         if (lineCurrent 
>= 1) 
 307                 prevComment 
= foldComment 
&& IsCommentLine(lineCurrent 
- 1, styler
); 
 309         // Process all characters to end of requested range or end of any triple quote 
 310         // or comment that hangs over the end of the range.  Cap processing in all cases 
 311         // to end of document (in case of unclosed quote or comment at end). 
 312         while ((lineCurrent 
<= docLines
) && ((lineCurrent 
<= maxLines
) || prevQuote 
|| prevComment
)) { 
 315                 int lev 
= indentCurrent
; 
 316                 int lineNext 
= lineCurrent 
+ 1; 
 317                 int indentNext 
= indentCurrent
; 
 319                 if (lineNext 
<= docLines
) { 
 320                         // Information about next line is only available if not at end of document 
 321                         indentNext 
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
); 
 322                         int style 
= styler
.StyleAt(styler
.LineStart(lineNext
)) & 31; 
 323                         quote 
= foldQuotes 
&& ((style 
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
)); 
 325                 const int quote_start 
= (quote 
&& !prevQuote
); 
 326                 const int quote_continue 
= (quote 
&& prevQuote
); 
 327                 const int comment 
= foldComment 
&& IsCommentLine(lineCurrent
, styler
); 
 328                 const int comment_start 
= (comment 
&& !prevComment 
&& (lineNext 
<= docLines
) && 
 329                         IsCommentLine(lineNext
, styler
) && (lev 
> SC_FOLDLEVELBASE
)); 
 330                 const int comment_continue 
= (comment 
&& prevComment
); 
 331                 if ((!quote 
|| !prevQuote
) && !comment
) 
 332                         indentCurrentLevel 
= indentCurrent 
& SC_FOLDLEVELNUMBERMASK
; 
 334                         indentNext 
= indentCurrentLevel
; 
 335                 if (indentNext 
& SC_FOLDLEVELWHITEFLAG
) 
 336                         indentNext 
= SC_FOLDLEVELWHITEFLAG 
| indentCurrentLevel
; 
 339                         // Place fold point at start of triple quoted string 
 340                         lev 
|= SC_FOLDLEVELHEADERFLAG
; 
 341                 } else if (quote_continue 
|| prevQuote
) { 
 342                         // Add level to rest of lines in the string 
 344                 } else if (comment_start
) { 
 345                         // Place fold point at start of a block of comments 
 346                         lev 
|= SC_FOLDLEVELHEADERFLAG
; 
 347                 } else if (comment_continue
) { 
 348                         // Add level to rest of lines in the block 
 352                 // Skip past any blank lines for next indent level info; we skip also comments 
 353                 // starting in column 0 which effectively folds them into surrounding code rather 
 354                 // than screwing up folding. 
 355                 const int saveIndentNext 
= indentNext
; 
 357                        (lineNext 
< docLines
) && 
 358                        ((indentNext 
& SC_FOLDLEVELWHITEFLAG
) ||  
 359                         (lineNext 
<= docLines 
&& styler
[styler
.LineStart(lineNext
)] == '#'))) { 
 362                         indentNext 
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
); 
 365                 // Next compute max indent level of current line and next non-blank line. 
 366                 // This is the level to which we set all the intervening blank or comment lines. 
 367                 const int skip_level 
= Platform::Maximum(indentCurrentLevel
, 
 368                                                    indentNext 
& SC_FOLDLEVELNUMBERMASK
); 
 370                 // Now set all the indent levels on the lines we skipped 
 371                 int skipLine 
= lineCurrent 
+ 1; 
 372                 int skipIndentNext 
= saveIndentNext
; 
 373                 while (skipLine 
< lineNext
) { 
 374                         int skipLineLevel 
= skip_level
; 
 375                         if (skipIndentNext 
& SC_FOLDLEVELWHITEFLAG
) 
 376                                 skipLineLevel 
= SC_FOLDLEVELWHITEFLAG 
| skipLineLevel
; 
 377                         styler
.SetLevel(skipLine
, skipLineLevel
); 
 379                         skipIndentNext 
= styler
.IndentAmount(skipLine
, &spaceFlags
, NULL
); 
 382                 // Set fold header on non-quote/non-comment line 
 383                 if (!quote 
&& !comment 
&& !(indentCurrent 
& SC_FOLDLEVELWHITEFLAG
) ) { 
 384                         if ((indentCurrent 
& SC_FOLDLEVELNUMBERMASK
) < (indentNext 
& SC_FOLDLEVELNUMBERMASK
)) 
 385                                 lev 
|= SC_FOLDLEVELHEADERFLAG
; 
 388                 // Keep track of triple quote and block comment state of previous line 
 390                 prevComment 
= comment_start 
|| comment_continue
; 
 392                 // Set fold level for this line and move to next line 
 393                 styler
.SetLevel(lineCurrent
, lev
); 
 394                 indentCurrent 
= indentNext
; 
 395                 lineCurrent 
= lineNext
; 
 398         // NOTE: Cannot set level of last line here because indentCurrent doesn't have 
 399         // header flag set; the loop above is crafted to take care of this case! 
 400         //styler.SetLevel(lineCurrent, indentCurrent); 
 403 LexerModule 
lmPython(SCLEX_PYTHON
, ColourisePyDoc
, "python", FoldPyDoc
);