diff options
| -rw-r--r-- | src/LexPython.cxx | 81 | 
1 files changed, 51 insertions, 30 deletions
| diff --git a/src/LexPython.cxx b/src/LexPython.cxx index ae5836b0b..221859035 100644 --- a/src/LexPython.cxx +++ b/src/LexPython.cxx @@ -270,14 +270,15 @@ static bool IsQuoteLine(int line, Accessor &styler) {  	return ((style == SCE_P_TRIPLE) || (style== SCE_P_TRIPLEDOUBLE));  } +  static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unused*/,  					WordList *[], Accessor &styler) { -	int maxPos = startPos + length; -	int maxLines = styler.GetLine(maxPos-1); -						 -	bool foldComment = styler.GetPropertyInt("fold.comment.python"); -	bool foldQuotes = styler.GetPropertyInt("fold.quotes.python"); - +	const int maxPos = startPos + length; +	const int maxLines = styler.GetLine(maxPos-1);             // Requested last line +	const int docLines = styler.GetLine(styler.Length() - 1);  // Available last line +	const bool foldComment = styler.GetPropertyInt("fold.comment.python"); +	const bool foldQuotes = styler.GetPropertyInt("fold.quotes.python"); +	  	// Backtrack to previous non-blank line so we can determine indent level  	// for any white space lines (needed esp. within triple quoted strings)  	// and so we can fix any preceding fold level (which is why we go back @@ -295,8 +296,8 @@ static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unuse  	}  	int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK; +	// Set up initial loop state  	startPos = styler.LineStart(lineCurrent); -	// Set up initial state  	int prev_state = SCE_P_DEFAULT & 31;  	if (lineCurrent >= 1)  		prev_state = styler.StyleAt(startPos-1) & 31; @@ -306,21 +307,27 @@ static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unuse  		prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler);  	// Process all characters to end of requested range or end of any triple quote -	// or comment that hangs over the end of the range -	while ((lineCurrent <= maxLines) || prevQuote || prevComment) { +	// or comment that hangs over the end of the range.  Cap processing in all cases +	// to end of document (in case of unclosed quote or comment at end). +	while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevQuote || prevComment)) {  		// Gather info  		int lev = indentCurrent;  		int lineNext = lineCurrent + 1; -		int style = styler.StyleAt(styler.LineStart(lineNext)) & 31; -		int indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); -		int quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style== SCE_P_TRIPLEDOUBLE)); -		int quote_start = (quote && !prevQuote); -		int quote_continue = (quote && prevQuote); -		int comment = foldComment && IsCommentLine(lineCurrent, styler); -		int comment_start = (comment && !prevComment &&  +		int indentNext = indentCurrent; +		int quote = false; +		if (lineNext <= docLines) { +			// Information about next line is only available if not at end of document +			indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL); +			int style = styler.StyleAt(styler.LineStart(lineNext)) & 31; +			quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style== SCE_P_TRIPLEDOUBLE)); +		} +		const int quote_start = (quote && !prevQuote); +		const int quote_continue = (quote && prevQuote); +		const int comment = foldComment && IsCommentLine(lineCurrent, styler); +		const int comment_start = (comment && !prevComment && (lineNext <= docLines) &&  			IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE)); -		int comment_continue = (comment && prevComment); +		const int comment_continue = (comment && prevComment);  		if ((!quote || !prevQuote) && !comment)  			indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;  		if (quote) @@ -343,22 +350,35 @@ static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unuse  		}  		// Skip past any blank lines for next indent level info; we skip also comments -		// starting in column 0 which effectively folds them into surrounding code -		// rather than screwing up folding.  Then set indent level on the lines -		// we skipped to be same as maximum of current and next indent.  This approach -		// does a reasonable job of collapsing white space into surrounding code -		// without getting confused by white space at the start of an indented level. +		// starting in column 0 which effectively folds them into surrounding code rather +		// than screwing up folding. +		const int saveIndentNext = indentNext;  		while (!quote && -		       ((indentNext & SC_FOLDLEVELWHITEFLAG) || styler[styler.LineStart(lineNext)] == '#') && -		       (lineNext < maxLines)) { -			int level = Platform::Maximum(indentCurrent, indentNext); -			if (indentNext & SC_FOLDLEVELWHITEFLAG) -				level = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel; -			styler.SetLevel(lineNext, level); +		       (lineNext < docLines) && +		       ((indentNext & SC_FOLDLEVELWHITEFLAG) ||  +		        (lineNext <= docLines && styler[styler.LineStart(lineNext)] == '#'))) { +  			lineNext++;  			indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);  		} +		// Next compute max indent level of current line and next non-blank line. +		// This is the level to which we set all the intervening blank or comment lines. +		const int skip_level = Platform::Maximum(indentCurrentLevel, +		                                   indentNext & SC_FOLDLEVELNUMBERMASK); +		 +		// Now set all the indent levels on the lines we skipped +		int skipLine = lineCurrent + 1; +		int skipIndentNext = saveIndentNext; +		while (skipLine < lineNext) { +			int skipLineLevel = skip_level; +			if (skipIndentNext & SC_FOLDLEVELWHITEFLAG) +				skipLineLevel = SC_FOLDLEVELWHITEFLAG | skipLineLevel; +			styler.SetLevel(skipLine, skipLineLevel); +			skipLine++; +			skipIndentNext = styler.IndentAmount(skipLine, &spaceFlags, NULL); +		} +		  		// Set fold header on non-quote/non-comment line  		if (!quote && !comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) {  			if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) @@ -375,8 +395,9 @@ static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unuse  		lineCurrent = lineNext;  	} -	// Make sure last line indent level is set too -	styler.SetLevel(lineCurrent, indentCurrent); +	// NOTE: Cannot set level of last line here because indentCurrent doesn't have +	// header flag set; the loop above is crafted to take care of this case! +	//styler.SetLevel(lineCurrent, indentCurrent);  }  LexerModule lmPython(SCLEX_PYTHON, ColourisePyDoc, "python", FoldPyDoc); | 
