├── .gitignore ├── LICENSE ├── QSourceHighlite.pri ├── QSourceHighlite.pro ├── README.md ├── languagedata.cpp ├── languagedata.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── qsourcehighliter.cpp ├── qsourcehighliter.h ├── qsourcehighliterthemes.cpp ├── qsourcehighliterthemes.h ├── screenshot └── syntax.png └── test_files ├── Asm.txt ├── C++.txt ├── C.txt ├── CMake.txt ├── Go.txt ├── Lua.txt ├── Make.txt └── Yaml.txt /.gitignore: -------------------------------------------------------------------------------- 1 | build-* 2 | *.user 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-2020 Waqar Ahmed -- 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /QSourceHighlite.pri: -------------------------------------------------------------------------------- 1 | QT += gui 2 | 3 | HEADERS += $$PWD/qsourcehighliter.h \ 4 | $$PWD/qsourcehighliterthemes.h \ 5 | $$PWD/languagedata.h 6 | 7 | SOURCES += $$PWD/qsourcehighliter.cpp \ 8 | $$PWD/languagedata.cpp \ 9 | $$PWD/qsourcehighliterthemes.cpp 10 | -------------------------------------------------------------------------------- /QSourceHighlite.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | include(QSourceHighlite.pri) 4 | 5 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 6 | 7 | CONFIG += c++11 8 | DEFINES += QT_DEPRECATED_WARNINGS 9 | 10 | SOURCES += \ 11 | main.cpp \ 12 | mainwindow.cpp \ 13 | 14 | HEADERS += \ 15 | mainwindow.h \ 16 | 17 | FORMS += \ 18 | mainwindow.ui 19 | 20 | # Default rules for deployment. 21 | qnx: target.path = /tmp/$${TARGET}/bin 22 | else: unix:!android: target.path = /opt/$${TARGET}/bin 23 | !isEmpty(target.path): INSTALLS += target 24 | 25 | DISTFILES += \ 26 | README.md 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | It started as an internal component of [qmarkdowntextedit](https://github.com/pbek/qmarkdowntextedit) to provide syntax highlighting(kind of like **highlight.js**). Ithttps://github.com/pbek/qmarkdowntextedit is currently being used in QOwnNotes and you can test it there or run the demo here. 4 | 5 | It doesn't use any regex because I want it to be fast. It can currently load a 100,000 lines of source code in ~0.4 seconds on my 4th Gen Intel Core i5 4300U. 6 | 7 | # Screenshot 8 | 9 | ![Cpp](screenshot/syntax.png) 10 | 11 | # Usage 12 | 13 | Add the `.pri` file to your project. Then initialize it like this: 14 | ```cpp 15 | highlighter = new QSourceHighliter(plainTextEdit->document()); 16 | highlighter->setCurrentLanguage(QSourceHighlighter::CodeCpp); 17 | ``` 18 | 19 | # Themes 20 | 21 | Currently there is only one theme 'Monokai' apart from the one that is created during highlighter initialization. More themes will be added soon. You can add more themes in QSourceHighlighterThemes. 22 | 23 | ## Supported Languages 24 | 25 | Currently the following languages are supported (more being added): 26 | - Bash script 27 | - C 28 | - C++ 29 | - C# 30 | - CMake 31 | - CSS 32 | - Go 33 | - Html 34 | - INI 35 | - Java 36 | - Javascript 37 | - JSON 38 | - Make 39 | - PHP 40 | - Python 41 | - QML 42 | - Rhai 43 | - Rust 44 | - SQL 45 | - Typescript 46 | - V lang 47 | - XML 48 | - YAML 49 | - Houdini Vex 50 | 51 | ## Adding more languages 52 | 53 | If you want to add a language, collect the language data like keywords and types and add it to the `languagedata.h` file. For some languages it may not work, so create an issue and I will write a separate parser for that language. 54 | 55 | ## Dependencies 56 | 57 | It has no dependency except Qt ofcourse. It should work with any Qt version > 5 but if it fails please create an issue. 58 | 59 | ## Building 60 | 61 | Load the project into Qt Creator and click run. 62 | 63 | ## LICENSE 64 | 65 | MIT License 66 | 67 | -------------------------------------------------------------------------------- /languagedata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #ifndef QOWNLANGUAGEDATA_H 25 | #define QOWNLANGUAGEDATA_H 26 | 27 | template 28 | class QMultiHash; 29 | 30 | class QLatin1String; 31 | 32 | namespace QSourceHighlite { 33 | 34 | using LanguageData = QMultiHash; 35 | 36 | /**********************************************************/ 37 | /* LuaData ************************************************/ 38 | /**********************************************************/ 39 | void loadLuaData(LanguageData &typess, 40 | LanguageData &keywordss, 41 | LanguageData &builtins, 42 | LanguageData &literalss, 43 | LanguageData &others); 44 | 45 | /**********************************************************/ 46 | /* C/C++ Data *********************************************/ 47 | /**********************************************************/ 48 | void loadCppData(LanguageData &typess, 49 | LanguageData &keywordss, 50 | LanguageData &builtins, 51 | LanguageData &literalss, 52 | LanguageData &others); 53 | 54 | /**********************************************************/ 55 | /* Shell Data *********************************************/ 56 | /**********************************************************/ 57 | void loadShellData(LanguageData &types, 58 | LanguageData &keywords, 59 | LanguageData &builtin, 60 | LanguageData &literals, 61 | LanguageData &other); 62 | 63 | /**********************************************************/ 64 | /* JS Data *********************************************/ 65 | /**********************************************************/ 66 | void loadJSData(LanguageData &types, 67 | LanguageData &keywords, 68 | LanguageData &builtin, 69 | LanguageData &literals, 70 | LanguageData &other); 71 | 72 | /**********************************************************/ 73 | /* PHP Data *********************************************/ 74 | /**********************************************************/ 75 | void loadPHPData(LanguageData &types, 76 | LanguageData &keywords, 77 | LanguageData &builtin, 78 | LanguageData &literals, 79 | LanguageData &other); 80 | 81 | /**********************************************************/ 82 | /* QML Data *********************************************/ 83 | /**********************************************************/ 84 | void loadQMLData(LanguageData &types, 85 | LanguageData &keywords, 86 | LanguageData &builtin, 87 | LanguageData &literals, 88 | LanguageData &other); 89 | 90 | /**********************************************************/ 91 | /* Python Data *********************************************/ 92 | /**********************************************************/ 93 | void loadPythonData(LanguageData &types, 94 | LanguageData &keywords, 95 | LanguageData &builtin, 96 | LanguageData &literals, 97 | LanguageData &other); 98 | 99 | /********************************************************/ 100 | /*** Rust DATA ***********************************/ 101 | /********************************************************/ 102 | void loadRustData(LanguageData &types, 103 | LanguageData &keywords, 104 | LanguageData &builtin, 105 | LanguageData &literals, 106 | LanguageData &other); 107 | 108 | /********************************************************/ 109 | /*** Java DATA ***********************************/ 110 | /********************************************************/ 111 | void loadJavaData(LanguageData &types, 112 | LanguageData &keywords, 113 | LanguageData &builtin, 114 | LanguageData &literals, 115 | LanguageData &other); 116 | 117 | /********************************************************/ 118 | /*** C# DATA *************************************/ 119 | /********************************************************/ 120 | void loadCSharpData(LanguageData &types, 121 | LanguageData &keywords, 122 | LanguageData &builtin, 123 | LanguageData &literals, 124 | LanguageData &other); 125 | 126 | /********************************************************/ 127 | /*** Go DATA *************************************/ 128 | /********************************************************/ 129 | void loadGoData(LanguageData &types, 130 | LanguageData &keywords, 131 | LanguageData &builtin, 132 | LanguageData &literals, 133 | LanguageData &other); 134 | 135 | /********************************************************/ 136 | /*** V DATA **************************************/ 137 | /********************************************************/ 138 | void loadVData(LanguageData &types, 139 | LanguageData &keywords, 140 | LanguageData &builtin, 141 | LanguageData &literals, 142 | LanguageData &other); 143 | 144 | /********************************************************/ 145 | /*** SQL DATA ************************************/ 146 | /********************************************************/ 147 | void loadSQLData(LanguageData &types, 148 | LanguageData &keywords, 149 | LanguageData &builtin, 150 | LanguageData &literals, 151 | LanguageData &other); 152 | 153 | /********************************************************/ 154 | /*** JSON DATA ***********************************/ 155 | /********************************************************/ 156 | void loadJSONData(LanguageData &types, 157 | LanguageData &keywords, 158 | LanguageData &builtin, 159 | LanguageData &literals, 160 | LanguageData &other); 161 | 162 | /********************************************************/ 163 | /*** CSS DATA ***********************************/ 164 | /********************************************************/ 165 | void loadCSSData(LanguageData &types, 166 | LanguageData &keywords, 167 | LanguageData &builtin, 168 | LanguageData &literals, 169 | LanguageData &other); 170 | 171 | /********************************************************/ 172 | /*** Typescript DATA *********************************/ 173 | /********************************************************/ 174 | void loadTypescriptData(LanguageData &types, 175 | LanguageData &keywords, 176 | LanguageData &builtin, 177 | LanguageData &literals, 178 | LanguageData &other); 179 | 180 | /********************************************************/ 181 | /*** YAML DATA ***************************************/ 182 | /********************************************************/ 183 | void loadYAMLData(LanguageData &types, 184 | LanguageData &keywords, 185 | LanguageData &builtin, 186 | LanguageData &literals, 187 | LanguageData &other); 188 | 189 | /********************************************************/ 190 | /*** VEX DATA ***************************************/ 191 | /********************************************************/ 192 | void loadVEXData(LanguageData &types, 193 | LanguageData &keywords, 194 | LanguageData &builtin, 195 | LanguageData &literals, 196 | LanguageData &other); 197 | 198 | /********************************************************/ 199 | /*** CMake DATA **************************************/ 200 | /********************************************************/ 201 | void loadCMakeData(QMultiHash &types, 202 | QMultiHash &keywords, 203 | QMultiHash &builtin, 204 | QMultiHash &literals, 205 | QMultiHash &other); 206 | 207 | /********************************************************/ 208 | /*** Make DATA ***************************************/ 209 | /********************************************************/ 210 | void loadMakeData(QMultiHash& types, 211 | QMultiHash& keywords, 212 | QMultiHash& builtin, 213 | QMultiHash& literals, 214 | QMultiHash& other); 215 | 216 | void loadAsmData(QMultiHash& types, 217 | QMultiHash& keywords, 218 | QMultiHash& builtin, 219 | QMultiHash& literals, 220 | QMultiHash& other); 221 | 222 | /********************************************************/ 223 | /*** Rhai DATA ***********************************/ 224 | /********************************************************/ 225 | void loadRhaiData(LanguageData &types, 226 | LanguageData &keywords, 227 | LanguageData &builtin, 228 | LanguageData &literals, 229 | LanguageData &other); 230 | } 231 | #endif 232 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #include "mainwindow.h" 25 | 26 | #include 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | QApplication a(argc, argv); 31 | MainWindow w; 32 | w.show(); 33 | return a.exec(); 34 | } 35 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #include "mainwindow.h" 25 | #include "ui_mainwindow.h" 26 | #include "qsourcehighliter.h" 27 | 28 | #include 29 | #include 30 | 31 | using namespace QSourceHighlite; 32 | 33 | QHash MainWindow::_langStringToEnum; 34 | 35 | MainWindow::MainWindow(QWidget *parent) 36 | : QMainWindow(parent) 37 | , ui(new Ui::MainWindow) 38 | { 39 | ui->setupUi(this); 40 | 41 | initLangsEnum(); 42 | initLangsComboBox(); 43 | initThemesComboBox(); 44 | 45 | //set highlighter 46 | QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont); 47 | ui->plainTextEdit->setFont(f); 48 | highlighter = new QSourceHighliter(ui->plainTextEdit->document()); 49 | 50 | connect(ui->langComboBox, 51 | static_cast(&QComboBox::currentTextChanged), 52 | this, &MainWindow::languageChanged); 53 | connect(ui->themeComboBox, 54 | static_cast(&QComboBox::currentIndexChanged), 55 | this, &MainWindow::themeChanged); 56 | 57 | ui->langComboBox->setCurrentText("Asm"); 58 | languageChanged("Asm"); 59 | // connect(ui->plainTextEdit, &QPlainTextEdit::textChanged, this, &MainWindow::printDebug); 60 | } 61 | 62 | MainWindow::~MainWindow() 63 | { 64 | delete ui; 65 | } 66 | 67 | void MainWindow::initLangsEnum() 68 | { 69 | MainWindow::_langStringToEnum = QHash { 70 | { QLatin1String("Asm"), QSourceHighliter::CodeAsm }, 71 | { QLatin1String("Bash"), QSourceHighliter::CodeBash }, 72 | { QLatin1String("C"), QSourceHighliter::CodeC }, 73 | { QLatin1String("C++"), QSourceHighliter::CodeCpp }, 74 | { QLatin1String("CMake"), QSourceHighliter::CodeCMake }, 75 | { QLatin1String("CSharp"), QSourceHighliter::CodeCSharp }, 76 | { QLatin1String("Css"), QSourceHighliter::CodeCSS }, 77 | { QLatin1String("Go"), QSourceHighliter::CodeGo }, 78 | { QLatin1String("Html"), QSourceHighliter::CodeXML }, 79 | { QLatin1String("Ini"), QSourceHighliter::CodeINI }, 80 | { QLatin1String("Java"), QSourceHighliter::CodeJava }, 81 | { QLatin1String("Javascript"), QSourceHighliter::CodeJava }, 82 | { QLatin1String("Json"), QSourceHighliter::CodeJSON }, 83 | { QLatin1String("Lua"), QSourceHighliter::CodeLua }, 84 | { QLatin1String("Make"), QSourceHighliter::CodeMake }, 85 | { QLatin1String("Php"), QSourceHighliter::CodePHP }, 86 | { QLatin1String("Python"), QSourceHighliter::CodePython }, 87 | { QLatin1String("Qml"), QSourceHighliter::CodeQML }, 88 | { QLatin1String("Rhai"), QSourceHighliter::CodeRhai }, 89 | { QLatin1String("Rust"), QSourceHighliter::CodeRust }, 90 | { QLatin1String("Sql"), QSourceHighliter::CodeSQL }, 91 | { QLatin1String("Typescript"), QSourceHighliter::CodeTypeScript }, 92 | { QLatin1String("V"), QSourceHighliter::CodeV }, 93 | { QLatin1String("Vex"), QSourceHighliter::CodeVex }, 94 | { QLatin1String("Xml"), QSourceHighliter::CodeXML }, 95 | { QLatin1String("Yaml"), QSourceHighliter::CodeYAML } 96 | }; 97 | } 98 | 99 | void MainWindow::initThemesComboBox() 100 | { 101 | ui->themeComboBox->addItem("Monokai", QSourceHighliter::Themes::Monokai); 102 | ui->themeComboBox->addItem("debug", QSourceHighliter::Themes::Monokai); 103 | } 104 | 105 | void MainWindow::initLangsComboBox() { 106 | ui->langComboBox->addItem("Asm"); 107 | ui->langComboBox->addItem("Bash"); 108 | ui->langComboBox->addItem("C"); 109 | ui->langComboBox->addItem("C++"); 110 | ui->langComboBox->addItem("CMake"); 111 | ui->langComboBox->addItem("CSharp"); 112 | ui->langComboBox->addItem("Css"); 113 | ui->langComboBox->addItem("Go"); 114 | ui->langComboBox->addItem("Html"); 115 | ui->langComboBox->addItem("Ini"); 116 | ui->langComboBox->addItem("Javascript"); 117 | ui->langComboBox->addItem("Java"); 118 | ui->langComboBox->addItem("Lua"); 119 | ui->langComboBox->addItem("Make"); 120 | ui->langComboBox->addItem("Php"); 121 | ui->langComboBox->addItem("Python"); 122 | ui->langComboBox->addItem("Qml"); 123 | ui->langComboBox->addItem("Rust"); 124 | ui->langComboBox->addItem("Sql"); 125 | ui->langComboBox->addItem("Typescript"); 126 | ui->langComboBox->addItem("V"); 127 | ui->langComboBox->addItem("Vex"); 128 | ui->langComboBox->addItem("Xml"); 129 | ui->langComboBox->addItem("Yaml"); 130 | } 131 | 132 | void MainWindow::themeChanged(int) { 133 | QSourceHighliter::Themes theme = (QSourceHighliter::Themes)ui->themeComboBox->currentData().toInt(); 134 | highlighter->setTheme(theme); 135 | } 136 | 137 | void MainWindow::languageChanged(const QString &lang) { 138 | highlighter->setCurrentLanguage(_langStringToEnum.value(lang)); 139 | 140 | QFile f(QDir::currentPath() + "/../test_files/" + lang + ".txt"); 141 | if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { 142 | const auto text = f.readAll(); 143 | ui->plainTextEdit->setPlainText(QString::fromUtf8(text)); 144 | } 145 | f.close(); 146 | } 147 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #ifndef MAINWINDOW_H 25 | #define MAINWINDOW_H 26 | 27 | #include 28 | #include 29 | 30 | QT_BEGIN_NAMESPACE 31 | namespace Ui { class MainWindow; } 32 | QT_END_NAMESPACE 33 | 34 | class MainWindow : public QMainWindow 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | MainWindow(QWidget *parent = nullptr); 40 | ~MainWindow(); 41 | 42 | private: 43 | Ui::MainWindow *ui; 44 | QSourceHighlite::QSourceHighliter *highlighter; 45 | static QHash _langStringToEnum; 46 | 47 | /* FUNCTIONS */ 48 | void initLangsEnum(); 49 | void initLangsComboBox(); 50 | void initThemesComboBox(); 51 | 52 | private slots: 53 | void themeChanged(int); 54 | void languageChanged(const QString &lang); 55 | 56 | }; 57 | #endif // MAINWINDOW_H 58 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | 27 | 28 | 0 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Language: 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -1 50 | 51 | 52 | 53 | 54 | 55 | 56 | Theme 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0 75 | 0 76 | 800 77 | 23 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /qsourcehighliter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #include "qsourcehighliter.h" 25 | #include "languagedata.h" 26 | #include "qsourcehighliterthemes.h" 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | namespace QSourceHighlite { 33 | 34 | QSourceHighliter::QSourceHighliter(QTextDocument *doc) 35 | : QSyntaxHighlighter(doc), 36 | _language(CodeC) 37 | { 38 | initFormats(); 39 | } 40 | 41 | QSourceHighliter::QSourceHighliter(QTextDocument *doc, QSourceHighliter::Themes theme) 42 | : QSyntaxHighlighter(doc), 43 | _language(CodeC) 44 | { 45 | setTheme(theme); 46 | } 47 | 48 | void QSourceHighliter::initFormats() { 49 | /**************************************** 50 | * Formats for syntax highlighting 51 | ***************************************/ 52 | 53 | QTextCharFormat format = QTextCharFormat(); 54 | 55 | _formats[Token::CodeBlock] = format; 56 | format = QTextCharFormat(); 57 | 58 | format.setForeground(QColor("#F92672")); 59 | _formats[Token::CodeKeyWord] = format; 60 | format = QTextCharFormat(); 61 | 62 | format.setForeground(QColor("#a39b4e")); 63 | _formats[Token::CodeString] = format; 64 | format = QTextCharFormat(); 65 | 66 | format.setForeground(QColor("#75715E")); 67 | _formats[Token::CodeComment] = format; 68 | format = QTextCharFormat(); 69 | 70 | format.setForeground(QColor("#54aebf")); 71 | _formats[Token::CodeType] = format; 72 | 73 | format = QTextCharFormat(); 74 | format.setForeground(QColor("#db8744")); 75 | _formats[Token::CodeOther] = format; 76 | 77 | format = QTextCharFormat(); 78 | format.setForeground(QColor("#AE81FF")); 79 | _formats[Token::CodeNumLiteral] = format; 80 | 81 | format = QTextCharFormat(); 82 | format.setForeground(QColor("#018a0f")); 83 | _formats[Token::CodeBuiltIn] = format; 84 | } 85 | 86 | void QSourceHighliter::setCurrentLanguage(Language language) { 87 | if (language != _language) 88 | _language = language; 89 | } 90 | 91 | QSourceHighliter::Language QSourceHighliter::currentLanguage() { 92 | return _language; 93 | } 94 | 95 | void QSourceHighliter::setTheme(QSourceHighliter::Themes theme) 96 | { 97 | _formats = QSourceHighliterTheme::theme(theme); 98 | rehighlight(); 99 | } 100 | 101 | void QSourceHighliter::highlightBlock(const QString &text) 102 | { 103 | if (currentBlock() == document()->firstBlock()) { 104 | setCurrentBlockState(_language); 105 | } else { 106 | previousBlockState() == _language ? 107 | setCurrentBlockState(_language) : 108 | setCurrentBlockState(_language + 1); 109 | } 110 | 111 | highlightSyntax(text); 112 | } 113 | 114 | /** 115 | * @brief Does the code syntax highlighting 116 | * @param text 117 | */ 118 | void QSourceHighliter::highlightSyntax(const QString &text) 119 | { 120 | if (text.isEmpty()) return; 121 | 122 | const auto textLen = text.length(); 123 | 124 | QChar comment; 125 | bool isCSS = false; 126 | bool isYAML = false; 127 | bool isMake = false; 128 | bool isAsm = false; 129 | bool isSQL = false; 130 | 131 | LanguageData keywords{}, 132 | others{}, 133 | types{}, 134 | builtin{}, 135 | literals{}; 136 | 137 | switch (currentBlockState()) { 138 | case CodeLua : 139 | case CodeLuaComment : 140 | loadLuaData(types, keywords, builtin, literals, others); 141 | break; 142 | case CodeCpp : 143 | case CodeCppComment : 144 | loadCppData(types, keywords, builtin, literals, others); 145 | break; 146 | case CodeJs : 147 | case CodeJsComment : 148 | loadJSData(types, keywords, builtin, literals, others); 149 | break; 150 | case CodeC : 151 | case CodeCComment : 152 | loadCppData(types, keywords, builtin, literals, others); 153 | break; 154 | case CodeBash : 155 | loadShellData(types, keywords, builtin, literals, others); 156 | comment = QLatin1Char('#'); 157 | break; 158 | case CodePHP : 159 | case CodePHPComment : 160 | loadPHPData(types, keywords, builtin, literals, others); 161 | break; 162 | case CodeQML : 163 | case CodeQMLComment : 164 | loadQMLData(types, keywords, builtin, literals, others); 165 | break; 166 | case CodePython : 167 | loadPythonData(types, keywords, builtin, literals, others); 168 | comment = QLatin1Char('#'); 169 | break; 170 | case CodeRust : 171 | case CodeRustComment : 172 | loadRustData(types, keywords, builtin, literals, others); 173 | break; 174 | case CodeJava : 175 | case CodeJavaComment : 176 | loadJavaData(types, keywords, builtin, literals, others); 177 | break; 178 | case CodeCSharp : 179 | case CodeCSharpComment : 180 | loadCSharpData(types, keywords, builtin, literals, others); 181 | break; 182 | case CodeGo : 183 | case CodeGoComment : 184 | loadGoData(types, keywords, builtin, literals, others); 185 | break; 186 | case CodeV : 187 | case CodeVComment : 188 | loadVData(types, keywords, builtin, literals, others); 189 | break; 190 | case CodeSQL : 191 | isSQL = true; 192 | loadSQLData(types, keywords, builtin, literals, others); 193 | break; 194 | case CodeJSON : 195 | loadJSONData(types, keywords, builtin, literals, others); 196 | break; 197 | case CodeXML : 198 | xmlHighlighter(text); 199 | return; 200 | case CodeCSS : 201 | case CodeCSSComment : 202 | isCSS = true; 203 | loadCSSData(types, keywords, builtin, literals, others); 204 | break; 205 | case CodeTypeScript: 206 | case CodeTypeScriptComment: 207 | loadTypescriptData(types, keywords, builtin, literals, others); 208 | break; 209 | case CodeYAML: 210 | isYAML = true; 211 | loadYAMLData(types, keywords, builtin, literals, others); 212 | comment = QLatin1Char('#'); 213 | break; 214 | case CodeINI: 215 | comment = QLatin1Char('#'); 216 | break; 217 | case CodeVex: 218 | case CodeVexComment: 219 | loadVEXData(types, keywords, builtin, literals, others); 220 | break; 221 | case CodeCMake: 222 | loadCMakeData(types, keywords, builtin, literals, others); 223 | comment = QLatin1Char('#'); 224 | break; 225 | case CodeMake: 226 | isMake = true; 227 | loadMakeData(types, keywords, builtin, literals, others); 228 | comment = QLatin1Char('#'); 229 | break; 230 | case CodeAsm: 231 | isAsm = true; 232 | loadAsmData(types, keywords, builtin, literals, others); 233 | comment = QLatin1Char('#'); 234 | break; 235 | case CodeRhai : 236 | case CodeRhaiComment : 237 | loadRhaiData(types, keywords, builtin, literals, others); 238 | break; 239 | default: 240 | break; 241 | } 242 | 243 | // keep the default code block format 244 | // this statement is very slow 245 | // TODO: do this formatting when necessary instead of 246 | // applying it to the whole block in the beginning 247 | setFormat(0, textLen, _formats[CodeBlock]); 248 | 249 | auto applyCodeFormat = 250 | [this](int i, const LanguageData &data, 251 | const QString &text, const QTextCharFormat &fmt) -> int { 252 | // check if we are at the beginning OR if this is the start of a word 253 | if (i == 0 || (!text.at(i - 1).isLetterOrNumber() && 254 | text.at(i-1) != QLatin1Char('_'))) { 255 | const auto wordList = data.values(text.at(i).toLatin1()); 256 | for (const QLatin1String &word : wordList) { 257 | // we have a word match check 258 | // 1. if we are at the end 259 | // 2. if we have a complete word 260 | if (word == strMidRef(text, i, word.size()) && 261 | (i + word.size() == text.length() || 262 | (!text.at(i + word.size()).isLetterOrNumber() && 263 | text.at(i + word.size()) != QLatin1Char('_')))) { 264 | setFormat(i, word.size(), fmt); 265 | i += word.size(); 266 | } 267 | } 268 | } 269 | return i; 270 | }; 271 | 272 | const QTextCharFormat &formatType = _formats[CodeType]; 273 | const QTextCharFormat &formatKeyword = _formats[CodeKeyWord]; 274 | const QTextCharFormat &formatComment = _formats[CodeComment]; 275 | const QTextCharFormat &formatNumLit = _formats[CodeNumLiteral]; 276 | const QTextCharFormat &formatBuiltIn = _formats[CodeBuiltIn]; 277 | const QTextCharFormat &formatOther = _formats[CodeOther]; 278 | 279 | for (int i = 0; i < textLen; ++i) { 280 | 281 | if (currentBlockState() % 2 != 0) goto Comment; 282 | 283 | while (i < textLen && !text[i].isLetter()) { 284 | if (text[i].isSpace()) { 285 | ++i; 286 | //make sure we don't cross the bound 287 | if (i == textLen) return; 288 | if (text[i].isLetter()) break; 289 | else continue; 290 | } 291 | //inline comment 292 | if (comment.isNull() && text[i] == QLatin1Char('/')) { 293 | if((i+1) < textLen){ 294 | if(text[i+1] == QLatin1Char('/')) { 295 | setFormat(i, textLen, formatComment); 296 | return; 297 | } else if(text[i+1] == QLatin1Char('*')) { 298 | Comment: 299 | //find a comment end after current position. 300 | int next = text.indexOf(QLatin1String("*/"),i); 301 | if (next == -1) { 302 | //we didn't find a comment end. 303 | //Check if we are already in a comment block 304 | if (currentBlockState() % 2 == 0) 305 | setCurrentBlockState(currentBlockState() + 1); 306 | setFormat(i, textLen, formatComment); 307 | return; 308 | } else { 309 | //we found a comment end 310 | //mark this block as code if it was previously comment 311 | //first check if the comment ended on the same line 312 | //if modulo 2 is not equal to zero, it means we are in a comment 313 | //-1 will set this block's state as language 314 | if (currentBlockState() % 2 != 0) { 315 | setCurrentBlockState(currentBlockState() - 1); 316 | } 317 | next += 2; 318 | setFormat(i, next - i, formatComment); 319 | i = next; 320 | if (i >= textLen) return; 321 | } 322 | } 323 | } 324 | } else if (isSQL && comment.isNull() && text[i] == QLatin1Char('-')) { 325 | if((i+1) < textLen){ 326 | if(text[i+1] == QLatin1Char('-')) { 327 | setFormat(i, textLen, formatComment); 328 | return; 329 | } 330 | } 331 | } else if (text[i] == comment) { 332 | setFormat(i, textLen, formatComment); 333 | i = textLen; 334 | //integer literal 335 | } else if (text[i].isNumber()) { 336 | i = highlightNumericLiterals(text, i); 337 | //string literals 338 | } else if (text[i] == QLatin1Char('\"')) { 339 | i = highlightStringLiterals('\"', text, i); 340 | } else if (text[i] == QLatin1Char('\'')) { 341 | i = highlightStringLiterals('\'', text, i); 342 | } 343 | if (i >= textLen) { 344 | break; 345 | } 346 | ++i; 347 | } 348 | 349 | const int pos = i; 350 | 351 | if (i == textLen || !text[i].isLetter()) continue; 352 | 353 | /* Highlight Types */ 354 | i = applyCodeFormat(i, types, text, formatType); 355 | /************************************************ 356 | next letter is usually a space, in that case 357 | going forward is useless, so continue; 358 | We can ++i here and go to the beginning of the next word 359 | so that the next formatter can check for formatting but this will 360 | cause problems in case the next word is also of 'Type' or the current 361 | type(keyword/builtin). We can work around it and reset the value of i 362 | in the beginning of the loop to the word's first letter but I am not 363 | sure about its efficiency yet. 364 | ************************************************/ 365 | if (i == textLen || !text[i].isLetter()) continue; 366 | 367 | /* Highlight Keywords */ 368 | i = applyCodeFormat(i, keywords, text, formatKeyword); 369 | if (i == textLen || !text[i].isLetter()) continue; 370 | 371 | /* Highlight Literals (true/false/NULL,nullptr) */ 372 | i = applyCodeFormat(i, literals, text, formatNumLit); 373 | if (i == textLen || !text[i].isLetter()) continue; 374 | 375 | /* Highlight Builtin library stuff */ 376 | i = applyCodeFormat(i, builtin, text, formatBuiltIn); 377 | if (i == textLen || !text[i].isLetter()) continue; 378 | 379 | /* Highlight other stuff (preprocessor etc.) */ 380 | if (( i == 0 || !text.at(i-1).isLetter()) && others.contains(text[i].toLatin1())) { 381 | const QList wordList = others.values(text[i].toLatin1()); 382 | for(const QLatin1String &word : wordList) { 383 | if (word == strMidRef(text, i, word.size()) // we have a word match 384 | && 385 | (i + word.size() == text.length() // check if we are at the end 386 | || 387 | !text.at(i + word.size()).isLetter()) //OR if we have a complete word 388 | ) { 389 | currentBlockState() == CodeCpp ? 390 | setFormat(i - 1, word.size() + 1, formatOther) : 391 | setFormat(i, word.size(), formatOther); 392 | i += word.size(); 393 | } 394 | } 395 | } 396 | 397 | //we were unable to find any match, lets skip this word 398 | if (pos == i) { 399 | int count = i; 400 | while (count < textLen) { 401 | if (!text[count].isLetter()) break; 402 | ++count; 403 | } 404 | i = count; 405 | } 406 | } 407 | 408 | if (isCSS) cssHighlighter(text); 409 | if (isYAML) ymlHighlighter(text); 410 | if (isMake) makeHighlighter(text); 411 | if (isAsm) asmHighlighter(text); 412 | } 413 | 414 | /** 415 | * @brief Highlight string literals in code 416 | * @param strType str type i.e., ' or " 417 | * @param text the text being scanned 418 | * @param i pos of i in loop 419 | * @return pos of i after the string 420 | */ 421 | int QSourceHighliter::highlightStringLiterals(const QChar strType, const QString &text, int i) { 422 | setFormat(i, 1, _formats[CodeString]); 423 | ++i; 424 | 425 | while (i < text.length()) { 426 | //look for string end 427 | //make sure it's not an escape seq 428 | if (text.at(i) == strType && text.at(i-1) != QLatin1Char('\\')) { 429 | setFormat(i, 1, _formats[CodeString]); 430 | ++i; 431 | break; 432 | } 433 | //look for escape sequence 434 | if (text.at(i) == QLatin1Char('\\') && (i+1) < text.length()) { 435 | int len = 0; 436 | switch(text.at(i+1).toLatin1()) { 437 | case 'a': 438 | case 'b': 439 | case 'e': 440 | case 'f': 441 | case 'n': 442 | case 'r': 443 | case 't': 444 | case 'v': 445 | case '\'': 446 | case '"': 447 | case '\\': 448 | case '\?': 449 | //2 because we have to highlight \ as well as the following char 450 | len = 2; 451 | break; 452 | //octal esc sequence \123 453 | case '0': 454 | case '1': 455 | case '2': 456 | case '3': 457 | case '4': 458 | case '5': 459 | case '6': 460 | case '7': 461 | { 462 | if (i + 4 <= text.length()) { 463 | bool isCurrentOctal = true; 464 | if (!isOctal(text.at(i+2).toLatin1())) { 465 | isCurrentOctal = false; 466 | break; 467 | } 468 | if (!isOctal(text.at(i+3).toLatin1())) { 469 | isCurrentOctal = false; 470 | break; 471 | } 472 | len = isCurrentOctal ? 4 : 0; 473 | } 474 | break; 475 | } 476 | //hex numbers \xFA 477 | case 'x': 478 | { 479 | if (i + 3 <= text.length()) { 480 | bool isCurrentHex = true; 481 | if (!isHex(text.at(i+2).toLatin1())) { 482 | isCurrentHex = false; 483 | break; 484 | } 485 | if (!isHex(text.at(i+3).toLatin1())) { 486 | isCurrentHex = false; 487 | break; 488 | } 489 | len = isCurrentHex ? 4 : 0; 490 | } 491 | break; 492 | } 493 | //TODO: implement unicode code point escaping 494 | default: 495 | break; 496 | } 497 | 498 | //if len is zero, that means this wasn't an esc seq 499 | //increment i so that we skip this backslash 500 | if (len == 0) { 501 | setFormat(i, 1, _formats[CodeString]); 502 | ++i; 503 | continue; 504 | } 505 | 506 | setFormat(i, len, _formats[CodeNumLiteral]); 507 | i += len; 508 | continue; 509 | } 510 | setFormat(i, 1, _formats[CodeString]); 511 | ++i; 512 | } 513 | return i; 514 | } 515 | 516 | /** 517 | * @brief Highlight number literals in code 518 | * @param text the text being scanned 519 | * @param i pos of i in loop 520 | * @return pos of i after the number 521 | */ 522 | int QSourceHighliter::highlightNumericLiterals(const QString &text, int i) 523 | { 524 | bool isPreAllowed = false; 525 | if (i == 0) isPreAllowed = true; 526 | else { 527 | //these values are allowed before a number 528 | switch(text.at(i - 1).toLatin1()) { 529 | //css number 530 | case ':': 531 | if (currentBlockState() == CodeCSS) 532 | isPreAllowed = true; 533 | break; 534 | case '$': 535 | if (currentBlockState() == CodeAsm) 536 | isPreAllowed = true; 537 | break; 538 | case '[': 539 | case '(': 540 | case '{': 541 | case ' ': 542 | case ',': 543 | case '=': 544 | case '+': 545 | case '-': 546 | case '*': 547 | case '/': 548 | case '%': 549 | case '<': 550 | case '>': 551 | isPreAllowed = true; 552 | break; 553 | } 554 | } 555 | 556 | if (!isPreAllowed) return i; 557 | 558 | const int start = i; 559 | 560 | if ((i+1) >= text.length()) { 561 | setFormat(i, 1, _formats[CodeNumLiteral]); 562 | return ++i; 563 | } 564 | 565 | ++i; 566 | //hex numbers highlighting (only if there's a preceding zero) 567 | if (text.at(i) == QChar('x') && text.at(i - 1) == QChar('0')) 568 | ++i; 569 | 570 | while (i < text.length()) { 571 | if (!text.at(i).isNumber() && text.at(i) != QChar('.') && 572 | text.at(i) != QChar('e')) //exponent 573 | break; 574 | ++i; 575 | } 576 | 577 | bool isPostAllowed = false; 578 | if (i == text.length()) { 579 | //cant have e at the end 580 | if (text.at(i - 1) != QChar('e')) 581 | isPostAllowed = true; 582 | } else { 583 | //these values are allowed after a number 584 | switch(text.at(i).toLatin1()) { 585 | case ']': 586 | case ')': 587 | case '}': 588 | case ' ': 589 | case ',': 590 | case '=': 591 | case '+': 592 | case '-': 593 | case '*': 594 | case '/': 595 | case '%': 596 | case '>': 597 | case '<': 598 | case ';': 599 | isPostAllowed = true; 600 | break; 601 | // for 100u, 1.0F 602 | case 'p': 603 | if (currentBlockState() == CodeCSS) 604 | if (i + 1 < text.length() && text.at(i+1) == QChar('x')) { 605 | if (i + 2 == text.length() || !text.at(i+2).isLetterOrNumber()) 606 | isPostAllowed = true; 607 | } 608 | break; 609 | case 'e': 610 | if (currentBlockState() == CodeCSS) 611 | if (i + 1 < text.length() && text.at(i+1) == QChar('m')) { 612 | if (i + 2 == text.length() || !text.at(i+2).isLetterOrNumber()) 613 | isPostAllowed = true; 614 | } 615 | break; 616 | case 'u': 617 | case 'l': 618 | case 'f': 619 | case 'U': 620 | case 'L': 621 | case 'F': 622 | if (i + 1 == text.length() || !text.at(i+1).isLetterOrNumber()) { 623 | isPostAllowed = true; 624 | ++i; 625 | } 626 | break; 627 | } 628 | } 629 | if (isPostAllowed) { 630 | int end = i; 631 | setFormat(start, end - start, _formats[CodeNumLiteral]); 632 | } 633 | //decrement so that the index is at the last number, not after it 634 | return --i; 635 | } 636 | 637 | /** 638 | * @brief The YAML highlighter 639 | * @param text 640 | * @details This function post processes a line after the main syntax 641 | * highlighter has run for additional highlighting. It does these things 642 | * 643 | * If the current line is a comment, skip it 644 | * 645 | * Highlight all the words that have a colon after them as 'keyword' except: 646 | * If the word is a string, skip it. 647 | * If the colon is in between a path, skip it (C:\) 648 | * 649 | * Once the colon is found, the function will skip every character except 'h' 650 | * 651 | * If an h letter is found, check the next 4/5 letters for http/https and 652 | * highlight them as a link (underlined) 653 | */ 654 | void QSourceHighliter::ymlHighlighter(const QString &text) { 655 | if (text.isEmpty()) return; 656 | const auto textLen = text.length(); 657 | bool colonNotFound = false; 658 | 659 | //if this is a comment don't do anything and just return 660 | if (text.trimmed().at(0) == QLatin1Char('#')) 661 | return; 662 | 663 | for (int i = 0; i < textLen; ++i) { 664 | if (!text.at(i).isLetter()) continue; 665 | 666 | if (colonNotFound && text.at(i) != QLatin1Char('h')) continue; 667 | 668 | //we found a string literal, skip it 669 | if (i != 0 && (text.at(i-1) == QLatin1Char('"') || text.at(i-1) == QLatin1Char('\''))) { 670 | const int next = text.indexOf(text.at(i-1), i); 671 | if (next == -1) break; 672 | i = next; 673 | continue; 674 | } 675 | 676 | const int colon = text.indexOf(QLatin1Char(':'), i); 677 | 678 | //if colon isn't found, we set this true 679 | if (colon == -1) colonNotFound = true; 680 | 681 | if (!colonNotFound) { 682 | //if the line ends here, format and return 683 | if (colon+1 == textLen) { 684 | setFormat(i, colon - i, _formats[CodeKeyWord]); 685 | return; 686 | } else { 687 | //colon is found, check if it isn't some path or something else 688 | if (!(text.at(colon+1) == QLatin1Char('\\') && text.at(colon+1) == QLatin1Char('/'))) { 689 | setFormat(i, colon - i, _formats[CodeKeyWord]); 690 | } 691 | } 692 | } 693 | 694 | //underlined links 695 | if (text.at(i) == QLatin1Char('h')) { 696 | if (strMidRef(text, i, 5) == QLatin1String("https") || 697 | strMidRef(text, i, 4) == QLatin1String("http")) { 698 | int space = text.indexOf(QChar(' '), i); 699 | if (space == -1) space = textLen; 700 | QTextCharFormat f = _formats[CodeString]; 701 | f.setUnderlineStyle(QTextCharFormat::SingleUnderline); 702 | setFormat(i, space - i, f); 703 | i = space; 704 | } 705 | } 706 | } 707 | } 708 | 709 | void QSourceHighliter::cssHighlighter(const QString &text) 710 | { 711 | if (text.isEmpty()) return; 712 | const auto textLen = text.length(); 713 | for (int i = 0; i= textLen) return; 716 | if (text[i + 1].isSpace() || text[i+1].isNumber()) continue; 717 | int space = text.indexOf(QLatin1Char(' '), i); 718 | if (space < 0) { 719 | space = text.indexOf('{'); 720 | if (space < 0) { 721 | space = textLen; 722 | } 723 | } 724 | setFormat(i, space - i, _formats[CodeKeyWord]); 725 | i = space; 726 | } else if (text[i] == QLatin1Char('c')) { 727 | if (strMidRef(text, i, 5) == QLatin1String("color")) { 728 | i += 5; 729 | int colon = text.indexOf(QLatin1Char(':'), i); 730 | if (colon < 0) continue; 731 | i = colon; 732 | i++; 733 | while(i < textLen) { 734 | if (!text[i].isSpace()) break; 735 | i++; 736 | } 737 | int semicolon = text.indexOf(QLatin1Char(';')); 738 | if (semicolon < 0) semicolon = textLen; 739 | const QString color = text.mid(i, semicolon-i); 740 | QTextCharFormat f = _formats[CodeBlock]; 741 | QColor c(color); 742 | if (color.startsWith(QLatin1String("rgb"))) { 743 | int t = text.indexOf(QLatin1Char('('), i); 744 | int rPos = text.indexOf(QLatin1Char(','), t); 745 | int gPos = text.indexOf(QLatin1Char(','), rPos+1); 746 | int bPos = text.indexOf(QLatin1Char(')'), gPos); 747 | if (rPos > -1 && gPos > -1 && bPos > -1) { 748 | const auto r = strMidRef(text, t+1, rPos - (t+1)); 749 | const auto g = strMidRef(text, rPos+1, gPos - (rPos + 1)); 750 | const auto b = strMidRef(text, gPos+1, bPos - (gPos+1)); 751 | c.setRgb(r.toInt(), g.toInt(), b.toInt()); 752 | } else { 753 | c = _formats[CodeBlock].background().color(); 754 | } 755 | } 756 | 757 | if (!c.isValid()) { 758 | continue; 759 | } 760 | 761 | int lightness{}; 762 | QColor foreground; 763 | //really dark 764 | if (c.lightness() <= 20) { 765 | foreground = Qt::white; 766 | } else if (c.lightness() > 20 && c.lightness() <= 51){ 767 | foreground = QColor("#ccc"); 768 | } else if (c.lightness() > 51 && c.lightness() <= 78){ 769 | foreground = QColor("#bbb"); 770 | } else if (c.lightness() > 78 && c.lightness() <= 110){ 771 | foreground = QColor("#bbb"); 772 | } else if (c.lightness() > 127) { 773 | lightness = c.lightness() + 100; 774 | foreground = c.darker(lightness); 775 | } 776 | else { 777 | lightness = c.lightness() + 100; 778 | foreground = c.lighter(lightness); 779 | } 780 | 781 | f.setBackground(c); 782 | f.setForeground(foreground); 783 | setFormat(i, semicolon - i, QTextCharFormat()); //clear prev format 784 | setFormat(i, semicolon - i, f); 785 | i = semicolon; 786 | } 787 | } 788 | } 789 | } 790 | 791 | 792 | void QSourceHighliter::xmlHighlighter(const QString &text) { 793 | if (text.isEmpty()) return; 794 | const auto textLen = text.length(); 795 | 796 | setFormat(0, textLen, _formats[CodeBlock]); 797 | 798 | for (int i = 0; i < textLen; ++i) { 799 | if (text[i] == QLatin1Char('<') && text[i+1] != QLatin1Char('!')) { 800 | 801 | const int found = text.indexOf(QLatin1Char('>'), i); 802 | if (found > 0) { 803 | ++i; 804 | if (text[i] == QLatin1Char('/')) ++i; 805 | setFormat(i, found - i, _formats[CodeKeyWord]); 806 | } 807 | } 808 | 809 | if (text[i] == QLatin1Char('=')) { 810 | int lastSpace = text.lastIndexOf(QLatin1Char(' '), i); 811 | if (lastSpace == i-1) lastSpace = text.lastIndexOf(QLatin1Char(' '), i-2); 812 | if (lastSpace > 0) { 813 | setFormat(lastSpace, i - lastSpace, _formats[CodeBuiltIn]); 814 | } 815 | } 816 | 817 | if (text[i] == QLatin1Char('\"')) { 818 | const int pos = i; 819 | int cnt = 1; 820 | ++i; 821 | //bound check 822 | if ( (i+1) >= textLen) return; 823 | while (i < textLen) { 824 | if (text[i] == QLatin1Char('\"')) { 825 | ++cnt; 826 | ++i; 827 | break; 828 | } 829 | ++i; ++cnt; 830 | //bound check 831 | if ( (i+1) >= textLen) { 832 | ++cnt; 833 | break; 834 | } 835 | } 836 | setFormat(pos, cnt, _formats[CodeString]); 837 | } 838 | } 839 | } 840 | 841 | void QSourceHighliter::makeHighlighter(const QString &text) 842 | { 843 | int colonPos = text.indexOf(QLatin1Char(':')); 844 | if (colonPos == -1) 845 | return; 846 | setFormat(0, colonPos, _formats[Token::CodeBuiltIn]); 847 | } 848 | 849 | /** 850 | * @brief highlight inline labels such as 'func()' in "call func()" 851 | * @param text 852 | */ 853 | void QSourceHighliter::highlightInlineAsmLabels(const QString &text) 854 | { 855 | #define Q(s) QStringLiteral(s) 856 | static const QString jumps[27] = { 857 | //0 - 19 858 | Q("jmp"), Q("je"), Q("jne"), Q("jz"), Q("jnz"), Q("ja"), Q("jb"), Q("jg"), Q("jge"), Q("jae"), Q("jl"), Q("jle"), 859 | Q("jbe"), Q("jo"), Q("jno"), Q("js"), Q("jns"), Q("jcxz"), Q("jecxz"), Q("jrcxz"), 860 | //20 - 24 861 | Q("loop"), Q("loope"), Q("loopne"), Q("loopz"), Q("loopnz"), 862 | //25 - 26 863 | Q("call"), Q("callq") 864 | }; 865 | #undef Q 866 | 867 | auto format = _formats[Token::CodeBuiltIn]; 868 | format.setFontUnderline(true); 869 | 870 | const QString trimmed = text.trimmed(); 871 | int start = -1; 872 | int end = -1; 873 | char c{}; 874 | if (!trimmed.isEmpty()) 875 | c = trimmed.at(0).toLatin1(); 876 | if (c == 'j') { 877 | start = 0; end = 20; 878 | } else if (c == 'c') { 879 | start = 25; end = 27; 880 | } else if (c == 'l') { 881 | start = 20; end = 25; 882 | } else { 883 | return; 884 | } 885 | 886 | auto skipSpaces = [&text](int& j){ 887 | while (text.at(j).isSpace()) j++; 888 | return j; 889 | }; 890 | 891 | for (int i = start; i < end; ++i) { 892 | if (trimmed.startsWith(jumps[i])) { 893 | int j = 0; 894 | skipSpaces(j); 895 | j = j + jumps[i].length() + 1; 896 | skipSpaces(j); 897 | int len = text.length() - j; 898 | setFormat(j, len, format); 899 | } 900 | } 901 | } 902 | 903 | void QSourceHighliter::asmHighlighter(const QString& text) 904 | { 905 | highlightInlineAsmLabels(text); 906 | //label highlighting 907 | //examples: 908 | //L1: 909 | //LFB1: # local func begin 910 | // 911 | //following e.gs are not a label 912 | //mov %eax, Count::count(%rip) 913 | //.string ": #%s" 914 | 915 | //look for the last occurence of a colon 916 | int colonPos = text.lastIndexOf(QLatin1Char(':')); 917 | if (colonPos == -1) 918 | return; 919 | //check if this colon is in a comment maybe? 920 | bool isComment = text.lastIndexOf('#', colonPos) != -1; 921 | if (isComment) { 922 | int commentPos = text.lastIndexOf('#', colonPos); 923 | colonPos = text.lastIndexOf(':', commentPos); 924 | } 925 | 926 | auto format = _formats[Token::CodeBuiltIn]; 927 | format.setFontUnderline(true); 928 | 929 | if (colonPos >= text.length() - 1) { 930 | setFormat(0, colonPos, format); 931 | } 932 | 933 | int i = 0; 934 | bool isLabel = true; 935 | for (i = colonPos + 1; i < text.length(); ++i) { 936 | if (!text.at(i).isSpace()) { 937 | isLabel = false; 938 | break; 939 | } 940 | } 941 | 942 | if (!isLabel && i < text.length() && text.at(i) == QLatin1Char('#')) 943 | setFormat(0, colonPos, format); 944 | } 945 | } 946 | -------------------------------------------------------------------------------- /qsourcehighliter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #ifndef QSOURCEHIGHLITER_H 25 | #define QSOURCEHIGHLITER_H 26 | 27 | #include 28 | 29 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 30 | #include 31 | #endif 32 | 33 | namespace QSourceHighlite { 34 | 35 | class QSourceHighliter : public QSyntaxHighlighter 36 | { 37 | public: 38 | enum Themes { 39 | Monokai = 1 40 | }; 41 | 42 | explicit QSourceHighliter(QTextDocument *doc); 43 | QSourceHighliter(QTextDocument *doc, Themes theme); 44 | 45 | //languages 46 | /********* 47 | * When adding a language make sure that its value is a multiple of 2 48 | * This is because we use the next number as comment for that language 49 | * In case the language doesn't support multiline comments in the traditional C++ 50 | * sense, leave the next value empty. Otherwise mark the next value as comment for 51 | * that language. 52 | * e.g 53 | * CodeCpp = 200 54 | * CodeCppComment = 201 55 | */ 56 | enum Language { 57 | //languages 58 | CodeCpp = 200, 59 | CodeCppComment = 201, 60 | CodeJs = 202, 61 | CodeJsComment = 203, 62 | CodeC = 204, 63 | CodeCComment = 205, 64 | CodeBash = 206, 65 | CodePHP = 208, 66 | CodePHPComment = 209, 67 | CodeQML = 210, 68 | CodeQMLComment = 211, 69 | CodePython = 212, 70 | CodeRust = 214, 71 | CodeRustComment = 215, 72 | CodeJava = 216, 73 | CodeJavaComment = 217, 74 | CodeCSharp = 218, 75 | CodeCSharpComment = 219, 76 | CodeGo = 220, 77 | CodeGoComment = 221, 78 | CodeV = 222, 79 | CodeVComment = 223, 80 | CodeSQL = 224, 81 | CodeJSON = 226, 82 | CodeXML = 228, 83 | CodeCSS = 230, 84 | CodeCSSComment = 231, 85 | CodeTypeScript = 232, 86 | CodeTypeScriptComment = 233, 87 | CodeYAML = 234, 88 | CodeINI = 236, 89 | CodeVex = 238, 90 | CodeVexComment = 239, 91 | CodeCMake = 240, 92 | CodeMake = 242, 93 | CodeAsm = 244, 94 | CodeLua = 246, 95 | CodeLuaComment = 247, 96 | CodeRhai = 248, 97 | CodeRhaiComment = 249 98 | }; 99 | Q_ENUM(Language) 100 | 101 | enum Token { 102 | CodeBlock, 103 | CodeKeyWord, 104 | CodeString, 105 | CodeComment, 106 | CodeType, 107 | CodeOther, 108 | CodeNumLiteral, 109 | CodeBuiltIn, 110 | }; 111 | Q_ENUM(Token) 112 | 113 | void setCurrentLanguage(Language language); 114 | Q_REQUIRED_RESULT Language currentLanguage(); 115 | void setTheme(Themes theme); 116 | 117 | protected: 118 | void highlightBlock(const QString &text) override; 119 | 120 | private: 121 | void highlightSyntax(const QString &text); 122 | Q_REQUIRED_RESULT int highlightNumericLiterals(const QString &text, int i); 123 | Q_REQUIRED_RESULT int highlightStringLiterals(const QChar strType, const QString &text, int i); 124 | 125 | /** 126 | * @brief returns true if c is octal 127 | * @param c the char being checked 128 | * @returns true if the number is octal, false otherwise 129 | */ 130 | Q_REQUIRED_RESULT static constexpr inline bool isOctal(const char c) { 131 | return (c >= '0' && c <= '7'); 132 | } 133 | 134 | /** 135 | * @brief returns true if c is hex 136 | * @param c the char being checked 137 | * @returns true if the number is hex, false otherwise 138 | */ 139 | Q_REQUIRED_RESULT static constexpr inline bool isHex(const char c) { 140 | return ( 141 | (c >= '0' && c <= '9') || 142 | (c >= 'a' && c <= 'f') || 143 | (c >= 'A' && c <= 'F') 144 | ); 145 | } 146 | 147 | void cssHighlighter(const QString &text); 148 | void ymlHighlighter(const QString &text); 149 | void xmlHighlighter(const QString &text); 150 | void makeHighlighter(const QString &text); 151 | void highlightInlineAsmLabels(const QString& text); 152 | void asmHighlighter(const QString& text); 153 | void initFormats(); 154 | 155 | #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 156 | static inline QStringView strMidRef(const QString& str, qsizetype position, qsizetype n = -1) 157 | { 158 | return QStringView(str).mid(position, n); 159 | } 160 | #else 161 | static inline QStringRef strMidRef(const QString& str, int position, int n = -1) 162 | { 163 | return str.midRef(position, n); 164 | } 165 | #endif 166 | 167 | QHash _formats; 168 | Language _language; 169 | }; 170 | } 171 | #endif // QSOURCEHIGHLITER_H 172 | -------------------------------------------------------------------------------- /qsourcehighliterthemes.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #include "qsourcehighliterthemes.h" 25 | 26 | namespace QSourceHighlite { 27 | 28 | static QHash formats() 29 | { 30 | QHash _formats; 31 | 32 | QTextCharFormat defaultFormat = QTextCharFormat(); 33 | 34 | _formats[QSourceHighliter::Token::CodeBlock] = defaultFormat; 35 | _formats[QSourceHighliter::Token::CodeKeyWord] = defaultFormat; 36 | _formats[QSourceHighliter::Token::CodeString] = defaultFormat; 37 | _formats[QSourceHighliter::Token::CodeComment] = defaultFormat; 38 | _formats[QSourceHighliter::Token::CodeType] = defaultFormat; 39 | _formats[QSourceHighliter::Token::CodeOther] = defaultFormat; 40 | _formats[QSourceHighliter::Token::CodeNumLiteral] = defaultFormat; 41 | _formats[QSourceHighliter::Token::CodeBuiltIn] = defaultFormat; 42 | 43 | return _formats; 44 | } 45 | 46 | static QHash monokai() 47 | { 48 | QHash _formats = formats(); 49 | 50 | _formats[QSourceHighliter::Token::CodeBlock].setForeground(QColor(227, 226, 214)); 51 | _formats[QSourceHighliter::Token::CodeKeyWord].setForeground(QColor(249, 38, 114)); 52 | _formats[QSourceHighliter::Token::CodeString].setForeground(QColor(230, 219, 116)); 53 | _formats[QSourceHighliter::Token::CodeComment].setForeground(QColor(117, 113, 94)); 54 | _formats[QSourceHighliter::Token::CodeType].setForeground(QColor(102, 217, 239)); 55 | _formats[QSourceHighliter::Token::CodeOther].setForeground(QColor(249, 38, 114)); 56 | _formats[QSourceHighliter::Token::CodeNumLiteral].setForeground(QColor(174, 129, 255)); 57 | _formats[QSourceHighliter::Token::CodeBuiltIn].setForeground(QColor(166, 226, 46)); 58 | 59 | return _formats; 60 | } 61 | 62 | QHash 63 | QSourceHighliterTheme::theme(QSourceHighliter::Themes theme) { 64 | switch (theme) { 65 | case QSourceHighliter::Themes::Monokai: 66 | return monokai(); 67 | default: 68 | return {}; 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /qsourcehighliterthemes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2020 Waqar Ahmed -- 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | * 22 | */ 23 | 24 | #ifndef QSOURCEHIGHLITERTHEMES_H 25 | #define QSOURCEHIGHLITERTHEMES_H 26 | 27 | #include "qsourcehighliter.h" 28 | 29 | namespace QSourceHighlite { 30 | 31 | namespace QSourceHighliterTheme 32 | { 33 | QHash theme(QSourceHighliter::Themes); 34 | 35 | } // namespace QSourceHighliterTheme 36 | 37 | } // namespace QSourceHighlite 38 | #endif // QSOURCEHIGHLITERTHEMES_H 39 | -------------------------------------------------------------------------------- /screenshot/syntax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waqar144/QSourceHighlite/d78f0d4171580a18646b15425c449db3f2bb240a/screenshot/syntax.png -------------------------------------------------------------------------------- /test_files/Asm.txt: -------------------------------------------------------------------------------- 1 | val(int): # @val(int) 2 | pushq %rbp 3 | movq %rsp, %rbp 4 | movl %edi, -4(%rbp) 5 | movl $0, -8(%rbp) 6 | .LBB0_1: # =>This Inner Loop Header: Depth=1 7 | cmpl $3, -8(%rbp) 8 | jge .LBB0_4 9 | movl -4(%rbp), %eax 10 | addl $1, %eax 11 | movl %eax, -4(%rbp) 12 | movl -8(%rbp), %eax 13 | addl $1, %eax 14 | movl %eax, -8(%rbp) 15 | jmp .LBB0_1 16 | .LBB0_4: 17 | movl -4(%rbp), %eax 18 | cltd 19 | movl $3, %ecx 20 | idivl %ecx 21 | shll $1, %eax 22 | popq %rbp 23 | retq 24 | leal -4(%rip), $eax 25 | movl Count::count_(%rip) 26 | 27 | section .data 28 | string: db "hello, world\n" 29 | section .bss 30 | 31 | section text 32 | global main 33 | main: 34 | 35 | val(int): # @val(int) 36 | push rbp 37 | mov rbp, rsp 38 | mov dword ptr [rbp - 4], edi 39 | mov dword ptr [rbp - 8], 0 40 | .LBB0_1: # =>This Inner Loop Header: Depth=1 41 | cmp dword ptr [rbp - 8], 3 42 | jge .LBB0_4 43 | mov eax, dword ptr [rbp - 4] 44 | add eax, 1 45 | mov dword ptr [rbp - 4], eax 46 | mov eax, dword ptr [rbp - 8] 47 | add eax, 1 48 | mov dword ptr [rbp - 8], eax 49 | jmp .LBB0_1 50 | .LBB0_4: 51 | mov eax, dword ptr [rbp - 4] 52 | cdq 53 | mov ecx, 3 54 | idiv ecx 55 | shl eax, 1 56 | pop rbp 57 | ret 58 | -------------------------------------------------------------------------------- /test_files/C++.txt: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | int main(int argc, char *argv[]) { 6 | std::cout << "C++ Code Highlighting Demo" << std::endl; 7 | int x = 10; 8 | std::cout << x; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /test_files/C.txt: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main (int argc, char *argv[]) 4 | { 5 | int x = 10; 6 | bool y = true; 7 | printf("Hello, world\n"); 8 | for (int i = 0; i < 10; ++i) 9 | printf("%d\n", i); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test_files/CMake.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(slate VERSION 1.0.0 LANGUAGES CXX C) 3 | 4 | # CMakeLists.txt 5 | 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | set(CMAKE_AUTORCC ON) 8 | set(CMAKE_AUTOMOC ON) 9 | 10 | option(ENABLE_TESTING "" ON) 11 | 12 | find_package(Qt5 5.12 COMPONENTS Core Gui Quick Widgets Test REQUIRED) 13 | 14 | add_library( 15 | projectWarning INTERFACE 16 | ) 17 | 18 | target_compile_options( 19 | projectWarning INTERFACE 20 | $<$:$> 21 | $<$:$> 22 | $<$:/W0> 23 | ) 24 | 25 | add_subdirectory(lib) 26 | add_subdirectory(app) 27 | if(ENABLE_TESTING) 28 | enable_testing() 29 | 30 | add_subdirectory(tests) 31 | endif() 32 | -------------------------------------------------------------------------------- /test_files/Go.txt: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | /** 8 | * @brief main 9 | */ 10 | func main() { 11 | fmt.print("hello") log.SetFlags(log.LstdFlags | log.Lshortfile) 12 | 13 | // Parse and handle flags 14 | flags := flags.NewFlags() 15 | flags.Parse() 16 | 17 | // Build the application 18 | tviewApp = tview.NewApplication() 19 | wtfApp := app.NewWtfApp(tviewApp, config, flags.Config) 20 | wtfApp.Start() 21 | 22 | if err := tviewApp.Run(); err != nil { 23 | fmt.Printf("\n%s %v\n", aurora.Red("ERROR"), err) 24 | os.Exit(1) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test_files/Lua.txt: -------------------------------------------------------------------------------- 1 | 2 | require('module') 3 | 4 | -- Meta class 5 | TankClass = { 6 | damage = 0 7 | } 8 | TankClass_mt = { __index = TankClass } 9 | 10 | function TankClass:new() 11 | local instance = {} 12 | setmetatable(instance, TankClass_mt) 13 | instance.damage = 123 14 | return instance 15 | end 16 | 17 | 18 | -- single line comment 19 | function Hello() 20 | 21 | local maybe = false 22 | local foo = 123 23 | local english = 'hello' 24 | local french = 'bonjour' 25 | local bavarian = 'servus' 26 | 27 | if (foo == 123) then 28 | print(english) 29 | elseif (foo == 321) then 30 | print(french) 31 | else 32 | print(bavarian) 33 | end 34 | 35 | if (foo == 123 and foo == 321) then 36 | return 37 | end 38 | end 39 | 40 | --[[ this comment can 41 | span multiple lines 42 | --]] 43 | 44 | -- call Hello function 45 | Hello() 46 | 47 | 48 | -- for loop 49 | for i = 0,10,1 50 | do 51 | print(i) 52 | end 53 | 54 | -- while loop 55 | local i=0 56 | while (i < 5) 57 | do 58 | print(i) 59 | i = i + 1 60 | end 61 | 62 | 63 | -------------------------------------------------------------------------------- /test_files/Make.txt: -------------------------------------------------------------------------------- 1 | CFLAGS= -g -Wall -O2 -Wextra -Isrc -rdynamic -DNDEBUG ($OPTFLAGS) 2 | LIBS=-ldl $(OPTLIBS) 3 | PREFIX?=/usr/local 4 | 5 | SOURCES=$(wildcard src/**/*.c src/*.c) 6 | OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 7 | 8 | TEST_SRC=$(wildcard tests/*_tests.c) 9 | TESTS=$(patsubst %.c,%,$(TEST_SRC)) 10 | 11 | TARGET=build/libYOUR_LIBRARY.a 12 | SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 13 | 14 | #The Target Build 15 | all: $(TARGET) $(SO_TARGET) tests 16 | 17 | dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 18 | dev: all 19 | 20 | $(TARGET): CFLAGS += -fPIC 21 | $(TARGET): build $(OBJECTS) 22 | ar rcs $@ $(OBJECTS) 23 | ranlib $@ 24 | 25 | $(SO_TARGET): $(TARGET) $(OBJECTS) 26 | $(CC) -shared -o $@ $(OBJECTS) 27 | 28 | build: 29 | @mkdir -p build 30 | $mkdir -p bin 31 | 32 | #The Unit Tests 33 | .PHONY: tests 34 | tests: CFLAGS += $(TARGET) 35 | tests: $(TESTS) 36 | sh ./tests/runtests.sh 37 | 38 | valgrind: 39 | VALGRIND="valgrind --log-file=/tmp/valgrind-%p.log" $(MAKE) 40 | 41 | #The Cleaner 42 | clean: 43 | rm -rf build $(OBJECTS) $(TESTS) 44 | rm -f tests/tests.log 45 | find . -name "*.gc*" -exec rm {} \; 46 | rm -rf `find . -name "*.dSYM" -print` 47 | 48 | #The Install 49 | install: all 50 | install -d $(DESTDIR)/$(PREFIX)/lib/ 51 | install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/ 52 | 53 | #The Checker 54 | BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy| 55 | a?sn?printf|byte_)' 56 | check: 57 | @echo Files with potentially dangerous functions. 58 | @egrep $(BADFUNCS) $(SOURCES) || true 59 | -------------------------------------------------------------------------------- /test_files/Yaml.txt: -------------------------------------------------------------------------------- 1 | url: http://google.com/google 2 | bcd: "hello" 3 | asd: 123 4 | for: true 5 | 6 | # Crowdin configuration file 7 | # see: https://support.crowdin.com/configuration-file/ 8 | # 9 | # you will need the Java CLI client 10 | # see: https://support.crowdin.com/cli-tool/ 11 | 12 | project_identifier: abc 13 | 14 | # the api key has to be provided by ~/.crowdin.yaml 15 | #api_key: XXXX 16 | 17 | files: 18 | - file 19 | # source files filter 20 | # where translations live 21 | #"languages_mapping" : { 22 | #"two_letters_code" : { 23 | #"pt" : "pt_PT", 24 | #"pt-BR" : "pt_BR" 25 | #} 26 | #} 27 | "languages_mapping" : { 28 | "locale_with_underscore" : { 29 | "ar_SA" : "ar", 30 | "ca_ES" : "ca", 31 | "cs_CZ" : "cs", 32 | "de_DE" : "de", 33 | } 34 | } 35 | --------------------------------------------------------------------------------