From a82651de310e4aedf7a634581e6369f528fb649c Mon Sep 17 00:00:00 2001 From: don bright Date: Tue, 8 Jan 2013 20:07:28 -0600 Subject: remove QCodeEditor inspired by Giles Bathgates Jan 7 2012 email to list diff --git a/setenv_mac-clang.sh b/setenv_mac-clang.sh index 2bc9234..0dcc51f 100644 --- a/setenv_mac-clang.sh +++ b/setenv_mac-clang.sh @@ -4,8 +4,7 @@ export QMAKESPEC=unsupported/macx-clang #export OPENCSGDIR=$PWD/../OpenCSG-1.3.0 #export CGALDIR=$PWD/../install/CGAL-3.6 -#export QCODEEDITDIR=$PWD/../qcodeedit-2.2.3/install -#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib:$QCODEEDITDIR/lib +#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib # ccache: export PATH=/opt/local/libexec/ccache:$PATH diff --git a/setenv_mjau.sh b/setenv_mjau.sh index 851cf0e..3e27665 100644 --- a/setenv_mjau.sh +++ b/setenv_mjau.sh @@ -4,8 +4,7 @@ export QMAKESPEC=macx-g++ #export OPENCSGDIR=$PWD/../OpenCSG-1.3.0 #export CGALDIR=$PWD/../install/CGAL-3.6 -#export QCODEEDITDIR=$PWD/../qcodeedit-2.2.3/install -#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib:$QCODEEDITDIR/lib +#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib # ccache: export PATH=/opt/local/libexec/ccache:$PATH diff --git a/src/editor.cc b/src/editor.cc index 92aeefe..08bf005 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -1,7 +1,6 @@ #include "editor.h" #include "Preferences.h" -#ifndef _QCODE_EDIT_ void Editor::indentSelection() { QTextCursor cursor = textCursor(); @@ -109,4 +108,3 @@ void Editor::wheelEvent ( QWheelEvent * event ) } } -#endif diff --git a/src/editor.h b/src/editor.h index bb338b0..09484f5 100644 --- a/src/editor.h +++ b/src/editor.h @@ -3,26 +3,11 @@ #include #include -#ifdef _QCODE_EDIT_ -#include -class Editor : public QEditor -#else #include class Editor : public QTextEdit -#endif { Q_OBJECT public: -#ifdef _QCODE_EDIT_ - Editor(QWidget *parent) : QEditor(parent) {} - QString toPlainText() const { return text(); } - void setPlainText(const QString& text) { setText(text); } -public slots: - //void zoomIn() { zoom(1); } - void zoomIn(int n = 1) { zoom(n); } - //void zoomOut() { zoom(-1); } - void zoomOut(int n = 1) { zoom(-n); } -#else Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); } public slots: void zoomIn(); @@ -36,5 +21,4 @@ public slots: void uncommentSelection(); private: void wheelEvent ( QWheelEvent * event ); -#endif }; diff --git a/src/highlighter.cc b/src/highlighter.cc index 64ea980..ca4b4cf 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -27,11 +27,7 @@ #include "highlighter.h" #include "parsersettings.h" // extern int parser_error_pos; -#ifdef _QCODE_EDIT_ -Highlighter::Highlighter(QDocument *parent) -#else Highlighter::Highlighter(QTextDocument *parent) -#endif : QSyntaxHighlighter(parent) { } diff --git a/src/highlighter.h b/src/highlighter.h index 1bd54d2..2eead6d 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -3,18 +3,10 @@ #include -#ifdef _QCODE_EDIT_ -#include "qdocument.h" -#endif - class Highlighter : public QSyntaxHighlighter { public: -#ifdef _QCODE_EDIT_ - Highlighter(QDocument *parent); -#else Highlighter(QTextDocument *parent); -#endif void highlightBlock(const QString &text); }; diff --git a/src/mainwin.cc b/src/mainwin.cc index dde6761..72254a3 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -70,11 +70,6 @@ #include #include #include -#ifdef _QCODE_EDIT_ -#include "qdocument.h" -#include "qformatscheme.h" -#include "qlanguagefactory.h" -#endif #include @@ -186,15 +181,7 @@ MainWindow::MainWindow(const QString &filename) fsteps = 1; highlighter = NULL; -#ifdef _QCODE_EDIT_ - QFormatScheme *formats = new QFormatScheme("qxs/openscad.qxf"); - QDocument::setDefaultFormatScheme(formats); - QLanguageFactory *languages = new QLanguageFactory(formats,this); - languages->addDefinitionPath("qxs"); - languages->setLanguage(editor, "openscad"); -#else editor->setTabStopWidth(30); -#endif editor->setLineWrapping(true); // Not designable this->glview->statusLabel = new QLabel(this); @@ -348,13 +335,8 @@ MainWindow::MainWindow(const QString &filename) updateRecentFileActions(); connect(editor->document(), SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged())); -#ifdef _QCODE_EDIT_ - connect(editor, SIGNAL(contentModified(bool)), this, SLOT(setWindowModified(bool))); - connect(editor, SIGNAL(contentModified(bool)), fileActionSave, SLOT(setEnabled(bool))); -#else connect(editor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setWindowModified(bool))); connect(editor->document(), SIGNAL(modificationChanged(bool)), fileActionSave, SLOT(setEnabled(bool))); -#endif connect(this->glview, SIGNAL(doAnimateUpdate()), this, SLOT(animateUpdate())); connect(Preferences::inst(), SIGNAL(requestRedraw()), this->glview, SLOT(updateGL())); @@ -483,12 +465,7 @@ void MainWindow::openFile(const QString &new_filename) { #ifdef ENABLE_MDI -#ifdef _QCODE_EDIT_ - if (this->editor->document()->lines() > 1 || - !this->editor->document()->text(true, false).trimmed().isEmpty()) { -#else if (!editor->toPlainText().isEmpty()) { -#endif new MainWindow(new_filename); clearCurrentOutput(); return; @@ -957,11 +934,7 @@ void MainWindow::hideEditor() void MainWindow::pasteViewportTranslation() { -#ifdef _QCODE_EDIT_ - QDocumentCursor cursor = editor->cursor(); -#else QTextCursor cursor = editor->textCursor(); -#endif QString txt; txt.sprintf("[ %.2f, %.2f, %.2f ]", -this->glview->object_trans_x, -this->glview->object_trans_y, -this->glview->object_trans_z); cursor.insertText(txt); @@ -969,11 +942,7 @@ void MainWindow::pasteViewportTranslation() void MainWindow::pasteViewportRotation() { -#ifdef _QCODE_EDIT_ - QDocumentCursor cursor = editor->cursor(); -#else QTextCursor cursor = editor->textCursor(); -#endif QString txt; txt.sprintf("[ %.2f, %.2f, %.2f ]", fmodf(360 - this->glview->object_rot_x + 90, 360), fmodf(360 - this->glview->object_rot_y, 360), fmodf(360 - this->glview->object_rot_z, 360)); @@ -1075,14 +1044,9 @@ bool MainWindow::compileTopLevelDocument(bool reload) this->highlighter = new Highlighter(editor->document()); if (!animate_panel->isVisible()) { -#ifdef _QCODE_EDIT_ - QDocumentCursor cursor = editor->cursor(); - cursor.setPosition(parser_error_pos); -#else QTextCursor cursor = editor->textCursor(); cursor.setPosition(parser_error_pos); editor->setTextCursor(cursor); -#endif } } } -- cgit v0.10.1 From b0cefc0f3b758a73ec7e30677f9f603400d9dc22 Mon Sep 17 00:00:00 2001 From: don bright Date: Tue, 8 Jan 2013 21:15:14 -0600 Subject: merge, by hand, Christopher Olah's syntax highlighter code diff --git a/src/highlighter.cc b/src/highlighter.cc index ca4b4cf..6e51ecc 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -24,16 +24,103 @@ * */ +// Syntax Highlight code by Chris Olah + #include "highlighter.h" #include "parsersettings.h" // extern int parser_error_pos; -Highlighter::Highlighter(QTextDocument *parent) +Highlighter::Highlighter(QTextDocument *parent, mode_e mode) : QSyntaxHighlighter(parent) { + this->mode = mode; + operators << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";"; + KeyWords << "for" << "intersection_for" << "if" << "assign" + << "module" << "function" + << "$children" << "child" << "$fn" << "$fa" << "$fb" // Lump special variables in here + << "union" << "intersection" << "difference" << "render"; //Lump CSG in here + Primitives3D << "cube" << "cylinder" << "sphere" << "polyhedron"; + Primitives2D << "square" << "polygon" << "circle"; + Transforms << "scale" << "translate" << "rotate" << "multmatrix" << "color" + << "linear_extrude" << "rotate_extrude"; // Lump extrudes in here. + Imports << "include" << "use" << "import_stl"; + + //this->OperatorStyle.setForeground + KeyWordStyle.setForeground(Qt::darkGreen); + TransformStyle.setForeground(Qt::darkGreen); + PrimitiveStyle3D.setForeground(Qt::darkBlue); + PrimitiveStyle2D.setForeground(Qt::blue); + ImportStyle.setForeground(Qt::darkYellow); + QuoteStyle.setForeground(Qt::darkMagenta); + CommentStyle.setForeground(Qt::darkCyan); + ErrorStyle.setForeground(Qt::red); } void Highlighter::highlightBlock(const QString &text) { + if ( mode == NORMAL_MODE) { + state_e state = (state_e) previousBlockState(); + //Key words and Primitives + QStringList::iterator it; + + for (it = KeyWords.begin(); it != KeyWords.end(); ++it){ + for (int i = 0; i < text.count(*it); ++i){ + setFormat(text.indexOf(*it),it->size(),KeyWordStyle); + } + } + for (it = Primitives3D.begin(); it != Primitives3D.end(); ++it){ + for (int i = 0; i < text.count(*it); ++i){ + setFormat(text.indexOf(*it),it->size(),PrimitiveStyle3D); + } + } + for (it = Primitives2D.begin(); it != Primitives2D.end(); ++it){ + for (int i = 0; i < text.count(*it); ++i){ + setFormat(text.indexOf(*it),it->size(),PrimitiveStyle2D); + } + } + for (it = Transforms.begin(); it != Transforms.end(); ++it){ + for (int i = 0; i < text.count(*it); ++i){ + setFormat(text.indexOf(*it),it->size(),TransformStyle); + } + } + for (it = Imports.begin(); it != Imports.end(); ++it){ + for (int i = 0; i < text.count(*it); ++i){ + setFormat(text.indexOf(*it),it->size(),ImportStyle); + } + } + + // Quoting and Comments. + for (int n = 0; n < text.size(); ++n){ + if (state == NORMAL){ + if (text[n] == '"'){ + state = QUOTE; + setFormat(n,1,QuoteStyle); + } else if (text[n] == '/'){ + if (text[n+1] == '/'){ + setFormat(n,text.size(),CommentStyle); + break; + } else if (text[n+1] == '*'){ + setFormat(n++,2,CommentStyle); + state = COMMENT; + } + } + } else if (state == QUOTE){ + setFormat(n,1,QuoteStyle); + if (text[n] == '"' && text[n-1] != '\\') + state = NORMAL; + } else if (state == COMMENT){ + setFormat(n,1,CommentStyle); + if (text[n] == '*' && text[n+1] == '/'){ + setFormat(++n,1,CommentStyle); + state = NORMAL; + } + } + } + + } // not ErrorMode (syntax highlighting) + + + // Errors + else if (mode == ERROR_MODE) { int n = previousBlockState(); if (n < 0) n = 0; @@ -49,5 +136,6 @@ void Highlighter::highlightBlock(const QString &text) setFormat(parser_error_pos - n, 1, style); #endif } + } // if errormode } diff --git a/src/highlighter.h b/src/highlighter.h index 2eead6d..a6e2dc3 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -6,7 +6,26 @@ class Highlighter : public QSyntaxHighlighter { public: - Highlighter(QTextDocument *parent); + enum state_e {NORMAL=-1,QUOTE,COMMENT}; + enum mode_e {NORMAL_MODE, ERROR_MODE}; + mode_e mode; + + QStringList operators; + QStringList KeyWords; + QStringList Primitives3D; + QStringList Primitives2D; + QStringList Transforms; + QStringList Imports; + QTextCharFormat ErrorStyle; + QTextCharFormat OperatorStyle; + QTextCharFormat CommentStyle; + QTextCharFormat QuoteStyle; + QTextCharFormat KeyWordStyle; + QTextCharFormat PrimitiveStyle3D; + QTextCharFormat PrimitiveStyle2D; + QTextCharFormat TransformStyle; + QTextCharFormat ImportStyle; + Highlighter(QTextDocument *parent, mode_e mode); void highlightBlock(const QString &text); }; diff --git a/src/mainwin.cc b/src/mainwin.cc index 72254a3..af4a532 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -180,7 +180,7 @@ MainWindow::MainWindow(const QString &filename) fps = 0; fsteps = 1; - highlighter = NULL; + highlighter = new Highlighter(editor->document(), Highlighter::NORMAL_MODE); editor->setTabStopWidth(30); editor->setLineWrapping(true); // Not designable @@ -1036,18 +1036,22 @@ bool MainWindow::compileTopLevelDocument(bool reload) QFileInfo(this->fileName).absolutePath().toLocal8Bit(), false); - // Error highlighting - delete this->highlighter; - this->highlighter = NULL; + // Syntax & Error highlighting if (!this->root_module) { - this->highlighter = new Highlighter(editor->document()); + if (highlighter->mode==Highlighter::NORMAL_MODE) { + delete this->highlighter; + highlighter = new Highlighter(editor->document(), Highlighter::ERROR_MODE); + } if (!animate_panel->isVisible()) { QTextCursor cursor = editor->textCursor(); cursor.setPosition(parser_error_pos); editor->setTextCursor(cursor); } + } else if (highlighter->mode==Highlighter::ERROR_MODE) { + delete this->highlighter; + this->highlighter = new Highlighter(editor->document(), Highlighter::NORMAL_MODE); } } -- cgit v0.10.1 From 3b7bc56bdeba2401f88afd46d3969bcc543796fd Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 14:05:10 -0600 Subject: rewrite large bit of syntax highlighter, add 'manual' test instructions diff --git a/src/highlighter.cc b/src/highlighter.cc index 6e51ecc..121d751 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -24,118 +24,174 @@ * */ -// Syntax Highlight code by Chris Olah +// based on Syntax Highlight code by Chris Olah + +/* test suite + +1. action: open example001, remove first {, hit f5 + expected result: red highlight appears on last }, cursor moves there + action: replace first {, hit f5 + expected result: red highlight disappears + +2. action: type a=b + expected result: '=' is highlighted as appropriate + +3. action: open example001, put '===' after first ; + expected result: red highlight appears in === + action: remove '===' + expected result: red highlight disappears + +4. action: open example001, remove last ';' but not trailing whitespace/\n + expected result: red highlight appears on last line + action: replace last ';' + expected result: red 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 + +*/ #include "highlighter.h" -#include "parsersettings.h" // extern int parser_error_pos; +#include -Highlighter::Highlighter(QTextDocument *parent, mode_e mode) +#include +Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) { - this->mode = mode; - operators << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";"; - KeyWords << "for" << "intersection_for" << "if" << "assign" - << "module" << "function" - << "$children" << "child" << "$fn" << "$fa" << "$fb" // Lump special variables in here - << "union" << "intersection" << "difference" << "render"; //Lump CSG in here - Primitives3D << "cube" << "cylinder" << "sphere" << "polyhedron"; - Primitives2D << "square" << "polygon" << "circle"; - Transforms << "scale" << "translate" << "rotate" << "multmatrix" << "color" - << "linear_extrude" << "rotate_extrude"; // Lump extrudes in here. - Imports << "include" << "use" << "import_stl"; - - //this->OperatorStyle.setForeground - KeyWordStyle.setForeground(Qt::darkGreen); - TransformStyle.setForeground(Qt::darkGreen); - PrimitiveStyle3D.setForeground(Qt::darkBlue); - PrimitiveStyle2D.setForeground(Qt::blue); - ImportStyle.setForeground(Qt::darkYellow); - QuoteStyle.setForeground(Qt::darkMagenta); - CommentStyle.setForeground(Qt::darkCyan); - ErrorStyle.setForeground(Qt::red); + QMap tokentypes; + QMap typeformats; + + tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";"; + typeformats["operator"].setForeground(Qt::blue); + + tokentypes["keyword"] << "for" << "intersection_for" << "if" << "assign" << "module" << "function"; + typeformats["keyword"].setForeground(Qt::darkGreen); + + tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron"; + typeformats["prim3d"].setForeground(Qt::darkBlue); + + tokentypes["prim2d"] << "square" << "polygon" << "circle"; + typeformats["prim2d"].setForeground(Qt::blue); + + tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection"; + typeformats["transform"].setForeground(Qt::darkGreen); + + tokentypes["import"] << "include" << "use" << "import_stl"; + typeformats["import"].setForeground(Qt::darkYellow); + + tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fb"; + typeformats["special"].setForeground(Qt::darkGreen); + + tokentypes["csgop"] << "union" << "intersection" << "difference" << "render"; + typeformats["csgop"].setForeground(Qt::darkGreen); + + tokentypes["extrude"] << "linear_extrude" << "rotate_extrude"; + typeformats["extrude"].setForeground(Qt::darkGreen); + + // for speed - put all tokens into single QHash, mapped to their format + QList::iterator ki; + QList toktypes = tokentypes.keys(); + for ( ki=toktypes.begin(); ki!=toktypes.end(); ++ki ) { + QString toktype = *ki; + QStringList::iterator it; + for ( it = tokentypes[toktype].begin(); it < tokentypes[toktype].end(); ++it) { + QString token = *it; + //std::cout << token.toStdString() << "\n"; + formatMap[ token ] = typeformats [ toktype ]; + } + } + + quoteFormat.setForeground(Qt::darkMagenta); + commentFormat.setForeground(Qt::darkCyan); + errorFormat.setBackground(Qt::red); + + // 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"; + errorPos = error_pos; + errorState = true; + //if (errorPos == document()->characterCount()-1) errorPos--; + rehighlightBlock( err_block ); // QT 4.6 + errorState = false; + lastErrorBlock = err_block; +} + +void Highlighter::unhighlightLastError() +{ + rehighlightBlock( lastErrorBlock ); } +#include void Highlighter::highlightBlock(const QString &text) { - if ( mode == NORMAL_MODE) { - state_e state = (state_e) previousBlockState(); - //Key words and Primitives - QStringList::iterator it; + std::cout << "block[" << currentBlock().position() << ":" + << currentBlock().length() + currentBlock().position() << "]" + << ", err:" << errorPos << ", text:'" << text.toStdString() << "'\n"; - for (it = KeyWords.begin(); it != KeyWords.end(); ++it){ - for (int i = 0; i < text.count(*it); ++i){ - setFormat(text.indexOf(*it),it->size(),KeyWordStyle); - } + // 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 + " "); } - for (it = Primitives3D.begin(); it != Primitives3D.end(); ++it){ - for (int i = 0; i < text.count(*it); ++i){ - setFormat(text.indexOf(*it),it->size(),PrimitiveStyle3D); - } - } - for (it = Primitives2D.begin(); it != Primitives2D.end(); ++it){ - for (int i = 0; i < text.count(*it); ++i){ - setFormat(text.indexOf(*it),it->size(),PrimitiveStyle2D); - } - } - for (it = Transforms.begin(); it != Transforms.end(); ++it){ - for (int i = 0; i < text.count(*it); ++i){ - setFormat(text.indexOf(*it),it->size(),TransformStyle); - } - } - for (it = Imports.begin(); it != Imports.end(); ++it){ - for (int i = 0; i < text.count(*it); ++i){ - setFormat(text.indexOf(*it),it->size(),ImportStyle); + 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){ if (text[n] == '"'){ state = QUOTE; - setFormat(n,1,QuoteStyle); + setFormat(n,1,quoteFormat); } else if (text[n] == '/'){ if (text[n+1] == '/'){ - setFormat(n,text.size(),CommentStyle); + setFormat(n,text.size(),commentFormat); break; } else if (text[n+1] == '*'){ - setFormat(n++,2,CommentStyle); + setFormat(n++,2,commentFormat); state = COMMENT; } } } else if (state == QUOTE){ - setFormat(n,1,QuoteStyle); + setFormat(n,1,quoteFormat); if (text[n] == '"' && text[n-1] != '\\') state = NORMAL; } else if (state == COMMENT){ - setFormat(n,1,CommentStyle); + setFormat(n,1,commentFormat); if (text[n] == '*' && text[n+1] == '/'){ - setFormat(++n,1,CommentStyle); + setFormat(++n,1,commentFormat); state = NORMAL; } } } - } // not ErrorMode (syntax highlighting) - - - // Errors - else if (mode == ERROR_MODE) { - int n = previousBlockState(); - if (n < 0) - n = 0; - int k = n + text.size() + 1; - setCurrentBlockState(k); - if (parser_error_pos >= n && parser_error_pos < k) { - QTextCharFormat style; - style.setBackground(Qt::red); - setFormat(0, text.size(), style); -#if 0 - style.setBackground(Qt::black); - style.setForeground(Qt::white); - setFormat(parser_error_pos - n, 1, style); -#endif + // Highlight an error. Do it last to 'overwrite' other formatting. + if (errorState) { + setFormat( errorPos - currentBlock().position() - 1, 1, errorFormat); } - } // if errormode } diff --git a/src/highlighter.h b/src/highlighter.h index a6e2dc3..043c34e 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -7,26 +7,17 @@ class Highlighter : public QSyntaxHighlighter { public: enum state_e {NORMAL=-1,QUOTE,COMMENT}; - enum mode_e {NORMAL_MODE, ERROR_MODE}; - mode_e mode; - - QStringList operators; - QStringList KeyWords; - QStringList Primitives3D; - QStringList Primitives2D; - QStringList Transforms; - QStringList Imports; - QTextCharFormat ErrorStyle; - QTextCharFormat OperatorStyle; - QTextCharFormat CommentStyle; - QTextCharFormat QuoteStyle; - QTextCharFormat KeyWordStyle; - QTextCharFormat PrimitiveStyle3D; - QTextCharFormat PrimitiveStyle2D; - QTextCharFormat TransformStyle; - QTextCharFormat ImportStyle; - Highlighter(QTextDocument *parent, mode_e mode); + QHash formatMap; + QTextCharFormat errorFormat, commentFormat, quoteFormat; + Highlighter(QTextDocument *parent); void highlightBlock(const QString &text); + void highlightError(int error_pos); + void unhighlightLastError(); +private: + QTextBlock lastErrorBlock; + int errorPos = -1; + bool errorState = false; + QStringList separators; }; #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index af4a532..644cc2e 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -180,7 +180,7 @@ MainWindow::MainWindow(const QString &filename) fps = 0; fsteps = 1; - highlighter = new Highlighter(editor->document(), Highlighter::NORMAL_MODE); + highlighter = new Highlighter(editor->document()); editor->setTabStopWidth(30); editor->setLineWrapping(true); // Not designable @@ -1036,22 +1036,15 @@ bool MainWindow::compileTopLevelDocument(bool reload) QFileInfo(this->fileName).absolutePath().toLocal8Bit(), false); - // Syntax & Error highlighting - - if (!this->root_module) { - if (highlighter->mode==Highlighter::NORMAL_MODE) { - delete this->highlighter; - highlighter = new Highlighter(editor->document(), Highlighter::ERROR_MODE); - } - - if (!animate_panel->isVisible()) { + if (!animate_panel->isVisible()) { + if (!this->root_module) { QTextCursor cursor = editor->textCursor(); - cursor.setPosition(parser_error_pos); - editor->setTextCursor(cursor); + cursor.setPosition( parser_error_pos ); + editor->setTextCursor( cursor ); + highlighter->highlightError( parser_error_pos ); + } else { + highlighter->unhighlightLastError(); } - } else if (highlighter->mode==Highlighter::ERROR_MODE) { - delete this->highlighter; - this->highlighter = new Highlighter(editor->document(), Highlighter::NORMAL_MODE); } } -- cgit v0.10.1 From 2c6d69645ff1391683ae6ffde8bd305277e17914 Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 16:11:19 -0600 Subject: now passes all tests in 'manual test suite' 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 tokentypes; - QMap 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 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 tokentypes; + QMap 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; -- cgit v0.10.1 From 8f986a339925f523e5bf19addce6c6e8bf8c9ec3 Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 16:36:07 -0600 Subject: make it work on Qt less than 4.6 diff --git a/src/highlighter.cc b/src/highlighter.cc index 7f6b5f9..45ba7f0 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -28,8 +28,13 @@ 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). + Speed Note: + + setFormat() is very slow. normally this doesnt matter because we + only highlight a block or two at once. But when OpenSCAD first starts, + QT automatigically calls 'highlightBlock' on every single textblock in the file + even if it's not visible in the window. On a large file (50,000 lines) this + can take several seconds. Test suite: @@ -101,8 +106,8 @@ #include "highlighter.h" #include +#include -#include Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) { @@ -133,7 +138,7 @@ Highlighter::Highlighter(QTextDocument *parent) tokentypes["extrude"] << "linear_extrude" << "rotate_extrude"; typeformats["extrude"].setForeground(Qt::darkGreen); - // for speed - put all tokens into single QHash, mapped to their format + // Put all tokens into single QHash, mapped to their format QList::iterator ki; QList toktypes = tokentypes.keys(); for ( ki=toktypes.begin(); ki!=toktypes.end(); ++ki ) { @@ -174,22 +179,31 @@ void Highlighter::highlightError(int error_pos) 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"; + errorPos--; } err_block = document()->findBlock(errorPos); - rehighlightBlock( err_block ); // QT 4.6 + portable_rehighlightBlock( err_block ); + errorState = false; lastErrorBlock = err_block; } void Highlighter::unhighlightLastError() { - rehighlightBlock( lastErrorBlock ); // QT 4.6 + portable_rehighlightBlock( lastErrorBlock ); +} + +void Highlighter::portable_rehighlightBlock( const QTextBlock &block ) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + rehighlightBlock( block ); +#else + rehighlight(); // slow on big files +#endif } -#include void Highlighter::highlightBlock(const QString &text) { int block_first_pos = currentBlock().position(); diff --git a/src/highlighter.h b/src/highlighter.h index a0ed0da..322ba2d 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -19,6 +19,7 @@ private: bool errorState = false; QMap tokentypes; QMap typeformats; + void portable_rehighlightBlock( const QTextBlock &text ); }; #endif -- cgit v0.10.1 From 1d9d3ef8044bb12036dbd8f363e14a60eeee3409 Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 16:39:45 -0600 Subject: oops % should not be bold diff --git a/src/highlighter.cc b/src/highlighter.cc index 45ba7f0..a636827 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -155,9 +155,6 @@ Highlighter::Highlighter(QTextDocument *parent) commentFormat.setForeground(Qt::darkCyan); errorFormat.setBackground(Qt::red); - // format tweaks - formatMap[ "%" ].setFontWeight(QFont::Bold); - lastErrorBlock = parent->begin(); } @@ -216,13 +213,13 @@ void Highlighter::highlightBlock(const QString &text) QString newtext = text; QStringList splitHelpers; QStringList::iterator sh, token; - int tokindex = -1; // tokindex helps w duplicate tokens in a single block + // splitHelpers - so "a+b" is treated as "a + b" and formatted 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")); + int tokindex = -1; // tokindex helps w duplicate tokens in a single block for ( token = tokens.begin(); token!=tokens.end(); ++token ){ if ( formatMap.contains( *token ) ) { tokindex = text.indexOf( *token, tokindex+1 ); -- cgit v0.10.1 From 3ff8ca36b5bbb57b4039d8f6372d52d2b6ab0eaf Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 16:48:19 -0600 Subject: note about speed on qt < 4.6 diff --git a/src/highlighter.cc b/src/highlighter.cc index a636827..ab0a071 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -36,6 +36,11 @@ even if it's not visible in the window. On a large file (50,000 lines) this can take several seconds. + Also, QT 4.5 and lower do not have rehighlightBlock(), so they will be slow + on large files as well, as they re-highlight everything after each compile. + + The vast majority of OpenSCAD files, however, are not 50,000 lines + Test suite: 1. action: open example001, remove first {, hit f5 -- cgit v0.10.1 From f4f06d48d852437ee0d70b7541c9b8a1893d9624 Mon Sep 17 00:00:00 2001 From: don bright Date: Sun, 13 Jan 2013 00:01:24 +0100 Subject: fix for gcc. simplify mainwin.cc a bit. diff --git a/src/highlighter.cc b/src/highlighter.cc index ab0a071..98eff8c 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -160,6 +160,8 @@ Highlighter::Highlighter(QTextDocument *parent) commentFormat.setForeground(Qt::darkCyan); errorFormat.setBackground(Qt::red); + errorState = false; + errorPos = -1; lastErrorBlock = parent->begin(); } @@ -209,7 +211,7 @@ void Highlighter::portable_rehighlightBlock( const QTextBlock &block ) void Highlighter::highlightBlock(const QString &text) { int block_first_pos = currentBlock().position(); - int block_last_pos = block_first_pos + currentBlock().length() - 1; + //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"; diff --git a/src/highlighter.h b/src/highlighter.h index 322ba2d..09bba39 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -15,8 +15,8 @@ public: void unhighlightLastError(); private: QTextBlock lastErrorBlock; - int errorPos = -1; - bool errorState = false; + int errorPos; + bool errorState; QMap tokentypes; QMap typeformats; void portable_rehighlightBlock( const QTextBlock &text ); diff --git a/src/mainwin.cc b/src/mainwin.cc index 8834b75..6bb43e6 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -1037,14 +1037,12 @@ bool MainWindow::compileTopLevelDocument(bool reload) false); if (!animate_panel->isVisible()) { + highlighter->unhighlightLastError(); if (!this->root_module) { - highlighter->unhighlightLastError(); QTextCursor cursor = editor->textCursor(); - cursor.setPosition( parser_error_pos ); - editor->setTextCursor( cursor ); + cursor.setPosition(parser_error_pos); + editor->setTextCursor(cursor); highlighter->highlightError( parser_error_pos ); - } else { - highlighter->unhighlightLastError(); } } -- cgit v0.10.1 From 987cd438f64b6b06cffe31a512584e55b41cad9d Mon Sep 17 00:00:00 2001 From: don bright Date: Sun, 13 Jan 2013 00:37:20 +0100 Subject: fix qt4.4, old gcc, and mention Giles' Rapcad higlighter diff --git a/src/highlighter.cc b/src/highlighter.cc index 98eff8c..a7592da 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -39,8 +39,13 @@ Also, QT 4.5 and lower do not have rehighlightBlock(), so they will be slow on large files as well, as they re-highlight everything after each compile. - The vast majority of OpenSCAD files, however, are not 50,000 lines + The vast majority of OpenSCAD files, however, are not 50,000 lines and + most machines ship with Qt > 4.5 + See Also: + + Giles Bathgate's Rapcad lexer-based highlighter: rapcad.org + Test suite: 1. action: open example001, remove first {, hit f5 @@ -177,7 +182,7 @@ void Highlighter::highlightError(int error_pos) err_block = err_block.previous(); errorPos = err_block.position()+err_block.length() - 2; } - if ( errorPos == document()->characterCount()-1 ) { + if ( errorPos == lastDocumentPos()-1 ) { errorPos--; } @@ -204,10 +209,22 @@ void Highlighter::portable_rehighlightBlock( const QTextBlock &block ) #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) rehighlightBlock( block ); #else - rehighlight(); // slow on big files + rehighlight(); // slow on very large files #endif } +int Highlighter::lastDocumentPos() +{ +// fixme - test it +#if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0)) + return document()->characterCount(); +#else + QTextBlock lastblock = document()->lastBlock(); + return lastblock.position() + lastblock.length(); +#endif +} + + void Highlighter::highlightBlock(const QString &text) { int block_first_pos = currentBlock().position(); diff --git a/src/highlighter.h b/src/highlighter.h index 09bba39..428bbbb 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -2,6 +2,8 @@ #define HIGHLIGHTER_H_ #include +#include +#include class Highlighter : public QSyntaxHighlighter { @@ -17,8 +19,9 @@ private: QTextBlock lastErrorBlock; int errorPos; bool errorState; - QMap tokentypes; - QMap typeformats; + QMap tokentypes; + QMap typeformats; + int lastDocumentPos(); void portable_rehighlightBlock( const QTextBlock &text ); }; -- cgit v0.10.1 From 59910af66ae166f2afd9925cbef9c026fe47f6ae Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 18:29:30 -0600 Subject: highlight numbers and brackets as well diff --git a/src/highlighter.cc b/src/highlighter.cc index a7592da..2d75b67 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -39,13 +39,13 @@ Also, QT 4.5 and lower do not have rehighlightBlock(), so they will be slow on large files as well, as they re-highlight everything after each compile. - The vast majority of OpenSCAD files, however, are not 50,000 lines and + The vast majority of OpenSCAD files, however, are not 50,000 lines and most machines ship with Qt > 4.5 See Also: Giles Bathgate's Rapcad lexer-based highlighter: rapcad.org - + Test suite: 1. action: open example001, remove first {, hit f5 @@ -117,6 +117,7 @@ #include "highlighter.h" #include #include +//#include Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) @@ -148,6 +149,9 @@ Highlighter::Highlighter(QTextDocument *parent) tokentypes["extrude"] << "linear_extrude" << "rotate_extrude"; typeformats["extrude"].setForeground(Qt::darkGreen); + tokentypes["bracket"] << "[" << "]"; + typeformats["bracket"].setForeground(Qt::darkGreen); + // Put all tokens into single QHash, mapped to their format QList::iterator ki; QList toktypes = tokentypes.keys(); @@ -164,6 +168,7 @@ Highlighter::Highlighter(QTextDocument *parent) quoteFormat.setForeground(Qt::darkMagenta); commentFormat.setForeground(Qt::darkCyan); errorFormat.setBackground(Qt::red); + formatMap["number"].setForeground(Qt::red); errorState = false; errorPos = -1; @@ -172,10 +177,11 @@ Highlighter::Highlighter(QTextDocument *parent) void Highlighter::highlightError(int error_pos) { - QTextBlock err_block = document()->findBlock(error_pos); - //std::cout << "error pos: " << error_pos << " doc len: " << document()->characterCount() << "\n"; - errorPos = error_pos; errorState = true; + errorPos = error_pos; + + QTextBlock err_block = document()->findBlock( errorPos ); + //std::cout << "error pos: " << error_pos << " doc len: " << document()->characterCount() << "\n"; while (err_block.text().remove(QRegExp("\\s+")).size()==0) { //std::cout << "special case - errors at end of file w whitespace\n"; @@ -224,7 +230,6 @@ int Highlighter::lastDocumentPos() #endif } - void Highlighter::highlightBlock(const QString &text) { int block_first_pos = currentBlock().position(); @@ -237,18 +242,23 @@ void Highlighter::highlightBlock(const QString &text) QString newtext = text; QStringList splitHelpers; QStringList::iterator sh, token; - // splitHelpers - so "a+b" is treated as "a + b" and formatted - splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]"; + // splitHelpers - so "[a+b]" is treated as "[ a + b ]" and formatted + splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]" << ","; for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) { newtext = newtext.replace( *sh, " " + *sh + " "); } + //std::cout << "newtext: " << newtext.toStdString() << "\n"; QStringList tokens = newtext.split(QRegExp("\\s")); - int tokindex = -1; // tokindex helps w duplicate tokens in a single block + int tokindex = 0; // tokindex helps w duplicate tokens in a single block + bool numtest; for ( token = tokens.begin(); token!=tokens.end(); ++token ){ + tokindex = text.indexOf( *token, tokindex ); if ( formatMap.contains( *token ) ) { - tokindex = text.indexOf( *token, tokindex+1 ); setFormat( tokindex, token->size(), formatMap[ *token ]); - // std::cout << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n"; + //std::cout << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n"; + } else { + (*token).toDouble( &numtest ); + if ( numtest ) setFormat( tokindex, token->size(), formatMap["number"] ); } } -- cgit v0.10.1 From d61593979199c1c025df07a5a1db879cce165529 Mon Sep 17 00:00:00 2001 From: don bright Date: Sat, 12 Jan 2013 20:07:15 -0600 Subject: balance colors, fix bug in numbers, highlight more stuff diff --git a/src/highlighter.cc b/src/highlighter.cc index 2d75b67..58912f3 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -40,7 +40,7 @@ on large files as well, as they re-highlight everything after each compile. The vast majority of OpenSCAD files, however, are not 50,000 lines and - most machines ship with Qt > 4.5 + most machines have Qt > 4.5 See Also: @@ -112,11 +112,18 @@ 9. action: open any file, and hold down 'f5' key to repeatedly reparse expected result: no crashing! +10. action: for i in examples/ex* ; do ./openscad $i ; done + expected result: make sure the colors look harmonious + +11. action: type random string of [][][][]()()[][90,3904,00,000] + expected result: all should be highlighted correctly + */ #include "highlighter.h" #include #include +#include //#include Highlighter::Highlighter(QTextDocument *parent) @@ -125,34 +132,41 @@ Highlighter::Highlighter(QTextDocument *parent) tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";"; typeformats["operator"].setForeground(Qt::blue); - tokentypes["keyword"] << "for" << "intersection_for" << "if" << "assign" << "module" << "function"; - typeformats["keyword"].setForeground(Qt::darkGreen); + tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign"; + typeformats["keyword"].setForeground(QColor("Green")); + typeformats["keyword"].setToolTip("Keyword"); + + tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull"; + typeformats["transform"].setForeground(QColor("Indigo")); + + tokentypes["csgop"] << "union" << "intersection" << "difference" << "render"; + typeformats["csgop"].setForeground(QColor("DarkGreen")); tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron"; - typeformats["prim3d"].setForeground(Qt::darkBlue); + typeformats["prim3d"].setForeground(QColor("DarkBlue")); tokentypes["prim2d"] << "square" << "polygon" << "circle"; - typeformats["prim2d"].setForeground(Qt::blue); - - tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection"; - typeformats["transform"].setForeground(Qt::darkGreen); + typeformats["prim2d"].setForeground(QColor("MidnightBlue")); - tokentypes["import"] << "include" << "use" << "import_stl"; + tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross"; typeformats["import"].setForeground(Qt::darkYellow); tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fb"; typeformats["special"].setForeground(Qt::darkGreen); - tokentypes["csgop"] << "union" << "intersection" << "difference" << "render"; - typeformats["csgop"].setForeground(Qt::darkGreen); - tokentypes["extrude"] << "linear_extrude" << "rotate_extrude"; typeformats["extrude"].setForeground(Qt::darkGreen); - tokentypes["bracket"] << "[" << "]"; - typeformats["bracket"].setForeground(Qt::darkGreen); + tokentypes["bracket"] << "[" << "]" << "(" << ")"; + typeformats["bracket"].setForeground(QColor("Green")); + + tokentypes["curlies"] << "{" << "}"; + typeformats["curlies"].setForeground(QColor(32,32,20)); - // Put all tokens into single QHash, mapped to their format + tokentypes["bool"] << "true" << "false"; + typeformats["bool"].setForeground(QColor("DarkRed")); + + // Put each tokens into single QHash, mapped to it's format QList::iterator ki; QList toktypes = tokentypes.keys(); for ( ki=toktypes.begin(); ki!=toktypes.end(); ++ki ) { @@ -161,14 +175,14 @@ Highlighter::Highlighter(QTextDocument *parent) for ( it = tokentypes[toktype].begin(); it < tokentypes[toktype].end(); ++it) { QString token = *it; //std::cout << token.toStdString() << "\n"; - formatMap[ token ] = typeformats [ toktype ]; + tokenFormats[ token ] = typeformats [ toktype ]; } } quoteFormat.setForeground(Qt::darkMagenta); commentFormat.setForeground(Qt::darkCyan); errorFormat.setBackground(Qt::red); - formatMap["number"].setForeground(Qt::red); + numberFormat.setForeground(QColor("DarkRed")); errorState = false; errorPos = -1; @@ -243,22 +257,28 @@ void Highlighter::highlightBlock(const QString &text) QStringList splitHelpers; QStringList::iterator sh, token; // splitHelpers - so "[a+b]" is treated as "[ a + b ]" and formatted - splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]" << ","; + splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]" << "," << ":"; for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) { newtext = newtext.replace( *sh, " " + *sh + " "); } - //std::cout << "newtext: " << newtext.toStdString() << "\n"; + //std::cout << "\nnewtext: " << newtext.toStdString() << "\n"; QStringList tokens = newtext.split(QRegExp("\\s")); int tokindex = 0; // tokindex helps w duplicate tokens in a single block bool numtest; for ( token = tokens.begin(); token!=tokens.end(); ++token ){ - tokindex = text.indexOf( *token, tokindex ); - if ( formatMap.contains( *token ) ) { - setFormat( tokindex, token->size(), formatMap[ *token ]); + if ( tokenFormats.contains( *token ) ) { + tokindex = text.indexOf( *token, tokindex ); + setFormat( tokindex, token->size(), tokenFormats[ *token ]); //std::cout << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n"; + tokindex += token->size(); } else { (*token).toDouble( &numtest ); - if ( numtest ) setFormat( tokindex, token->size(), formatMap["number"] ); + if ( numtest ) { + tokindex = text.indexOf( *token, tokindex ); + setFormat( tokindex, token->size(), numberFormat ); + //std::cout << "found num '" << (*token).toStdString() << "' at " << tokindex << "\n"; + tokindex += token->size(); + } } } diff --git a/src/highlighter.h b/src/highlighter.h index 428bbbb..b4ffae8 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -9,8 +9,8 @@ class Highlighter : public QSyntaxHighlighter { public: enum state_e {NORMAL=-1,QUOTE,COMMENT}; - QHash formatMap; - QTextCharFormat errorFormat, commentFormat, quoteFormat; + QHash tokenFormats; + QTextCharFormat errorFormat, commentFormat, quoteFormat, numberFormat; Highlighter(QTextDocument *parent); void highlightBlock(const QString &text); void highlightError(int error_pos); -- cgit v0.10.1 From 49fe4998d08c7095dd39731f9ff8a336b3fb42a4 Mon Sep 17 00:00:00 2001 From: don bright Date: Sun, 13 Jan 2013 05:06:15 +0100 Subject: doc length tested ok. remove FIXME note diff --git a/src/highlighter.cc b/src/highlighter.cc index 58912f3..44ef368 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -235,7 +235,6 @@ void Highlighter::portable_rehighlightBlock( const QTextBlock &block ) int Highlighter::lastDocumentPos() { -// fixme - test it #if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0)) return document()->characterCount(); #else -- cgit v0.10.1 From 99a0b67cd4500b8f4410231b30fd67c0fa3aa4cb Mon Sep 17 00:00:00 2001 From: don bright Date: Sun, 13 Jan 2013 10:16:21 -0600 Subject: remove duplicate test from test list. clarify speed lanuage on large file diff --git a/src/highlighter.cc b/src/highlighter.cc index 44ef368..77d1bb8 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -94,28 +94,26 @@ 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: error highlight of '=' you added - -7. action: open example001, remove first ')' +6. 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 +7. action: create a large file (50,000 lines). eg at a bash prompt: + for i in {1..2000}; do cat examples/example001.scad >> test5k.scad ; done action: open file in openscad - expected result: there should not be a slowdown due to highlighting + expected result: it should load in a reasonable amount of time 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 + action: comment out the highlighter code from mainwin.cc, recompile, + run openscad again on the large file. put '=' after last ; + expected result: there should be only a small difference in speed. -9. action: open any file, and hold down 'f5' key to repeatedly reparse +8. action: open any file, and hold down 'f5' key to repeatedly reparse expected result: no crashing! -10. action: for i in examples/ex* ; do ./openscad $i ; done +9. action: for i in examples/ex* ; do ./openscad $i ; done expected result: make sure the colors look harmonious -11. action: type random string of [][][][]()()[][90,3904,00,000] +10. action: type random string of [][][][]()()[][90,3904,00,000] expected result: all should be highlighted correctly */ -- cgit v0.10.1