diff options
| -rw-r--r-- | src/highlighter.cc | 123 | ||||
| -rw-r--r-- | src/highlighter.h | 3 | ||||
| -rw-r--r-- | src/mainwin.cc | 2 | 
3 files changed, 95 insertions, 33 deletions
| diff --git a/src/highlighter.cc b/src/highlighter.cc index 121d751..7f6b5f9 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -24,33 +24,78 @@   *   */ -// based on Syntax Highlight code by Chris Olah +/* + Syntax Highlighter for OpenSCAD + based on Syntax Highlight code by Christopher Olah + + Speed Note: setFormat() is very slow, making 'full re-highlight' impractical. + Thus QT only updates 'blocks' (usually lines). -/* test suite + Test suite:  1. action: open example001, remove first {, hit f5 -   expected result: red highlight appears on last }, cursor moves there +   expected result: error highlight appears on last }, cursor moves there     action: replace first {, hit f5 -   expected result: red highlight disappears +   expected result: error highlight disappears + +1a. action: open example001, remove first {, hit f5 +   expected result: error highlight appears on last }, cursor moves there +   action: replace first { with the letter 'P', hit f5 +   expected result: error highlight on last } disappears, appears on elsewhere +   action: replace first {, hit f5 +   expected result: error highlight disappears + +2. action: type a=b into any file +   expected result: '=' is highlighted with its appropriate format -2. action: type a=b -   expected result: '=' is highlighted as appropriate +2a. action: type a=b=c=d=e=f= into any file +   expected result: each '=' is highlighted with its appropriate format -3. action: open example001, put '===' after first ; -   expected result: red highlight appears in === +3. action: open example001, put '===' after first ; hit f5 +   expected result: error highlight appears in ===     action: remove '===' -   expected result: red highlight disappears +   expected result: error highlight disappears + +3a. action: open example001, put '=' after first ; hit f5 +   expected result: error highlight appears +   action: remove '=' +   expected result: error highlight disappears + +3b. action: open example001, put '=' after first { +   expected result: error highlight appears +   action: remove '=' +   expected result: error highlight disappears + +3c. action: open example001, replace first { with '=' +   expected result: error highlight appears +   action: remove '=', replace with { +   expected result: error highlight disappears  4. action: open example001, remove last ';' but not trailing whitespace/\n -   expected result: red highlight appears on last line +   expected result: error highlight appears somewhere near end     action: replace last ';' -   expected result: red highlight disappears +   expected result: error highlight disappears  5. action: open file, type in a multi-line comment     expected result: multiline comment should be highlighted appropriately  6. action: open example001, put a single '=' after first { -   expected result: red highlight of '=' you added +   expected result: error highlight of '=' you added + +7. action: open example001, remove first ')' +   expected result: highlight should appear appropriately + +8. action: create a large file (50,000 lines). eg at a bash prompt: +     for i in {1..1000}; do cat examples/example001.scad >> test5k.scad ; done +   action: open file in openscad +   expected result: there should not be a slowdown due to highlighting +   action: scroll to bottom, put '=' after last ; +   expected result: there should be a highlight, and a report of syntax error +   action: comment out the highlighter code from mainwin.cc, recompile, put '=' after last ; +   expected result: there should be almost no difference in speed + +9. action: open any file, and hold down 'f5' key to repeatedly reparse +   expected result: no crashing!  */ @@ -61,9 +106,6 @@  Highlighter::Highlighter(QTextDocument *parent)  		: QSyntaxHighlighter(parent)  { -	QMap<QString,QStringList> tokentypes; -	QMap<QString,QTextCharFormat> typeformats; -  	tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";";  	typeformats["operator"].setForeground(Qt::blue); @@ -111,19 +153,32 @@ Highlighter::Highlighter(QTextDocument *parent)  	// format tweaks  	formatMap[ "%" ].setFontWeight(QFont::Bold); -	separators << tokentypes["operator"]; -	separators << "(" << ")" << "[" << "]"; -  	lastErrorBlock = parent->begin();  }  void Highlighter::highlightError(int error_pos)  {  	QTextBlock err_block = document()->findBlock(error_pos); -	std::cout << "error pos: "  << error_pos << " doc len: " << document()->characterCount() << "\n"; +	//std::cout << "error pos: "  << error_pos << " doc len: " << document()->characterCount() << "\n";  	errorPos = error_pos;  	errorState = true; -	//if (errorPos == document()->characterCount()-1) errorPos--; + +	while (err_block.text().remove(QRegExp("\\s+")).size()==0) { +		//std::cout << "special case - errors at end of file w whitespace\n"; +		err_block = err_block.previous(); +		errorPos = err_block.position()+err_block.length() - 2; +	} +	if ( errorPos == document()->characterCount()-1 ) { +		errorPos--; +	} + +	int block_last_pos = err_block.position() + err_block.length() - 1; +	if ( errorPos == block_last_pos ) { +		errorPos--; +		//std::cout << "special case - errors at ends of certain blocks\n"; +	} +	err_block = document()->findBlock(errorPos); +  	rehighlightBlock( err_block ); // QT 4.6  	errorState = false;  	lastErrorBlock = err_block; @@ -131,36 +186,38 @@ void Highlighter::highlightError(int error_pos)  void Highlighter::unhighlightLastError()  { -	rehighlightBlock( lastErrorBlock ); +	rehighlightBlock( lastErrorBlock ); // QT 4.6  }  #include <iostream>  void Highlighter::highlightBlock(const QString &text)  { -	std::cout << "block[" << currentBlock().position() << ":" -	  << currentBlock().length() + currentBlock().position() << "]" -	  << ", err:" << errorPos << ", text:'" << text.toStdString() << "'\n"; +	int block_first_pos = currentBlock().position(); +	int block_last_pos = block_first_pos + currentBlock().length() - 1; +	//std::cout << "block[" << block_first_pos << ":" << block_last_pos << "]" +	//  << ", err:" << errorPos << "," << errorState +	//  << ", text:'" << text.toStdString() << "'\n";  	// Split the block into pieces and highlight each as appropriate  	QString newtext = text; -	QStringList::iterator sep, token; -	int tokindex = -1; // deals w duplicate tokens in a single block -	for ( sep = separators.begin(); sep!=separators.end(); ++sep ) { -		// so a=b will have '=' highlighted -		newtext = newtext.replace( *sep, " " + *sep + " "); +	QStringList splitHelpers; +	QStringList::iterator sh, token; +	int tokindex = -1; // tokindex helps w duplicate tokens in a single block +	splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]"; +	for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) { +		// so "a+b" is treated as "a + b" and formatted +		newtext = newtext.replace( *sh, " " + *sh + " ");  	}  	QStringList tokens = newtext.split(QRegExp("\\s"));  	for ( token = tokens.begin(); token!=tokens.end(); ++token ){  		if ( formatMap.contains( *token ) ) {  			tokindex = text.indexOf( *token, tokindex+1 ); -			// Speed note: setFormat() is the big slowdown in all of this code  			setFormat( tokindex, token->size(), formatMap[ *token ]);  			// std::cout  << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n";  		}  	}  	// Quoting and Comments. -	// fixme multiline coments dont work  	state_e state = (state_e) previousBlockState();  	for (int n = 0; n < text.size(); ++n){  		if (state == NORMAL){ @@ -188,10 +245,12 @@ void Highlighter::highlightBlock(const QString &text)  			}  		}  	} +	setCurrentBlockState((int) state);  	// Highlight an error. Do it last to 'overwrite' other formatting.  	if (errorState) { -		setFormat( errorPos - currentBlock().position() - 1, 1, errorFormat); +		setFormat( errorPos - block_first_pos, 1, errorFormat);  	} +  } diff --git a/src/highlighter.h b/src/highlighter.h index 043c34e..a0ed0da 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -17,7 +17,8 @@ private:  	QTextBlock lastErrorBlock;  	int errorPos = -1;  	bool errorState = false; -	QStringList separators; +  QMap<QString,QStringList> tokentypes; +  QMap<QString,QTextCharFormat> typeformats;  };  #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index 644cc2e..8834b75 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -1038,6 +1038,7 @@ bool MainWindow::compileTopLevelDocument(bool reload)  		if (!animate_panel->isVisible()) {  			if (!this->root_module) { +				highlighter->unhighlightLastError();  				QTextCursor cursor = editor->textCursor();  				cursor.setPosition( parser_error_pos );  				editor->setTextCursor( cursor ); @@ -1046,6 +1047,7 @@ bool MainWindow::compileTopLevelDocument(bool reload)  				highlighter->unhighlightLastError();  			}  		} +  	}  	bool changed = shouldcompiletoplevel; | 
