1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "stylesci.h"
6#include "stylecolor.h"
7#include "stylejsonfile.h"
8#include "textedittabwidget/textedit.h"
9
10#include "common/common.h"
11#include "ILexer.h"
12#include "Lexilla.h"
13
14#include <QJsonObject>
15#include <QFileInfo>
16#include <QLibrary>
17#include <QDir>
18
19#include <bitset>
20
21QString lexillaFileName()
22{
23 return QString(LEXILLA_LIB) + LEXILLA_EXTENSION;
24}
25
26QString lexillaFilePath()
27{
28 return CustomPaths::global(CustomPaths::DependLibs)
29 + QDir::separator() + lexillaFileName();
30}
31
32sptr_t createLexerFromLib(const char *LanguageID)
33{
34 QFileInfo info(lexillaFilePath());
35 if (!info.exists()) {
36 qCritical() << "Failed, can't found lexilla library: " << info.filePath();
37 abort();
38 }
39
40 static QLibrary lexillaLibrary(info.filePath());
41 if (!lexillaLibrary.isLoaded()) {
42 if (!lexillaLibrary.load()) {
43 qCritical() << "Failed, to loading lexilla library: "
44 << info.filePath()
45 << lexillaLibrary.errorString();
46 abort();
47 }
48 qInfo() << "Successful, Loaded lexilla library:" << info.filePath()
49 << "\nand lexilla library support language count:";
50
51#ifdef QT_DEBUG
52 int langIDCount = ((Lexilla::GetLexerCountFn)(lexillaLibrary.resolve(LEXILLA_GETLEXERCOUNT)))();
53 QStringList sciSupportLangs;
54 for (int i = 0; i < langIDCount; i++) {
55 sciSupportLangs << ((Lexilla::LexerNameFromIDFn)(lexillaLibrary.resolve(LEXILLA_LEXERNAMEFROMID)))(i);
56 }
57 qInfo() << "scintilla support language: " << sciSupportLangs;
58#endif
59 }
60 QFunctionPointer fn = lexillaLibrary.resolve(LEXILLA_CREATELEXER);
61 if (!fn) {
62 qCritical() << lexillaLibrary.errorString();
63 abort();
64 }
65 void *lexer = ((Lexilla::CreateLexerFn)fn)(LanguageID);
66 return sptr_t(lexer);
67}
68
69class StyleSciPrivate
70{
71 friend class StyleSci;
72 TextEdit *edit;
73};
74
75void StyleSci::setKeyWords()
76{
77 auto tokens = support_file::Language::tokenWords(d->edit->supportLanguage());
78 auto codeKeyWordsMap = this->keyWords();
79
80 for (auto key : codeKeyWordsMap.keys()) {
81 auto codeKeyWords = codeKeyWordsMap[key].split(" ").toSet();
82 auto fileKeyWords = tokens.value(key).split(" ").toSet();
83 auto mergeKeywords = (codeKeyWords + fileKeyWords).values().join(" ").toLatin1();
84 d->edit->setKeyWords(key, mergeKeywords);
85 }
86
87 return;
88}
89
90void StyleSci::setStyle()
91{
92 auto fileJson = d->edit->getStyleFile();
93
94 auto themes = fileJson->themes();
95 if (!themes.isEmpty()) {
96
97 d->edit->styleResetDefault(); //clean all
98 fileJson->setTheme(themes.first());
99
100 auto selfObj = fileJson->value(StyleJsonFile::Key_1::get()->Self).toObject();
101 auto self_foreground = selfObj.value(StyleJsonFile::Key_2::get()->Foreground).toString().toInt(nullptr, 16);
102 auto self_background = selfObj.value(StyleJsonFile::Key_2::get()->Background).toString().toInt(nullptr, 16);
103 auto self_cursor = selfObj.value(StyleJsonFile::Key_2::get()->Cursor).toString().toInt(nullptr, 16);
104 d->edit->styleSetFore(STYLE_DEFAULT, self_foreground);
105 d->edit->styleSetBack(STYLE_DEFAULT, self_background);
106 d->edit->setCaretFore(self_cursor);
107 qInfo() << "Editor self jsonObject:" << selfObj;
108 qInfo() << "Editor self setting Style fore: " << hex << self_foreground;
109 qInfo() << "Editor self setting Style back: " << hex << self_background;
110 qInfo() << "Editor self setting Style cursor: " << hex << self_cursor;
111 // auto self_fontSize = selfObj.value(key_2.FontSize).toInt();
112 // d->edit->styleSetSize(STYLE_DEFAULT, self_fontSize);
113 for(int i = sectionStart(); i <= sectionEnd(); i++) {
114 if (i == sectionStart())
115 d->edit->styleSetFore(sectionStart(), self_foreground);
116 d->edit->styleSetBack(i, self_background);
117 }
118 d->edit->styleHotSpot(sectionEnd() + 1);
119 d->edit->styleSetUnderline(sectionEnd() + 1, true);
120 }
121
122 d->edit->annotationSetStyleOffset(AnnotationInfo::Role::get()->Fatal.code);
123 d->edit->annotationSetVisible(ANNOTATION_BOXED);
124
125 d->edit->styleSetBack(AnnotationInfo::Role::get()->Note.code, StyleColor::color(StyleColor::Table::get()->Blue));
126 d->edit->styleSetItalic(AnnotationInfo::Role::get()->Note.code, true);
127
128 d->edit->styleSetFore(AnnotationInfo::Role::get()->Warning.code, StyleColor::color(StyleColor::Table::get()->Yellow));
129 d->edit->styleSetBack(AnnotationInfo::Role::get()->Warning.code, StyleColor::color(StyleColor::Table::get()->Blue));
130 d->edit->styleSetItalic(AnnotationInfo::Role::get()->Warning.code, true);
131
132 d->edit->styleSetFore(AnnotationInfo::Role::get()->Error.code, StyleColor::color(StyleColor::Table::get()->Red));
133 d->edit->styleSetBack(AnnotationInfo::Role::get()->Error.code, StyleColor::color(StyleColor::Table::get()->Blue));
134 d->edit->styleSetItalic(AnnotationInfo::Role::get()->Error.code, true);
135
136 d->edit->styleSetFore(AnnotationInfo::Role::get()->Fatal.code , StyleColor::color(StyleColor::Table::get()->Red));
137 d->edit->styleSetBack(AnnotationInfo::Role::get()->Fatal.code, StyleColor::color(StyleColor::Table::get()->Blue));
138 d->edit->styleSetItalic(AnnotationInfo::Role::get()->Fatal.code, true);
139
140 return;
141}
142
143void StyleSci::setMargin()
144{
145 d->edit->setMargins(SC_MAX_MARGIN);
146
147 d->edit->setMarginSensitiveN(Margin::LineNumber, SCN_MARGINCLICK);
148 d->edit->setMarginWidthN(Margin::LineNumber, d->edit->textWidth(STYLE_LINENUMBER ,"999999"));
149 d->edit->setMarginBackN(Margin::LineNumber, d->edit->styleBack(STYLE_DEFAULT));
150
151 //runtime margin
152 d->edit->setMarginSensitiveN(Margin::Runtime, SCN_MARGINCLICK);
153 d->edit->setMarginWidthN(Margin::Runtime, 16);
154 d->edit->setMarginTypeN(Margin::Runtime, SC_MARGIN_SYMBOL);
155 d->edit->setMarginMaskN(Margin::Runtime, 1 << MarkerNumber::Debug
156 | 1 << MarkerNumber::Running
157 | 1 << MarkerNumber::RunningLineBackground
158 | 1 << MarkerNumber::CustomLineBackground);
159
160 d->edit->markerDefine(MarkerNumber::Debug, SC_MARK_CIRCLE);
161 d->edit->markerDefine(MarkerNumber::Running, SC_MARK_SHORTARROW);
162 d->edit->markerDefine(MarkerNumber::RunningLineBackground, SC_MARK_BACKGROUND);
163 d->edit->markerDefine(MarkerNumber::CustomLineBackground, SC_MARK_BACKGROUND);
164
165 d->edit->markerSetFore(MarkerNumber::Debug, StyleColor::color(StyleColor::Table::get()->FireBrick));
166 d->edit->markerSetBack(MarkerNumber::Debug, StyleColor::color(StyleColor::Table::get()->FireBrick));
167
168 d->edit->markerSetFore(MarkerNumber::Running, StyleColor::color(StyleColor::Table::get()->YellowGreen));
169 d->edit->markerSetBack(MarkerNumber::Running, StyleColor::color(StyleColor::Table::get()->YellowGreen));
170
171 d->edit->markerSetFore(MarkerNumber::RunningLineBackground, StyleColor::color(StyleColor::Table::get()->YellowGreen));
172 d->edit->markerSetBack(MarkerNumber::RunningLineBackground, StyleColor::color(StyleColor::Table::get()->YellowGreen));
173 d->edit->markerSetAlpha(MarkerNumber::RunningLineBackground, 0x55);
174}
175
176void StyleSci::setLexer()
177{
178 if (!d->edit->lexer()) {
179 //set token splitter
180 d->edit->setILexer(createLexerFromLib(d->edit->supportLanguage().toLatin1()));
181 if (!d->edit->lexer()) {
182 qCritical() << "Failed, can't create and load sci lexer";
183 }
184 }
185}
186
187StyleSci::StyleSci(TextEdit *parent)
188 : QObject (parent)
189 , d (new StyleSciPrivate())
190{
191 d->edit = parent;
192}
193
194StyleSci::~StyleSci()
195{
196 if (d) {
197 delete d;
198 }
199}
200
201TextEdit *StyleSci::edit()
202{
203 return d->edit;
204}
205
206QMap<int, QString> StyleSci::keyWords() const
207{
208 QMap<int, QString> result;
209 for(int i = 0; i <= KEYWORDSET_MAX; i++) {
210 result[i] = "";
211 }
212 return result;
213}
214
215int StyleSci::sectionEnd() const
216{
217 return 0;
218}
219
220int StyleSci::sectionStart() const
221{
222 return 0;
223}
224