notepad--/src/scintillaeditview.cpp

4027 lines
114 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "scintillaeditview.h"
#include "common.h"
#include "rgba_icons.h"
#include "ccnotepad.h"
#include "styleset.h"
#include "qtlangset.h"
#include "findwin.h"
#include "filemanager.h"
#include <Scintilla.h>
#include <SciLexer.h>
#include <QImage>
#include <Qsci/qscilexerpython.h>
//#include <Qsci/qscilexeravs.h>
#include <Qsci/qscilexerasm.h>
#include <Qsci/qscilexerbash.h>
#include <Qsci/qscilexerbatch.h>
#include <Qsci/qscilexercmake.h>
#include <Qsci/qscilexercoffeescript.h>
#include <Qsci/qscilexercpp.h>
#include <Qsci/qscilexercsharp.h>
#include <Qsci/qscilexercss.h>
#include <Qsci/qscilexercustom.h>
#include <Qsci/qscilexerd.h>
#include <Qsci/qscilexerdiff.h>
#include <Qsci/qscilexeredifact.h>
#include <Qsci/qscilexerfortran.h>
#include <Qsci/qscilexerfortran77.h>
#include <Qsci/qscilexerhtml.h>
#include <Qsci/qscilexeridl.h>
#include <Qsci/qscilexerjava.h>
#include <Qsci/qscilexerjavascript.h>
#include <Qsci/qscilexerjson.h>
#include <Qsci/qscilexerlua.h>
#include <Qsci/qscilexermakefile.h>
#include <Qsci/qscilexermarkdown.h>
#include <Qsci/qscilexermatlab.h>
#include <Qsci/qscilexeroctave.h>
#include <Qsci/qscilexerpascal.h>
#include <Qsci/qscilexerperl.h>
#include <Qsci/qscilexerpo.h>
#include <Qsci/qscilexerpostscript.h>
#include <Qsci/qscilexerpov.h>
#include <Qsci/qscilexerproperties.h>
#include <Qsci/qscilexerpython.h>
#include <Qsci/qscilexerr.h>
#include <Qsci/qscilexerruby.h>
#include <Qsci/qscilexerspice.h>
#include <Qsci/qscilexersql.h>
#include <Qsci/qscilexertcl.h>
#include <Qsci/qscilexertex.h>
#include <Qsci/qscilexerverilog.h>
#include <Qsci/qscilexervhdl.h>
#include <Qsci/qscilexerxml.h>
#include <Qsci/qscilexeryaml.h>
#include <Qsci/qscilexergo.h>
#include <Qsci/qscilexertext.h>
#include <Qsci/qscilexernsis.h>
#include <Qsci/qscilexerglobal.h>
#include <Qsci/qscilexerrust.h>
#include <Qsci/qscilexervb.h>
#include <QScrollBar>
#include <unordered_set>
#include <QClipboard>
#include <QDesktopServices>
#include <QDebug>
#include <QMessageBox>
#include <stdexcept>
#include <mutex>
// initialize the static variable
#define DEFAULT_FONT_NAME "Courier New" //"Microsoft YaHei"
int ScintillaEditView::s_tabLens = 4;
//默认不使用tab使用space替换
bool ScintillaEditView::s_noUseTab = true;
int ScintillaEditView::s_bigTextSize = 100;
const int ScintillaEditView::_SC_MARGE_LINENUMBER = 0;
const int ScintillaEditView::_SC_MARGE_SYBOLE = 1;
const int ScintillaEditView::_SC_MARGE_FOLDER = 2;
//大文本是分块显示,务必要把真实的偏移行号给显示出来
const int SC_BIGTEXT_LINES = 0;
const int MAX_PRE_NEXT_TIMES = 30;
const int INIT_BIG_RO_TEXT_LINE_WIDTH = 8;
#ifdef Q_OS_WIN
LanguageName ScintillaEditView::langNames[L_EXTERNAL + 1] = {
{QString("normal"), QString("Normal QString"), QString("Normal text file"), L_TXT, SCLEX_NULL},
{QString("php"), QString("PHP"), QString("PHP Hypertext Preprocessor file"), L_PHP, SCLEX_HTML},
{QString("c"), QString("C"), QString("C source file"), L_C, SCLEX_CPP},
{QString("cpp"), QString("C++"), QString("C++ source file"), L_CPP, SCLEX_CPP},
{QString("cs"), QString("C#"), QString("C# source file"), L_CS, SCLEX_CPP},
{QString("objc"), QString("Objective-C"), QString("Objective-C source file"), L_OBJC, SCLEX_CPP},
{QString("java"), QString("Java"), QString("Java source file"), L_JAVA, SCLEX_CPP},
{QString("rc"), QString("RC"), QString("Windows Resource file"), L_RC, SCLEX_CPP},
{QString("html"), QString("HTML"), QString("Hyper Text Markup Language file"), L_HTML, SCLEX_HTML},
{QString("xml"), QString("XML"), QString("eXtensible Markup Language file"), L_XML, SCLEX_XML},
{QString("makefile"), QString("Makefile"), QString("Makefile"), L_MAKEFILE, SCLEX_MAKEFILE},
{QString("pascal"), QString("Pascal"), QString("Pascal source file"), L_PASCAL, SCLEX_PASCAL},
{QString("batch"), QString("Batch"), QString("Batch file"), L_BATCH, SCLEX_BATCH},
{QString("ini"), QString("ini"), QString("MS ini file"), L_INI, SCLEX_PROPERTIES},
{QString("nfo"), QString("NFO"), QString("MSDOS Style/ASCII Art"), L_ASCII, SCLEX_NULL},
{QString("udf"), QString("udf"), QString("User Defined language file"), L_USER, SCLEX_USER},
{QString("asp"), QString("ASP"), QString("Active Server Pages script file"), L_ASP, SCLEX_HTML},
{QString("sql"), QString("SQL"), QString("Structured Query Language file"), L_SQL, SCLEX_SQL},
{QString("vb"), QString("Visual Basic"), QString("Visual Basic file"), L_VB, SCLEX_VB},
{QString("javascript"), QString("JavaScript"), QString("JavaScript file"), L_JS, L_JAVASCRIPT},
{QString("css"), QString("CSS"), QString("Cascade Style Sheets File"), L_CSS, SCLEX_CSS},
{QString("perl"), QString("Perl"), QString("Perl source file"), L_PERL, SCLEX_PERL},
{QString("python"), QString("Python"), QString("Python file"), L_PYTHON, SCLEX_PYTHON},
{QString("lua"), QString("Lua"), QString("Lua source File"), L_LUA, SCLEX_LUA},
{QString("tex"), QString("TeX"), QString("TeX file"), L_TEX, SCLEX_TEX},
{QString("fortran"), QString("Fortran free form"), QString("Fortran free form source file"), L_FORTRAN, SCLEX_FORTRAN},
{QString("bash"), QString("Shell"), QString("Unix script file"), L_BASH, SCLEX_BASH},
{QString("actionscript"), QString("ActionScript"), QString("Flash ActionScript file"), L_FLASH, SCLEX_CPP},
{QString("nsis"), QString("NSIS"), QString("Nullsoft Scriptable Install System script file"), L_NSIS, SCLEX_NSIS},
{QString("tcl"), QString("TCL"), QString("Tool Command Language file"), L_TCL, SCLEX_TCL},
{QString("lisp"), QString("Lisp"), QString("List Processing language file"), L_LISP, SCLEX_LISP},
{QString("scheme"), QString("Scheme"), QString("Scheme file"), L_SCHEME, SCLEX_LISP},
{QString("asm"), QString("Assembly"), QString("Assembly language source file"), L_ASM, SCLEX_ASM},
{QString("diff"), QString("Diff"), QString("Diff file"), L_DIFF, SCLEX_DIFF},
{QString("props"), QString("Properties file"), QString("Properties file"), L_PROPS, SCLEX_PROPERTIES},
{QString("postscript"), QString("PostScript"), QString("PostScript file"), L_PS, SCLEX_PS},
{QString("ruby"), QString("Ruby"), QString("Ruby file"), L_RUBY, SCLEX_RUBY},
{QString("smalltalk"), QString("Smalltalk"), QString("Smalltalk file"), L_SMALLTALK, SCLEX_SMALLTALK},
{QString("vhdl"), QString("VHDL"), QString("VHSIC Hardware Description Language file"), L_VHDL, SCLEX_VHDL},
{QString("kix"), QString("KiXtart"), QString("KiXtart file"), L_KIX, SCLEX_KIX},
{QString("autoit"), QString("AutoIt"), QString("AutoIt"), L_AU3, SCLEX_AU3},
{QString("caml"), QString("CAML"), QString("Categorical Abstract Machine Language"), L_CAML, SCLEX_CAML},
{QString("ada"), QString("Ada"), QString("Ada file"), L_ADA, SCLEX_ADA},
{QString("verilog"), QString("Verilog"), QString("Verilog file"), L_VERILOG, SCLEX_VERILOG},
{QString("matlab"), QString("MATLAB"), QString("MATrix LABoratory"), L_MATLAB, SCLEX_MATLAB},
{QString("haskell"), QString("Haskell"), QString("Haskell"), L_HASKELL, SCLEX_HASKELL},
{QString("inno"), QString("Inno Setup"), QString("Inno Setup script"), L_INNO, SCLEX_INNOSETUP},
{QString("searchResult"), QString("Internal Search"), QString("Internal Search"), L_SEARCHRESULT, SCLEX_SEARCHRESULT},
{QString("cmake"), QString("CMake"), QString("CMake file"), L_CMAKE, SCLEX_CMAKE},
{QString("yaml"), QString("YAML"), QString("YAML Ain't Markup Language"), L_YAML, SCLEX_YAML},
{QString("cobol"), QString("COBOL"), QString("COmmon Business Oriented Language"), L_COBOL, SCLEX_COBOL},
{QString("gui4cli"), QString("Gui4Cli"), QString("Gui4Cli file"), L_GUI4CLI, SCLEX_GUI4CLI},
{QString("d"), QString("D"), QString("D programming language"), L_D, SCLEX_D},
{QString("powershell"), QString("PowerShell"), QString("Windows PowerShell"), L_POWERSHELL, SCLEX_POWERSHELL},
{QString("r"), QString("R"), QString("R programming language"), L_R, SCLEX_R},
{QString("jsp"), QString("JSP"), QString("JavaServer Pages script file"), L_JSP, SCLEX_HTML},
{QString("coffeescript"), QString("CoffeeScript"), QString("CoffeeScript file"), L_COFFEESCRIPT, SCLEX_COFFEESCRIPT},
{QString("json"), QString("json"), QString("JSON file"), L_JSON, SCLEX_JSON },
{QString("javascript.js"), QString("JavaScript"), QString("JavaScript file"), L_JAVASCRIPT, SCLEX_CPP },
{QString("fortran77"), QString("Fortran fixed form"), QString("Fortran fixed form source file"), L_FORTRAN_77, SCLEX_F77},
{QString("baanc"), QString("BaanC"), QString("BaanC File"), L_BAANC, SCLEX_BAAN },
{QString("srec"), QString("S-Record"), QString("Motorola S-Record binary data"), L_SREC, SCLEX_SREC},
{QString("ihex"), QString("Intel HEX"), QString("Intel HEX binary data"), L_IHEX, SCLEX_IHEX},
{QString("tehex"), QString("Tektronix extended HEX"), QString("Tektronix extended HEX binary data"), L_TEHEX, SCLEX_TEHEX},
{QString("swift"), QString("Swift"), QString("Swift file"), L_SWIFT, SCLEX_CPP},
{QString("asn1"), QString("ASN.1"), QString("Abstract Syntax Notation One file"), L_ASN1, SCLEX_ASN1},
{QString("avs"), QString("AviSynth"), QString("AviSynth scripts files"), L_AVS, SCLEX_AVS},
{QString("blitzbasic"), QString("BlitzBasic"), QString("BlitzBasic file"), L_BLITZBASIC, SCLEX_BLITZBASIC},
{QString("purebasic"), QString("PureBasic"), QString("PureBasic file"), L_PUREBASIC, SCLEX_PUREBASIC},
{QString("freebasic"), QString("FreeBasic"), QString("FreeBasic file"), L_FREEBASIC, SCLEX_FREEBASIC},
{QString("csound"), QString("Csound"), QString("Csound file"), L_CSOUND, SCLEX_CSOUND},
{QString("erlang"), QString("Erlang"), QString("Erlang file"), L_ERLANG, SCLEX_ERLANG},
{QString("escript"), QString("ESCRIPT"), QString("ESCRIPT file"), L_ESCRIPT, SCLEX_ESCRIPT},
{QString("forth"), QString("Forth"), QString("Forth file"), L_FORTH, SCLEX_FORTH},
{QString("latex"), QString("LaTeX"), QString("LaTeX file"), L_LATEX, SCLEX_LATEX},
{QString("mmixal"), QString("MMIXAL"), QString("MMIXAL file"), L_MMIXAL, SCLEX_MMIXAL},
{QString("nim"), QString("Nim"), QString("Nim file"), L_NIM, SCLEX_NIMROD},
{QString("nncrontab"), QString("Nncrontab"), QString("extended crontab file"), L_NNCRONTAB, SCLEX_NNCRONTAB},
{QString("oscript"), QString("OScript"), QString("OScript source file"), L_OSCRIPT, SCLEX_OSCRIPT},
{QString("rebol"), QString("REBOL"), QString("REBOL file"), L_REBOL, SCLEX_REBOL},
{QString("registry"), QString("registry"), QString("registry file"), L_REGISTRY, SCLEX_REGISTRY},
{QString("rust"), QString("Rust"), QString("Rust file"), L_RUST, SCLEX_RUST},
{QString("spice"), QString("Spice"), QString("spice file"), L_SPICE, SCLEX_SPICE},
{QString("txt2tags"), QString("txt2tags"), QString("txt2tags file"), L_TXT2TAGS, SCLEX_TXT2TAGS},
{QString("visualprolog"), QString("Visual Prolog"), QString("Visual Prolog file"), L_VISUALPROLOG, SCLEX_VISUALPROLOG},
{QString("typescript"), QString("TypeScript"), QString("TypeScript file"), L_TYPESCRIPT, SCLEX_CPP},
{QString("edifact"), QString("Edifact"), QString("Edifact file"), L_EDIFACT, SCLEX_EDIFACT},
{QString("markdown"), QString("Markdown"), QString("Markdown file"), L_MARKDOWN, SCLEX_MARKDOWN},
{QString("octave"), QString("Octave"), QString("Octave file"), L_OCTAVE, SCLEX_OCTAVE},
{QString("po"), QString("PO"), QString("PO file"), L_PO, SCLEX_PO},
{QString("pov"), QString("POV"), QString("POV file"), L_POV, SCLEX_POV},
{QString("avs"), QString("AVS"), QString("AVS file"), L_AVS, SCLEX_AVS},
{QString("idl"), QString("IDL"), QString("IDL file"), L_IDL, SCLEX_IDL},
{QString("go"), QString("GO"), QString("GO file"), L_GO, SCLEX_GO},
{QString("txt"), QString("TEXT"), QString("TXT file"), L_TXT, SCLEX_TXT},
{QString("ext"), QString("External"), QString("External"), L_EXTERNAL, SCLEX_NULL}
};
#endif
ScintillaEditView::ScintillaEditView(QWidget *parent,bool isBigText)
: QsciScintilla(parent), m_NoteWin(nullptr), m_preFirstLineNum(0), m_curPos(0), m_hasHighlight(false), m_bookmarkPng(nullptr), m_styleColorMenu(nullptr), m_isBigText(isBigText), m_curBlockLineStartNum(0)
{
init();
}
ScintillaEditView::~ScintillaEditView()
{
releaseAllMark();
if (m_bookmarkPng != nullptr)
{
delete m_bookmarkPng;
}
}
void ScintillaEditView::setBigTextMode(bool isBigText)
{
m_isBigText = isBigText;
}
void ScintillaEditView::setLexer(QsciLexer * lexer)
{
QsciScintilla::setLexer(lexer);
if (lexer != nullptr && lexer->lexerId() == L_TXT)
{
showMargin(_SC_MARGE_FOLDER,false);
updateThemes();
}
else if(lexer != nullptr && lexer->lexerId() != L_TXT)
{
showMargin(_SC_MARGE_FOLDER, true);
updateThemes();
}
}
void ScintillaEditView::setNoteWidget(QWidget * win)
{
CCNotePad* pv = dynamic_cast<CCNotePad*>(win);
if (pv != nullptr)
{
m_NoteWin = pv;
if (m_styleColorMenu != nullptr)
{
m_styleColorMenu->addAction(tr("Clear Select"), m_NoteWin, &CCNotePad::slot_clearWordHighlight);
m_styleColorMenu->addAction(tr("Clear All"), m_NoteWin, &CCNotePad::slot_clearMark);
}
}
}
void ScintillaEditView::updateLineNumbersMargin(bool forcedToHide) {
if (forcedToHide)
{
execute(SCI_SETMARGINWIDTHN, _SC_MARGE_LINENUMBER, (sptr_t)0);
}
else
{
updateLineNumberWidth(0);
}
}
//根据现有滚动条来决定是否更新屏幕线宽长度。每滚动200个单位必须调整line宽
void ScintillaEditView::autoAdjustLineWidth(int xScrollValue)
{
//如果是大文本模式,行号长度目前是固定不变的,不需要动态调整。
if (m_isBigText)
{
return;
}
if (std::abs(xScrollValue - m_preFirstLineNum) > 200)
{
m_preFirstLineNum = xScrollValue;
updateLineNumberWidth(1);
}
}
void ScintillaEditView::updateLineNumberWidth(int lineNumberMarginDynamicWidth)
{
if (!m_isBigText)
{
auto linesVisible = execute(SCI_LINESONSCREEN);
if (linesVisible)
{
int nbDigits = 0;
if (lineNumberMarginDynamicWidth != 0)
{
int firstVisibleLineVis = execute(SCI_GETFIRSTVISIBLELINE);
int lastVisibleLineVis = linesVisible + firstVisibleLineVis + 1;
int lastVisibleLineDoc = execute(SCI_DOCLINEFROMVISIBLE, (long)lastVisibleLineVis);
nbDigits = nbDigitsFromNbLines(lastVisibleLineDoc);
nbDigits = nbDigits < 4 ? 4 : nbDigits;
}
else
{
int nbLines = execute(SCI_GETLINECOUNT);
nbDigits = nbDigitsFromNbLines(nbLines);
nbDigits = nbDigits < 4 ? 4 : nbDigits;
}
auto pixelWidth = 6 + nbDigits * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
execute(SCI_SETMARGINWIDTHN, _SC_MARGE_LINENUMBER, pixelWidth);
}
}
else
{
int pixelWidth = 6 + INIT_BIG_RO_TEXT_LINE_WIDTH * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
execute(SCI_SETMARGINWIDTHN, SC_BIGTEXT_LINES, pixelWidth);
}
}
void ScintillaEditView::showMargin(int whichMarge, bool willBeShowed)
{
if (whichMarge == _SC_MARGE_LINENUMBER)
{
bool forcedToHide = !willBeShowed;
updateLineNumbersMargin(forcedToHide);
}
else
{
//后面再来解决像素的问题
//DPIManager& dpiManager = NppParameters::getInstance()._dpiManager;
int width = 3;
if (whichMarge == _SC_MARGE_SYBOLE)
width = 14;
else if (whichMarge == _SC_MARGE_FOLDER)
width = 14;
execute(SCI_SETMARGINWIDTHN, whichMarge, willBeShowed ? width : 0);
}
}
sptr_t ScintillaEditView::execute(quint32 Msg, uptr_t wParam, sptr_t lParam) const {
try {
return (m_pScintillaFunc) ? m_pScintillaFunc(m_pScintillaPtr, Msg, wParam, lParam) : -1;
}
catch (...)
{
return -1;
}
};
QString ScintillaEditView::getTagByLexerId(int lexerId)
{
switch (lexerId)
{
case L_PHP:
return "php";
case L_HTML:
return ("html");
case L_ASP:
return ("asp");
case L_JSP:
return("jsp");
case L_C:
return("c");
case L_RC:
return("rc");
case L_CPP:
return "cpp";
case L_OBJC:
return ("objc");
case L_CS:
return ("csharp");
case L_JAVA:
return ("java");
case L_XML:
return "xml";
case L_MAKEFILE:
return "makefile";
case L_PASCAL:
return "pascal";
case L_BATCH:
return "batch";
case L_INI:
return("ini");
case L_ASCII:
break;
case L_USER:
break;
case L_SQL:
return "sql";
case L_VB:
return "vb";
case L_CSS:
return "css";
case L_PERL:
return "perl";
case L_PYTHON:
return "python";
case L_LUA:
return "lua";
case L_TEX:
break;
case L_FORTRAN:
return "fortran";
case L_BASH:
return "bash";
case L_FLASH:
return("flash");
case L_NSIS:
return "nsis";
case L_TCL:
return "tcl";
case L_LISP:
break;
case L_SCHEME:
break;
case L_ASM:
break;
case L_DIFF:
return "diff";
case L_PROPS:
return "props";
case L_PS:
break;
case L_R:
return "r";
case L_RUBY:
return "ruby";
case L_SMALLTALK:
break;
case L_VHDL:
return "vhdl";
case L_KIX:
break;
case L_AU3:
break;
case L_CAML:
break;
case L_ADA:
break;
case L_VERILOG:
return "verilog";
case L_MATLAB:
return "matlab";
case L_HASKELL:
break;
case L_INNO:
break;
case L_SEARCHRESULT:
break;
case L_CMAKE:
return "cmake";
case L_YAML:
return "yaml";
case L_COBOL:
break;
case L_GUI4CLI:
break;
case L_D:
break;
case L_POWERSHELL:
break;
case L_COFFEESCRIPT:
return "coffeescript";
case L_JSON:
return "json";
case L_JAVASCRIPT:
return ("javascript");
case L_FORTRAN_77:
return "fortran77";
case L_BAANC:
break;
case L_SREC:
break;
case L_IHEX:
break;
case L_TEHEX:
break;
case L_SWIFT:
break;
case L_ASN1:
break;
//case L_AVS:
// return "avs";
case L_BLITZBASIC:
break;
case L_PUREBASIC:
break;
case L_FREEBASIC:
break;
case L_CSOUND:
break;
case L_ERLANG:
break;
case L_ESCRIPT:
break;
case L_FORTH:
break;
case L_LATEX:
break;
case L_MMIXAL:
break;
case L_NIM:
break;
case L_NNCRONTAB:
break;
case L_OSCRIPT:
break;
case L_REBOL:
break;
case L_REGISTRY:
break;
case L_RUST:
return "rust";
case L_SPICE:
return "spice";
case L_TXT2TAGS:
break;
case L_VISUALPROLOG:
break;
case L_TYPESCRIPT:
return("typescript");
case L_EXTERNAL:
break;
case L_IDL:
return("idl");
case L_GO:
return("go");
case L_GLOBAL:
return("AllGlobal");
case L_TXT:
return("txt");
case L_USER_TXT:
break;
case L_USER_CPP:
break;
default:
break;
}
return "";
}
//status : true 表示存在, false 表示不存在
//tag只有在用户自定义语法是才需要给出。内部自带的语法不需要给出
//isOrigin:是否原生lexer即不读取用户修改过的配置风格
QsciLexer* ScintillaEditView::createLexer(int lexerId, QString tag, bool isOrigin, int styleId)
{
QsciLexer* ret = nullptr;
switch (lexerId)
{
case L_PHP:
ret = new QsciLexerHTML();
ret->setLexerTag("php");
ret->setCommentLineSymbol("//");
ret->setCommentStart("/*");
ret->setCommentEnd("*/");
break;
case L_HTML:
ret = new QsciLexerHTML();
ret->setLexerTag("html");
break;
case L_ASP:
ret = new QsciLexerHTML();
ret->setLexerTag("asp");
break;
case L_JSP:
ret = new QsciLexerHTML();
ret->setLexerTag("jsp");
break;
case L_C:
ret = new QsciLexerCPP();
ret->setLexerTag("c");
break;
case L_RC:
ret = new QsciLexerCPP();
ret->setLexerTag("rc");
break;
case L_CPP:
ret = new QsciLexerCPP();
break;
case L_OBJC:
ret = new QsciLexerCPP();
ret->setLexerTag("objc");
break;
case L_CS:
ret = new QsciLexerCSharp();
ret->setLexerTag("csharp");
break;
case L_JAVA:
ret = new QsciLexerJava();
ret->setLexerTag("java");
break;
case L_XML:
ret = new QsciLexerXML();
break;
case L_MAKEFILE:
ret = new QsciLexerMakefile();
break;
case L_PASCAL:
ret = new QsciLexerPascal();
break;
case L_BATCH:
ret = new QsciLexerBatch();
break;
case L_INI:
ret = new QsciLexerProperties();
ret->setLexerTag("ini");
break;
case L_ASCII:
break;
case L_USER:
break;
case L_SQL:
ret = new QsciLexerSQL();
break;
case L_VB:
ret = new QsciLexerVB();
break;
case L_CSS:
ret = new QsciLexerCSS();
break;
case L_PERL:
ret = new QsciLexerPerl();
break;
case L_PYTHON:
ret = new QsciLexerPython();
break;
case L_LUA:
ret = new QsciLexerLua();
break;
case L_TEX:
break;
case L_FORTRAN:
ret = new QsciLexerFortran();
break;
case L_BASH:
ret = new QsciLexerBash();
break;
case L_FLASH:
ret = new QsciLexerCPP();
ret->setLexerTag("flash");
break;
case L_NSIS:
ret = new QsciLexerNsis();
break;
case L_TCL:
ret = new QsciLexerTCL();
break;
case L_LISP:
break;
case L_SCHEME:
break;
case L_ASM:
ret = new QsciLexerAsm();
break;
case L_DIFF:
ret = new QsciLexerDiff();
break;
case L_PROPS:
ret = new QsciLexerProperties();
break;
case L_PS:
break;
case L_R:
ret = new QsciLexerR();
break;
case L_RUBY:
ret = new QsciLexerRuby();
break;
case L_SMALLTALK:
break;
case L_VHDL:
ret = new QsciLexerVHDL();
break;
case L_KIX:
break;
case L_AU3:
break;
case L_CAML:
break;
case L_ADA:
break;
case L_VERILOG:
ret = new QsciLexerVerilog();
break;
case L_MATLAB:
ret = new QsciLexerMatlab();
break;
case L_HASKELL:
break;
case L_INNO:
break;
case L_SEARCHRESULT:
break;
case L_CMAKE:
ret = new QsciLexerCMake();
break;
case L_YAML:
ret = new QsciLexerYAML();
break;
case L_COBOL:
break;
case L_GUI4CLI:
break;
case L_D:
break;
case L_POWERSHELL:
break;
case L_COFFEESCRIPT:
ret = new QsciLexerCoffeeScript();
break;
case L_JSON:
ret = new QsciLexerJSON();
break;
case L_JAVASCRIPT:
ret = new QsciLexerJavaScript();
ret->setLexerTag("javascript");
break;
case L_FORTRAN_77:
ret = new QsciLexerFortran77();
break;
case L_BAANC:
break;
case L_SREC:
break;
case L_IHEX:
break;
case L_TEHEX:
break;
case L_SWIFT:
break;
case L_ASN1:
break;
case L_AVS:
//ret = new QsciLexerAVS();
break;
case L_BLITZBASIC:
break;
case L_PUREBASIC:
break;
case L_FREEBASIC:
break;
case L_CSOUND:
break;
case L_ERLANG:
break;
case L_ESCRIPT:
break;
case L_FORTH:
break;
case L_LATEX:
break;
case L_MMIXAL:
break;
case L_NIM:
break;
case L_NNCRONTAB:
break;
case L_OSCRIPT:
break;
case L_REBOL:
break;
case L_REGISTRY:
break;
case L_RUST:
ret = new QsciLexerRust();
break;
case L_SPICE:
ret = new QsciLexerSpice();
break;
case L_TXT2TAGS:
break;
case L_VISUALPROLOG:
break;
case L_TYPESCRIPT:
ret = new QsciLexerCPP();
ret->setLexerTag("typescript");
break;
case L_EXTERNAL:
break;
case L_IDL:
ret = new QsciLexerIDL();
ret->setLexerTag("idl");
break;
case L_GO:
ret = new QsciLexerGO();
ret->setLexerTag("go");
break;
case L_GLOBAL:
ret = new QsciLexerGlobal();
ret->setLexerTag("AllGlobal");
break;
case L_TXT:
ret = new QsciLexerText();
ret->setLexerTag("txt");
break;
case L_USER_TXT:
//使用txt的语法解析器但是自定义关键字自定义tag语言标签。下同
ret = new QsciLexerText();
ret->setLexerTag(tag);
ret->setIsUserDefineKeywords(true);
break;
case L_USER_CPP:
ret = new QsciLexerCPP();
ret->setLexerTag(tag);
ret->setIsUserDefineKeywords(true);
break;
default:
break;
}
if (ret != nullptr)
{
ret->setLexerId(lexerId);
if (!isOrigin)
{
QtLangSet::readLangSettings(ret, ret->lexerTag(), styleId);
}
else
{
//如果是读取原生风格,则只有默认主题具备,其余主题要从模板中加载
QtLangSet::readLangOriginSettings(ret, ret->lexerTag(), styleId);
}
}
return ret;
}
void ScintillaEditView::appendMarkRecord(FindRecords * r)
{
m_curMarkList.append(r);
}
void ScintillaEditView::releaseAllMark()
{
for (int i = 0; i < m_curMarkList.size(); ++i)
{
delete m_curMarkList.at(i);
}
m_curMarkList.clear();
}
QList<FindRecords *>& ScintillaEditView::getCurMarkRecord()
{
return m_curMarkList;
}
////调整颜色
//void ScintillaEditView::adjuctSkinStyle()
//{
// if (StyleSet::m_curStyleId != BLACK_SE)
// {
// setMarginsForegroundColor(QColor(0x80, 0x80, 0x80)); //默认0x80, 0x80, 0x80
// }
// else
// {
// setMarginsForegroundColor(QColor(0xde, 0xde, 0xde)); //默认0x80, 0x80, 0x80
// }
// setMarginsBackgroundColor(StyleSet::marginsBackgroundColor);
//
// setMarginBackgroundColor(_SC_MARGE_SYBOLE, StyleSet::bookmarkBkColor);
// setFoldMarginColors(StyleSet::marginsBackgroundColor, StyleSet::marginsBackgroundColor);
// setStyleOptions();
//}
void ScintillaEditView::setIndentGuide(bool willBeShowed)
{
QsciLexer* pLexer = this->lexer();
if (nullptr == pLexer)
{
return;
}
const int docIndentMode = (pLexer->lexerId() == L_PYTHON) ? SC_IV_LOOKFORWARD : SC_IV_LOOKBOTH;
execute(SCI_SETINDENTATIONGUIDES, willBeShowed ? docIndentMode : SC_IV_NONE);
QsciScintilla::setIndentGuide(willBeShowed);
}
void ScintillaEditView::init()
{
m_pScintillaFunc = (SCINTILLA_FUNC)this->SendScintillaPtrResult(SCI_GETDIRECTFUNCTION);
m_pScintillaPtr = (SCINTILLA_PTR)this->SendScintillaPtrResult(SCI_GETDIRECTPOINTER);
if (!m_pScintillaFunc)
{
throw std::runtime_error("ScintillaEditView::init : SCI_GETDIRECTFUNCTION message failed");
}
if (!m_pScintillaPtr)
{
throw std::runtime_error("ScintillaEditView::init : SCI_GETDIRECTPOINTER message failed");
}
if (m_isBigText)
{
this->setMarginType(SC_BIGTEXT_LINES, TextMargin);
}
else
{
//开启行号marge
setMarginLineNumbers(_SC_MARGE_LINENUMBER, true);
showMargin(_SC_MARGE_LINENUMBER, true);
//通过fold发现尽量使用qscint的功能因为他做了大量封装和简化
setFolding(BoxedTreeFoldStyle, _SC_MARGE_FOLDER);
}
//行号、符号、折叠。中间符号留一个很小的间隔。用于圆形的标记符号
showMargin(_SC_MARGE_SYBOLE, true);
setMarginType(_SC_MARGE_SYBOLE, QsciScintilla::SymbolMarginColor);
m_bookmarkPng = new QPixmap(QString(":/Resources/img/bookmark.png"));
markerDefine(*m_bookmarkPng, _SC_MARGE_SYBOLE);
setMarginSensitivity(_SC_MARGE_SYBOLE, true);
connect(this, &QsciScintilla::marginClicked, this, &ScintillaEditView::slot_bookMarkClicked);
//开始括号匹配比如html的<>,开启前后这类字段的匹配
setBraceMatching(SloppyBraceMatch);
//自动补全效果不好不开启20211017
//setAutoCompletionSource(QsciScintilla::AcsAPIs); //设置源,自动补全所有地方出现的
//setAutoCompletionCaseSensitivity(true); //设置自动补全大小写敏感
//setAutoCompletionThreshold(1); //设置每输入一个字符就会出现自动补全的提示
//设置字体
QFont font(DEFAULT_FONT_NAME, 11, QFont::Normal);
setFont(font);
setMarginsFont(font);
execute(SCI_SETTABWIDTH, ScintillaEditView::s_tabLens);
//使用空格替换tab
setIndentationsUseTabs(!ScintillaEditView::s_noUseTab);
//这个无比要设置false否则双击后高亮单词拷贝时会拷贝多个选择。
execute(SCI_SETMULTIPLESELECTION, true);
execute(SCI_SETADDITIONALSELECTIONTYPING, true);
execute(SCI_SETMULTIPASTE, SC_MULTIPASTE_EACH);
execute(SCI_SETADDITIONALCARETSVISIBLE, true);
execute(SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION);
//execute(SCI_SETSELFORE, true, 0x0);
//execute(SCI_SETSELBACK, true, 0x9bff9b); //0x00ffff原来的黄色
//设置查找到Mark的风格。定义其前景颜色和形状
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_EXT5, INDIC_ROUNDBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_EXT5, 130);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_FOUND_STYLE_EXT5, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT5, 0x00ffff);
//设置查找到Mark的风格。定义其前景颜色和形状
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_EXT4, INDIC_ROUNDBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_EXT4, 130);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_FOUND_STYLE_EXT4, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT4, 0xffff00);
//设置查找到Mark的风格。定义其前景颜色和形状
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_EXT3, INDIC_ROUNDBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_EXT3, 130);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_FOUND_STYLE_EXT3, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT3, 0x0080ff);
//设置查找到Mark的风格。定义其前景颜色和形状
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_EXT2, INDIC_ROUNDBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_EXT2, 130);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_FOUND_STYLE_EXT2, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT2, 0xff0080);
//设置查找到Mark的风格。定义其前景颜色和形状
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_EXT1, INDIC_ROUNDBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_EXT1, 130);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_FOUND_STYLE_EXT1, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT1, 0xff8000);
//下面这两个是HTML文件的tag高亮的表示。
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_TAGMATCH, INDIC_STRAIGHTBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_TAGMATCH, 100);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_TAGMATCH, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_TAGMATCH, 0xff0080);
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_TAGATTR, INDIC_STRAIGHTBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_TAGATTR, 100);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_TAGATTR, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_TAGATTR, 0x00ffff);
//双击后同样的字段进行高亮
execute(SCI_INDICSETSTYLE, SCE_UNIVERSAL_FOUND_STYLE_SMART, INDIC_ROUNDBOX);
execute(SCI_INDICSETALPHA, SCE_UNIVERSAL_FOUND_STYLE_SMART, 100);
execute(SCI_INDICSETUNDER, SCE_UNIVERSAL_FOUND_STYLE_SMART, false);
//execute(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_SMART, 0x00ff00);
//设置空白字符的默认前景色
//execute(SCI_SETWHITESPACEFORE, true, 0x6ab5ff);
execute(SCI_SETWHITESPACESIZE,3);
setCaretLineVisible(true);
//统一设置全局前景、背景、字体大小三个要素
updateThemes();
//记住position变化。不能使用cursorPositionChanged因为他的列考虑uft8字符中文一个也算1个每次列不一定相等。
//要使用自定义的cursorPosChange跟踪的是SCI_GETCURRENTPOS 的值。换行才会触发这个cursorPosChange。自定义的信号
connect(this,&QsciScintilla::cursorPosChange,this,&ScintillaEditView::slot_linePosChanged, Qt::QueuedConnection);
connect(this, &QsciScintilla::selectionChanged, this, &ScintillaEditView::slot_clearHightWord, Qt::QueuedConnection);
execute(SCI_SETSCROLLWIDTH, 1);
connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &ScintillaEditView::slot_scrollYValueChange);
connect(this, &ScintillaEditView::delayWork, this,&ScintillaEditView::slot_delayWork, Qt::QueuedConnection);
//设置换行符号的格式
#if defined(Q_OS_WIN)
execute(SCI_SETEOLMODE, SC_EOL_CRLF);
#elif !defined(Q_OS_MAC)
execute(SCI_SETEOLMODE, SC_EOL_CR);
#elif !defined(Q_OS_UNIX)
execute(SCI_SETEOLMODE, SC_EOL_LF);
#endif
//开启新行自动缩进
setAutoIndent(true);
//开启后可以保证长行在滚动条下完整显示
execute(SCI_SETSCROLLWIDTHTRACKING, true);
}
//大文本不能显示行号,其实显示的是每一行的地址。
//因为要跳转,所以没法实时计算当前位置所在的行号
void ScintillaEditView::showBigTextLineAddr(qint64 fileOffset)
{
int nbDigits = 0;
if (fileOffset < 0xffffffff)
{
nbDigits = 9;
}
else
{
nbDigits = 13;
}
char* lineString = new char[17];
memset(lineString, 0, 17);
auto pixelWidth = 6 + nbDigits * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
this->execute(SCI_SETMARGINWIDTHN, SC_BIGTEXT_LINES, pixelWidth);
int lineNums = this->lines();
int lineLength = 0;
int style = STYLE_LINENUMBER;
for (int i = 0; i < lineNums; ++i)
{
memset(lineString, 0, 17);
lineLength = this->lineLength(i);
if (fileOffset < 0xffffffff)
{
sprintf(lineString, "%08llX ", fileOffset);
}
else
{
sprintf(lineString, "%012llX ", fileOffset);
}
QString num(lineString);
fileOffset += lineLength;
this->setMarginText(i, num, style);
}
delete[]lineString;
}
void ScintillaEditView::clearSuperBitLineCache()
{
m_addrLineNumMap.clear();
}
//20230116新增尽可能的还是显示行号。如果发生了跳转则没有办法计算前面的行号
//则只能显示地址。如果没跳转,而是动态顺序翻页,则可以显示行号
//20230201发现一个问题。底层qscint是按照utf8字节流来计算字符大小的。如果原始文件的编码
//不是utf8,比如GBK LE等则大小是不能统一的。这是一个显示问题但是不影响什么。
//通过this->lineLength(i);来计算是以utf8计算。
void ScintillaEditView::showBigTextLineAddr(qint64 fileOffset, qint64 fileEndOffset)
{
int nbDigits = 0;
if (fileOffset < 0xffffffff)
{
nbDigits = INIT_BIG_RO_TEXT_LINE_WIDTH;
}
else
{
nbDigits = 12;
}
char* lineString = new char[17];
memset(lineString, 0, 17);
auto pixelWidth = 6 + nbDigits * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
this->execute(SCI_SETMARGINWIDTHN, SC_BIGTEXT_LINES, pixelWidth);
int lineNums = this->lines();
int lineLength = 0;
int style = STYLE_LINENUMBER;
quint32 startLineNumOffset = 0;
quint32 endLineNumOffset = 0;
bool isShowLineNum = false; //显示行号还是地址
bool startLineExist = false;
bool endLineExist = false;
if (fileOffset == 0)
{
isShowLineNum = true;
startLineExist = true;
m_addrLineNumMap.insert(0, 1); //0地址对应第1行
m_addrLineNumMap.insert(fileEndOffset, lineNums+1); //fileEndOffset地址对应最后一行
}
if (lineNums >= 1)
{
if (m_addrLineNumMap.contains(fileOffset))
{
isShowLineNum = true;
startLineExist = true;
startLineNumOffset = m_addrLineNumMap.value(fileOffset);
}
else if (m_addrLineNumMap.contains(fileEndOffset))
{
isShowLineNum = true;
endLineExist = true;
endLineNumOffset = m_addrLineNumMap.value(fileEndOffset);
}
}
//不存在行号,只能显示地址
if (!isShowLineNum)
{
for (int i = 0; i < lineNums; ++i)
{
memset(lineString, 0, 17);
lineLength = this->lineLength(i);
if (fileOffset < 0xffffffff)
{
sprintf(lineString, "%08llX ", fileOffset);
}
else
{
sprintf(lineString, "%012llX ", fileOffset);
}
QString num(lineString);
fileOffset += lineLength;
this->setMarginText(i, num, style);
}
}
else
{
//首行地址存在,从头到尾增加行号
if (startLineExist)
{
for (int i = 0; i < lineNums; ++i)
{
if (i == (lineNums - 1))
{
//m_addrLineNumMap.insert(fileOffset, startLineNumOffset + i);
m_addrLineNumMap.insert(fileEndOffset, startLineNumOffset + i);
}
memset(lineString, 0, 17);
//lineLength = this->lineLength(i);
sprintf(lineString, "%08lld ", startLineNumOffset + i);
QString num(lineString);
//fileOffset += lineLength;
this->setMarginText(i, num, style);
}
}
else if (endLineExist)
{
startLineNumOffset = endLineNumOffset - lineNums;
for (int i = 0; i < lineNums; ++i)
{
if (i == 0)
{
//m_addrLineNumMap.insert(fileOffset, startLineNumOffset + i);
m_addrLineNumMap.insert(fileOffset, startLineNumOffset + i);
}
memset(lineString, 0, 17);
//lineLength = this->lineLength(i);
sprintf(lineString, "%08lld ", startLineNumOffset + i);
QString num(lineString);
//fileOffset += lineLength;
this->setMarginText(i, num, style);
}
}
}
delete[]lineString;
}
//大文本只读模式下,显示其文本
void ScintillaEditView::showBigTextRoLineNum(BigTextEditFileMgr* txtFile, int blockIndex)
{
BlockIndex bi = txtFile->blocks.at(blockIndex);
int nbDigits = 0;
if (bi.fileOffset < 0xffffffff)
{
nbDigits = INIT_BIG_RO_TEXT_LINE_WIDTH;
}
else
{
nbDigits = 12;
}
char* lineString = new char[17];
memset(lineString, 0, 17);
auto pixelWidth = 6 + nbDigits * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
this->execute(SCI_SETMARGINWIDTHN, SC_BIGTEXT_LINES, pixelWidth);
int lineNums = this->lines();
qint64 curLineNum = bi.lineNumStart + 1;//行号从1开始
int style = STYLE_LINENUMBER;
for (int i = 0; i < lineNums; ++i)
{
memset(lineString, 0, 17);
if (bi.fileOffset < 0xffffffff)
{
sprintf(lineString, "%08lld ", curLineNum+i);
}
else
{
sprintf(lineString, "%012lld ", curLineNum + i);
}
QString num(lineString);
this->setMarginText(i, num, style);
}
delete[]lineString;
}
void ScintillaEditView::bookmarkNext(bool forwardScan)
{
size_t lineno = this->getCurrentLineNumber();
int sci_marker = SCI_MARKERNEXT;
size_t lineStart = lineno + 1; //Scan starting from next line
int lineRetry = 0; //If not found, try from the beginning
if (!forwardScan)
{
lineStart = lineno - 1; //Scan starting from previous line
lineRetry = int(this->execute(SCI_GETLINECOUNT)); //If not found, try from the end
sci_marker = SCI_MARKERPREVIOUS;
}
int nextLine = int(this->execute(sci_marker, lineStart, 1 << _SC_MARGE_SYBOLE));
if (nextLine < 0)
nextLine = int(this->execute(sci_marker, lineRetry, 1 << _SC_MARGE_SYBOLE));
if (nextLine < 0)
return;
this->execute(SCI_ENSUREVISIBLEENFORCEPOLICY, nextLine);
this->execute(SCI_GOTOLINE, nextLine);
}
void ScintillaEditView::bookmarkAdd(intptr_t lineno) const {
if (lineno == -1)
lineno = getCurrentLineNumber();
if (!bookmarkPresent(lineno))
this->execute(SCI_MARKERADD, lineno, _SC_MARGE_SYBOLE);
}
void ScintillaEditView::bookmarkDelete(size_t lineno) const {
if (lineno == -1)
lineno = this->getCurrentLineNumber();
while (bookmarkPresent(lineno))
this->execute(SCI_MARKERDELETE, lineno, _SC_MARGE_SYBOLE);
}
bool ScintillaEditView::bookmarkPresent(intptr_t lineno) const {
if (lineno == -1)
lineno = this->getCurrentLineNumber();
int state = this->execute(SCI_MARKERGET, lineno);
return ((state & (1 << _SC_MARGE_SYBOLE)) != 0);
}
void ScintillaEditView::bookmarkToggle(intptr_t lineno) const {
if (lineno == -1)
lineno = this->getCurrentLineNumber();
if (bookmarkPresent(lineno))
bookmarkDelete(lineno);
else
bookmarkAdd(lineno);
}
void ScintillaEditView::bookmarkClearAll() const {
this->execute(SCI_MARKERDELETEALL, _SC_MARGE_SYBOLE);
}
void ScintillaEditView::slot_bookMarkClicked(int margin, int line, Qt::KeyboardModifiers state)
{
if (margin == _SC_MARGE_SYBOLE)
{
bookmarkToggle(line);
}
}
std::mutex mark_mutex;
QString ScintillaEditView::getMarkedLine(int ln)
{
auto lineLen = this->execute(SCI_LINELENGTH, ln);
auto lineBegin = this->execute(SCI_POSITIONFROMLINE, ln);
return this->getGenericTextAsQString(lineBegin, lineBegin + lineLen);
}
void ScintillaEditView::deleteMarkedline(int ln)
{
int lineLen = static_cast<int32_t>(this->execute(SCI_LINELENGTH, ln));
int lineBegin = static_cast<int32_t>(this->execute(SCI_POSITIONFROMLINE, ln));
bookmarkDelete(ln);
QByteArray str2replace;
this->replaceTarget(str2replace, lineBegin, lineBegin + lineLen);
}
void str2Cliboard(QString& text)
{
QClipboard* clip = QApplication::clipboard();
clip->setText(text);
}
void ScintillaEditView::cutMarkedLines()
{
std::lock_guard<std::mutex> lock(mark_mutex);
int lastLine = this->lastZeroBasedLineNumber();
QString globalStr;
this->execute(SCI_BEGINUNDOACTION);
for (int i = lastLine; i >= 0; i--)
{
if (bookmarkPresent(i))
{
QString currentStr = getMarkedLine(i) + globalStr;
globalStr = currentStr;
deleteMarkedline(i);
}
}
this->execute(SCI_ENDUNDOACTION);
str2Cliboard(globalStr);
}
void ScintillaEditView::copyMarkedLines()
{
int lastLine = this->lastZeroBasedLineNumber();
QString globalStr;
for (int i = lastLine; i >= 0; i--)
{
if (bookmarkPresent(i))
{
QString currentStr = getMarkedLine(i) + globalStr;
globalStr = currentStr;
}
}
str2Cliboard(globalStr);
}
void ScintillaEditView::replaceMarkedline(int ln, QByteArray& str)
{
int lineBegin = static_cast<int32_t>(this->execute(SCI_POSITIONFROMLINE, ln));
int lineEnd = static_cast<int32_t>(this->execute(SCI_GETLINEENDPOSITION, ln));
this->replaceTarget(str, lineBegin, lineEnd);
}
void ScintillaEditView::pasteToMarkedLines()
{
std::lock_guard<std::mutex> lock(mark_mutex);
QClipboard* clip = QApplication::clipboard();
const QMimeData *mimeData = clip->mimeData();
if (!mimeData->hasText())
{
return;
}
int lastLine = this->lastZeroBasedLineNumber();
QString clipboardStr = clip->text();
this->execute(SCI_BEGINUNDOACTION);
for (int i = lastLine; i >= 0; i--)
{
if (bookmarkPresent(i))
{
QByteArray text = clipboardStr.toUtf8();
replaceMarkedline(i, text);
}
}
this->execute(SCI_ENDUNDOACTION);
}
//Y方向滚动条值变化后的槽函数
void ScintillaEditView::slot_scrollYValueChange(int value)
{
//使用滚动条翻页的效果并不好。暂时不放开
/*bool changePage = false;
qDebug() << value << verticalScrollBar()->maximum() << verticalScrollBar()->minimum();
if (value >= this->verticalScrollBar()->maximum())
{
if (m_NoteWin != nullptr)
{
changePage = m_NoteWin->nextPage(this);
}
}
else if (value == this->verticalScrollBar()->minimum())
{
if (m_NoteWin != nullptr)
{
changePage = m_NoteWin->prePage(this);
}
}*/
if (value >= this->verticalScrollBar()->maximum())
{
if (m_NoteWin != nullptr)
{
m_NoteWin->showChangePageTips(this);
}
}
else if (value == this->verticalScrollBar()->minimum())
{
if (m_NoteWin != nullptr)
{
m_NoteWin->showChangePageTips(this);
}
}
slot_delayWork();
autoAdjustLineWidth(value);
}
void ScintillaEditView::deleteMarkedLines(bool isMarked)
{
std::lock_guard<std::mutex> lock(mark_mutex);
int lastLine = this->lastZeroBasedLineNumber();
this->execute(SCI_BEGINUNDOACTION);
for (int i = lastLine; i >= 0; i--)
{
if (bookmarkPresent(i) == isMarked)
deleteMarkedline(i);
}
this->execute(SCI_ENDUNDOACTION);
}
void ScintillaEditView::inverseMarks()
{
int lastLine = this->lastZeroBasedLineNumber();
for (int i = 0; i <= lastLine; ++i)
{
if (bookmarkPresent(i))
{
bookmarkDelete(i);
}
else
{
bookmarkAdd(i);
}
}
}
void ScintillaEditView::slot_linePosChanged(int /*line*/, int pos)
{
//避免循环触发的slot_positionChanged
if (m_curPos == pos)
{
return;
}
m_prePosRecord.append(pos);
if (m_prePosRecord.size() >= MAX_PRE_NEXT_TIMES)
{
m_prePosRecord.takeFirst();
}
}
//回退一个位置
bool ScintillaEditView::gotoPrePos()
{
if (m_prePosRecord.size() > 1)
{
int v = m_prePosRecord.takeLast();
m_nextPosRecord.push_front(v);
if (m_nextPosRecord.size() >= MAX_PRE_NEXT_TIMES)
{
m_nextPosRecord.takeLast();
}
int pos = m_prePosRecord.last();
//下面这个函数比较坑里面要循环Index次每次返回的index值是不一样的。只能使用SCI_GOTOPOS可自定义的信号
//setCursorPosition(pos.line, pos.index);
//会循环触发slot_positionChanged
this->execute(SCI_GOTOPOS, pos);
m_curPos = pos;
return true;
}
return false;
}
bool ScintillaEditView::gotoNextPos()
{
if (m_nextPosRecord.size() > 0)
{
int pos = m_nextPosRecord.takeFirst();
m_prePosRecord.append(pos);
this->execute(SCI_GOTOPOS, pos);
m_curPos = pos;
return true;
}
return false;
}
const int MAXLINEHIGHLIGHT = 400;
void ScintillaEditView::clearIndicator(int indicatorNumber) {
size_t docStart = 0;
size_t docEnd = length();
execute(SCI_SETINDICATORCURRENT, indicatorNumber);
execute(SCI_INDICATORCLEARRANGE, docStart, docEnd - docStart);
};
void ScintillaEditView::slot_clearHightWord()
{
if (m_hasHighlight)
{
m_hasHighlight = false;
clearIndicator(SCE_UNIVERSAL_FOUND_STYLE_SMART);
}
}
intptr_t ScintillaEditView::searchInTarget(QByteArray& text2Find,size_t fromPos, size_t toPos) const
{
execute(SCI_SETTARGETRANGE, fromPos, toPos);
return execute(SCI_SEARCHINTARGET, text2Find.size(), reinterpret_cast<sptr_t>(text2Find.data()));
}
intptr_t ScintillaEditView::replaceTargetRegExMode(QByteArray& re, intptr_t fromTargetPos, intptr_t toTargetPos) const
{
if (fromTargetPos != -1 || toTargetPos != -1)
{
execute(SCI_SETTARGETRANGE, fromTargetPos, toTargetPos);
}
return execute(SCI_REPLACETARGETRE, re.size(), reinterpret_cast<sptr_t>(re.data()));
}
//替换fromTargetPos 到 toTargetPos的内容为str2replace。
intptr_t ScintillaEditView::replaceTarget(QByteArray& str2replace, intptr_t fromTargetPos, intptr_t toTargetPos) const
{
if (fromTargetPos != -1 || toTargetPos != -1)
{
execute(SCI_SETTARGETRANGE, fromTargetPos, toTargetPos);
}
return execute(SCI_REPLACETARGET, str2replace.size(), reinterpret_cast<sptr_t>(str2replace.data()));
}
void ScintillaEditView::highlightViewWithWord(QString & word2Hilite)
{
int originalStartPos = execute(SCI_GETTARGETSTART);
int originalEndPos = execute(SCI_GETTARGETEND);
int firstLine = static_cast<int>(this->execute(SCI_GETFIRSTVISIBLELINE));
int nbLineOnScreen = this->execute(SCI_LINESONSCREEN);
int nbLines = std::min(nbLineOnScreen, MAXLINEHIGHLIGHT) + 1;
int lastLine = firstLine + nbLines;
int startPos = 0;
int endPos = 0;
auto currentLine = firstLine;
int prevDocLineChecked = -1; //invalid start
auto searchMark = [this](int &startPos, int &endPos, QByteArray &word2Mark){
int targetStart = 0;
int targetEnd = 0;
long lens = word2Mark.length();
while (targetStart >= 0)
{
execute(SCI_SETTARGETRANGE, startPos, endPos);
targetStart = SendScintilla(SCI_SEARCHINTARGET, lens, word2Mark.data());
if (targetStart == -1 || targetStart == -2)
break;
targetEnd = int(this->execute(SCI_GETTARGETEND));
if (targetEnd > endPos)
{
//we found a result but outside our range, therefore do not process it
break;
}
int foundTextLen = targetEnd - targetStart;
if (foundTextLen > 0)
{
this->execute(SCI_SETINDICATORCURRENT, SCE_UNIVERSAL_FOUND_STYLE_SMART);
this->execute(SCI_INDICATORFILLRANGE, targetStart, foundTextLen);
}
if (targetStart + foundTextLen == endPos)
break;
startPos = targetStart + foundTextLen;
}
};
QByteArray whatMark = word2Hilite.toUtf8();
SendScintilla(SCI_SETSEARCHFLAGS, SCFIND_REGEXP | SCFIND_MATCHCASE | SCFIND_WHOLEWORD | SCFIND_REGEXP_SKIPCRLFASONE);
for (; currentLine < lastLine; ++currentLine)
{
int docLine = static_cast<int>(this->execute(SCI_DOCLINEFROMVISIBLE, currentLine));
if (docLine == prevDocLineChecked)
continue; //still on same line (wordwrap)
prevDocLineChecked = docLine;
startPos = static_cast<int>(this->execute(SCI_POSITIONFROMLINE, docLine));
endPos = static_cast<int>(this->execute(SCI_POSITIONFROMLINE, docLine + 1));
if (endPos == -1)
{ //past EOF
endPos = this->length() - 1;
searchMark(startPos, endPos, whatMark);
break;
}
else
{
searchMark(startPos, endPos, whatMark);
}
}
m_hasHighlight = true;
// restore the original targets to avoid conflicts with the search/replace functions
this->execute(SCI_SETTARGETRANGE, originalStartPos, originalEndPos);
}
void ScintillaEditView::slot_markColorGroup(QAction *action)
{
CCNotePad::s_curMarkColorId = action->data().toInt();
if (m_NoteWin != nullptr)
{
m_NoteWin->slot_wordHighlight();
}
}
//修改标记样式的颜色
void ScintillaEditView::changeStyleColor(int sytleId)
{
if (m_styleColorMenu == nullptr)
{
initStyleColorMenu();
}
if( sytleId < 5)
{
QPixmap colorBar(36, 36);
colorBar.fill((&StyleSet::s_global_style->mark_style_1)[sytleId].bgColor);
m_styleMarkActList.at(sytleId)->setIcon(colorBar);
if (m_NoteWin != nullptr)
{
m_NoteWin->changeMarkColor(sytleId);
}
}
}
void ScintillaEditView::initStyleColorMenu()
{
if (m_styleColorMenu == nullptr)
{
m_styleColorMenu = new QMenu(tr("mark with color"), this);
QPixmap colorBar(36, 36);
QActionGroup* markColorGroup = new QActionGroup(this);
connect(markColorGroup, &QActionGroup::triggered, this, &ScintillaEditView::slot_markColorGroup, Qt::QueuedConnection);
int index = 1;
auto initColorBar = [this, markColorGroup, &index](QPixmap& colorBar)->QAction* {
QAction* action = new QAction(m_styleColorMenu);
action->setIcon(colorBar);
action->setCheckable(true);
action->setText(tr("Color %1").arg(index));
action->setData(index + SCE_UNIVERSAL_FOUND_STYLE_EXT5 - 1);
++index;
m_styleColorMenu->addAction(action);
markColorGroup->addAction(action);
return action;
};
colorBar.fill(StyleSet::s_global_style->mark_style_1.bgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_2.bgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_3.bgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_4.bgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_5.bgColor);
m_styleMarkActList.append(initColorBar(colorBar));
m_styleColorMenu->addSeparator();
if (m_NoteWin != nullptr)
{
m_styleColorMenu->addAction(tr("Clear Select"), m_NoteWin, &CCNotePad::slot_clearWordHighlight);
m_styleColorMenu->addAction(tr("Clear All"), m_NoteWin, &CCNotePad::slot_clearMark);
}
}
}
void ScintillaEditView::contextUserDefineMenuEvent(QMenu* menu)
{
//QAction* action;
if (menu != nullptr && (m_NoteWin !=nullptr))
{
menu->addAction(tr("Show File in Explorer"), m_NoteWin, &CCNotePad::slot_showFileInExplorer);
if (m_styleColorMenu == nullptr)
{
m_styleColorMenu = new QMenu(tr("mark with color"),this);
QPixmap colorBar(36, 36);
QActionGroup* markColorGroup = new QActionGroup(this);
connect(markColorGroup, &QActionGroup::triggered, this, &ScintillaEditView::slot_markColorGroup, Qt::QueuedConnection);
int index = 1;
auto initColorBar = [this, markColorGroup, &index](QPixmap& colorBar)->QAction* {
QAction* action = new QAction(m_styleColorMenu);
action->setIcon(colorBar);
action->setCheckable(true);
action->setText(tr("Color %1").arg(index));
action->setData(index + SCE_UNIVERSAL_FOUND_STYLE_EXT5-1);
++index;
m_styleColorMenu->addAction(action);
markColorGroup->addAction(action);
return action;
};
colorBar.fill(StyleSet::s_global_style->mark_style_1.fgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_2.fgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_3.fgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_4.fgColor);
m_styleMarkActList.append(initColorBar(colorBar));
colorBar.fill(StyleSet::s_global_style->mark_style_5.fgColor);
m_styleMarkActList.append(initColorBar(colorBar));
m_styleColorMenu->addSeparator();
m_styleColorMenu->addAction(tr("Clear Select"), m_NoteWin, &CCNotePad::slot_clearWordHighlight);
m_styleColorMenu->addAction(tr("Clear All"), m_NoteWin, &CCNotePad::slot_clearMark);
}
menu->addMenu(m_styleColorMenu);
menu->addSeparator();
menu->addAction(tr("Add/Del line comment"), [this]() {
doBlockComment(cm_toggle);
});
menu->addAction(tr("Add Block comment"), [this]() {
doStreamComment();
});
menu->addAction(tr("Del Block comment"), [this]() {
undoStreamComment();
});
menu->addSeparator();
menu->addAction(tr("Word Count"), [this]() {
showWordNums();
});
}
menu->show();
}
void ScintillaEditView::replaceSelWith(const char* replaceText)
{
execute(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(replaceText));
}
bool ScintillaEditView::doBlockComment(Comment_Mode currCommentMode)
{
if (this->isReadOnly())
{
return false;
}
//-- BlockToStreamComment:
QByteArray commentStart;
QByteArray commentEnd;
QByteArray symbolStart;
QByteArray symbolEnd;
QByteArray commentLineSymbol;
QByteArray symbol;
bool isSingleLineAdvancedMode = false;
QsciLexer* pLexer = this->lexer();
if (pLexer == nullptr)
{
return false;
}
else
{
commentLineSymbol = pLexer->getCommentLineSymbol();
commentStart = pLexer->getCommentStart();
commentEnd = pLexer->getCommentEnd();
}
if ((commentLineSymbol.isEmpty()) || commentLineSymbol.isEmpty())
{
// BlockToStreamComment: If there is no block-comment symbol, try the stream comment:
if (!(commentStart.isEmpty() || commentEnd.isEmpty()))
{
if (currCommentMode == cm_comment)
{
isSingleLineAdvancedMode = true;
}
else if (currCommentMode == cm_uncomment)
{
return undoStreamComment(false);
}
else if (currCommentMode == cm_toggle)
{
isSingleLineAdvancedMode = true;
}
else
{
return false;
}
}
else
{
return false;
}
}
//For Single Line NORMAL MODE
QByteArray comment;
size_t comment_length = 0;
//For Single Line ADVANCED MODE
QByteArray advCommentStart;
QByteArray advCommentEnd;
size_t advCommentStart_length = 0;
size_t advCommentEnd_length = 0;
QByteArray aSpace(" ");
//Only values that have passed through will be assigned, to be sure they are valid!
if (!isSingleLineAdvancedMode)
{
comment = commentLineSymbol;
if (!(pLexer->lexerId() == L_BAANC)) // BaanC standardization - no space.
{
comment += aSpace;
}
comment_length = comment.length();
}
else // isSingleLineAdvancedMode
{
advCommentStart = commentStart;
advCommentStart += aSpace;
advCommentEnd = aSpace;
advCommentEnd += commentEnd;
advCommentStart_length = advCommentStart.length();
advCommentEnd_length = advCommentEnd.length();
}
size_t selectionStart = this->execute(SCI_GETSELECTIONSTART);
size_t selectionEnd = this->execute(SCI_GETSELECTIONEND);
size_t caretPosition = this->execute(SCI_GETCURRENTPOS);
bool move_caret = caretPosition < selectionEnd;
intptr_t selStartLine = this->execute(SCI_LINEFROMPOSITION, selectionStart);
intptr_t selEndLine = this->execute(SCI_LINEFROMPOSITION, selectionEnd);
intptr_t lines = selEndLine - selStartLine;
if ((lines > 0) && (selectionEnd == static_cast<size_t>(this->execute(SCI_POSITIONFROMLINE, selEndLine))))
{
selEndLine--;
}
// count lines which were un-commented to decide if undoStreamComment() shall be called.
int nUncomments = 0;
//Some Lexers need line-comments at the beginning of a line.
const bool avoidIndent = (pLexer->lexerId() == L_FORTRAN_77 || pLexer->lexerId() == L_BAANC);
//Some Lexers comment blank lines, per their standards.
const bool commentEmptyLines = (pLexer->lexerId() == L_BAANC);
this->execute(SCI_BEGINUNDOACTION);
for (intptr_t i = selStartLine; i <= selEndLine; ++i)
{
size_t lineStart = this->execute(SCI_POSITIONFROMLINE, i);
size_t lineIndent = this->execute(SCI_GETLINEINDENTPOSITION, i);
size_t lineEnd = this->execute(SCI_GETLINEENDPOSITION, i);
// empty lines are not commented, unless required by the language.
if (lineIndent == lineEnd && !commentEmptyLines)
continue;
if (avoidIndent)
lineIndent = lineStart;
//这里linebufferSize不需要包含字符串后面的\0所以不需要预留1个\0符号
size_t linebufferSize = lineEnd - lineIndent;
QByteArray linebuf;
linebuf.resize(linebufferSize);
this->getText(linebuf.data(), lineIndent, lineEnd);
QByteArray linebufStr = linebuf;
if (currCommentMode != cm_comment) // uncomment/toggle
{
if (!isSingleLineAdvancedMode)
{
if (qstrncmp(linebufStr.data(), comment.data(), !(pLexer->lexerId() == L_BAANC) ? comment_length - 1 : comment_length) == 0)
{
size_t len = (linebufStr[(int)comment_length - 1] == aSpace[0]) ? comment_length : (!(pLexer->lexerId() == L_BAANC) ? comment_length - 1 : comment_length);
this->execute(SCI_SETSEL, lineIndent, lineIndent + len);
this->replaceSelWith("");
// SELECTION RANGE ADJUSTMENT .......................
if (i == selStartLine) // first selected line
{
if (selectionStart > lineIndent + len)
selectionStart -= len;
else if (selectionStart > lineIndent)
selectionStart = lineIndent;
} // ................................................
if (i == selEndLine) // last selected line
{
if (selectionEnd > lineIndent + len)
selectionEnd -= len;
else if (selectionEnd > lineIndent)
{
selectionEnd = lineIndent;
if (lineIndent == lineStart && i != selStartLine)
++selectionEnd; // avoid caret return in this case
}
} // ................................................
else // every iteration except the last selected line
selectionEnd -= len;
// ..................................................
++nUncomments;
continue;
}
}
else
{
if ((qstrncmp(linebufStr.data(), advCommentStart.data(), advCommentStart_length - 1) == 0) &&
(qstrncmp(linebufStr.mid(linebufStr.length() - advCommentEnd_length + 1, advCommentEnd_length - 1).data(), advCommentEnd.mid(1, advCommentEnd_length - 1).data(), advCommentEnd_length - 1) == 0))
{
size_t startLen = linebufStr[(int)advCommentStart_length - 1] == aSpace[0] ? advCommentStart_length : advCommentStart_length - 1;
size_t endLen = linebufStr[int(linebufStr.length() - advCommentEnd_length)] == aSpace[0] ? advCommentEnd_length : advCommentEnd_length - 1;
this->execute(SCI_SETSEL, lineIndent, lineIndent + startLen);
this->replaceSelWith("");
this->execute(SCI_SETSEL, lineEnd - startLen - endLen, lineEnd - startLen);
this->replaceSelWith("");
// SELECTION RANGE ADJUSTMENT .......................
if (i == selStartLine) // first selected line
{
if (selectionStart > lineEnd - endLen)
selectionStart = lineEnd - startLen - endLen;
else if (selectionStart > lineIndent + startLen)
selectionStart -= startLen;
else if (selectionStart > lineIndent)
selectionStart = lineIndent;
} // ................................................
if (i == selEndLine) // last selected line
{
if (selectionEnd > lineEnd)
selectionEnd -= (startLen + endLen);
else if (selectionEnd > lineEnd - endLen)
selectionEnd = lineEnd - startLen - endLen;
else if (selectionEnd > lineIndent + startLen)
selectionEnd -= startLen;
else if (selectionEnd > lineIndent)
{
selectionEnd = lineIndent;
if (lineIndent == lineStart && i != selStartLine)
++selectionEnd; // avoid caret return in this case
}
} // ................................................
else // every iteration except the last selected line
selectionEnd -= (startLen + endLen);
// ..................................................
++nUncomments;
continue;
}
}
} // uncomment/toggle
if (currCommentMode != cm_uncomment) // comment/toggle
{
if (!isSingleLineAdvancedMode)
{
this->insertCharsFrom(lineIndent, comment);
// SELECTION RANGE ADJUSTMENT .......................
if (i == selStartLine) // first selected line
{
if (selectionStart >= lineIndent)
selectionStart += comment_length;
} // ................................................
if (i == selEndLine) // last selected line
{
if (selectionEnd >= lineIndent)
selectionEnd += comment_length;
} // ................................................
else // every iteration except the last selected line
selectionEnd += comment_length;
// ..................................................
}
else // isSingleLineAdvancedMode
{
this->insertCharsFrom(lineIndent, advCommentStart);
this->insertCharsFrom(lineEnd + advCommentStart_length, advCommentEnd);
// SELECTION RANGE ADJUSTMENT .......................
if (i == selStartLine) // first selected line
{
if (selectionStart >= lineIndent)
selectionStart += advCommentStart_length;
} // ................................................
if (i == selEndLine) // last selected line
{
if (selectionEnd > lineEnd)
selectionEnd += (advCommentStart_length + advCommentEnd_length);
else if (selectionEnd >= lineIndent)
selectionEnd += advCommentStart_length;
} // ................................................
else // every iteration except the last selected line
selectionEnd += (advCommentStart_length + advCommentEnd_length);
// ..................................................
}
} // comment/toggle
} // for (...)
if (move_caret)
{
// moving caret to the beginning of selected block
this->execute(SCI_GOTOPOS, selectionEnd);
this->execute(SCI_SETCURRENTPOS, selectionStart);
}
else
{
this->execute(SCI_SETSEL, selectionStart, selectionEnd);
}
this->execute(SCI_ENDUNDOACTION);
// undoStreamComment: If there were no block-comments to un-comment try uncommenting of stream-comment.
if ((currCommentMode == cm_uncomment) && (nUncomments == 0))
{
return undoStreamComment(false);
}
return true;
}
//显示文字的字数
void ScintillaEditView::showWordNums()
{
if (hasSelectedText())
{
QString word = selectedText();
if (!word.isEmpty())
{
QMessageBox::about(this, tr("Word Nums"), tr("Current Select Word Nums is %1 .").arg(word.size()));
}
}
else
{
QMessageBox::about(this, tr("Word Nums"), tr("Current Doc Word Nums is %1 .").arg(this->text().size()));
}
}
bool ScintillaEditView::undoStreamComment(bool tryBlockComment)
{
QByteArray commentStart;
QByteArray commentEnd;
QByteArray commentLineSymbol;
QByteArray symbolStart;
QByteArray symbolEnd;
QByteArray symbol;
const int charbufLen = 10;
QByteArray charbuf;
charbuf.reserve(charbufLen);
bool retVal = false;
QsciLexer* pLexer = this->lexer();
//-- Avoid side-effects (e.g. cursor moves number of comment-characters) when file is read-only.
if (this->isReadOnly())
return false;
if (pLexer->lexer() == nullptr)
{
return false;
}
else
{
commentLineSymbol = pLexer->getCommentLineSymbol();
commentStart = pLexer->getCommentStart();
commentEnd = pLexer->getCommentEnd();
}
// BlockToStreamComment: If there is no stream-comment symbol and we came not from doBlockComment, try the block comment:
if (commentStart.isEmpty() || commentEnd.isEmpty())
{
if (!commentLineSymbol.isEmpty() && tryBlockComment)
return doBlockComment(cm_uncomment);
else
return false;
}
QByteArray start_comment(commentStart);
QByteArray end_comment(commentEnd);
QByteArray white_space(" ");
size_t start_comment_length = start_comment.length();
size_t end_comment_length = end_comment.length();
// do as long as stream-comments are within selection
do
{
auto selectionStart = this->execute(SCI_GETSELECTIONSTART);
auto selectionEnd = this->execute(SCI_GETSELECTIONEND);
auto caretPosition = this->execute(SCI_GETCURRENTPOS);
auto docLength = this->execute(SCI_GETLENGTH);
// checking if caret is located in _beginning_ of selected block
bool move_caret = caretPosition < selectionEnd;
//-- Note: The caretPosition is either at selectionEnd or at selectionStart!! selectionStart is always before (smaller) than selectionEnd!!
//-- First, search all start_comment and end_comment before and after the selectionStart and selectionEnd position.
const int iSelStart = 0, iSelEnd = 1;
const size_t N_CMNT = 2;
intptr_t posStartCommentBefore[N_CMNT], posEndCommentBefore[N_CMNT], posStartCommentAfter[N_CMNT], posEndCommentAfter[N_CMNT];
bool blnStartCommentBefore[N_CMNT], blnEndCommentBefore[N_CMNT], blnStartCommentAfter[N_CMNT], blnEndCommentAfter[N_CMNT];
intptr_t posStartComment, posEndComment;
intptr_t selectionStartMove, selectionEndMove;
int flags;
//-- Directly use Scintilla-Functions
// rather than _findReplaceDlg.processFindNext()which does not return the find-position and is not quiet!
flags = SCFIND_WORDSTART;
this->execute(SCI_SETSEARCHFLAGS, flags);
//-- Find all start- and end-comments before and after the selectionStart position.
//-- When searching upwards the start-position for searching must be moved one after the current position
// to find a search-string just starting before the current position!
//-- Direction DIR_UP ---
posStartCommentBefore[iSelStart] = this->searchInTarget(start_comment, selectionStart, 0);
(posStartCommentBefore[iSelStart] == -1 ? blnStartCommentBefore[iSelStart] = false : blnStartCommentBefore[iSelStart] = true);
posEndCommentBefore[iSelStart] = this->searchInTarget(end_comment, selectionStart, 0);
(posEndCommentBefore[iSelStart] == -1 ? blnEndCommentBefore[iSelStart] = false : blnEndCommentBefore[iSelStart] = true);
//-- Direction DIR_DOWN ---
posStartCommentAfter[iSelStart] = this->searchInTarget(start_comment, selectionStart, docLength);
(posStartCommentAfter[iSelStart] == -1 ? blnStartCommentAfter[iSelStart] = false : blnStartCommentAfter[iSelStart] = true);
posEndCommentAfter[iSelStart] = this->searchInTarget(end_comment, selectionStart, docLength);
(posEndCommentAfter[iSelStart] == -1 ? blnEndCommentAfter[iSelStart] = false : blnEndCommentAfter[iSelStart] = true);
//-- Check, if selectionStart or selectionEnd is within a stream comment -----
// or if the selection includes a complete stream-comment!! ----------------
//-- First, check if there is a stream-comment around the selectionStart position:
if ((blnStartCommentBefore[iSelStart] && blnEndCommentAfter[iSelStart])
&& (!blnEndCommentBefore[iSelStart] || (posStartCommentBefore[iSelStart] >= posEndCommentBefore[iSelStart]))
&& (!blnStartCommentAfter[iSelStart] || (posEndCommentAfter[iSelStart] <= posStartCommentAfter[iSelStart])))
{
posStartComment = posStartCommentBefore[iSelStart];
posEndComment = posEndCommentAfter[iSelStart];
}
else //-- Second, check if there is a stream-comment around the selectionEnd position:
{
//-- Find all start- and end-comments before and after the selectionEnd position.
//-- Direction DIR_UP ---
posStartCommentBefore[iSelEnd] = this->searchInTarget(start_comment, selectionEnd, 0);
(posStartCommentBefore[iSelEnd] == -1 ? blnStartCommentBefore[iSelEnd] = false : blnStartCommentBefore[iSelEnd] = true);
posEndCommentBefore[iSelEnd] = this->searchInTarget(end_comment, selectionEnd, 0);
(posEndCommentBefore[iSelEnd] == -1 ? blnEndCommentBefore[iSelEnd] = false : blnEndCommentBefore[iSelEnd] = true);
//-- Direction DIR_DOWN ---
posStartCommentAfter[iSelEnd] = this->searchInTarget(start_comment, selectionEnd, docLength);
(posStartCommentAfter[iSelEnd] == -1 ? blnStartCommentAfter[iSelEnd] = false : blnStartCommentAfter[iSelEnd] = true);
posEndCommentAfter[iSelEnd] = this->searchInTarget(end_comment, selectionEnd, docLength);
(posEndCommentAfter[iSelEnd] == -1 ? blnEndCommentAfter[iSelEnd] = false : blnEndCommentAfter[iSelEnd] = true);
if ((blnStartCommentBefore[iSelEnd] && blnEndCommentAfter[iSelEnd])
&& (!blnEndCommentBefore[iSelEnd] || (posStartCommentBefore[iSelEnd] >= posEndCommentBefore[iSelEnd]))
&& (!blnStartCommentAfter[iSelEnd] || (posEndCommentAfter[iSelEnd] <= posStartCommentAfter[iSelEnd])))
{
posStartComment = posStartCommentBefore[iSelEnd];
posEndComment = posEndCommentAfter[iSelEnd];
}
//-- Third, check if there is a stream-comment within the selected area:
else if ((blnStartCommentAfter[iSelStart] && (posStartCommentAfter[iSelStart] < selectionEnd))
&& (blnEndCommentBefore[iSelEnd] && (posEndCommentBefore[iSelEnd] > selectionStart)))
{
//-- If there are more than one stream-comment within the selection, take the first one after selectionStart!!
posStartComment = posStartCommentAfter[iSelStart];
posEndComment = posEndCommentAfter[iSelStart];
}
//-- Finally, if there is no stream-comment, return
else
return retVal;
}
//-- Ok, there are valid start-comment and valid end-comment around the caret-position.
// Now, un-comment stream-comment:
retVal = true;
intptr_t startCommentLength = start_comment_length;
intptr_t endCommentLength = end_comment_length;
//-- First delete end-comment, so that posStartCommentBefore does not change!
//-- Get character before end-comment to decide, if there is a white character before the end-comment, which will be removed too!
this->getText(charbuf.data(), posEndComment - 1, posEndComment);
if (qstrncmp(charbuf, white_space, white_space.length()) == 0)
{
endCommentLength += 1;
posEndComment -= 1;
}
//-- Delete end stream-comment string ---------
this->execute(SCI_BEGINUNDOACTION);
this->execute(SCI_SETSEL, posEndComment, posEndComment + endCommentLength);
this->execute(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(""));
//-- Get character after start-comment to decide, if there is a white character after the start-comment, which will be removed too!
this->getText(charbuf.data(), posStartComment + startCommentLength, posStartComment + startCommentLength + 1);
if (qstrncmp(charbuf, white_space, white_space.length()) == 0)
startCommentLength += 1;
//-- Delete starting stream-comment string ---------
this->execute(SCI_SETSEL, posStartComment, posStartComment + startCommentLength);
this->execute(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(""));
this->execute(SCI_ENDUNDOACTION);
//-- Reset selection before calling the routine
//-- Determine selection movement
// selectionStart
if (selectionStart > posStartComment)
{
if (selectionStart >= posStartComment + startCommentLength)
selectionStartMove = -startCommentLength;
else
selectionStartMove = -selectionStart - posStartComment;
}
else
selectionStartMove = 0;
// selectionEnd
if (selectionEnd >= posEndComment + endCommentLength)
selectionEndMove = -startCommentLength + endCommentLength;
else if (selectionEnd <= posEndComment)
selectionEndMove = -startCommentLength;
else
selectionEndMove = -startCommentLength + (selectionEnd - posEndComment);
//-- Reset selection of text without deleted stream-comment-string
if (move_caret)
{
// moving caret to the beginning of selected block
this->execute(SCI_GOTOPOS, selectionEnd + selectionEndMove);
this->execute(SCI_SETCURRENTPOS, selectionStart + selectionStartMove);
}
else
{
this->execute(SCI_SETSEL, selectionStart + selectionStartMove, selectionEnd + selectionEndMove);
}
} while (1); //do as long as stream-comments are within selection
}
bool ScintillaEditView::doStreamComment()
{
QByteArray commentStart;
QByteArray commentEnd;
QByteArray symbolStart;
QByteArray symbolEnd;
// BlockToStreamComment:
QByteArray commentLineSymbol;
QByteArray symbol;
if (this->isReadOnly())
return false;
QsciLexer* pLexer = this->lexer();
if (pLexer == nullptr)
{
return false;
}
else
{
// BlockToStreamComment: Next line needed to decide, if block-comment can be called below!
commentLineSymbol = pLexer->getCommentLineSymbol();
commentStart = pLexer->getCommentStart();
commentEnd = pLexer->getCommentEnd();
}
// BlockToStreamComment: If there is no stream-comment symbol, try the block comment:
if (commentStart.isEmpty()||commentEnd.isEmpty())
{
if (!commentLineSymbol.isEmpty())
return doBlockComment(cm_comment);
else
{
return false;
}
}
QByteArray start_comment(commentStart);
QByteArray end_comment(commentEnd);
QByteArray white_space(" ");
start_comment += white_space;
white_space += end_comment;
end_comment = white_space;
size_t start_comment_length = start_comment.length();
size_t selectionStart = this->execute(SCI_GETSELECTIONSTART);
size_t selectionEnd = this->execute(SCI_GETSELECTIONEND);
size_t caretPosition = this->execute(SCI_GETCURRENTPOS);
// checking if caret is located in _beginning_ of selected block
bool move_caret = caretPosition < selectionEnd;
// if there is no selection?
if (selectionEnd - selectionStart <= 0)
{
auto selLine = this->execute(SCI_LINEFROMPOSITION, selectionStart);
selectionStart = this->execute(SCI_GETLINEINDENTPOSITION, selLine);
selectionEnd = this->execute(SCI_GETLINEENDPOSITION, selLine);
}
this->execute(SCI_BEGINUNDOACTION);
this->insertCharsFrom(selectionStart, start_comment);
selectionEnd += start_comment_length;
selectionStart += start_comment_length;
this->insertCharsFrom(selectionEnd, end_comment);
if (move_caret)
{
// moving caret to the beginning of selected block
this->execute(SCI_GOTOPOS, selectionEnd);
this->execute(SCI_SETCURRENTPOS, selectionStart);
}
else
{
this->execute(SCI_SETSEL, selectionStart, selectionEnd);
}
this->execute(SCI_ENDUNDOACTION);
return true;
}
void ScintillaEditView::slot_delayWork()
{
if (!hasSelectedText())
{
return;
}
QString word = selectedText();
if (!word.isEmpty())
{
highlightViewWithWord(word);
}
}
void ScintillaEditView::dragEnterEvent(QDragEnterEvent* event)
{
event->accept();
}
void ScintillaEditView::dropEvent(QDropEvent* e)
{
QList<QUrl> urls = e->mimeData()->urls();
if (!urls.isEmpty())
{
CCNotePad* pv = dynamic_cast<CCNotePad*>(m_NoteWin);
if (pv != nullptr)
{
pv->receiveEditDrop(e);
}
return;
}
QsciScintilla::dropEvent(e);
}
void ScintillaEditView::mouseDoubleClickEvent(QMouseEvent * e)
{
if (CCNotePad::s_hightWebAddr == 1)
{
do {
int position = this->execute(SCI_GETCURRENTPOS);
auto indicMsk = this->execute(SCI_INDICATORALLONFOR, position);
if (!(indicMsk & (1 << URL_INDIC)))
break;
auto startPos = this->execute(SCI_INDICATORSTART, URL_INDIC, position);
auto endPos = this->execute(SCI_INDICATOREND, URL_INDIC, position);
if ((position < startPos) || (position > endPos))
break;
// WM_LBUTTONUP goes to opening browser instead of Scintilla here, because the mouse is not captured.
// The missing message causes mouse cursor flicker as soon as the mouse cursor is moved to a position outside the text editing area.
//::PostMessage(this->getHSelf(), WM_LBUTTONUP, 0, 0);
// Revert selection of current word. Best to this early, otherwise the
// selected word is visible all the time while the browser is starting
execute(SCI_SETSEL, position, position);
// Open URL
QByteArray url;
url.resize(endPos - startPos);
this->getText(url.data(), static_cast<size_t>(startPos), static_cast<size_t>(endPos));
QUrl urlweb(url);
if (urlweb.isValid())
{
QDesktopServices::openUrl(urlweb);
return;
}
} while (0);
}
QsciScintilla::mouseDoubleClickEvent(e);
if (hasSelectedText())
{
emit delayWork();
}
}
void ScintillaEditView::changeCase(const TextCaseType & caseToConvert, QString& strToConvert) const
{
if (strToConvert.isEmpty())
return;
int nbChars = strToConvert.size();
switch (caseToConvert)
{
case UPPERCASE:
{
strToConvert = strToConvert.toUpper();
break;
}
case LOWERCASE:
{
strToConvert = strToConvert.toLower();
break;
}
case TITLECASE_FORCE:
case TITLECASE_BLEND:
{
for (int i = 0; i < nbChars; ++i)
{
if (strToConvert[i].isLetter())
{
if ((i < 1) ? true : !strToConvert[i - 1].isLetterOrNumber())
strToConvert[i] = strToConvert[i].toUpper();
else if (caseToConvert == TITLECASE_FORCE)
strToConvert[i] = strToConvert[i].toLower();
//An exception
if ((i < 2) ? false : (strToConvert[i - 1] == L'\'' && (strToConvert[i - 2].isLetter())))
strToConvert[i] = strToConvert[i].toLower();
}
}
break;
} //case TITLECASE
case SENTENCECASE_FORCE:
case SENTENCECASE_BLEND:
{
bool isNewSentence = true;
bool wasEolR = false;
bool wasEolN = false;
for (int i = 0; i < nbChars; ++i)
{
if (strToConvert[i].isLetter())
{
if (isNewSentence)
{
strToConvert[i] = strToConvert[i].toUpper();
isNewSentence = false;
}
else if (caseToConvert == SENTENCECASE_FORCE)
{
strToConvert[i] = strToConvert[i].toLower();
}
wasEolR = false;
wasEolN = false;
//An exception
if (strToConvert[i] == L'i' &&
((i < 1) ? false : (strToConvert[i - 1].isSpace() || strToConvert[i - 1] == '(' || strToConvert[i - 1] == '"')) && \
((i + 1 == nbChars) ? false : (strToConvert[i + 1].isSpace() || strToConvert[i + 1] == '\'')))
{
strToConvert[i] = L'I';
}
}
else if (strToConvert[i] == '.' || strToConvert[i] == '!' || strToConvert[i] == '?')
{
if ((i + 1 == nbChars) ? true : strToConvert[i + 1].isLetterOrNumber())
isNewSentence = false;
else
isNewSentence = true;
}
else if (strToConvert[i] == '\r')
{
if (wasEolR)
isNewSentence = true;
else
wasEolR = true;
}
else if (strToConvert[i] == '\n')
{
if (wasEolN)
isNewSentence = true;
else
wasEolN = true;
}
}
break;
} //case SENTENCECASE
case INVERTCASE:
{
for (int i = 0; i < nbChars; ++i)
{
if (strToConvert[i].isLower())
strToConvert[i] = strToConvert[i].toUpper();
else
strToConvert[i] = strToConvert[i].toLower();
}
break;
} //case INVERTCASE
case RANDOMCASE:
{
for (int i = 0; i < nbChars; ++i)
{
if (strToConvert[i].isLetter())
{
if (std::rand() & true)
strToConvert[i] = strToConvert[i].toUpper();
else
strToConvert[i] = strToConvert[i].toLower();
}
}
break;
}
} //switch (caseToConvert)
}
void ScintillaEditView::convertSelectedTextTo(const TextCaseType & caseToConvert)
{
int selectionStart = execute(SCI_GETSELECTIONSTART);
int selectionEnd = execute(SCI_GETSELECTIONEND);
int strLen = (selectionEnd - selectionStart);
if (strLen != 0)
{
int strSize = strLen + 1;
char *selectedStr = new char[strSize];
execute(SCI_GETSELTEXT, 0, reinterpret_cast<sptr_t>(selectedStr));
QString utf8Str(selectedStr);
changeCase(caseToConvert, utf8Str);
QByteArray bytes = utf8Str.toUtf8();
execute(SCI_SETTARGETRANGE, selectionStart, selectionEnd);
execute(SCI_BEGINUNDOACTION);
execute(SCI_REPLACETARGET, strLen, reinterpret_cast<sptr_t>(bytes.data()));
execute(SCI_ENDUNDOACTION);
execute(SCI_SETSEL, selectionStart, selectionEnd);
delete[] selectedStr;
}
}
//获取当前选择的行范围
std::pair<size_t, size_t> ScintillaEditView::getSelectionLinesRange(intptr_t selectionNumber /* = -1 */) const
{
size_t numSelections = execute(SCI_GETSELECTIONS);
size_t start_pos, end_pos;
if ((selectionNumber < 0) || (static_cast<size_t>(selectionNumber) >= numSelections))
{
start_pos = execute(SCI_GETSELECTIONSTART);
end_pos = execute(SCI_GETSELECTIONEND);
}
else
{
start_pos = execute(SCI_GETSELECTIONNSTART, selectionNumber);
end_pos = execute(SCI_GETSELECTIONNEND, selectionNumber);
}
size_t line1 = execute(SCI_LINEFROMPOSITION, start_pos);
size_t line2 = execute(SCI_LINEFROMPOSITION, end_pos);
if ((line1 != line2) && (static_cast<size_t>(execute(SCI_POSITIONFROMLINE, line2)) == end_pos))
{
// if the end of the selection includes the line-ending,
// then don't include the following line in the range
--line2;
}
return std::pair<size_t, size_t>(line1, line2);
}
//获取内容。是uft8格式的。所有字符都以utf8编码
void ScintillaEditView::getText(char *dest, size_t start, size_t end) const
{
Sci_TextRange tr;
tr.chrg.cpMin = static_cast<Sci_PositionCR>(start);
tr.chrg.cpMax = static_cast<Sci_PositionCR>(end);
tr.lpstrText = dest;
this->SendScintilla(SCI_GETTEXTRANGE, 0, &tr);
}
QString ScintillaEditView::getGenericTextAsQString(size_t start, size_t end) const
{
assert(end > start);
const size_t bufSize = end - start + 1;
QByteArray bytes;
bytes.resize(bufSize);
getText(bytes.data(), start, end);
return QString(bytes);
}
QString ScintillaEditView::getEOLString()
{
intptr_t eol_mode = execute(SCI_GETEOLMODE);
if (eol_mode == SC_EOL_CRLF)
{
return QString("\r\n");
}
else if (eol_mode == SC_EOL_LF)
{
return QString("\n");
}
else
{
return QString("\r");
}
}
size_t vecRemoveDuplicates(QList<QString>& vec)
{
std::unordered_set<std::string> seen;
auto newEnd = std::remove_if(vec.begin(), vec.end(), [&seen](const QString& value)
{
return !seen.insert(value.toStdString()).second;
});
vec.erase(newEnd, vec.end());
return vec.size();
}
void ScintillaEditView::removeAnyDuplicateLines()
{
size_t fromLine = 0, toLine = 0;
bool hasLineSelection = false;
auto selStart = execute(SCI_GETSELECTIONSTART);
auto selEnd = execute(SCI_GETSELECTIONEND);
hasLineSelection = selStart != selEnd;
if (hasLineSelection)
{
const std::pair<size_t, size_t> lineRange = getSelectionLinesRange();
// One single line selection is not allowed.
if (lineRange.first == lineRange.second)
{
return;
}
fromLine = lineRange.first;
toLine = lineRange.second;
}
else
{
// No selection.
fromLine = 0;
toLine = execute(SCI_GETLINECOUNT) - 1;
}
if (fromLine >= toLine)
{
return;
}
const auto startPos = execute(SCI_POSITIONFROMLINE, fromLine);
const auto endPos = execute(SCI_POSITIONFROMLINE, toLine) + execute(SCI_LINELENGTH, toLine);
const QString text = getGenericTextAsQString(startPos, endPos);
QStringList linesVect = text.split(getEOLString());
const size_t lineCount = execute(SCI_GETLINECOUNT);
const bool doingEntireDocument = (toLine == (lineCount - 1));
if (!doingEntireDocument)
{
if (linesVect.rbegin()->isEmpty())
{
linesVect.pop_back();
}
}
size_t origSize = linesVect.size();
size_t newSize = vecRemoveDuplicates(linesVect);
if (origSize != newSize)
{
QString joined = linesVect.join(getEOLString());
if (!doingEntireDocument)
{
joined += getEOLString();
}
if (text != joined)
{
QByteArray str2replace;
str2replace = joined.toUtf8();
replaceTarget(str2replace, startPos, endPos);
}
}
}
void ScintillaEditView::insertCharsFrom(size_t position, const QByteArray & text2insert) const
{
this->SendScintilla(SCI_INSERTTEXT, position, text2insert.data());
}
void ScintillaEditView::appandGenericText(const QByteArray &text2Append) const
{
this->SendScintilla(SCI_APPENDTEXT, text2Append.size(), text2Append.data());
}
void ScintillaEditView::insertNewLineAboveCurrentLine(bool)
{
QString newline = getEOLString();
const auto current_line = getCurrentLineNumber();
if (current_line == 0)
{
// Special handling if caret is at first line.
insertCharsFrom(0, newline.toUtf8());
}
else
{
const auto eol_length = newline.length();
const auto position = execute(SCI_POSITIONFROMLINE, current_line) - eol_length;
insertCharsFrom(position, newline.toUtf8());
}
execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line));
}
void ScintillaEditView::insertNewLineBelowCurrentLine(bool)
{
QString newline = getEOLString();
const auto line_count = execute(SCI_GETLINECOUNT);
const auto current_line = getCurrentLineNumber();
if (current_line == line_count - 1)
{
// Special handling if caret is at last line.
appandGenericText(newline.toUtf8());
}
else
{
const auto eol_length = newline.length();
const auto position = eol_length + execute(SCI_GETLINEENDPOSITION, current_line);
insertCharsFrom(position, newline.toUtf8());
}
execute(SCI_SETEMPTYSELECTION, execute(SCI_POSITIONFROMLINE, current_line + 1));
}
void ScintillaEditView::sortLines(size_t fromLine, size_t toLine, ISorter* pSort)
{
if (fromLine >= toLine)
{
return;
}
const auto startPos = execute(SCI_POSITIONFROMLINE, fromLine);
const auto endPos = execute(SCI_POSITIONFROMLINE, toLine) + execute(SCI_LINELENGTH, toLine);
const QString text = getGenericTextAsQString(startPos, endPos);
QStringList splitText = text.split(getEOLString());
const size_t lineCount = execute(SCI_GETLINECOUNT);
const bool sortEntireDocument = toLine == lineCount - 1;
if (!sortEntireDocument)
{
if (splitText.rbegin()->isEmpty())
{
splitText.pop_back();
}
}
assert(toLine - fromLine + 1 == splitText.size());
const QList<QString> sortedText = pSort->sort(splitText);
QString joined = sortedText.join(getEOLString());
if (sortEntireDocument)
{
assert(joined.length() == text.length());
}
else
{
assert(joined.length() + getEOLString().length() == text.length());
joined += getEOLString();
}
if (text != joined)
{
QByteArray bytes = joined.toUtf8();
replaceTarget(bytes, startPos, endPos);
}
}
void ScintillaEditView::setFoldColor(int margin, QColor fgClack, QColor bkColor, QColor foreActive)
{
SendScintilla(SCI_MARKERSETFORE, margin, fgClack);
SendScintilla(SCI_MARKERSETBACK, margin, bkColor);
SendScintilla(SCI_MARKERSETBACKSELECTED, margin, foreActive);
}
ColumnModeInfos ScintillaEditView::getColumnModeSelectInfo()
{
ColumnModeInfos columnModeInfos;
if (execute(SCI_GETSELECTIONS) > 1) // Multi-Selection || Column mode
{
intptr_t nbSel = execute(SCI_GETSELECTIONS);
for (int i = 0; i < nbSel; ++i)
{
intptr_t absPosSelStartPerLine = execute(SCI_GETSELECTIONNANCHOR, i);
intptr_t absPosSelEndPerLine = execute(SCI_GETSELECTIONNCARET, i);
intptr_t nbVirtualAnchorSpc = execute(SCI_GETSELECTIONNANCHORVIRTUALSPACE, i);
intptr_t nbVirtualCaretSpc = execute(SCI_GETSELECTIONNCARETVIRTUALSPACE, i);
if (absPosSelStartPerLine == absPosSelEndPerLine && execute(SCI_SELECTIONISRECTANGLE))
{
bool dir = nbVirtualAnchorSpc < nbVirtualCaretSpc ? L2R : R2L;
columnModeInfos.push_back(ColumnModeInfo(absPosSelStartPerLine, absPosSelEndPerLine, i, dir, nbVirtualAnchorSpc, nbVirtualCaretSpc));
}
else if (absPosSelStartPerLine > absPosSelEndPerLine)
columnModeInfos.push_back(ColumnModeInfo(absPosSelEndPerLine, absPosSelStartPerLine, i, R2L, nbVirtualAnchorSpc, nbVirtualCaretSpc));
else
columnModeInfos.push_back(ColumnModeInfo(absPosSelStartPerLine, absPosSelEndPerLine, i, L2R, nbVirtualAnchorSpc, nbVirtualCaretSpc));
}
}
return columnModeInfos;
}
void ScintillaEditView::columnReplace(ColumnModeInfos& cmi, QByteArray& str)
{
intptr_t totalDiff = 0;
for (size_t i = 0, len = cmi.size(); i < len; ++i)
{
if (cmi[i].isValid())
{
intptr_t len2beReplace = cmi[i]._selRpos - cmi[i]._selLpos;
intptr_t diff = str.size() - len2beReplace;
cmi[i]._selLpos += totalDiff;
cmi[i]._selRpos += totalDiff;
bool hasVirtualSpc = cmi[i]._nbVirtualAnchorSpc > 0;
if (hasVirtualSpc) // if virtual space is present, then insert space
{
for (intptr_t j = 0, k = cmi[i]._selLpos; j < cmi[i]._nbVirtualCaretSpc; ++j, ++k)
{
execute(SCI_INSERTTEXT, k, reinterpret_cast<sptr_t>(" "));
}
cmi[i]._selLpos += cmi[i]._nbVirtualAnchorSpc;
cmi[i]._selRpos += cmi[i]._nbVirtualCaretSpc;
}
execute(SCI_SETTARGETRANGE, cmi[i]._selLpos, cmi[i]._selRpos);
execute(SCI_REPLACETARGET, static_cast<int>(-1), reinterpret_cast<sptr_t>(str.data()));
if (hasVirtualSpc)
{
totalDiff += cmi[i]._nbVirtualAnchorSpc + str.size();
// Now there's no more virtual space
cmi[i]._nbVirtualAnchorSpc = 0;
cmi[i]._nbVirtualCaretSpc = 0;
}
else
{
totalDiff += diff;
}
cmi[i]._selRpos += diff;
}
}
}
void ScintillaEditView::setMultiSelections(const ColumnModeInfos& cmi)
{
for (size_t i = 0, len = cmi.size(); i < len; ++i)
{
if (cmi[i].isValid())
{
intptr_t selStart = cmi[i]._direction == L2R ? cmi[i]._selLpos : cmi[i]._selRpos;
intptr_t selEnd = cmi[i]._direction == L2R ? cmi[i]._selRpos : cmi[i]._selLpos;
execute(SCI_SETSELECTIONNSTART, i, selStart);
execute(SCI_SETSELECTIONNEND, i, selEnd);
}
if (cmi[i]._nbVirtualAnchorSpc)
execute(SCI_SETSELECTIONNANCHORVIRTUALSPACE, i, cmi[i]._nbVirtualAnchorSpc);
if (cmi[i]._nbVirtualCaretSpc)
execute(SCI_SETSELECTIONNCARETVIRTUALSPACE, i, cmi[i]._nbVirtualCaretSpc);
}
}
int getNbDigits(int aNum, int base)
{
int nbChiffre = 1;
int diviseur = base;
for (;;)
{
int result = aNum / diviseur;
if (!result)
break;
else
{
diviseur *= base;
++nbChiffre;
}
}
if ((base == 16) && (nbChiffre % 2 != 0))
nbChiffre += 1;
return nbChiffre;
}
void ScintillaEditView::columnReplace(ColumnModeInfos& cmi, int initial, int incr, int repeat, int format, bool isCapital, QByteArray& prefix)
{
assert(repeat > 0);
// If there is no column mode info available, no need to do anything
// If required a message can be shown to user, that select column properly or something similar
// It is just a double check as taken in callee method (in case this method is called from multiple places)
if (cmi.size() <= 0)
return;
// 0000 00 00 : Dec BASE_10
// 0000 00 01 : Hex BASE_16
// 0000 00 10 : Oct BASE_08
// 0000 00 11 : Bin BASE_02
// 0000 01 00 : 0 leading
//Defined in ScintillaEditView.h :
//const UCHAR MASK_FORMAT = 0x03;
//const UCHAR MASK_ZERO_LEADING = 0x04;
int base = format;
const int stringSize = 512;
QByteArray str;
str.reserve(stringSize) ;
// Compute the numbers to be placed at each column.
std::vector<int> numbers;
{
int curNumber = initial;
const size_t kiMaxSize = cmi.size();
while (numbers.size() < kiMaxSize)
{
for (int i = 0; i < repeat; i++)
{
numbers.push_back(curNumber);
if (numbers.size() >= kiMaxSize)
{
break;
}
}
curNumber += incr;
}
}
assert(numbers.size() > 0);
/*const int kibEnd = getNbDigits(*numbers.rbegin(), base);
const int kibInit = getNbDigits(initial, base);
const int kib = std::max<int>(kibInit, kibEnd);*/
intptr_t totalDiff = 0;
const size_t len = cmi.size();
for (size_t i = 0; i < len; i++)
{
if (cmi[i].isValid())
{
const intptr_t len2beReplaced = cmi[i]._selRpos - cmi[i]._selLpos;
if (base != 16)
{
str = prefix + QString::number(numbers.at(i), base).toUtf8();
}
else
{
//16进制判断大小写
if (isCapital)
{
str = prefix + QString::number(numbers.at(i), base).toUpper().toUtf8();
}
else
{
str = prefix + QString::number(numbers.at(i), base).toUtf8();
}
}
const intptr_t diff = str.size() - len2beReplaced;
cmi[i]._selLpos += totalDiff;
cmi[i]._selRpos += totalDiff;
const bool hasVirtualSpc = cmi[i]._nbVirtualAnchorSpc > 0;
if (hasVirtualSpc) // if virtual space is present, then insert space
{
for (intptr_t j = 0, k = cmi[i]._selLpos; j < cmi[i]._nbVirtualCaretSpc; ++j, ++k)
{
execute(SCI_INSERTTEXT, k, reinterpret_cast<sptr_t>(" "));
}
cmi[i]._selLpos += cmi[i]._nbVirtualAnchorSpc;
cmi[i]._selRpos += cmi[i]._nbVirtualCaretSpc;
}
execute(SCI_SETTARGETRANGE, cmi[i]._selLpos, cmi[i]._selRpos);
execute(SCI_REPLACETARGET, static_cast<int>(-1), reinterpret_cast<sptr_t>(str.data()));
if (hasVirtualSpc)
{
totalDiff += cmi[i]._nbVirtualAnchorSpc + str.size();
// Now there's no more virtual space
cmi[i]._nbVirtualAnchorSpc = 0;
cmi[i]._nbVirtualCaretSpc = 0;
}
else
{
totalDiff += diff;
}
cmi[i]._selRpos += diff;
}
}
}
void ScintillaEditView::getVisibleStartAndEndPosition(int * startPos, int * endPos)
{
assert(startPos != NULL && endPos != NULL);
// Get the position of the 1st and last showing chars from the edit view
QRect rcEditView;
rcEditView = this->rect();
int pos = execute(SCI_POSITIONFROMPOINT, 0, 0);
int line = execute(SCI_LINEFROMPOSITION, pos);
*startPos = static_cast<int32_t>(execute(SCI_POSITIONFROMLINE, line));
pos = execute(SCI_POSITIONFROMPOINT, rcEditView.right() - rcEditView.left(), rcEditView.bottom() - rcEditView.top());
line = execute(SCI_LINEFROMPOSITION, pos);
*endPos = static_cast<int32_t>(execute(SCI_GETLINEENDPOSITION, line));
}
bool isUrlSchemeStartChar(QChar const c)
{
return ((c >= 'A') && (c <= 'Z'))
|| ((c >= 'a') && (c <= 'z'));
}
bool isUrlSchemeDelimiter(QChar const c)
{
return !(((c >= '0') && (c <= '9'))
|| ((c >= 'A') && (c <= 'Z'))
|| ((c >= 'a') && (c <= 'z'))
|| (c == '_'));
}
bool scanToUrlStart(QString &text, int textLen, int start, int* distance, int* schemeLength)
{
int p = start;
int p0 = 0;
enum { sUnknown, sScheme } s = sUnknown;
while (p < textLen)
{
switch (s)
{
case sUnknown:
if (isUrlSchemeStartChar(text[p]) && ((p == 0) || isUrlSchemeDelimiter(text[p - 1])))
{
p0 = p;
s = sScheme;
}
break;
case sScheme:
if (text[p] == ':')
{
*distance = p0 - start;
*schemeLength = p - p0 + 1;
return true;
}
if (!isUrlSchemeStartChar(text[p]))
s = sUnknown;
break;
}
p++;
}
*schemeLength = 0;
*distance = p - start;
return false;
}
bool isUrlTextChar(QChar const c)
{
if (c <= ' ') return false;
switch (c.digitValue())
{
case ('"'):
case ('#'):
case ('<'):
case ('>'):
case ('{'):
case ('}'):
case ('?'):
case ('\u007F'):
return false;
}
return true;
}
bool isUrlQueryDelimiter(QChar const c)
{
switch (c.digitValue())
{
case '&':
case '+':
case '=':
case ';':
return true;
}
return false;
}
void scanToUrlEnd(QString & text, int textLen, int start, int* distance)
{
int p = start;
QChar q = 0;
enum { sHostAndPath, sQuery, sQueryAfterDelimiter, sQueryQuotes, sQueryAfterQuotes, sFragment } s = sHostAndPath;
while (p < textLen)
{
switch (s)
{
case sHostAndPath:
if (text[p] == QChar('?'))
s = sQuery;
else if (text[p] == '#')
s = sFragment;
else if (!isUrlTextChar(text[p]))
{
*distance = p - start;
return;
}
break;
case sQuery:
if (text[p] == '#')
s = sFragment;
else if (isUrlQueryDelimiter(text[p]))
s = sQueryAfterDelimiter;
else if (!isUrlTextChar(text[p]))
{
*distance = p - start;
return;
}
break;
case sQueryAfterDelimiter:
if ((text[p] == '\'') || (text[p] == '"') || (text[p] == '`'))
{
q = text[p];
s = sQueryQuotes;
}
else if (text[p] == '(')
{
q = ')';
s = sQueryQuotes;
}
else if (text[p] == '[')
{
q = ']';
s = sQueryQuotes;
}
else if (text[p] == '{')
{
q = '}';
s = sQueryQuotes;
}
else if (isUrlTextChar(text[p]))
s = sQuery;
else
{
*distance = p - start;
return;
}
break;
case sQueryQuotes:
if (text[p] < ' ')
{
*distance = p - start;
return;
}
if (text[p] == q)
s = sQueryAfterQuotes;
break;
case sQueryAfterQuotes:
if (isUrlQueryDelimiter(text[p]))
s = sQueryAfterDelimiter;
else
{
*distance = p - start;
return;
}
break;
case sFragment:
if (!isUrlTextChar(text[p]))
{
*distance = p - start;
return;
}
break;
}
p++;
}
*distance = p - start;
}
// removeUnwantedTrailingCharFromUrl removes a single unwanted trailing character from an URL.
// It has to be called repeatedly, until it returns false, meaning that all unwanted characters are gone.
bool removeUnwantedTrailingCharFromUrl(QChar const *text, int* length)
{
int l = *length - 1;
if (l <= 0) return false;
{ // remove unwanted single characters
const char *singleChars = ".,:;?!#";
for (int i = 0; singleChars[i]; i++)
if (text[l] == singleChars[i])
{
*length = l;
return true;
}
}
{ // remove unwanted closing parenthesis
const char *closingParenthesis = ")]";
const char *openingParenthesis = "([";
for (int i = 0; closingParenthesis[i]; i++)
if (text[l] == closingParenthesis[i])
{
int count = 0;
for (int j = l - 1; j >= 0; j--)
{
if (text[j] == closingParenthesis[i])
count++;
if (text[j] == openingParenthesis[i])
if (count > 0)
count--;
else
return false;
}
if (count != 0)
return false;
*length = l;
return true;
}
}
return false;
}
bool isUrl(QString& text, int textLen, int start, int* segmentLen)
{
int dist = 0, schemeLen = 0;
if (scanToUrlStart(text, textLen, start, &dist, &schemeLen))
{
if (dist)
{
*segmentLen = dist;
return false;
}
int len = 0;
scanToUrlEnd(text, textLen, start + schemeLen, &len);
if (len)
{
len += schemeLen;
QString urlStr = text.mid(start, len);
if (urlStr.startsWith("http://") || urlStr.startsWith("https://"))
{
QUrl url(urlStr);
bool r = url.isValid();
if (r)
{
while (removeUnwantedTrailingCharFromUrl(text.data() + start, &len));
*segmentLen = len;
return true;
}
}
}
len = 1;
int lMax = textLen - start;
while (isUrlSchemeStartChar(text[start + len]) && (len < lMax)) len++;
*segmentLen = len;
return false;
}
*segmentLen = dist;
return false;
}
quint32 ScintillaEditView::getBigTextBlockStartLine()
{
return m_curBlockLineStartNum;
}
void ScintillaEditView::setBigTextBlockStartLine(quint32 line)
{
m_curBlockLineStartNum = line;
}
void ScintillaEditView::addHotSpot()
{
if (CCNotePad::s_hightWebAddr == 1)
{
int urlAction = urlNoUnderLineFg;
int indicStyle = INDIC_PLAIN;
int indicHoverStyle = INDIC_EXPLORERLINK;
int indicStyleCur = this->execute(SCI_INDICGETSTYLE, URL_INDIC);
int indicHoverStyleCur = this->execute(SCI_INDICGETHOVERSTYLE, URL_INDIC);
if ((indicStyleCur != indicStyle) || (indicHoverStyleCur != indicHoverStyle))
{
this->execute(SCI_INDICSETSTYLE, URL_INDIC, indicStyle);
this->execute(SCI_INDICSETHOVERSTYLE, URL_INDIC, indicHoverStyle);
this->execute(SCI_INDICSETALPHA, URL_INDIC, 70);
this->execute(SCI_INDICSETFLAGS, URL_INDIC, SC_INDICFLAG_VALUEFORE);
}
int startPos = 0;
int endPos = -1;
this->getVisibleStartAndEndPosition(&startPos, &endPos);
if (startPos >= endPos)
{
return;
}
this->execute(SCI_SETINDICATORCURRENT, URL_INDIC);
if (urlAction == urlDisable)
{
this->execute(SCI_INDICATORCLEARRANGE, startPos, endPos - startPos);
return;
}
int indicFore = this->execute(SCI_STYLEGETFORE, STYLE_DEFAULT);
this->execute(SCI_SETINDICATORVALUE, indicFore);
QByteArray encodedText;
encodedText.resize(endPos - startPos);
this->getText(encodedText.data(), startPos, endPos);
QString encodedTextStr(encodedText);
int wideTextLen = encodedTextStr.size();
if (wideTextLen > 0)
{
int startWide = 0;
int lenWide = 0;
int startEncoded = 0;
int lenEncoded = 0;
while (true)
{
bool r = isUrl(encodedTextStr, encodedTextStr.size(), startWide, &lenWide);
if (lenWide <= 0)
break;
lenEncoded = encodedTextStr.mid(startWide, lenWide).toUtf8().size();
if (r)
this->execute(SCI_INDICATORFILLRANGE, startEncoded + startPos, lenEncoded);
else
this->execute(SCI_INDICATORCLEARRANGE, startEncoded + startPos, lenEncoded);
startWide += lenWide;
startEncoded += lenEncoded;
if ((startWide >= wideTextLen) || ((startEncoded + startPos) >= endPos))
break;
}
assert((startEncoded + startPos) == endPos);
assert(startWide == wideTextLen);
}
}
}
void ScintillaEditView::setStyleOptions()
{
#if 0
//如果是黑色主题,则单独做一些风格设置
if (StyleSet::m_curStyleId == BLACK_SE)
{
setCaretLineBackgroundColor(QColor(0x333333));
setMatchedBraceForegroundColor(QColor(246, 81, 246));
setMatchedBraceBackgroundColor(QColor(18, 90, 36));
setCaretForegroundColor(QColor(255, 255, 255));
setFoldColor(SC_MARKNUM_FOLDEROPEN, QColor(45, 130, 45), QColor(222, 222, 222));
setFoldColor(SC_MARKNUM_FOLDER, QColor(45, 130, 45), QColor(222, 222, 222));
setFoldColor(SC_MARKNUM_FOLDERSUB, QColor(45, 130, 45), QColor(222, 222, 222));
setFoldColor(SC_MARKNUM_FOLDERTAIL, QColor(45, 130, 45), QColor(222, 222, 222));
setFoldColor(SC_MARKNUM_FOLDEREND, QColor(45, 130, 45), QColor(222, 222, 222));
setFoldColor(SC_MARKNUM_FOLDEROPENMID, QColor(45, 130, 45), QColor(222, 222, 222));
setFoldColor(SC_MARKNUM_FOLDERMIDTAIL, QColor(45, 130, 45), QColor(222, 222, 222));
}
else
{
setCaretLineBackgroundColor(QColor(0xe8e8ff));
setMatchedBraceForegroundColor(QColor(191, 141, 255));
setMatchedBraceBackgroundColor(QColor(222, 222, 222));
setCaretForegroundColor(QColor(0, 0, 0));
setFoldColor(SC_MARKNUM_FOLDEROPEN, QColor(Qt::white), QColor(128, 128, 128));
setFoldColor(SC_MARKNUM_FOLDER, QColor(Qt::white), QColor(128, 128, 128));
setFoldColor(SC_MARKNUM_FOLDERSUB, QColor(Qt::white), QColor(128, 128, 128));
setFoldColor(SC_MARKNUM_FOLDERTAIL, QColor(Qt::white), QColor(128, 128, 128));
setFoldColor(SC_MARKNUM_FOLDEREND, QColor(Qt::white), QColor(128, 128, 128));
setFoldColor(SC_MARKNUM_FOLDEROPENMID, QColor(Qt::white), QColor(128, 128, 128));
setFoldColor(SC_MARKNUM_FOLDERMIDTAIL, QColor(Qt::white), QColor(128, 128, 128));
}
#endif
}
//在ScintillaEditView中直接设置这些One_Stype_Info的属性值
//这里的style不一定是在lexer中的而是默认的STYLE_*自定义的那些全局内部风格。
void ScintillaEditView::updateThemes()
{
//第0个是GLOBAL_OVERRIDE是Lexer的样式不属于全局
for (int i = 1; i <= URL_HOVERRED; ++i)
{
setGlobalFgColor(i);
setGlobalBgColor(i);
setGlobalFont(i);
}
}
void getFoldColor(QColor& fgColor, QColor& bgColor, QColor& activeFgColor)
{
//这里看起来反了,但是实际代码就是如此
fgColor = StyleSet::s_global_style->fold.bgColor;
bgColor = StyleSet::s_global_style->fold.fgColor;
activeFgColor = StyleSet::s_global_style->fold_active.fgColor;
}
void ScintillaEditView::setGlobalFgColor(int style)
{
switch (style)
{
case GLOBAL_OVERRIDE:
{
//全局前景色修改是针对语法的lexer属性进行的修改而非其余全局属性的修改。这点要区分开来
}
break;
case DEFAULT_STYLE:
{
//修改默认前景色
SendScintilla(SCI_STYLESETFORE, StyleSet::s_global_style->default_style.styleId, StyleSet::s_global_style->default_style.fgColor);
}
break;
case INDENT_GUIDELINE:
{
//修改默认前景色
SendScintilla(SCI_STYLESETFORE, StyleSet::s_global_style->indent_guideline.styleId, StyleSet::s_global_style->indent_guideline.fgColor);
}
break;
case BRACE_HIGHIGHT:
{
//修改默认前景色
SendScintilla(SCI_STYLESETFORE, StyleSet::s_global_style->brace_highight.styleId, StyleSet::s_global_style->brace_highight.fgColor);
}
break;
case BAD_BRACE_COLOUR:
{
//修改默认前景色
SendScintilla(SCI_STYLESETFORE, StyleSet::s_global_style->bad_brace_color.styleId, StyleSet::s_global_style->bad_brace_color.fgColor);
}
break;
case CURRENT_LINE_BACKGROUND_COLOR:
//不能设置前景色,只能设置背景
break;
case SELECT_TEXT_COLOR:
SendScintilla(SCI_SETSELFORE, true, StyleSet::s_global_style->select_text_color.fgColor);
break;
case CARET_COLOUR:
SendScintilla(SCI_SETCARETFORE, StyleSet::s_global_style->caret_colour.fgColor);
break;
case EDGE_COLOUR:
SendScintilla(SCI_SETEDGECOLOUR, StyleSet::s_global_style->edge_colour.fgColor);
break;
case LINE_NUMBER_MARGIN:
{
//修改默认前景色
SendScintilla(SCI_STYLESETFORE, StyleSet::s_global_style->line_number_margin.styleId, StyleSet::s_global_style->line_number_margin.fgColor);
}
break;
case BOOKMARK_MARGIN:
//不能设置
break;
case FOLD:
case FOLD_ACTIVE:
{
QColor foldfgColor = Qt::white, foldbgColor = Qt::gray, activeFoldFgColor = Qt::red;
getFoldColor(foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDEROPEN, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDER, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDERSUB, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDERTAIL, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDEREND, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDEROPENMID, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDERMIDTAIL, foldfgColor, foldbgColor, activeFoldFgColor);
//暂时开启,看看后面是否有错误
//execute(SCI_MARKERENABLEHIGHLIGHT, true);
}
break;
case FOLD_MARGIN:
//前景背景一起设置,不分开
{
setFoldMarginColors(StyleSet::s_global_style->fold_margin.fgColor, StyleSet::s_global_style->fold_margin.bgColor);
}
break;
case WHITE_SPACE_SYMBOL:
SendScintilla(SCI_SETWHITESPACEFORE, true, StyleSet::s_global_style->white_space_stybol.fgColor);
break;
case SMART_HIGHLIGHTING:
//只能设置前景,不能设置背景
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_SMART, StyleSet::s_global_style->smart_highlighting.fgColor);
break;
case FIND_MARK_STYLE:
//只能设置前景,不能设置背景。目前这条是空的,暂时没有使用
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE, StyleSet::s_global_style->find_mark_style.fgColor);
break;
case MARK_STYLE_1:
case MARK_STYLE_2:
case MARK_STYLE_3:
case MARK_STYLE_4:
case MARK_STYLE_5:
case INCREMENTAL_HIGHLIGHT:
//暂时没有使用
break;
case TAGS_MATCH_HIGHLIGHT:
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_TAGMATCH, StyleSet::s_global_style->tags_match_highlight.fgColor);
break;
case TAGS_ATTRIBUTE:
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_TAGATTR, StyleSet::s_global_style->tags_attribute.fgColor);
break;
//case ACTIVE_TAB_FOCUSED:
//case ACTIVE_TAB_UNFOCUSED:
//case ACTIVE_TAB_TEXT:
//case INACTIVE_TABS:
// break;
case URL_HOVERRED:
SendScintilla(SCI_INDICSETHOVERFORE, URL_INDIC, StyleSet::s_global_style->url_hoverred.fgColor);
break;
default:
break;
}
};
void ScintillaEditView::setGlobalBgColor(int style)
{
switch (style)
{
case GLOBAL_OVERRIDE:
{
}
break;
case DEFAULT_STYLE:
{
//修改默认前景色
SendScintilla(SCI_STYLESETBACK, StyleSet::s_global_style->default_style.styleId, StyleSet::s_global_style->default_style.bgColor);
}
break;
case INDENT_GUIDELINE:
{
//修改默认前景色
SendScintilla(SCI_STYLESETBACK, StyleSet::s_global_style->indent_guideline.styleId, StyleSet::s_global_style->indent_guideline.bgColor);
}
break;
case BRACE_HIGHIGHT:
{
//修改默认前景色
SendScintilla(SCI_STYLESETBACK, StyleSet::s_global_style->brace_highight.styleId, StyleSet::s_global_style->brace_highight.bgColor);
}
break;
case BAD_BRACE_COLOUR:
{
//修改默认前景色
SendScintilla(SCI_STYLESETBACK, StyleSet::s_global_style->bad_brace_color.styleId, StyleSet::s_global_style->bad_brace_color.bgColor);
}
break;
case CURRENT_LINE_BACKGROUND_COLOR:
//不能设置前景色,只能设置背景
SendScintilla(SCI_SETCARETLINEBACK, StyleSet::s_global_style->current_line_background_color.bgColor);
break;
case SELECT_TEXT_COLOR:
SendScintilla(SCI_SETSELBACK, true, StyleSet::s_global_style->select_text_color.bgColor);
break;
case CARET_COLOUR:
//不能设置
break;
case EDGE_COLOUR:
//不能设置
break;
case LINE_NUMBER_MARGIN:
{
//修改默认背景色
SendScintilla(SCI_STYLESETBACK, StyleSet::s_global_style->line_number_margin.styleId, StyleSet::s_global_style->line_number_margin.bgColor);
}
break;
case BOOKMARK_MARGIN:
{
if (StyleSet::s_global_style->bookmark_margin.bgColor.isValid())
{
SendScintilla(SCI_SETMARGINBACKN, _SC_MARGE_SYBOLE, StyleSet::s_global_style->bookmark_margin.bgColor);
}
else
{
SendScintilla(SCI_SETMARGINBACKN, _SC_MARGE_SYBOLE, StyleSet::s_global_style->line_number_margin.bgColor);
}
}
break;
case FOLD:
case FOLD_ACTIVE:
{
QColor foldfgColor = Qt::white, foldbgColor = Qt::gray, activeFoldFgColor = Qt::red;
getFoldColor(foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDEROPEN, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDER, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDERSUB, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDERTAIL, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDEREND, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDEROPENMID, foldfgColor, foldbgColor, activeFoldFgColor);
setFoldColor(SC_MARKNUM_FOLDERMIDTAIL, foldfgColor, foldbgColor, activeFoldFgColor);
//暂时不能开启。因为QT下面有一个1Pix的差异如果开启当前fold的变化会缺失1pix的宽度看起来难看。
// 这是QT的bug暂时解决不了。
//execute(SCI_MARKERENABLEHIGHLIGHT, true);
}
break;
case FOLD_MARGIN:
//前景背景一起设置,不分开
{
setFoldMarginColors(StyleSet::s_global_style->fold_margin.fgColor, StyleSet::s_global_style->fold_margin.bgColor);
}
break;
case WHITE_SPACE_SYMBOL:
//不能设置
break;
case SMART_HIGHLIGHTING:
//不能设置
break;
case FIND_MARK_STYLE:
//不能设置
break;
//下面五个比较特殊,选择改动的是背景。单本质改动的样式却是前景
case MARK_STYLE_1:
//只能设置前景,不能设置背景
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT5, StyleSet::s_global_style->mark_style_1.bgColor);
changeStyleColor(0);
break;
case MARK_STYLE_2:
//只能设置前景,不能设置背景
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT4, StyleSet::s_global_style->mark_style_2.bgColor);
changeStyleColor(1);
break;
case MARK_STYLE_3:
//只能设置前景,不能设置背景
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT3, StyleSet::s_global_style->mark_style_3.bgColor);
changeStyleColor(2);
break;
case MARK_STYLE_4:
//只能设置前景,不能设置背景
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT2, StyleSet::s_global_style->mark_style_4.bgColor);
changeStyleColor(3);
break;
case MARK_STYLE_5:
//只能设置前景,不能设置背景
SendScintilla(SCI_INDICSETFORE, SCE_UNIVERSAL_FOUND_STYLE_EXT1, StyleSet::s_global_style->mark_style_5.bgColor);
changeStyleColor(4);
break;
case INCREMENTAL_HIGHLIGHT:
case TAGS_MATCH_HIGHLIGHT:
case TAGS_ATTRIBUTE:
break;
//case ACTIVE_TAB_FOCUSED:
//case ACTIVE_TAB_UNFOCUSED:
//case ACTIVE_TAB_TEXT:
//case INACTIVE_TABS:
// break;
case URL_HOVERRED:
break;
default:
break;
}
};
// Set the font for a style.
//enum Font_Set_Bit {
// Bold_Bit = 0x1,
// Italic_Bit = 0x2,
// Underline_Bit = 0x4,
// Font_Name_Bit = 0x8,
// Font_Size_Bit = 0x10,
//};
void ScintillaEditView::setStylesFont(const QFont& f, int style, int setBitMask)
{
if (setBitMask & Font_Name_Bit)
{
SendScintilla(SCI_STYLESETFONT, style, f.family().toUtf8().data());
}
if (setBitMask & Bold_Bit)
{
SendScintilla(SCI_STYLESETBOLD, style, f.bold());
}
if (setBitMask & Italic_Bit)
{
SendScintilla(SCI_STYLESETITALIC, style, f.italic());
}
if (setBitMask & Underline_Bit)
{
SendScintilla(SCI_STYLESETUNDERLINE, style, f.underline());
}
if (setBitMask & Font_Size_Bit && f.pointSize() > 2)
{
SendScintilla(SCI_STYLESETSIZE, style, f.pointSize());
}
//如果是行号大小变化,则必须动态计算行宽度
if (style == STYLE_LINENUMBER)
{
updateLineNumberWidth(1);
}
}
void ScintillaEditView::setGlobalFont(int style)
{
switch (style)
{
case GLOBAL_OVERRIDE:
case INDENT_GUIDELINE:
case CURRENT_LINE_BACKGROUND_COLOR:
case SELECT_TEXT_COLOR:
case CARET_COLOUR:
case EDGE_COLOUR:
case BOOKMARK_MARGIN:
case FOLD:
case FOLD_ACTIVE:
case FOLD_MARGIN:
case WHITE_SPACE_SYMBOL:
case SMART_HIGHLIGHTING:
case FIND_MARK_STYLE:
case MARK_STYLE_1:
case MARK_STYLE_2:
case MARK_STYLE_3:
case MARK_STYLE_4:
case MARK_STYLE_5:
case INCREMENTAL_HIGHLIGHT:
case TAGS_MATCH_HIGHLIGHT:
case TAGS_ATTRIBUTE:
//case ACTIVE_TAB_FOCUSED:
//case ACTIVE_TAB_UNFOCUSED:
//case ACTIVE_TAB_TEXT:
//case INACTIVE_TABS:
case URL_HOVERRED:
break;
case DEFAULT_STYLE:
{
setStylesFont(StyleSet::s_global_style->default_style.font, STYLE_DEFAULT, 0x1f);
}
break;
case BRACE_HIGHIGHT:
{
setStylesFont(StyleSet::s_global_style->brace_highight.font, STYLE_BRACELIGHT, 0x1f);
}
break;
case BAD_BRACE_COLOUR:
{
setStylesFont(StyleSet::s_global_style->bad_brace_color.font, STYLE_BRACEBAD, 0x1f);
}
break;
case LINE_NUMBER_MARGIN:
{
//除了下划线不加,其余的都需要设置
setStylesFont(StyleSet::s_global_style->line_number_margin.font, STYLE_LINENUMBER, 0x1b);
}
break;
default:
break;
}
}