File indexing completed on 2024-04-28 05:49:01

0001 /*
0002     SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 #include "semantic_tokens_legend.h"
0007 
0008 #include <KSyntaxHighlighting/Theme>
0009 #include <KTextEditor/Editor>
0010 
0011 SemanticTokensLegend::SemanticTokensLegend(QObject *parent)
0012     : QObject(parent)
0013 {
0014     themeChange(KTextEditor::Editor::instance());
0015     connect(KTextEditor::Editor::instance(), &KTextEditor::Editor::configChanged, this, &SemanticTokensLegend::themeChange);
0016 }
0017 
0018 enum {
0019     FuncAttr = 0,
0020     TypeAttr,
0021     MacroAttr,
0022     CommentAttr,
0023     VarParamAttr,
0024     ConstantAttr,
0025     KeywordAttr,
0026 };
0027 
0028 void SemanticTokensLegend::themeChange(KTextEditor::Editor *e)
0029 {
0030     if (!e) {
0031         return;
0032     }
0033 
0034     using Style = KSyntaxHighlighting::Theme::TextStyle;
0035 
0036     const auto theme = e->theme();
0037 
0038     QColor f = QColor::fromRgba(theme.textColor(Style::Function));
0039     QColor fs = QColor::fromRgba(theme.selectedTextColor(Style::Function));
0040     if (!fixedAttrs[FuncAttr]) {
0041         fixedAttrs[FuncAttr] = new KTextEditor::Attribute();
0042     }
0043     fixedAttrs[FuncAttr]->setForeground(f);
0044     fixedAttrs[FuncAttr]->setSelectedForeground(fs);
0045     fixedAttrs[FuncAttr]->setFontBold(theme.isBold(Style::Function));
0046     fixedAttrs[FuncAttr]->setFontItalic(theme.isItalic(Style::Function));
0047 
0048     if (!fixedAttrs[VarParamAttr]) {
0049         fixedAttrs[VarParamAttr] = new KTextEditor::Attribute();
0050     }
0051     {
0052         // This is only for function parameter which are not
0053         // directly supported by themes so we load some hard
0054         // coded values here for some of the themes we have
0055         // and for others we just read the "Variable" text-style.
0056         QColor v;
0057         QColor vs;
0058         bool italic = false;
0059         static const char MonokaiVP[] = "#fd971f";
0060         static const char DraculaVP[] = "#ffb86c";
0061         static const char AyuDarkLightVP[] = "#a37acc";
0062         static const char AyuMirageVP[] = "#d4bfff";
0063         if (theme.name() == QStringLiteral("Monokai")) {
0064             v = QColor(MonokaiVP);
0065             vs = v;
0066             italic = true;
0067         } else if (theme.name() == QStringLiteral("Dracula")) {
0068             v = QColor(DraculaVP);
0069             vs = v;
0070             italic = true;
0071         } else if (theme.name() == QStringLiteral("ayu Light") || theme.name() == QStringLiteral("ayu Dark")) {
0072             v = QColor(AyuDarkLightVP);
0073             vs = v;
0074         } else if (theme.name() == QStringLiteral("ayu Mirage")) {
0075             v = QColor(AyuMirageVP);
0076             vs = v;
0077         } else {
0078             v = QColor::fromRgba(theme.textColor(Style::Variable));
0079             italic = theme.isItalic(Style::Variable);
0080             vs = QColor::fromRgba(theme.selectedTextColor(Style::Variable));
0081         }
0082 
0083         fixedAttrs[VarParamAttr]->setForeground(v);
0084         fixedAttrs[VarParamAttr]->setSelectedForeground(vs);
0085         fixedAttrs[VarParamAttr]->setFontBold(theme.isBold(Style::Variable));
0086         fixedAttrs[VarParamAttr]->setFontItalic(italic);
0087     }
0088 
0089     QColor c = QColor::fromRgba(theme.textColor(Style::Constant));
0090     QColor cs = QColor::fromRgba(theme.selectedTextColor(Style::Constant));
0091     if (!fixedAttrs[ConstantAttr]) {
0092         fixedAttrs[ConstantAttr] = new KTextEditor::Attribute();
0093     }
0094     fixedAttrs[ConstantAttr]->setForeground(c);
0095     fixedAttrs[ConstantAttr]->setSelectedForeground(cs);
0096     fixedAttrs[ConstantAttr]->setFontBold(theme.isBold(Style::Constant));
0097     fixedAttrs[ConstantAttr]->setFontItalic(theme.isItalic(Style::Constant));
0098 
0099     QColor k = QColor::fromRgba(theme.textColor(Style::Keyword));
0100     QColor ks = QColor::fromRgba(theme.selectedTextColor(Style::Keyword));
0101     if (!fixedAttrs[KeywordAttr]) {
0102         fixedAttrs[KeywordAttr] = new KTextEditor::Attribute();
0103     }
0104     fixedAttrs[KeywordAttr]->setForeground(k);
0105     fixedAttrs[KeywordAttr]->setSelectedForeground(ks);
0106     fixedAttrs[KeywordAttr]->setFontBold(theme.isBold(Style::Keyword));
0107     fixedAttrs[KeywordAttr]->setFontItalic(theme.isItalic(Style::Keyword));
0108 
0109     QColor cm = QColor::fromRgba(theme.textColor(Style::Comment));
0110     QColor cms = QColor::fromRgba(theme.selectedTextColor(Style::Comment));
0111     if (!fixedAttrs[CommentAttr]) {
0112         fixedAttrs[CommentAttr] = new KTextEditor::Attribute();
0113     }
0114     fixedAttrs[CommentAttr]->setForeground(cm);
0115     fixedAttrs[CommentAttr]->setSelectedForeground(cms);
0116     fixedAttrs[CommentAttr]->setFontBold(theme.isBold(Style::Comment));
0117     fixedAttrs[CommentAttr]->setFontItalic(theme.isItalic(Style::Comment));
0118 
0119     QColor p = QColor::fromRgba(theme.textColor(Style::Preprocessor));
0120     QColor ps = QColor::fromRgba(theme.selectedTextColor(Style::Preprocessor));
0121     if (!fixedAttrs[MacroAttr]) {
0122         fixedAttrs[MacroAttr] = new KTextEditor::Attribute();
0123     }
0124     fixedAttrs[MacroAttr]->setForeground(p);
0125     fixedAttrs[MacroAttr]->setSelectedForeground(ps);
0126     fixedAttrs[MacroAttr]->setFontBold(theme.isBold(Style::Preprocessor));
0127     fixedAttrs[MacroAttr]->setFontItalic(theme.isItalic(Style::Preprocessor));
0128 
0129     QColor tp = QColor::fromRgba(theme.textColor(Style::DataType));
0130     QColor tps = QColor::fromRgba(theme.selectedTextColor(Style::DataType));
0131     if (!fixedAttrs[TypeAttr]) {
0132         fixedAttrs[TypeAttr] = new KTextEditor::Attribute();
0133     }
0134     fixedAttrs[TypeAttr]->setForeground(tp);
0135     fixedAttrs[TypeAttr]->setSelectedForeground(tps);
0136     fixedAttrs[TypeAttr]->setFontBold(theme.isBold(Style::DataType));
0137     fixedAttrs[TypeAttr]->setFontItalic(theme.isItalic(Style::DataType));
0138 }
0139 
0140 void SemanticTokensLegend::initialize(const std::vector<QString> &types)
0141 {
0142     std::vector<TokenType> tokenTypes(types.size());
0143     int i = 0;
0144     for (const auto &type : types) {
0145         if (type == QStringLiteral("type"))
0146             tokenTypes[i] = TokenType::Type;
0147         else if (type == QStringLiteral("class"))
0148             tokenTypes[i] = TokenType::Class;
0149         else if (type == QStringLiteral("enum"))
0150             tokenTypes[i] = TokenType::Enum;
0151         else if (type == QStringLiteral("type"))
0152             tokenTypes[i] = TokenType::Type;
0153         else if (type == QStringLiteral("interface"))
0154             tokenTypes[i] = TokenType::Interface;
0155         else if (type == QStringLiteral("struct"))
0156             tokenTypes[i] = TokenType::Struct;
0157         else if (type == QStringLiteral("typeParameter"))
0158             tokenTypes[i] = TokenType::TypeParameter;
0159         else if (type == QStringLiteral("parameter"))
0160             tokenTypes[i] = TokenType::Parameter;
0161         else if (type == QStringLiteral("variable"))
0162             tokenTypes[i] = TokenType::Variable;
0163         else if (type == QStringLiteral("property"))
0164             tokenTypes[i] = TokenType::Property;
0165         else if (type == QStringLiteral("enumMember"))
0166             tokenTypes[i] = TokenType::EnumMember;
0167         else if (type == QStringLiteral("event"))
0168             tokenTypes[i] = TokenType::Event;
0169         else if (type == QStringLiteral("function"))
0170             tokenTypes[i] = TokenType::Function;
0171         else if (type == QStringLiteral("method"))
0172             tokenTypes[i] = TokenType::Method;
0173         else if (type == QStringLiteral("macro"))
0174             tokenTypes[i] = TokenType::Macro;
0175         else if (type == QStringLiteral("keyword"))
0176             tokenTypes[i] = TokenType::Keyword;
0177         else if (type == QStringLiteral("modifier"))
0178             tokenTypes[i] = TokenType::Modifier;
0179         else if (type == QStringLiteral("comment"))
0180             tokenTypes[i] = TokenType::Comment; // Can mean inactive code
0181         else if (type == QStringLiteral("string"))
0182             tokenTypes[i] = TokenType::String;
0183         else if (type == QStringLiteral("number"))
0184             tokenTypes[i] = TokenType::Number;
0185         else if (type == QStringLiteral("regexp"))
0186             tokenTypes[i] = TokenType::Regexp;
0187         else if (type == QStringLiteral("operator"))
0188             tokenTypes[i] = TokenType::Operator;
0189         else if (type == QStringLiteral("namespace"))
0190             tokenTypes[i] = TokenType::Namespace;
0191         else
0192             tokenTypes[i] = TokenType::Unsupported;
0193         i++;
0194     }
0195     totalTokenTypes = tokenTypes.size();
0196     refresh(tokenTypes);
0197 }
0198 
0199 void SemanticTokensLegend::refresh(const std::vector<TokenType> &tokenTypes)
0200 {
0201     sharedAttrs.resize(tokenTypes.size());
0202     for (size_t i = 0; i < tokenTypes.size(); ++i) {
0203         switch (tokenTypes.at(i)) {
0204         case Type:
0205         case Class:
0206         case Interface:
0207         case Struct:
0208         case Enum:
0209             sharedAttrs[i] = fixedAttrs[TypeAttr];
0210             break;
0211         case Namespace:
0212             sharedAttrs[i] = fixedAttrs[KeywordAttr];
0213             break;
0214         case TypeParameter:
0215         case Parameter:
0216             sharedAttrs[i] = fixedAttrs[VarParamAttr];
0217             break;
0218         case Macro:
0219             sharedAttrs[i] = fixedAttrs[MacroAttr];
0220             break;
0221         case Function:
0222         case Method:
0223             sharedAttrs[i] = fixedAttrs[FuncAttr];
0224             break;
0225         case EnumMember:
0226             sharedAttrs[i] = fixedAttrs[ConstantAttr];
0227             break;
0228         case Comment:
0229             sharedAttrs[i] = fixedAttrs[CommentAttr];
0230             break;
0231             // Only these for now
0232         default:
0233             sharedAttrs[i] = {};
0234         }
0235     }
0236 }