325 lines
12 KiB
C++
325 lines
12 KiB
C++
#include "sciedit.h"
|
|
|
|
#include <SciLexer.h>
|
|
|
|
#include <QColor>
|
|
#include <QDebug>
|
|
|
|
static sptr_t toBgr(const QColor &color) {
|
|
return (color.blue() << 16) | (color.green() << 8) | color.red();
|
|
}
|
|
|
|
SciEdit::SciEdit(QWidget * parent)
|
|
: ScintillaEdit(parent)
|
|
{
|
|
connect(this, &ScintillaEditBase::updateUi, this, [this](){
|
|
int curPos = currentPos();
|
|
emit cursorPosChanged(lineFromPosition(curPos) + 1, column(curPos));
|
|
updateLineNumberMarginWidth();
|
|
});
|
|
|
|
// 连接文本变化信号
|
|
connect(this, QOverload<Scintilla::ModificationFlags, Scintilla::Position, Scintilla::Position, Scintilla::Position, const QByteArray &, Scintilla::Position, Scintilla::FoldLevel, Scintilla::FoldLevel>::of(&ScintillaEditBase::modified),
|
|
this, &SciEdit::textChanged);
|
|
|
|
setLineNumbersEnabled(true);
|
|
}
|
|
|
|
void SciEdit::setStyleFont(const QFont &font, int style)
|
|
{
|
|
styleSetFont(style, font.family().toUtf8().constData());
|
|
styleSetSizeFractional(style, long(font.pointSizeF() * SC_FONT_SIZE_MULTIPLIER));
|
|
}
|
|
|
|
void SciEdit::setFolding(FoldType foldType, int margin)
|
|
{
|
|
if (foldType == NoFoldType) {
|
|
setMarginWidthN(margin, 0L);
|
|
return;
|
|
}
|
|
|
|
int mask = modEventMask();
|
|
setModEventMask(mask | SC_MOD_CHANGEFOLD);
|
|
setFoldFlags(SC_FOLDFLAG_LINEAFTER_CONTRACTED);
|
|
setMarginTypeN(margin, SC_MARGIN_SYMBOL);
|
|
setMarginMaskN(margin, SC_MASK_FOLDERS);
|
|
setMarginSensitiveN(margin, 1);
|
|
|
|
setMarkerDefine(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
|
|
setMarkerDefine(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
|
|
setMarkerDefine(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
|
|
setMarkerDefine(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
|
|
setMarkerDefine(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
|
|
setMarkerDefine(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
|
|
setMarkerDefine(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
|
|
|
|
setMarginWidthN(margin, 14);
|
|
return;
|
|
}
|
|
|
|
void SciEdit::setLexer(Scintilla::ILexer5 *lexer)
|
|
{
|
|
setILexer((sptr_t)lexer);
|
|
m_lexerName = lexer ? QString::fromUtf8(lexer->GetName()) : QString();
|
|
if (lexer == nullptr) {
|
|
clearDocumentStyle();
|
|
}
|
|
applyLexerStyles();
|
|
colourise(0, -1);
|
|
}
|
|
|
|
void SciEdit::setLineNumbersEnabled(bool enabled)
|
|
{
|
|
m_lineNumbersEnabled = enabled;
|
|
setMarginTypeN(0, SC_MARGIN_NUMBER);
|
|
updateLineNumberMarginWidth();
|
|
}
|
|
|
|
void SciEdit::setEditorFont(const QFont &font)
|
|
{
|
|
m_editorFont = font;
|
|
applyTheme(m_isDarkTheme);
|
|
}
|
|
|
|
void SciEdit::applyTheme(bool dark)
|
|
{
|
|
m_isDarkTheme = dark;
|
|
|
|
const QColor bg = dark ? QColor(0x1e, 0x1e, 0x1e) : QColor(0xff, 0xff, 0xff);
|
|
const QColor fg = dark ? QColor(0xd4, 0xd4, 0xd4) : QColor(0x00, 0x00, 0x00);
|
|
const QColor caret = dark ? QColor(0xff, 0xff, 0xff) : QColor(0x00, 0x00, 0x00);
|
|
const QColor selectionBg = dark ? QColor(0x26, 0x4f, 0x78) : QColor(0xcc, 0xe8, 0xff);
|
|
const QColor caretLineBg = dark ? QColor(0x2a, 0x2a, 0x2a) : QColor(0xf5, 0xf5, 0xf5);
|
|
const QColor lineNumberFg = dark ? QColor(0x85, 0x85, 0x85) : QColor(0x80, 0x80, 0x80);
|
|
const QColor lineNumberBg = dark ? QColor(0x25, 0x25, 0x26) : QColor(0xf0, 0xf0, 0xf0);
|
|
|
|
styleResetDefault();
|
|
if (!m_editorFont.family().isEmpty()) {
|
|
setStyleFont(m_editorFont, STYLE_DEFAULT);
|
|
}
|
|
styleSetFore(STYLE_DEFAULT, toBgr(fg));
|
|
styleSetBack(STYLE_DEFAULT, toBgr(bg));
|
|
styleClearAll();
|
|
|
|
setCaretFore(toBgr(caret));
|
|
setSelFore(true, toBgr(fg));
|
|
setSelBack(true, toBgr(selectionBg));
|
|
setCaretLineVisible(true);
|
|
setCaretLineBack(toBgr(caretLineBg));
|
|
|
|
styleSetFore(STYLE_LINENUMBER, toBgr(lineNumberFg));
|
|
styleSetBack(STYLE_LINENUMBER, toBgr(lineNumberBg));
|
|
setMarginBackN(0, toBgr(lineNumberBg));
|
|
|
|
updateLineNumberMarginWidth();
|
|
applyLexerStyles();
|
|
}
|
|
|
|
void SciEdit::sendColor(unsigned int iMessage, uptr_t wParam, const QColor &color) const
|
|
{
|
|
send(iMessage, wParam, toBgr(color));
|
|
}
|
|
|
|
void SciEdit::setMarkerDefine(int markerNumber, int markerSymbol)
|
|
{
|
|
markerDefine(markerNumber, markerSymbol);
|
|
// necessary?
|
|
if (markerSymbol != SC_MARK_EMPTY) {
|
|
sendColor(SCI_MARKERSETFORE, markerNumber, QColor(Qt::white));
|
|
sendColor(SCI_MARKERSETBACK, markerNumber, QColor(128, 128, 128));
|
|
}
|
|
}
|
|
|
|
void SciEdit::updateLineNumberMarginWidth()
|
|
{
|
|
if (!m_lineNumbersEnabled) {
|
|
setMarginWidthN(0, 0);
|
|
return;
|
|
}
|
|
|
|
const int lines = qMax<sptr_t>(1, lineCount());
|
|
const int digits = QString::number(lines).size();
|
|
if (digits == m_lastLineNumberDigits && marginWidthN(0) > 0) {
|
|
return;
|
|
}
|
|
m_lastLineNumberDigits = digits;
|
|
|
|
const QString sample = QString(digits, QLatin1Char('9'));
|
|
const QByteArray sampleBytes = sample.toUtf8();
|
|
const sptr_t width = textWidth(STYLE_LINENUMBER, sampleBytes.constData()) + 10;
|
|
setMarginWidthN(0, width);
|
|
}
|
|
|
|
void SciEdit::applyLexerStyles()
|
|
{
|
|
if (m_lexerName.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
const bool dark = m_isDarkTheme;
|
|
const QColor comment = dark ? QColor(0x6a, 0x99, 0x55) : QColor(0x00, 0x80, 0x00);
|
|
const QColor docComment = dark ? QColor(0x60, 0x80, 0x4f) : QColor(0x00, 0x80, 0x00);
|
|
const QColor keyword = dark ? QColor(0x56, 0x9c, 0xd6) : QColor(0x00, 0x00, 0xff);
|
|
const QColor type = dark ? QColor(0x4e, 0xc9, 0xb0) : QColor(0x2b, 0x91, 0xaf);
|
|
const QColor identifier = dark ? QColor(0x9c, 0xdc, 0xfe) : QColor(0x00, 0x10, 0x80);
|
|
const QColor function = dark ? QColor(0xdc, 0xdc, 0xaa) : QColor(0x79, 0x59, 0x00);
|
|
const QColor number = dark ? QColor(0xb5, 0xce, 0xa8) : QColor(0x09, 0x86, 0x58);
|
|
const QColor string = dark ? QColor(0xce, 0x91, 0x78) : QColor(0xa3, 0x15, 0x15);
|
|
const QColor preprocessor = dark ? QColor(0xc5, 0x86, 0xc0) : QColor(0xaf, 0x00, 0xdb);
|
|
const QColor tag = dark ? QColor(0x56, 0x9c, 0xd6) : QColor(0x80, 0x00, 0x00);
|
|
const QColor attr = dark ? QColor(0x9c, 0xdc, 0xfe) : QColor(0xff, 0x00, 0x00);
|
|
|
|
auto setFore = [&](int style, const QColor &c) {
|
|
styleSetFore(style, toBgr(c));
|
|
};
|
|
auto setBold = [&](int style, bool b) {
|
|
styleSetBold(style, b);
|
|
};
|
|
|
|
if (m_lexerName == QStringLiteral("cpp")) {
|
|
setFore(SCE_C_COMMENT, comment);
|
|
setFore(SCE_C_COMMENTLINE, comment);
|
|
setFore(SCE_C_COMMENTDOC, docComment);
|
|
setFore(SCE_C_COMMENTLINEDOC, docComment);
|
|
setFore(SCE_C_COMMENTDOCKEYWORD, docComment);
|
|
setFore(SCE_C_COMMENTDOCKEYWORDERROR, docComment);
|
|
setFore(SCE_C_PREPROCESSORCOMMENT, comment);
|
|
setFore(SCE_C_PREPROCESSORCOMMENTDOC, docComment);
|
|
setFore(SCE_C_NUMBER, number);
|
|
setFore(SCE_C_STRING, string);
|
|
setFore(SCE_C_CHARACTER, string);
|
|
setFore(SCE_C_STRINGEOL, string);
|
|
setFore(SCE_C_VERBATIM, string);
|
|
setFore(SCE_C_STRINGRAW, string);
|
|
setFore(SCE_C_TRIPLEVERBATIM, string);
|
|
setFore(SCE_C_HASHQUOTEDSTRING, string);
|
|
setFore(SCE_C_USERLITERAL, string);
|
|
setFore(SCE_C_PREPROCESSOR, preprocessor);
|
|
setFore(SCE_C_WORD, keyword);
|
|
setBold(SCE_C_WORD, true);
|
|
setFore(SCE_C_WORD2, type);
|
|
setBold(SCE_C_WORD2, true);
|
|
setFore(SCE_C_GLOBALCLASS, type);
|
|
setFore(SCE_C_IDENTIFIER, identifier);
|
|
setFore(SCE_C_ESCAPESEQUENCE, preprocessor);
|
|
} else if (m_lexerName == QStringLiteral("python")) {
|
|
setFore(SCE_P_COMMENTLINE, comment);
|
|
setFore(SCE_P_COMMENTBLOCK, comment);
|
|
setFore(SCE_P_NUMBER, number);
|
|
setFore(SCE_P_STRING, string);
|
|
setFore(SCE_P_CHARACTER, string);
|
|
setFore(SCE_P_TRIPLE, string);
|
|
setFore(SCE_P_TRIPLEDOUBLE, string);
|
|
setFore(SCE_P_FSTRING, string);
|
|
setFore(SCE_P_FCHARACTER, string);
|
|
setFore(SCE_P_FTRIPLE, string);
|
|
setFore(SCE_P_FTRIPLEDOUBLE, string);
|
|
setFore(SCE_P_STRINGEOL, string);
|
|
setFore(SCE_P_WORD, keyword);
|
|
setBold(SCE_P_WORD, true);
|
|
setFore(SCE_P_WORD2, type);
|
|
setBold(SCE_P_WORD2, true);
|
|
setFore(SCE_P_DECORATOR, preprocessor);
|
|
setFore(SCE_P_CLASSNAME, type);
|
|
setBold(SCE_P_CLASSNAME, true);
|
|
setFore(SCE_P_DEFNAME, function);
|
|
setBold(SCE_P_DEFNAME, true);
|
|
setFore(SCE_P_ATTRIBUTE, attr);
|
|
setFore(SCE_P_OPERATOR, preprocessor);
|
|
setFore(SCE_P_IDENTIFIER, identifier);
|
|
} else if (m_lexerName == QStringLiteral("hypertext")) {
|
|
setFore(SCE_H_COMMENT, comment);
|
|
setFore(SCE_H_TAG, tag);
|
|
setFore(SCE_H_TAGUNKNOWN, tag);
|
|
setFore(SCE_H_TAGEND, tag);
|
|
setFore(SCE_H_ATTRIBUTE, attr);
|
|
setFore(SCE_H_ATTRIBUTEUNKNOWN, attr);
|
|
setFore(SCE_H_NUMBER, number);
|
|
setFore(SCE_H_DOUBLESTRING, string);
|
|
setFore(SCE_H_SINGLESTRING, string);
|
|
setFore(SCE_H_VALUE, string);
|
|
setFore(SCE_H_ENTITY, preprocessor);
|
|
} else if (m_lexerName == QStringLiteral("xml")) {
|
|
setFore(SCE_H_COMMENT, comment);
|
|
setFore(SCE_H_TAG, tag);
|
|
setFore(SCE_H_TAGUNKNOWN, tag);
|
|
setFore(SCE_H_TAGEND, tag);
|
|
setFore(SCE_H_ATTRIBUTE, attr);
|
|
setFore(SCE_H_ATTRIBUTEUNKNOWN, attr);
|
|
setFore(SCE_H_NUMBER, number);
|
|
setFore(SCE_H_DOUBLESTRING, string);
|
|
setFore(SCE_H_SINGLESTRING, string);
|
|
setFore(SCE_H_VALUE, string);
|
|
setFore(SCE_H_ENTITY, preprocessor);
|
|
} else if (m_lexerName == QStringLiteral("json")) {
|
|
setFore(SCE_JSON_NUMBER, number);
|
|
setFore(SCE_JSON_STRING, string);
|
|
setFore(SCE_JSON_STRINGEOL, string);
|
|
setFore(SCE_JSON_PROPERTYNAME, attr);
|
|
setFore(SCE_JSON_KEYWORD, keyword);
|
|
setFore(SCE_JSON_LDKEYWORD, keyword);
|
|
setFore(SCE_JSON_URI, string);
|
|
setFore(SCE_JSON_COMPACTIRI, string);
|
|
setFore(SCE_JSON_ESCAPESEQUENCE, preprocessor);
|
|
setFore(SCE_JSON_OPERATOR, preprocessor);
|
|
setFore(SCE_JSON_LINECOMMENT, comment);
|
|
setFore(SCE_JSON_BLOCKCOMMENT, comment);
|
|
setFore(SCE_JSON_ERROR, preprocessor);
|
|
} else if (m_lexerName == QStringLiteral("css")) {
|
|
setFore(SCE_CSS_COMMENT, comment);
|
|
setFore(SCE_CSS_CLASS, attr);
|
|
setFore(SCE_CSS_ID, attr);
|
|
setFore(SCE_CSS_TAG, tag);
|
|
setFore(SCE_CSS_ATTRIBUTE, attr);
|
|
setFore(SCE_CSS_PSEUDOCLASS, attr);
|
|
setFore(SCE_CSS_PSEUDOELEMENT, attr);
|
|
setFore(SCE_CSS_EXTENDED_PSEUDOCLASS, attr);
|
|
setFore(SCE_CSS_EXTENDED_PSEUDOELEMENT, attr);
|
|
setFore(SCE_CSS_DOUBLESTRING, string);
|
|
setFore(SCE_CSS_SINGLESTRING, string);
|
|
setFore(SCE_CSS_VALUE, string);
|
|
setFore(SCE_CSS_IDENTIFIER, keyword);
|
|
setBold(SCE_CSS_IDENTIFIER, true);
|
|
setFore(SCE_CSS_IDENTIFIER2, keyword);
|
|
setFore(SCE_CSS_IDENTIFIER3, keyword);
|
|
setFore(SCE_CSS_OPERATOR, preprocessor);
|
|
setFore(SCE_CSS_IMPORTANT, keyword);
|
|
setBold(SCE_CSS_IMPORTANT, true);
|
|
setFore(SCE_CSS_DIRECTIVE, keyword);
|
|
setBold(SCE_CSS_DIRECTIVE, true);
|
|
setFore(SCE_CSS_GROUP_RULE, keyword);
|
|
setBold(SCE_CSS_GROUP_RULE, true);
|
|
setFore(SCE_CSS_VARIABLE, identifier);
|
|
} else if (m_lexerName == QStringLiteral("yaml")) {
|
|
setFore(SCE_YAML_COMMENT, comment);
|
|
setFore(SCE_YAML_IDENTIFIER, identifier);
|
|
setFore(SCE_YAML_KEYWORD, attr);
|
|
setFore(SCE_YAML_NUMBER, number);
|
|
setFore(SCE_YAML_REFERENCE, tag);
|
|
setFore(SCE_YAML_DOCUMENT, tag);
|
|
setFore(SCE_YAML_TEXT, string);
|
|
setFore(SCE_YAML_OPERATOR, preprocessor);
|
|
} else if (m_lexerName == QStringLiteral("cmake")) {
|
|
setFore(SCE_CMAKE_COMMENT, comment);
|
|
setFore(SCE_CMAKE_NUMBER, number);
|
|
setFore(SCE_CMAKE_VARIABLE, identifier);
|
|
setFore(SCE_CMAKE_STRINGDQ, string);
|
|
setFore(SCE_CMAKE_STRINGLQ, string);
|
|
setFore(SCE_CMAKE_STRINGRQ, string);
|
|
setFore(SCE_CMAKE_STRINGVAR, identifier);
|
|
setFore(SCE_CMAKE_COMMANDS, function);
|
|
setBold(SCE_CMAKE_COMMANDS, true);
|
|
setFore(SCE_CMAKE_USERDEFINED, function);
|
|
setBold(SCE_CMAKE_USERDEFINED, true);
|
|
setFore(SCE_CMAKE_MACRODEF, function);
|
|
setBold(SCE_CMAKE_MACRODEF, true);
|
|
setFore(SCE_CMAKE_WHILEDEF, keyword);
|
|
setBold(SCE_CMAKE_WHILEDEF, true);
|
|
setFore(SCE_CMAKE_FOREACHDEF, keyword);
|
|
setBold(SCE_CMAKE_FOREACHDEF, true);
|
|
setFore(SCE_CMAKE_IFDEFINEDEF, keyword);
|
|
setBold(SCE_CMAKE_IFDEFINEDEF, true);
|
|
setFore(SCE_CMAKE_PARAMETERS, attr);
|
|
}
|
|
}
|