| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162 |
- //https://github.com/BalazsJako/ImGuiColorTextEdit
- #include <algorithm>
- #include <chrono>
- #include <string>
- #include <regex>
- #include <cmath>
- #include "TextEditor.h"
- #define IMGUI_DEFINE_MATH_OPERATORS
- #include "imgui.h" // for imGui::GetCurrentWindow()
- // TODO
- // - multiline comments vs single-line: latter is blocking start of a ML
- template<class InputIt1, class InputIt2, class BinaryPredicate>
- bool equals(InputIt1 first1, InputIt1 last1,
- InputIt2 first2, InputIt2 last2, BinaryPredicate p)
- {
- for (; first1 != last1 && first2 != last2; ++first1, ++first2)
- {
- if (!p(*first1, *first2))
- return false;
- }
- return first1 == last1 && first2 == last2;
- }
- TextEditor::TextEditor()
- : mLineSpacing(1.0f)
- , mUndoIndex(0)
- , mTabSize(4)
- , mOverwrite(false)
- , mReadOnly(false)
- , mWithinRender(false)
- , mScrollToCursor(false)
- , mScrollToTop(false)
- , mTextChanged(false)
- , mColorizerEnabled(true)
- , mTextStart(20.0f)
- , mLeftMargin(10)
- , mCursorPositionChanged(false)
- , mColorRangeMin(0)
- , mColorRangeMax(0)
- , mSelectionMode(SelectionMode::Normal)
- , mCheckComments(true)
- , mLastClick(-1.0f)
- , mHandleKeyboardInputs(true)
- , mHandleMouseInputs(true)
- , mIgnoreImGuiChild(false)
- , mShowWhitespaces(true)
- , mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count())
- {
- SetPalette(GetDarkPalette());
- //SetLanguageDefinition(LanguageDefinition::HLSL());
- mLines.push_back(Line());
- }
- TextEditor::~TextEditor()
- {
- }
- void TextEditor::SetLanguageDefinition(const LanguageDefinition & aLanguageDef)
- {
- mLanguageDefinition = aLanguageDef;
- mRegexList.clear();
- for (auto& r : mLanguageDefinition.mTokenRegexStrings)
- mRegexList.push_back(std::make_pair(std::regex(r.first, std::regex_constants::optimize), r.second));
- Colorize();
- }
- void TextEditor::SetPalette(const Palette & aValue)
- {
- mPaletteBase = aValue;
- }
- std::string TextEditor::GetText(const Coordinates & aStart, const Coordinates & aEnd) const
- {
- std::string result;
- auto lstart = aStart.mLine;
- auto lend = aEnd.mLine;
- auto istart = GetCharacterIndex(aStart);
- auto iend = GetCharacterIndex(aEnd);
- size_t s = 0;
- for (size_t i = lstart; i < lend; i++)
- s += mLines[i].size();
- result.reserve(s + s / 8);
- while (istart < iend || lstart < lend)
- {
- if (lstart >= (int)mLines.size())
- break;
- auto& line = mLines[lstart];
- if (istart < (int)line.size())
- {
- result += line[istart].mChar;
- istart++;
- }
- else
- {
- istart = 0;
- ++lstart;
- result += '\n';
- }
- }
- return result;
- }
- TextEditor::Coordinates TextEditor::GetActualCursorCoordinates() const
- {
- return SanitizeCoordinates(mState.mCursorPosition);
- }
- TextEditor::Coordinates TextEditor::SanitizeCoordinates(const Coordinates & aValue) const
- {
- auto line = aValue.mLine;
- auto column = aValue.mColumn;
- if (line >= (int)mLines.size())
- {
- if (mLines.empty())
- {
- line = 0;
- column = 0;
- }
- else
- {
- line = (int)mLines.size() - 1;
- column = GetLineMaxColumn(line);
- }
- return Coordinates(line, column);
- }
- else
- {
- column = mLines.empty() ? 0 : std::min(column, GetLineMaxColumn(line));
- return Coordinates(line, column);
- }
- }
- // https://en.wikipedia.org/wiki/UTF-8
- // We assume that the char is a standalone character (<128) or a leading byte of an UTF-8 code sequence (non-10xxxxxx code)
- static int UTF8CharLength(TextEditor::Char c)
- {
- if ((c & 0xFE) == 0xFC)
- return 6;
- if ((c & 0xFC) == 0xF8)
- return 5;
- if ((c & 0xF8) == 0xF0)
- return 4;
- else if ((c & 0xF0) == 0xE0)
- return 3;
- else if ((c & 0xE0) == 0xC0)
- return 2;
- return 1;
- }
- // "Borrowed" from ImGui source
- static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
- {
- if (c < 0x80)
- {
- buf[0] = (char)c;
- return 1;
- }
- if (c < 0x800)
- {
- if (buf_size < 2) return 0;
- buf[0] = (char)(0xc0 + (c >> 6));
- buf[1] = (char)(0x80 + (c & 0x3f));
- return 2;
- }
- if (c >= 0xdc00 && c < 0xe000)
- {
- return 0;
- }
- if (c >= 0xd800 && c < 0xdc00)
- {
- if (buf_size < 4) return 0;
- buf[0] = (char)(0xf0 + (c >> 18));
- buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
- buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
- buf[3] = (char)(0x80 + ((c) & 0x3f));
- return 4;
- }
- //else if (c < 0x10000)
- {
- if (buf_size < 3) return 0;
- buf[0] = (char)(0xe0 + (c >> 12));
- buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
- buf[2] = (char)(0x80 + ((c) & 0x3f));
- return 3;
- }
- }
- void TextEditor::Advance(Coordinates & aCoordinates) const
- {
- if (aCoordinates.mLine < (int)mLines.size())
- {
- auto& line = mLines[aCoordinates.mLine];
- auto cindex = GetCharacterIndex(aCoordinates);
- if (cindex + 1 < (int)line.size())
- {
- auto delta = UTF8CharLength(line[cindex].mChar);
- cindex = std::min(cindex + delta, (int)line.size() - 1);
- }
- else
- {
- ++aCoordinates.mLine;
- cindex = 0;
- }
- aCoordinates.mColumn = GetCharacterColumn(aCoordinates.mLine, cindex);
- }
- }
- void TextEditor::DeleteRange(const Coordinates & aStart, const Coordinates & aEnd)
- {
- assert(aEnd >= aStart);
- assert(!mReadOnly);
- //printf("D(%d.%d)-(%d.%d)\n", aStart.mLine, aStart.mColumn, aEnd.mLine, aEnd.mColumn);
- if (aEnd == aStart)
- return;
- auto start = GetCharacterIndex(aStart);
- auto end = GetCharacterIndex(aEnd);
- if (aStart.mLine == aEnd.mLine)
- {
- auto& line = mLines[aStart.mLine];
- auto n = GetLineMaxColumn(aStart.mLine);
- if (aEnd.mColumn >= n)
- line.erase(line.begin() + start, line.end());
- else
- line.erase(line.begin() + start, line.begin() + end);
- }
- else
- {
- auto& firstLine = mLines[aStart.mLine];
- auto& lastLine = mLines[aEnd.mLine];
- firstLine.erase(firstLine.begin() + start, firstLine.end());
- lastLine.erase(lastLine.begin(), lastLine.begin() + end);
- if (aStart.mLine < aEnd.mLine)
- firstLine.insert(firstLine.end(), lastLine.begin(), lastLine.end());
- if (aStart.mLine < aEnd.mLine)
- RemoveLine(aStart.mLine + 1, aEnd.mLine + 1);
- }
- mTextChanged = true;
- }
- int TextEditor::InsertTextAt(Coordinates& /* inout */ aWhere, const char * aValue)
- {
- assert(!mReadOnly);
- int cindex = GetCharacterIndex(aWhere);
- int totalLines = 0;
- while (*aValue != '\0')
- {
- assert(!mLines.empty());
- if (*aValue == '\r')
- {
- // skip
- ++aValue;
- }
- else if (*aValue == '\n')
- {
- if (cindex < (int)mLines[aWhere.mLine].size())
- {
- auto& newLine = InsertLine(aWhere.mLine + 1);
- auto& line = mLines[aWhere.mLine];
- newLine.insert(newLine.begin(), line.begin() + cindex, line.end());
- line.erase(line.begin() + cindex, line.end());
- }
- else
- {
- InsertLine(aWhere.mLine + 1);
- }
- ++aWhere.mLine;
- aWhere.mColumn = 0;
- cindex = 0;
- ++totalLines;
- ++aValue;
- }
- else
- {
- auto& line = mLines[aWhere.mLine];
- auto d = UTF8CharLength(*aValue);
- while (d-- > 0 && *aValue != '\0')
- line.insert(line.begin() + cindex++, Glyph(*aValue++, PaletteIndex::Default));
- ++aWhere.mColumn;
- }
- mTextChanged = true;
- }
- return totalLines;
- }
- void TextEditor::AddUndo(UndoRecord& aValue)
- {
- assert(!mReadOnly);
- //printf("AddUndo: (@%d.%d) +\'%s' [%d.%d .. %d.%d], -\'%s', [%d.%d .. %d.%d] (@%d.%d)\n",
- // aValue.mBefore.mCursorPosition.mLine, aValue.mBefore.mCursorPosition.mColumn,
- // aValue.mAdded.c_str(), aValue.mAddedStart.mLine, aValue.mAddedStart.mColumn, aValue.mAddedEnd.mLine, aValue.mAddedEnd.mColumn,
- // aValue.mRemoved.c_str(), aValue.mRemovedStart.mLine, aValue.mRemovedStart.mColumn, aValue.mRemovedEnd.mLine, aValue.mRemovedEnd.mColumn,
- // aValue.mAfter.mCursorPosition.mLine, aValue.mAfter.mCursorPosition.mColumn
- // );
- mUndoBuffer.resize((size_t)(mUndoIndex + 1));
- mUndoBuffer.back() = aValue;
- ++mUndoIndex;
- }
- TextEditor::Coordinates TextEditor::ScreenPosToCoordinates(const ImVec2& aPosition) const
- {
- ImVec2 origin = ImGui::GetCursorScreenPos();
- ImVec2 local(aPosition.x - origin.x, aPosition.y - origin.y);
- int lineNo = std::max(0, (int)floor(local.y / mCharAdvance.y));
- int columnCoord = 0;
- if (lineNo >= 0 && lineNo < (int)mLines.size())
- {
- auto& line = mLines.at(lineNo);
- int columnIndex = 0;
- float columnX = 0.0f;
- while ((size_t)columnIndex < line.size())
- {
- float columnWidth = 0.0f;
- if (line[columnIndex].mChar == '\t')
- {
- float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ").x;
- float oldX = columnX;
- float newColumnX = (1.0f + std::floor((1.0f + columnX) / (float(mTabSize) * spaceSize))) * (float(mTabSize) * spaceSize);
- columnWidth = newColumnX - oldX;
- if (mTextStart + columnX + columnWidth * 0.5f > local.x)
- break;
- columnX = newColumnX;
- columnCoord = (columnCoord / mTabSize) * mTabSize + mTabSize;
- columnIndex++;
- }
- else
- {
- char buf[7];
- auto d = UTF8CharLength(line[columnIndex].mChar);
- int i = 0;
- while (i < 6 && d-- > 0)
- buf[i++] = line[columnIndex++].mChar;
- buf[i] = '\0';
- columnWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf).x;
- if (mTextStart + columnX + columnWidth * 0.5f > local.x)
- break;
- columnX += columnWidth;
- columnCoord++;
- }
- }
- }
- return SanitizeCoordinates(Coordinates(lineNo, columnCoord));
- }
- TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates & aFrom) const
- {
- Coordinates at = aFrom;
- if (at.mLine >= (int)mLines.size())
- return at;
- auto& line = mLines[at.mLine];
- auto cindex = GetCharacterIndex(at);
- if (cindex >= (int)line.size())
- return at;
- while (cindex > 0 && isspace(line[cindex].mChar))
- --cindex;
- auto cstart = (PaletteIndex)line[cindex].mColorIndex;
- while (cindex > 0)
- {
- auto c = line[cindex].mChar;
- if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx
- {
- if (c <= 32 && isspace(c))
- {
- cindex++;
- break;
- }
- if (cstart != (PaletteIndex)line[size_t(cindex - 1)].mColorIndex)
- break;
- }
- --cindex;
- }
- return Coordinates(at.mLine, GetCharacterColumn(at.mLine, cindex));
- }
- TextEditor::Coordinates TextEditor::FindWordEnd(const Coordinates & aFrom) const
- {
- Coordinates at = aFrom;
- if (at.mLine >= (int)mLines.size())
- return at;
- auto& line = mLines[at.mLine];
- auto cindex = GetCharacterIndex(at);
- if (cindex >= (int)line.size())
- return at;
- bool prevspace = (bool)isspace(line[cindex].mChar);
- auto cstart = (PaletteIndex)line[cindex].mColorIndex;
- while (cindex < (int)line.size())
- {
- auto c = line[cindex].mChar;
- auto d = UTF8CharLength(c);
- if (cstart != (PaletteIndex)line[cindex].mColorIndex)
- break;
- if (prevspace != !!isspace(c))
- {
- if (isspace(c))
- while (cindex < (int)line.size() && isspace(line[cindex].mChar))
- ++cindex;
- break;
- }
- cindex += d;
- }
- return Coordinates(aFrom.mLine, GetCharacterColumn(aFrom.mLine, cindex));
- }
- TextEditor::Coordinates TextEditor::FindNextWord(const Coordinates & aFrom) const
- {
- Coordinates at = aFrom;
- if (at.mLine >= (int)mLines.size())
- return at;
- // skip to the next non-word character
- auto cindex = GetCharacterIndex(aFrom);
- bool isword = false;
- bool skip = false;
- if (cindex < (int)mLines[at.mLine].size())
- {
- auto& line = mLines[at.mLine];
- isword = isalnum(line[cindex].mChar);
- skip = isword;
- }
- while (!isword || skip)
- {
- if (at.mLine >= mLines.size())
- {
- auto l = std::max(0, (int) mLines.size() - 1);
- return Coordinates(l, GetLineMaxColumn(l));
- }
- auto& line = mLines[at.mLine];
- if (cindex < (int)line.size())
- {
- isword = isalnum(line[cindex].mChar);
- if (isword && !skip)
- return Coordinates(at.mLine, GetCharacterColumn(at.mLine, cindex));
- if (!isword)
- skip = false;
- cindex++;
- }
- else
- {
- cindex = 0;
- ++at.mLine;
- skip = false;
- isword = false;
- }
- }
- return at;
- }
- int TextEditor::GetCharacterIndex(const Coordinates& aCoordinates) const
- {
- if (aCoordinates.mLine >= mLines.size())
- return -1;
- auto& line = mLines[aCoordinates.mLine];
- int c = 0;
- int i = 0;
- for (; i < line.size() && c < aCoordinates.mColumn;)
- {
- if (line[i].mChar == '\t')
- c = (c / mTabSize) * mTabSize + mTabSize;
- else
- ++c;
- i += UTF8CharLength(line[i].mChar);
- }
- return i;
- }
- int TextEditor::GetCharacterColumn(int aLine, int aIndex) const
- {
- if (aLine >= mLines.size())
- return 0;
- auto& line = mLines[aLine];
- int col = 0;
- int i = 0;
- while (i < aIndex && i < (int)line.size())
- {
- auto c = line[i].mChar;
- i += UTF8CharLength(c);
- if (c == '\t')
- col = (col / mTabSize) * mTabSize + mTabSize;
- else
- col++;
- }
- return col;
- }
- int TextEditor::GetLineCharacterCount(int aLine) const
- {
- if (aLine >= mLines.size())
- return 0;
- auto& line = mLines[aLine];
- int c = 0;
- for (unsigned i = 0; i < line.size(); c++)
- i += UTF8CharLength(line[i].mChar);
- return c;
- }
- int TextEditor::GetLineMaxColumn(int aLine) const
- {
- if (aLine >= mLines.size())
- return 0;
- auto& line = mLines[aLine];
- int col = 0;
- for (unsigned i = 0; i < line.size(); )
- {
- auto c = line[i].mChar;
- if (c == '\t')
- col = (col / mTabSize) * mTabSize + mTabSize;
- else
- col++;
- i += UTF8CharLength(c);
- }
- return col;
- }
- bool TextEditor::IsOnWordBoundary(const Coordinates & aAt) const
- {
- if (aAt.mLine >= (int)mLines.size() || aAt.mColumn == 0)
- return true;
- auto& line = mLines[aAt.mLine];
- auto cindex = GetCharacterIndex(aAt);
- if (cindex >= (int)line.size())
- return true;
- if (mColorizerEnabled)
- return line[cindex].mColorIndex != line[size_t(cindex - 1)].mColorIndex;
- return isspace(line[cindex].mChar) != isspace(line[cindex - 1].mChar);
- }
- void TextEditor::RemoveLine(int aStart, int aEnd)
- {
- assert(!mReadOnly);
- assert(aEnd >= aStart);
- assert(mLines.size() > (size_t)(aEnd - aStart));
- ErrorMarkers etmp;
- for (auto& i : mErrorMarkers)
- {
- ErrorMarkers::value_type e(i.first >= aStart ? i.first - 1 : i.first, i.second);
- if (e.first >= aStart && e.first <= aEnd)
- continue;
- etmp.insert(e);
- }
- mErrorMarkers = std::move(etmp);
- Breakpoints btmp;
- for (auto i : mBreakpoints)
- {
- if (i >= aStart && i <= aEnd)
- continue;
- btmp.insert(i >= aStart ? i - 1 : i);
- }
- mBreakpoints = std::move(btmp);
- mLines.erase(mLines.begin() + aStart, mLines.begin() + aEnd);
- assert(!mLines.empty());
- mTextChanged = true;
- }
- void TextEditor::RemoveLine(int aIndex)
- {
- assert(!mReadOnly);
- assert(mLines.size() > 1);
- ErrorMarkers etmp;
- for (auto& i : mErrorMarkers)
- {
- ErrorMarkers::value_type e(i.first > aIndex ? i.first - 1 : i.first, i.second);
- if (e.first - 1 == aIndex)
- continue;
- etmp.insert(e);
- }
- mErrorMarkers = std::move(etmp);
- Breakpoints btmp;
- for (auto i : mBreakpoints)
- {
- if (i == aIndex)
- continue;
- btmp.insert(i >= aIndex ? i - 1 : i);
- }
- mBreakpoints = std::move(btmp);
- mLines.erase(mLines.begin() + aIndex);
- assert(!mLines.empty());
- mTextChanged = true;
- }
- TextEditor::Line& TextEditor::InsertLine(int aIndex)
- {
- assert(!mReadOnly);
- auto& result = *mLines.insert(mLines.begin() + aIndex, Line());
- ErrorMarkers etmp;
- for (auto& i : mErrorMarkers)
- etmp.insert(ErrorMarkers::value_type(i.first >= aIndex ? i.first + 1 : i.first, i.second));
- mErrorMarkers = std::move(etmp);
- Breakpoints btmp;
- for (auto i : mBreakpoints)
- btmp.insert(i >= aIndex ? i + 1 : i);
- mBreakpoints = std::move(btmp);
- return result;
- }
- std::string TextEditor::GetWordUnderCursor() const
- {
- auto c = GetCursorPosition();
- return GetWordAt(c);
- }
- std::string TextEditor::GetWordAt(const Coordinates & aCoords) const
- {
- auto start = FindWordStart(aCoords);
- auto end = FindWordEnd(aCoords);
- std::string r;
- auto istart = GetCharacterIndex(start);
- auto iend = GetCharacterIndex(end);
- for (auto it = istart; it < iend; ++it)
- r.push_back(mLines[aCoords.mLine][it].mChar);
- return r;
- }
- ImU32 TextEditor::GetGlyphColor(const Glyph & aGlyph) const
- {
- if (!mColorizerEnabled)
- return mPalette[(int)PaletteIndex::Default];
- if (aGlyph.mComment)
- return mPalette[(int)PaletteIndex::Comment];
- if (aGlyph.mMultiLineComment)
- return mPalette[(int)PaletteIndex::MultiLineComment];
- auto const color = mPalette[(int)aGlyph.mColorIndex];
- if (aGlyph.mPreprocessor)
- {
- const auto ppcolor = mPalette[(int)PaletteIndex::Preprocessor];
- const int c0 = ((ppcolor & 0xff) + (color & 0xff)) / 2;
- const int c1 = (((ppcolor >> 8) & 0xff) + ((color >> 8) & 0xff)) / 2;
- const int c2 = (((ppcolor >> 16) & 0xff) + ((color >> 16) & 0xff)) / 2;
- const int c3 = (((ppcolor >> 24) & 0xff) + ((color >> 24) & 0xff)) / 2;
- return ImU32(c0 | (c1 << 8) | (c2 << 16) | (c3 << 24));
- }
- return color;
- }
- void TextEditor::HandleKeyboardInputs()
- {
- ImGuiIO& io = ImGui::GetIO();
- auto shift = io.KeyShift;
- auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
- auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
- if (ImGui::IsWindowFocused())
- {
- if (ImGui::IsWindowHovered())
- ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput);
- //ImGui::CaptureKeyboardFromApp(true);
- io.WantCaptureKeyboard = true;
- io.WantTextInput = true;
- if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z)))
- Undo();
- else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
- Undo();
- else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
- Redo();
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
- MoveUp(1, shift);
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
- MoveDown(1, shift);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
- MoveLeft(1, shift, ctrl);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
- MoveRight(1, shift, ctrl);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)))
- MoveUp(GetPageSize() - 4, shift);
- else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)))
- MoveDown(GetPageSize() - 4, shift);
- else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
- MoveTop(shift);
- else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
- MoveBottom(shift);
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
- MoveHome(shift);
- else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
- MoveEnd(shift);
- else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
- Delete();
- else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
- Backspace();
- else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
- mOverwrite ^= true;
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
- Copy();
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
- Copy();
- else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
- Paste();
- else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
- Paste();
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
- Cut();
- else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
- Cut();
- else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A)))
- SelectAll();
- else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
- EnterCharacter('\n', false);
- else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab)))
- EnterCharacter('\t', shift);
- if (!IsReadOnly() && !io.InputQueueCharacters.empty())
- {
- for (int i = 0; i < io.InputQueueCharacters.Size; i++)
- {
- auto c = io.InputQueueCharacters[i];
- if (c != 0 && (c == '\n' || c >= 32))
- EnterCharacter(c, shift);
- }
- io.InputQueueCharacters.resize(0);
- }
- }
- }
- void TextEditor::HandleMouseInputs()
- {
- ImGuiIO& io = ImGui::GetIO();
- auto shift = io.KeyShift;
- auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
- auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
- if (ImGui::IsWindowHovered())
- {
- if (!shift && !alt)
- {
- auto click = ImGui::IsMouseClicked(0);
- auto doubleClick = ImGui::IsMouseDoubleClicked(0);
- auto t = ImGui::GetTime();
- auto tripleClick = click && !doubleClick && (mLastClick != -1.0f && (t - mLastClick) < io.MouseDoubleClickTime);
- /*
- Left mouse button triple click
- */
- if (tripleClick)
- {
- if (!ctrl)
- {
- mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos());
- mSelectionMode = SelectionMode::Line;
- SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
- }
- mLastClick = -1.0f;
- }
- /*
- Left mouse button double click
- */
- else if (doubleClick)
- {
- if (!ctrl)
- {
- mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos());
- if (mSelectionMode == SelectionMode::Line)
- mSelectionMode = SelectionMode::Normal;
- else
- mSelectionMode = SelectionMode::Word;
- SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
- }
- mLastClick = (float)ImGui::GetTime();
- }
- /*
- Left mouse button click
- */
- else if (click)
- {
- mState.mCursorPosition = mInteractiveStart = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos());
- if (ctrl)
- mSelectionMode = SelectionMode::Word;
- else
- mSelectionMode = SelectionMode::Normal;
- SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
- mLastClick = (float)ImGui::GetTime();
- }
- // Mouse left button dragging (=> update selection)
- else if (ImGui::IsMouseDragging(0) && ImGui::IsMouseDown(0))
- {
- io.WantCaptureMouse = true;
- mState.mCursorPosition = mInteractiveEnd = ScreenPosToCoordinates(ImGui::GetMousePos());
- SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
- }
- }
- }
- }
- void TextEditor::Render()
- {
- /* Compute mCharAdvance regarding to scaled font size (Ctrl + mouse wheel)*/
- const float fontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x;
- mCharAdvance = ImVec2(fontSize, ImGui::GetTextLineHeightWithSpacing() * mLineSpacing);
- /* Update palette with the current alpha from style */
- for (int i = 0; i < (int)PaletteIndex::Max; ++i)
- {
- auto color = ImGui::ColorConvertU32ToFloat4(mPaletteBase[i]);
- color.w *= ImGui::GetStyle().Alpha;
- mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
- }
- assert(mLineBuffer.empty());
- auto contentSize = ImGui::GetWindowContentRegionMax();
- auto drawList = ImGui::GetWindowDrawList();
- float longest(mTextStart);
- if (mScrollToTop)
- {
- mScrollToTop = false;
- ImGui::SetScrollY(0.f);
- }
- ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
- auto scrollX = ImGui::GetScrollX();
- auto scrollY = ImGui::GetScrollY();
- auto lineNo = (int)floor(scrollY / mCharAdvance.y);
- auto globalLineMax = (int)mLines.size();
- auto lineMax = std::max(0, std::min((int)mLines.size() - 1, lineNo + (int)floor((scrollY + contentSize.y) / mCharAdvance.y)));
- // Deduce mTextStart by evaluating mLines size (global lineMax) plus two spaces as text width
- char buf[16];
- snprintf(buf, 16, " %d ", globalLineMax);
- mTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x + mLeftMargin;
- if (!mLines.empty())
- {
- float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x;
- while (lineNo <= lineMax)
- {
- ImVec2 lineStartScreenPos = ImVec2(cursorScreenPos.x, cursorScreenPos.y + lineNo * mCharAdvance.y);
- ImVec2 textScreenPos = ImVec2(lineStartScreenPos.x + mTextStart, lineStartScreenPos.y);
- auto& line = mLines[lineNo];
- longest = std::max(mTextStart + TextDistanceToLineStart(Coordinates(lineNo, GetLineMaxColumn(lineNo))), longest);
- auto columnNo = 0;
- Coordinates lineStartCoord(lineNo, 0);
- Coordinates lineEndCoord(lineNo, GetLineMaxColumn(lineNo));
- // Draw selection for the current line
- float sstart = -1.0f;
- float ssend = -1.0f;
- assert(mState.mSelectionStart <= mState.mSelectionEnd);
- if (mState.mSelectionStart <= lineEndCoord)
- sstart = mState.mSelectionStart > lineStartCoord ? TextDistanceToLineStart(mState.mSelectionStart) : 0.0f;
- if (mState.mSelectionEnd > lineStartCoord)
- ssend = TextDistanceToLineStart(mState.mSelectionEnd < lineEndCoord ? mState.mSelectionEnd : lineEndCoord);
- if (mState.mSelectionEnd.mLine > lineNo)
- ssend += mCharAdvance.x;
- if (sstart != -1 && ssend != -1 && sstart < ssend)
- {
- ImVec2 vstart(lineStartScreenPos.x + mTextStart + sstart, lineStartScreenPos.y);
- ImVec2 vend(lineStartScreenPos.x + mTextStart + ssend, lineStartScreenPos.y + mCharAdvance.y);
- drawList->AddRectFilled(vstart, vend, mPalette[(int)PaletteIndex::Selection]);
- }
- // Draw breakpoints
- auto start = ImVec2(lineStartScreenPos.x + scrollX, lineStartScreenPos.y);
- if (mBreakpoints.count(lineNo + 1) != 0)
- {
- auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y);
- drawList->AddRectFilled(start, end, mPalette[(int)PaletteIndex::Breakpoint]);
- }
- // Draw error markers
- auto errorIt = mErrorMarkers.find(lineNo + 1);
- if (errorIt != mErrorMarkers.end())
- {
- auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX, lineStartScreenPos.y + mCharAdvance.y);
- drawList->AddRectFilled(start, end, mPalette[(int)PaletteIndex::ErrorMarker]);
- if (ImGui::IsMouseHoveringRect(lineStartScreenPos, end))
- {
- ImGui::BeginTooltip();
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.2f, 0.2f, 1.0f));
- ImGui::Text("Error at line %d:", errorIt->first);
- ImGui::PopStyleColor();
- ImGui::Separator();
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.2f, 1.0f));
- ImGui::Text("%s", errorIt->second.c_str());
- ImGui::PopStyleColor();
- ImGui::EndTooltip();
- }
- }
- // Draw line number (right aligned)
- snprintf(buf, 16, "%d ", lineNo + 1);
- auto lineNoWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x;
- drawList->AddText(ImVec2(lineStartScreenPos.x + mTextStart - lineNoWidth, lineStartScreenPos.y), mPalette[(int)PaletteIndex::LineNumber], buf);
- if (mState.mCursorPosition.mLine == lineNo)
- {
- auto focused = ImGui::IsWindowFocused();
- // Highlight the current line (where the cursor is)
- if (!HasSelection())
- {
- auto end = ImVec2(start.x + contentSize.x + scrollX, start.y + mCharAdvance.y);
- drawList->AddRectFilled(start, end, mPalette[(int)(focused ? PaletteIndex::CurrentLineFill : PaletteIndex::CurrentLineFillInactive)]);
- drawList->AddRect(start, end, mPalette[(int)PaletteIndex::CurrentLineEdge], 1.0f);
- }
- // Render the cursor
- if (focused)
- {
- auto timeEnd = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
- auto elapsed = timeEnd - mStartTime;
- if (elapsed > 400)
- {
- float width = 1.0f;
- auto cindex = GetCharacterIndex(mState.mCursorPosition);
- float cx = TextDistanceToLineStart(mState.mCursorPosition);
- if (mOverwrite && cindex < (int)line.size())
- {
- auto c = line[cindex].mChar;
- if (c == '\t')
- {
- auto x = (1.0f + std::floor((1.0f + cx) / (float(mTabSize) * spaceSize))) * (float(mTabSize) * spaceSize);
- width = x - cx;
- }
- else
- {
- char buf2[2];
- buf2[0] = line[cindex].mChar;
- buf2[1] = '\0';
- width = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf2).x;
- }
- }
- ImVec2 cstart(textScreenPos.x + cx, lineStartScreenPos.y);
- ImVec2 cend(textScreenPos.x + cx + width, lineStartScreenPos.y + mCharAdvance.y);
- drawList->AddRectFilled(cstart, cend, mPalette[(int)PaletteIndex::Cursor]);
- if (elapsed > 800)
- mStartTime = timeEnd;
- }
- }
- }
- // Render colorized text
- auto prevColor = line.empty() ? mPalette[(int)PaletteIndex::Default] : GetGlyphColor(line[0]);
- ImVec2 bufferOffset;
- for (int i = 0; i < line.size();)
- {
- auto& glyph = line[i];
- auto color = GetGlyphColor(glyph);
- if ((color != prevColor || glyph.mChar == '\t' || glyph.mChar == ' ') && !mLineBuffer.empty())
- {
- const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
- drawList->AddText(newOffset, prevColor, mLineBuffer.c_str());
- auto textSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, mLineBuffer.c_str(), nullptr, nullptr);
- bufferOffset.x += textSize.x;
- mLineBuffer.clear();
- }
- prevColor = color;
- if (glyph.mChar == '\t')
- {
- auto oldX = bufferOffset.x;
- bufferOffset.x = (1.0f + std::floor((1.0f + bufferOffset.x) / (float(mTabSize) * spaceSize))) * (float(mTabSize) * spaceSize);
- ++i;
- if (mShowWhitespaces)
- {
- const auto s = ImGui::GetFontSize();
- const auto x1 = textScreenPos.x + oldX + 1.0f;
- const auto x2 = textScreenPos.x + bufferOffset.x - 1.0f;
- const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f;
- const ImVec2 p1(x1, y);
- const ImVec2 p2(x2, y);
- const ImVec2 p3(x2 - s * 0.2f, y - s * 0.2f);
- const ImVec2 p4(x2 - s * 0.2f, y + s * 0.2f);
- drawList->AddLine(p1, p2, 0x90909090);
- drawList->AddLine(p2, p3, 0x90909090);
- drawList->AddLine(p2, p4, 0x90909090);
- }
- }
- else if (glyph.mChar == ' ')
- {
- if (mShowWhitespaces)
- {
- const auto s = ImGui::GetFontSize();
- const auto x = textScreenPos.x + bufferOffset.x + spaceSize * 0.5f;
- const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f;
- drawList->AddCircleFilled(ImVec2(x, y), 1.5f, 0x80808080, 4);
- }
- bufferOffset.x += spaceSize;
- i++;
- }
- else
- {
- auto l = UTF8CharLength(glyph.mChar);
- while (l-- > 0)
- mLineBuffer.push_back(line[i++].mChar);
- }
- ++columnNo;
- }
- if (!mLineBuffer.empty())
- {
- const ImVec2 newOffset(textScreenPos.x + bufferOffset.x, textScreenPos.y + bufferOffset.y);
- drawList->AddText(newOffset, prevColor, mLineBuffer.c_str());
- mLineBuffer.clear();
- }
- ++lineNo;
- }
- // Draw a tooltip on known identifiers/preprocessor symbols
- if (ImGui::IsMousePosValid())
- {
- auto id = GetWordAt(ScreenPosToCoordinates(ImGui::GetMousePos()));
- if (!id.empty())
- {
- auto it = mLanguageDefinition.mIdentifiers.find(id);
- if (it != mLanguageDefinition.mIdentifiers.end())
- {
- ImGui::BeginTooltip();
- ImGui::TextUnformatted(it->second.mDeclaration.c_str());
- ImGui::EndTooltip();
- }
- else
- {
- auto pi = mLanguageDefinition.mPreprocIdentifiers.find(id);
- if (pi != mLanguageDefinition.mPreprocIdentifiers.end())
- {
- ImGui::BeginTooltip();
- ImGui::TextUnformatted(pi->second.mDeclaration.c_str());
- ImGui::EndTooltip();
- }
- }
- }
- }
- }
- ImGui::Dummy(ImVec2((longest + 2), mLines.size() * mCharAdvance.y));
- if (mScrollToCursor)
- {
- EnsureCursorVisible();
- ImGui::SetWindowFocus();
- mScrollToCursor = false;
- }
- }
- void TextEditor::Render(const char* aTitle, const ImVec2& aSize, bool aBorder)
- {
- mWithinRender = true;
- mTextChanged = false;
- mCursorPositionChanged = false;
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::ColorConvertU32ToFloat4(mPalette[(int)PaletteIndex::Background]));
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
- if (!mIgnoreImGuiChild)
- ImGui::BeginChild(aTitle, aSize, aBorder, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NoMove);
- if (mHandleKeyboardInputs)
- {
- HandleKeyboardInputs();
- ImGui::PushAllowKeyboardFocus(true);
- }
- if (mHandleMouseInputs)
- HandleMouseInputs();
- ColorizeInternal();
- Render();
- if (mHandleKeyboardInputs)
- ImGui::PopAllowKeyboardFocus();
- if (!mIgnoreImGuiChild)
- ImGui::EndChild();
- ImGui::PopStyleVar();
- ImGui::PopStyleColor();
- mWithinRender = false;
- }
- void TextEditor::SetText(const std::string & aText)
- {
- mLines.clear();
- mLines.emplace_back(Line());
- for (auto chr : aText)
- {
- if (chr == '\r')
- {
- // ignore the carriage return character
- }
- else if (chr == '\n')
- mLines.emplace_back(Line());
- else
- {
- mLines.back().emplace_back(Glyph(chr, PaletteIndex::Default));
- }
- }
- mTextChanged = true;
- mScrollToTop = true;
- mUndoBuffer.clear();
- mUndoIndex = 0;
- Colorize();
- }
- void TextEditor::SetTextLines(const std::vector<std::string> & aLines)
- {
- mLines.clear();
- if (aLines.empty())
- {
- mLines.emplace_back(Line());
- }
- else
- {
- mLines.resize(aLines.size());
- for (size_t i = 0; i < aLines.size(); ++i)
- {
- const std::string & aLine = aLines[i];
- mLines[i].reserve(aLine.size());
- for (size_t j = 0; j < aLine.size(); ++j)
- mLines[i].emplace_back(Glyph(aLine[j], PaletteIndex::Default));
- }
- }
- mTextChanged = true;
- mScrollToTop = true;
- mUndoBuffer.clear();
- mUndoIndex = 0;
- Colorize();
- }
- void TextEditor::EnterCharacter(ImWchar aChar, bool aShift)
- {
- assert(!mReadOnly);
- UndoRecord u;
- u.mBefore = mState;
- if (HasSelection())
- {
- if (aChar == '\t' && mState.mSelectionStart.mLine != mState.mSelectionEnd.mLine)
- {
- auto start = mState.mSelectionStart;
- auto end = mState.mSelectionEnd;
- auto originalEnd = end;
- if (start > end)
- std::swap(start, end);
- start.mColumn = 0;
- // end.mColumn = end.mLine < mLines.size() ? mLines[end.mLine].size() : 0;
- if (end.mColumn == 0 && end.mLine > 0)
- --end.mLine;
- if (end.mLine >= (int)mLines.size())
- end.mLine = mLines.empty() ? 0 : (int)mLines.size() - 1;
- end.mColumn = GetLineMaxColumn(end.mLine);
- //if (end.mColumn >= GetLineMaxColumn(end.mLine))
- // end.mColumn = GetLineMaxColumn(end.mLine) - 1;
- u.mRemovedStart = start;
- u.mRemovedEnd = end;
- u.mRemoved = GetText(start, end);
- bool modified = false;
- for (int i = start.mLine; i <= end.mLine; i++)
- {
- auto& line = mLines[i];
- if (aShift)
- {
- if (!line.empty())
- {
- if (line.front().mChar == '\t')
- {
- line.erase(line.begin());
- modified = true;
- }
- else
- {
- for (int j = 0; j < mTabSize && !line.empty() && line.front().mChar == ' '; j++)
- {
- line.erase(line.begin());
- modified = true;
- }
- }
- }
- }
- else
- {
- line.insert(line.begin(), Glyph('\t', TextEditor::PaletteIndex::Background));
- modified = true;
- }
- }
- if (modified)
- {
- start = Coordinates(start.mLine, GetCharacterColumn(start.mLine, 0));
- Coordinates rangeEnd;
- if (originalEnd.mColumn != 0)
- {
- end = Coordinates(end.mLine, GetLineMaxColumn(end.mLine));
- rangeEnd = end;
- u.mAdded = GetText(start, end);
- }
- else
- {
- end = Coordinates(originalEnd.mLine, 0);
- rangeEnd = Coordinates(end.mLine - 1, GetLineMaxColumn(end.mLine - 1));
- u.mAdded = GetText(start, rangeEnd);
- }
- u.mAddedStart = start;
- u.mAddedEnd = rangeEnd;
- u.mAfter = mState;
- mState.mSelectionStart = start;
- mState.mSelectionEnd = end;
- AddUndo(u);
- mTextChanged = true;
- EnsureCursorVisible();
- }
- return;
- } // c == '\t'
- else
- {
- u.mRemoved = GetSelectedText();
- u.mRemovedStart = mState.mSelectionStart;
- u.mRemovedEnd = mState.mSelectionEnd;
- DeleteSelection();
- }
- } // HasSelection
- auto coord = GetActualCursorCoordinates();
- u.mAddedStart = coord;
- assert(!mLines.empty());
- if (aChar == '\n')
- {
- InsertLine(coord.mLine + 1);
- auto& line = mLines[coord.mLine];
- auto& newLine = mLines[coord.mLine + 1];
- if (mLanguageDefinition.mAutoIndentation)
- for (size_t it = 0; it < line.size() && isascii(line[it].mChar) && isblank(line[it].mChar); ++it)
- newLine.push_back(line[it]);
- const size_t whitespaceSize = newLine.size();
- auto cindex = GetCharacterIndex(coord);
- newLine.insert(newLine.end(), line.begin() + cindex, line.end());
- line.erase(line.begin() + cindex, line.begin() + line.size());
- SetCursorPosition(Coordinates(coord.mLine + 1, GetCharacterColumn(coord.mLine + 1, (int)whitespaceSize)));
- u.mAdded = (char)aChar;
- }
- else
- {
- char buf[7];
- int e = ImTextCharToUtf8(buf, 7, aChar);
- if (e > 0)
- {
- buf[e] = '\0';
- auto& line = mLines[coord.mLine];
- auto cindex = GetCharacterIndex(coord);
- if (mOverwrite && cindex < (int)line.size())
- {
- auto d = UTF8CharLength(line[cindex].mChar);
- u.mRemovedStart = mState.mCursorPosition;
- u.mRemovedEnd = Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex + d));
- while (d-- > 0 && cindex < (int)line.size())
- {
- u.mRemoved += line[cindex].mChar;
- line.erase(line.begin() + cindex);
- }
- }
- for (auto p = buf; *p != '\0'; p++, ++cindex)
- line.insert(line.begin() + cindex, Glyph(*p, PaletteIndex::Default));
- u.mAdded = buf;
- SetCursorPosition(Coordinates(coord.mLine, GetCharacterColumn(coord.mLine, cindex)));
- }
- else
- return;
- }
- mTextChanged = true;
- u.mAddedEnd = GetActualCursorCoordinates();
- u.mAfter = mState;
- AddUndo(u);
- Colorize(coord.mLine - 1, 3);
- EnsureCursorVisible();
- }
- void TextEditor::SetReadOnly(bool aValue)
- {
- mReadOnly = aValue;
- }
- void TextEditor::SetColorizerEnable(bool aValue)
- {
- mColorizerEnabled = aValue;
- }
- void TextEditor::SetCursorPosition(const Coordinates & aPosition)
- {
- if (mState.mCursorPosition != aPosition)
- {
- mState.mCursorPosition = aPosition;
- mCursorPositionChanged = true;
- EnsureCursorVisible();
- }
- }
- void TextEditor::SetSelectionStart(const Coordinates & aPosition)
- {
- mState.mSelectionStart = SanitizeCoordinates(aPosition);
- if (mState.mSelectionStart > mState.mSelectionEnd)
- std::swap(mState.mSelectionStart, mState.mSelectionEnd);
- }
- void TextEditor::SetSelectionEnd(const Coordinates & aPosition)
- {
- mState.mSelectionEnd = SanitizeCoordinates(aPosition);
- if (mState.mSelectionStart > mState.mSelectionEnd)
- std::swap(mState.mSelectionStart, mState.mSelectionEnd);
- }
- void TextEditor::SetSelection(const Coordinates & aStart, const Coordinates & aEnd, SelectionMode aMode)
- {
- auto oldSelStart = mState.mSelectionStart;
- auto oldSelEnd = mState.mSelectionEnd;
- mState.mSelectionStart = SanitizeCoordinates(aStart);
- mState.mSelectionEnd = SanitizeCoordinates(aEnd);
- if (mState.mSelectionStart > mState.mSelectionEnd)
- std::swap(mState.mSelectionStart, mState.mSelectionEnd);
- switch (aMode)
- {
- case TextEditor::SelectionMode::Normal:
- break;
- case TextEditor::SelectionMode::Word:
- {
- mState.mSelectionStart = FindWordStart(mState.mSelectionStart);
- if (!IsOnWordBoundary(mState.mSelectionEnd))
- mState.mSelectionEnd = FindWordEnd(FindWordStart(mState.mSelectionEnd));
- break;
- }
- case TextEditor::SelectionMode::Line:
- {
- const auto lineNo = mState.mSelectionEnd.mLine;
- const auto lineSize = (size_t)lineNo < mLines.size() ? mLines[lineNo].size() : 0;
- mState.mSelectionStart = Coordinates(mState.mSelectionStart.mLine, 0);
- mState.mSelectionEnd = Coordinates(lineNo, GetLineMaxColumn(lineNo));
- break;
- }
- default:
- break;
- }
- if (mState.mSelectionStart != oldSelStart ||
- mState.mSelectionEnd != oldSelEnd)
- mCursorPositionChanged = true;
- }
- void TextEditor::SetTabSize(int aValue)
- {
- mTabSize = std::max(0, std::min(32, aValue));
- }
- void TextEditor::InsertText(const std::string & aValue)
- {
- InsertText(aValue.c_str());
- }
- void TextEditor::InsertText(const char * aValue)
- {
- if (aValue == nullptr)
- return;
- auto pos = GetActualCursorCoordinates();
- auto start = std::min(pos, mState.mSelectionStart);
- int totalLines = pos.mLine - start.mLine;
- totalLines += InsertTextAt(pos, aValue);
- SetSelection(pos, pos);
- SetCursorPosition(pos);
- Colorize(start.mLine - 1, totalLines + 2);
- }
- void TextEditor::DeleteSelection()
- {
- assert(mState.mSelectionEnd >= mState.mSelectionStart);
- if (mState.mSelectionEnd == mState.mSelectionStart)
- return;
- DeleteRange(mState.mSelectionStart, mState.mSelectionEnd);
- SetSelection(mState.mSelectionStart, mState.mSelectionStart);
- SetCursorPosition(mState.mSelectionStart);
- Colorize(mState.mSelectionStart.mLine, 1);
- }
- void TextEditor::MoveUp(int aAmount, bool aSelect)
- {
- auto oldPos = mState.mCursorPosition;
- mState.mCursorPosition.mLine = std::max(0, mState.mCursorPosition.mLine - aAmount);
- if (oldPos != mState.mCursorPosition)
- {
- if (aSelect)
- {
- if (oldPos == mInteractiveStart)
- mInteractiveStart = mState.mCursorPosition;
- else if (oldPos == mInteractiveEnd)
- mInteractiveEnd = mState.mCursorPosition;
- else
- {
- mInteractiveStart = mState.mCursorPosition;
- mInteractiveEnd = oldPos;
- }
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd);
- EnsureCursorVisible();
- }
- }
- void TextEditor::MoveDown(int aAmount, bool aSelect)
- {
- assert(mState.mCursorPosition.mColumn >= 0);
- auto oldPos = mState.mCursorPosition;
- mState.mCursorPosition.mLine = std::max(0, std::min((int)mLines.size() - 1, mState.mCursorPosition.mLine + aAmount));
- if (mState.mCursorPosition != oldPos)
- {
- if (aSelect)
- {
- if (oldPos == mInteractiveEnd)
- mInteractiveEnd = mState.mCursorPosition;
- else if (oldPos == mInteractiveStart)
- mInteractiveStart = mState.mCursorPosition;
- else
- {
- mInteractiveStart = oldPos;
- mInteractiveEnd = mState.mCursorPosition;
- }
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd);
- EnsureCursorVisible();
- }
- }
- static bool IsUTFSequence(char c)
- {
- return (c & 0xC0) == 0x80;
- }
- void TextEditor::MoveLeft(int aAmount, bool aSelect, bool aWordMode)
- {
- if (mLines.empty())
- return;
- auto oldPos = mState.mCursorPosition;
- mState.mCursorPosition = GetActualCursorCoordinates();
- auto line = mState.mCursorPosition.mLine;
- auto cindex = GetCharacterIndex(mState.mCursorPosition);
- while (aAmount-- > 0)
- {
- if (cindex == 0)
- {
- if (line > 0)
- {
- --line;
- if ((int)mLines.size() > line)
- cindex = (int)mLines[line].size();
- else
- cindex = 0;
- }
- }
- else
- {
- --cindex;
- if (cindex > 0)
- {
- if ((int)mLines.size() > line)
- {
- while (cindex > 0 && IsUTFSequence(mLines[line][cindex].mChar))
- --cindex;
- }
- }
- }
- mState.mCursorPosition = Coordinates(line, GetCharacterColumn(line, cindex));
- if (aWordMode)
- {
- mState.mCursorPosition = FindWordStart(mState.mCursorPosition);
- cindex = GetCharacterIndex(mState.mCursorPosition);
- }
- }
- mState.mCursorPosition = Coordinates(line, GetCharacterColumn(line, cindex));
- assert(mState.mCursorPosition.mColumn >= 0);
- if (aSelect)
- {
- if (oldPos == mInteractiveStart)
- mInteractiveStart = mState.mCursorPosition;
- else if (oldPos == mInteractiveEnd)
- mInteractiveEnd = mState.mCursorPosition;
- else
- {
- mInteractiveStart = mState.mCursorPosition;
- mInteractiveEnd = oldPos;
- }
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd, aSelect && aWordMode ? SelectionMode::Word : SelectionMode::Normal);
- EnsureCursorVisible();
- }
- void TextEditor::MoveRight(int aAmount, bool aSelect, bool aWordMode)
- {
- auto oldPos = mState.mCursorPosition;
- if (mLines.empty() || oldPos.mLine >= mLines.size())
- return;
- auto cindex = GetCharacterIndex(mState.mCursorPosition);
- while (aAmount-- > 0)
- {
- auto lindex = mState.mCursorPosition.mLine;
- auto& line = mLines[lindex];
- if (cindex >= line.size())
- {
- if (mState.mCursorPosition.mLine < mLines.size() - 1)
- {
- mState.mCursorPosition.mLine = std::max(0, std::min((int)mLines.size() - 1, mState.mCursorPosition.mLine + 1));
- mState.mCursorPosition.mColumn = 0;
- }
- else
- return;
- }
- else
- {
- cindex += UTF8CharLength(line[cindex].mChar);
- mState.mCursorPosition = Coordinates(lindex, GetCharacterColumn(lindex, cindex));
- if (aWordMode)
- mState.mCursorPosition = FindNextWord(mState.mCursorPosition);
- }
- }
- if (aSelect)
- {
- if (oldPos == mInteractiveEnd)
- mInteractiveEnd = SanitizeCoordinates(mState.mCursorPosition);
- else if (oldPos == mInteractiveStart)
- mInteractiveStart = mState.mCursorPosition;
- else
- {
- mInteractiveStart = oldPos;
- mInteractiveEnd = mState.mCursorPosition;
- }
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd, aSelect && aWordMode ? SelectionMode::Word : SelectionMode::Normal);
- EnsureCursorVisible();
- }
- void TextEditor::MoveTop(bool aSelect)
- {
- auto oldPos = mState.mCursorPosition;
- SetCursorPosition(Coordinates(0, 0));
- if (mState.mCursorPosition != oldPos)
- {
- if (aSelect)
- {
- mInteractiveEnd = oldPos;
- mInteractiveStart = mState.mCursorPosition;
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd);
- }
- }
- void TextEditor::TextEditor::MoveBottom(bool aSelect)
- {
- auto oldPos = GetCursorPosition();
- auto newPos = Coordinates((int)mLines.size() - 1, 0);
- SetCursorPosition(newPos);
- if (aSelect)
- {
- mInteractiveStart = oldPos;
- mInteractiveEnd = newPos;
- }
- else
- mInteractiveStart = mInteractiveEnd = newPos;
- SetSelection(mInteractiveStart, mInteractiveEnd);
- }
- void TextEditor::MoveHome(bool aSelect)
- {
- auto oldPos = mState.mCursorPosition;
- SetCursorPosition(Coordinates(mState.mCursorPosition.mLine, 0));
- if (mState.mCursorPosition != oldPos)
- {
- if (aSelect)
- {
- if (oldPos == mInteractiveStart)
- mInteractiveStart = mState.mCursorPosition;
- else if (oldPos == mInteractiveEnd)
- mInteractiveEnd = mState.mCursorPosition;
- else
- {
- mInteractiveStart = mState.mCursorPosition;
- mInteractiveEnd = oldPos;
- }
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd);
- }
- }
- void TextEditor::MoveEnd(bool aSelect)
- {
- auto oldPos = mState.mCursorPosition;
- SetCursorPosition(Coordinates(mState.mCursorPosition.mLine, GetLineMaxColumn(oldPos.mLine)));
- if (mState.mCursorPosition != oldPos)
- {
- if (aSelect)
- {
- if (oldPos == mInteractiveEnd)
- mInteractiveEnd = mState.mCursorPosition;
- else if (oldPos == mInteractiveStart)
- mInteractiveStart = mState.mCursorPosition;
- else
- {
- mInteractiveStart = oldPos;
- mInteractiveEnd = mState.mCursorPosition;
- }
- }
- else
- mInteractiveStart = mInteractiveEnd = mState.mCursorPosition;
- SetSelection(mInteractiveStart, mInteractiveEnd);
- }
- }
- void TextEditor::Delete()
- {
- assert(!mReadOnly);
- if (mLines.empty())
- return;
- UndoRecord u;
- u.mBefore = mState;
- if (HasSelection())
- {
- u.mRemoved = GetSelectedText();
- u.mRemovedStart = mState.mSelectionStart;
- u.mRemovedEnd = mState.mSelectionEnd;
- DeleteSelection();
- }
- else
- {
- auto pos = GetActualCursorCoordinates();
- SetCursorPosition(pos);
- auto& line = mLines[pos.mLine];
- if (pos.mColumn == GetLineMaxColumn(pos.mLine))
- {
- if (pos.mLine == (int)mLines.size() - 1)
- return;
- u.mRemoved = '\n';
- u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates();
- Advance(u.mRemovedEnd);
- auto& nextLine = mLines[pos.mLine + 1];
- line.insert(line.end(), nextLine.begin(), nextLine.end());
- RemoveLine(pos.mLine + 1);
- }
- else
- {
- auto cindex = GetCharacterIndex(pos);
- u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates();
- u.mRemovedEnd.mColumn++;
- u.mRemoved = GetText(u.mRemovedStart, u.mRemovedEnd);
- auto d = UTF8CharLength(line[cindex].mChar);
- while (d-- > 0 && cindex < (int)line.size())
- line.erase(line.begin() + cindex);
- }
- mTextChanged = true;
- Colorize(pos.mLine, 1);
- }
- u.mAfter = mState;
- AddUndo(u);
- }
- void TextEditor::Backspace()
- {
- assert(!mReadOnly);
- if (mLines.empty())
- return;
- UndoRecord u;
- u.mBefore = mState;
- if (HasSelection())
- {
- u.mRemoved = GetSelectedText();
- u.mRemovedStart = mState.mSelectionStart;
- u.mRemovedEnd = mState.mSelectionEnd;
- DeleteSelection();
- }
- else
- {
- auto pos = GetActualCursorCoordinates();
- SetCursorPosition(pos);
- if (mState.mCursorPosition.mColumn == 0)
- {
- if (mState.mCursorPosition.mLine == 0)
- return;
- u.mRemoved = '\n';
- u.mRemovedStart = u.mRemovedEnd = Coordinates(pos.mLine - 1, GetLineMaxColumn(pos.mLine - 1));
- Advance(u.mRemovedEnd);
- auto& line = mLines[mState.mCursorPosition.mLine];
- auto& prevLine = mLines[mState.mCursorPosition.mLine - 1];
- auto prevSize = GetLineMaxColumn(mState.mCursorPosition.mLine - 1);
- prevLine.insert(prevLine.end(), line.begin(), line.end());
- ErrorMarkers etmp;
- for (auto& i : mErrorMarkers)
- etmp.insert(ErrorMarkers::value_type(i.first - 1 == mState.mCursorPosition.mLine ? i.first - 1 : i.first, i.second));
- mErrorMarkers = std::move(etmp);
- RemoveLine(mState.mCursorPosition.mLine);
- --mState.mCursorPosition.mLine;
- mState.mCursorPosition.mColumn = prevSize;
- }
- else
- {
- auto& line = mLines[mState.mCursorPosition.mLine];
- auto cindex = GetCharacterIndex(pos) - 1;
- auto cend = cindex + 1;
- while (cindex > 0 && IsUTFSequence(line[cindex].mChar))
- --cindex;
- //if (cindex > 0 && UTF8CharLength(line[cindex].mChar) > 1)
- // --cindex;
- u.mRemovedStart = u.mRemovedEnd = GetActualCursorCoordinates();
- --u.mRemovedStart.mColumn;
- --mState.mCursorPosition.mColumn;
- while (cindex < line.size() && cend-- > cindex)
- {
- u.mRemoved += line[cindex].mChar;
- line.erase(line.begin() + cindex);
- }
- }
- mTextChanged = true;
- EnsureCursorVisible();
- Colorize(mState.mCursorPosition.mLine, 1);
- }
- u.mAfter = mState;
- AddUndo(u);
- }
- void TextEditor::SelectWordUnderCursor()
- {
- auto c = GetCursorPosition();
- SetSelection(FindWordStart(c), FindWordEnd(c));
- }
- void TextEditor::SelectAll()
- {
- SetSelection(Coordinates(0, 0), Coordinates((int)mLines.size(), 0));
- }
- bool TextEditor::HasSelection() const
- {
- return mState.mSelectionEnd > mState.mSelectionStart;
- }
- void TextEditor::Copy()
- {
- if (HasSelection())
- {
- ImGui::SetClipboardText(GetSelectedText().c_str());
- }
- else
- {
- if (!mLines.empty())
- {
- std::string str;
- auto& line = mLines[GetActualCursorCoordinates().mLine];
- for (auto& g : line)
- str.push_back(g.mChar);
- ImGui::SetClipboardText(str.c_str());
- }
- }
- }
- void TextEditor::Cut()
- {
- if (IsReadOnly())
- {
- Copy();
- }
- else
- {
- if (HasSelection())
- {
- UndoRecord u;
- u.mBefore = mState;
- u.mRemoved = GetSelectedText();
- u.mRemovedStart = mState.mSelectionStart;
- u.mRemovedEnd = mState.mSelectionEnd;
- Copy();
- DeleteSelection();
- u.mAfter = mState;
- AddUndo(u);
- }
- }
- }
- void TextEditor::Paste()
- {
- if (IsReadOnly())
- return;
- auto clipText = ImGui::GetClipboardText();
- if (clipText != nullptr && strlen(clipText) > 0)
- {
- UndoRecord u;
- u.mBefore = mState;
- if (HasSelection())
- {
- u.mRemoved = GetSelectedText();
- u.mRemovedStart = mState.mSelectionStart;
- u.mRemovedEnd = mState.mSelectionEnd;
- DeleteSelection();
- }
- u.mAdded = clipText;
- u.mAddedStart = GetActualCursorCoordinates();
- InsertText(clipText);
- u.mAddedEnd = GetActualCursorCoordinates();
- u.mAfter = mState;
- AddUndo(u);
- }
- }
- bool TextEditor::CanUndo() const
- {
- return !mReadOnly && mUndoIndex > 0;
- }
- bool TextEditor::CanRedo() const
- {
- return !mReadOnly && mUndoIndex < (int)mUndoBuffer.size();
- }
- void TextEditor::Undo(int aSteps)
- {
- while (CanUndo() && aSteps-- > 0)
- mUndoBuffer[--mUndoIndex].Undo(this);
- }
- void TextEditor::Redo(int aSteps)
- {
- while (CanRedo() && aSteps-- > 0)
- mUndoBuffer[mUndoIndex++].Redo(this);
- }
- const TextEditor::Palette & TextEditor::GetDarkPalette()
- {
- const static Palette p = { {
- 0xff7f7f7f, // Default
- 0xffd69c56, // Keyword
- 0xff00ff00, // Number
- 0xff7070e0, // String
- 0xff70a0e0, // Char literal
- 0xffffffff, // Punctuation
- 0xff408080, // Preprocessor
- 0xffaaaaaa, // Identifier
- 0xff9bc64d, // Known identifier
- 0xffc040a0, // Preproc identifier
- 0xff206020, // Comment (single line)
- 0xff406020, // Comment (multi line)
- 0xff101010, // Background
- 0xffe0e0e0, // Cursor
- 0x80a06020, // Selection
- 0x800020ff, // ErrorMarker
- 0x40f08000, // Breakpoint
- 0xff707000, // Line number
- 0x40000000, // Current line fill
- 0x40808080, // Current line fill (inactive)
- 0x40a0a0a0, // Current line edge
- } };
- return p;
- }
- const TextEditor::Palette & TextEditor::GetLightPalette()
- {
- const static Palette p = { {
- 0xff7f7f7f, // None
- 0xffff0c06, // Keyword
- 0xff008000, // Number
- 0xff2020a0, // String
- 0xff304070, // Char literal
- 0xff000000, // Punctuation
- 0xff406060, // Preprocessor
- 0xff404040, // Identifier
- 0xff606010, // Known identifier
- 0xffc040a0, // Preproc identifier
- 0xff205020, // Comment (single line)
- 0xff405020, // Comment (multi line)
- 0xffffffff, // Background
- 0xff000000, // Cursor
- 0x80600000, // Selection
- 0xa00010ff, // ErrorMarker
- 0x80f08000, // Breakpoint
- 0xff505000, // Line number
- 0x40000000, // Current line fill
- 0x40808080, // Current line fill (inactive)
- 0x40000000, // Current line edge
- } };
- return p;
- }
- const TextEditor::Palette & TextEditor::GetRetroBluePalette()
- {
- const static Palette p = { {
- 0xff00ffff, // None
- 0xffffff00, // Keyword
- 0xff00ff00, // Number
- 0xff808000, // String
- 0xff808000, // Char literal
- 0xffffffff, // Punctuation
- 0xff008000, // Preprocessor
- 0xff00ffff, // Identifier
- 0xffffffff, // Known identifier
- 0xffff00ff, // Preproc identifier
- 0xff808080, // Comment (single line)
- 0xff404040, // Comment (multi line)
- 0xff800000, // Background
- 0xff0080ff, // Cursor
- 0x80ffff00, // Selection
- 0xa00000ff, // ErrorMarker
- 0x80ff8000, // Breakpoint
- 0xff808000, // Line number
- 0x40000000, // Current line fill
- 0x40808080, // Current line fill (inactive)
- 0x40000000, // Current line edge
- } };
- return p;
- }
- std::string TextEditor::GetText() const
- {
- return GetText(Coordinates(), Coordinates((int)mLines.size(), 0));
- }
- std::vector<std::string> TextEditor::GetTextLines() const
- {
- std::vector<std::string> result;
- result.reserve(mLines.size());
- for (auto & line : mLines)
- {
- std::string text;
- text.resize(line.size());
- for (size_t i = 0; i < line.size(); ++i)
- text[i] = line[i].mChar;
- result.emplace_back(std::move(text));
- }
- return result;
- }
- std::string TextEditor::GetSelectedText() const
- {
- return GetText(mState.mSelectionStart, mState.mSelectionEnd);
- }
- std::string TextEditor::GetCurrentLineText()const
- {
- auto lineLength = GetLineMaxColumn(mState.mCursorPosition.mLine);
- return GetText(
- Coordinates(mState.mCursorPosition.mLine, 0),
- Coordinates(mState.mCursorPosition.mLine, lineLength));
- }
- void TextEditor::ProcessInputs()
- {
- }
- void TextEditor::Colorize(int aFromLine, int aLines)
- {
- int toLine = aLines == -1 ? (int)mLines.size() : std::min((int)mLines.size(), aFromLine + aLines);
- mColorRangeMin = std::min(mColorRangeMin, aFromLine);
- mColorRangeMax = std::max(mColorRangeMax, toLine);
- mColorRangeMin = std::max(0, mColorRangeMin);
- mColorRangeMax = std::max(mColorRangeMin, mColorRangeMax);
- mCheckComments = true;
- }
- void TextEditor::ColorizeRange(int aFromLine, int aToLine)
- {
- if (mLines.empty() || aFromLine >= aToLine)
- return;
- std::string buffer;
- std::cmatch results;
- std::string id;
- int endLine = std::max(0, std::min((int)mLines.size(), aToLine));
- for (int i = aFromLine; i < endLine; ++i)
- {
- auto& line = mLines[i];
- if (line.empty())
- continue;
- buffer.resize(line.size());
- for (size_t j = 0; j < line.size(); ++j)
- {
- auto& col = line[j];
- buffer[j] = col.mChar;
- col.mColorIndex = PaletteIndex::Default;
- }
- const char * bufferBegin = &buffer.front();
- const char * bufferEnd = bufferBegin + buffer.size();
- auto last = bufferEnd;
- for (auto first = bufferBegin; first != last; )
- {
- const char * token_begin = nullptr;
- const char * token_end = nullptr;
- PaletteIndex token_color = PaletteIndex::Default;
- bool hasTokenizeResult = false;
- if (mLanguageDefinition.mTokenize != nullptr)
- {
- if (mLanguageDefinition.mTokenize(first, last, token_begin, token_end, token_color))
- hasTokenizeResult = true;
- }
- if (hasTokenizeResult == false)
- {
- // todo : remove
- //printf("using regex for %.*s\n", first + 10 < last ? 10 : int(last - first), first);
- for (auto& p : mRegexList)
- {
- if (std::regex_search(first, last, results, p.first, std::regex_constants::match_continuous))
- {
- hasTokenizeResult = true;
- auto& v = *results.begin();
- token_begin = v.first;
- token_end = v.second;
- token_color = p.second;
- break;
- }
- }
- }
- if (hasTokenizeResult == false)
- {
- first++;
- }
- else
- {
- const size_t token_length = token_end - token_begin;
- if (token_color == PaletteIndex::Identifier)
- {
- id.assign(token_begin, token_end);
- // todo : allmost all language definitions use lower case to specify keywords, so shouldn't this use ::tolower ?
- if (!mLanguageDefinition.mCaseSensitive)
- std::transform(id.begin(), id.end(), id.begin(), ::toupper);
- if (!line[first - bufferBegin].mPreprocessor)
- {
- if (mLanguageDefinition.mKeywords.count(id) != 0)
- token_color = PaletteIndex::Keyword;
- else if (mLanguageDefinition.mIdentifiers.count(id) != 0)
- token_color = PaletteIndex::KnownIdentifier;
- else if (mLanguageDefinition.mPreprocIdentifiers.count(id) != 0)
- token_color = PaletteIndex::PreprocIdentifier;
- }
- else
- {
- if (mLanguageDefinition.mPreprocIdentifiers.count(id) != 0)
- token_color = PaletteIndex::PreprocIdentifier;
- }
- }
- for (size_t j = 0; j < token_length; ++j)
- line[(token_begin - bufferBegin) + j].mColorIndex = token_color;
- first = token_end;
- }
- }
- }
- }
- void TextEditor::ColorizeInternal()
- {
- if (mLines.empty() || !mColorizerEnabled)
- return;
- if (mCheckComments)
- {
- auto endLine = mLines.size();
- auto endIndex = 0;
- auto commentStartLine = endLine;
- auto commentStartIndex = endIndex;
- auto withinString = false;
- auto withinSingleLineComment = false;
- auto withinPreproc = false;
- auto firstChar = true; // there is no other non-whitespace characters in the line before
- auto concatenate = false; // '\' on the very end of the line
- auto currentLine = 0;
- auto currentIndex = 0;
- while (currentLine < endLine || currentIndex < endIndex)
- {
- auto& line = mLines[currentLine];
- if (currentIndex == 0 && !concatenate)
- {
- withinSingleLineComment = false;
- withinPreproc = false;
- firstChar = true;
- }
- concatenate = false;
- if (!line.empty())
- {
- auto& g = line[currentIndex];
- auto c = g.mChar;
- if (c != mLanguageDefinition.mPreprocChar && !isspace(c))
- firstChar = false;
- if (currentIndex == (int)line.size() - 1 && line[line.size() - 1].mChar == '\\')
- concatenate = true;
- bool inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
- if (withinString)
- {
- line[currentIndex].mMultiLineComment = inComment;
- if (c == '\"')
- {
- if (currentIndex + 1 < (int)line.size() && line[currentIndex + 1].mChar == '\"')
- {
- currentIndex += 1;
- if (currentIndex < (int)line.size())
- line[currentIndex].mMultiLineComment = inComment;
- }
- else
- withinString = false;
- }
- else if (c == '\\')
- {
- currentIndex += 1;
- if (currentIndex < (int)line.size())
- line[currentIndex].mMultiLineComment = inComment;
- }
- }
- else
- {
- if (firstChar && c == mLanguageDefinition.mPreprocChar)
- withinPreproc = true;
- if (c == '\"')
- {
- withinString = true;
- line[currentIndex].mMultiLineComment = inComment;
- }
- else
- {
- auto pred = [](const char& a, const Glyph& b) { return a == b.mChar; };
- auto from = line.begin() + currentIndex;
- auto& startStr = mLanguageDefinition.mCommentStart;
- auto& singleStartStr = mLanguageDefinition.mSingleLineComment;
- if (singleStartStr.size() > 0 &&
- currentIndex + singleStartStr.size() <= line.size() &&
- equals(singleStartStr.begin(), singleStartStr.end(), from, from + singleStartStr.size(), pred))
- {
- withinSingleLineComment = true;
- }
- else if (!withinSingleLineComment && currentIndex + startStr.size() <= line.size() &&
- equals(startStr.begin(), startStr.end(), from, from + startStr.size(), pred))
- {
- commentStartLine = currentLine;
- commentStartIndex = currentIndex;
- }
- inComment = inComment = (commentStartLine < currentLine || (commentStartLine == currentLine && commentStartIndex <= currentIndex));
- line[currentIndex].mMultiLineComment = inComment;
- line[currentIndex].mComment = withinSingleLineComment;
- auto& endStr = mLanguageDefinition.mCommentEnd;
- if (currentIndex + 1 >= (int)endStr.size() &&
- equals(endStr.begin(), endStr.end(), from + 1 - endStr.size(), from + 1, pred))
- {
- commentStartIndex = endIndex;
- commentStartLine = endLine;
- }
- }
- }
- line[currentIndex].mPreprocessor = withinPreproc;
- currentIndex += UTF8CharLength(c);
- if (currentIndex >= (int)line.size())
- {
- currentIndex = 0;
- ++currentLine;
- }
- }
- else
- {
- currentIndex = 0;
- ++currentLine;
- }
- }
- mCheckComments = false;
- }
- if (mColorRangeMin < mColorRangeMax)
- {
- const int increment = (mLanguageDefinition.mTokenize == nullptr) ? 10 : 10000;
- const int to = std::min(mColorRangeMin + increment, mColorRangeMax);
- ColorizeRange(mColorRangeMin, to);
- mColorRangeMin = to;
- if (mColorRangeMax == mColorRangeMin)
- {
- mColorRangeMin = std::numeric_limits<int>::max();
- mColorRangeMax = 0;
- }
- return;
- }
- }
- float TextEditor::TextDistanceToLineStart(const Coordinates& aFrom) const
- {
- auto& line = mLines[aFrom.mLine];
- float distance = 0.0f;
- float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x;
- int colIndex = GetCharacterIndex(aFrom);
- for (size_t it = 0u; it < line.size() && it < colIndex; )
- {
- if (line[it].mChar == '\t')
- {
- distance = (1.0f + std::floor((1.0f + distance) / (float(mTabSize) * spaceSize))) * (float(mTabSize) * spaceSize);
- ++it;
- }
- else
- {
- auto d = UTF8CharLength(line[it].mChar);
- char tempCString[7];
- int i = 0;
- for (; i < 6 && d-- > 0 && it < (int)line.size(); i++, it++)
- tempCString[i] = line[it].mChar;
- tempCString[i] = '\0';
- distance += ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, tempCString, nullptr, nullptr).x;
- }
- }
- return distance;
- }
- void TextEditor::EnsureCursorVisible()
- {
- if (!mWithinRender)
- {
- mScrollToCursor = true;
- return;
- }
- float scrollX = ImGui::GetScrollX();
- float scrollY = ImGui::GetScrollY();
- auto height = ImGui::GetWindowHeight();
- auto width = ImGui::GetWindowWidth();
- auto top = 1 + (int)ceil(scrollY / mCharAdvance.y);
- auto bottom = (int)ceil((scrollY + height) / mCharAdvance.y);
- auto left = (int)ceil(scrollX / mCharAdvance.x);
- auto right = (int)ceil((scrollX + width) / mCharAdvance.x);
- auto pos = GetActualCursorCoordinates();
- auto len = TextDistanceToLineStart(pos);
- if (pos.mLine < top)
- ImGui::SetScrollY(std::max(0.0f, (pos.mLine - 1) * mCharAdvance.y));
- if (pos.mLine > bottom - 4)
- ImGui::SetScrollY(std::max(0.0f, (pos.mLine + 4) * mCharAdvance.y - height));
- if (len + mTextStart < left + 4)
- ImGui::SetScrollX(std::max(0.0f, len + mTextStart - 4));
- if (len + mTextStart > right - 4)
- ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width));
- }
- int TextEditor::GetPageSize() const
- {
- auto height = ImGui::GetWindowHeight() - 20.0f;
- return (int)floor(height / mCharAdvance.y);
- }
- TextEditor::UndoRecord::UndoRecord(
- const std::string& aAdded,
- const TextEditor::Coordinates aAddedStart,
- const TextEditor::Coordinates aAddedEnd,
- const std::string& aRemoved,
- const TextEditor::Coordinates aRemovedStart,
- const TextEditor::Coordinates aRemovedEnd,
- TextEditor::EditorState& aBefore,
- TextEditor::EditorState& aAfter)
- : mAdded(aAdded)
- , mAddedStart(aAddedStart)
- , mAddedEnd(aAddedEnd)
- , mRemoved(aRemoved)
- , mRemovedStart(aRemovedStart)
- , mRemovedEnd(aRemovedEnd)
- , mBefore(aBefore)
- , mAfter(aAfter)
- {
- assert(mAddedStart <= mAddedEnd);
- assert(mRemovedStart <= mRemovedEnd);
- }
- void TextEditor::UndoRecord::Undo(TextEditor * aEditor)
- {
- if (!mAdded.empty())
- {
- aEditor->DeleteRange(mAddedStart, mAddedEnd);
- aEditor->Colorize(mAddedStart.mLine - 1, mAddedEnd.mLine - mAddedStart.mLine + 2);
- }
- if (!mRemoved.empty())
- {
- auto start = mRemovedStart;
- aEditor->InsertTextAt(start, mRemoved.c_str());
- aEditor->Colorize(mRemovedStart.mLine - 1, mRemovedEnd.mLine - mRemovedStart.mLine + 2);
- }
- aEditor->mState = mBefore;
- aEditor->EnsureCursorVisible();
- }
- void TextEditor::UndoRecord::Redo(TextEditor * aEditor)
- {
- if (!mRemoved.empty())
- {
- aEditor->DeleteRange(mRemovedStart, mRemovedEnd);
- aEditor->Colorize(mRemovedStart.mLine - 1, mRemovedEnd.mLine - mRemovedStart.mLine + 1);
- }
- if (!mAdded.empty())
- {
- auto start = mAddedStart;
- aEditor->InsertTextAt(start, mAdded.c_str());
- aEditor->Colorize(mAddedStart.mLine - 1, mAddedEnd.mLine - mAddedStart.mLine + 1);
- }
- aEditor->mState = mAfter;
- aEditor->EnsureCursorVisible();
- }
- static bool TokenizeCStyleString(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
- {
- const char * p = in_begin;
- if (*p == '"')
- {
- p++;
- while (p < in_end)
- {
- // handle end of string
- if (*p == '"')
- {
- out_begin = in_begin;
- out_end = p + 1;
- return true;
- }
- // handle escape character for "
- if (*p == '\\' && p + 1 < in_end && p[1] == '"')
- p++;
- p++;
- }
- }
- return false;
- }
- static bool TokenizeCStyleCharacterLiteral(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
- {
- const char * p = in_begin;
- if (*p == '\'')
- {
- p++;
- // handle escape characters
- if (p < in_end && *p == '\\')
- p++;
- if (p < in_end)
- p++;
- // handle end of character literal
- if (p < in_end && *p == '\'')
- {
- out_begin = in_begin;
- out_end = p + 1;
- return true;
- }
- }
- return false;
- }
- static bool TokenizeCStyleIdentifier(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
- {
- const char * p = in_begin;
- if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '_')
- {
- p++;
- while ((p < in_end) && ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_'))
- p++;
- out_begin = in_begin;
- out_end = p;
- return true;
- }
- return false;
- }
- static bool TokenizeCStyleNumber(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
- {
- const char * p = in_begin;
- const bool startsWithNumber = *p >= '0' && *p <= '9';
- if (*p != '+' && *p != '-' && !startsWithNumber)
- return false;
- p++;
- bool hasNumber = startsWithNumber;
- while (p < in_end && (*p >= '0' && *p <= '9'))
- {
- hasNumber = true;
- p++;
- }
- if (hasNumber == false)
- return false;
- bool isFloat = false;
- bool isHex = false;
- bool isBinary = false;
- if (p < in_end)
- {
- if (*p == '.')
- {
- isFloat = true;
- p++;
- while (p < in_end && (*p >= '0' && *p <= '9'))
- p++;
- }
- else if (*p == 'x' || *p == 'X')
- {
- // hex formatted integer of the type 0xef80
- isHex = true;
- p++;
- while (p < in_end && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
- p++;
- }
- else if (*p == 'b' || *p == 'B')
- {
- // binary formatted integer of the type 0b01011101
- isBinary = true;
- p++;
- while (p < in_end && (*p >= '0' && *p <= '1'))
- p++;
- }
- }
- if (isHex == false && isBinary == false)
- {
- // floating point exponent
- if (p < in_end && (*p == 'e' || *p == 'E'))
- {
- isFloat = true;
- p++;
- if (p < in_end && (*p == '+' || *p == '-'))
- p++;
- bool hasDigits = false;
- while (p < in_end && (*p >= '0' && *p <= '9'))
- {
- hasDigits = true;
- p++;
- }
- if (hasDigits == false)
- return false;
- }
- // single precision floating point type
- if (p < in_end && *p == 'f')
- p++;
- }
- if (isFloat == false)
- {
- // integer size type
- while (p < in_end && (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'))
- p++;
- }
- out_begin = in_begin;
- out_end = p;
- return true;
- }
- static bool TokenizeCStylePunctuation(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end)
- {
- (void)in_end;
- switch (*in_begin)
- {
- case '[':
- case ']':
- case '{':
- case '}':
- case '!':
- case '%':
- case '^':
- case '&':
- case '*':
- case '(':
- case ')':
- case '-':
- case '+':
- case '=':
- case '~':
- case '|':
- case '<':
- case '>':
- case '?':
- case ':':
- case '/':
- case ';':
- case ',':
- case '.':
- out_begin = in_begin;
- out_end = in_begin + 1;
- return true;
- }
- return false;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::CPlusPlus()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const cppKeywords[] = {
- "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
- "compl", "concept", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float",
- "for", "friend", "goto", "if", "import", "inline", "int", "long", "module", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public",
- "register", "reinterpret_cast", "requires", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "synchronized", "template", "this", "thread_local",
- "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
- };
- for (auto& k : cppKeywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph",
- "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "printf", "sprintf", "snprintf", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper",
- "std", "string", "vector", "map", "unordered_map", "set", "unordered_set", "min", "max"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenize = [](const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex) -> bool
- {
- paletteIndex = PaletteIndex::Max;
- while (in_begin < in_end && isascii(*in_begin) && isblank(*in_begin))
- in_begin++;
- if (in_begin == in_end)
- {
- out_begin = in_end;
- out_end = in_end;
- paletteIndex = PaletteIndex::Default;
- }
- else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::String;
- else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::CharLiteral;
- else if (TokenizeCStyleIdentifier(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Identifier;
- else if (TokenizeCStyleNumber(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Number;
- else if (TokenizeCStylePunctuation(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Punctuation;
- return paletteIndex != PaletteIndex::Max;
- };
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
- langDef.mName = "C++";
- inited = true;
- }
- return langDef;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::HLSL()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "AppendStructuredBuffer", "asm", "asm_fragment", "BlendState", "bool", "break", "Buffer", "ByteAddressBuffer", "case", "cbuffer", "centroid", "class", "column_major", "compile", "compile_fragment",
- "CompileShader", "const", "continue", "ComputeShader", "ConsumeStructuredBuffer", "default", "DepthStencilState", "DepthStencilView", "discard", "do", "double", "DomainShader", "dword", "else",
- "export", "extern", "false", "float", "for", "fxgroup", "GeometryShader", "groupshared", "half", "Hullshader", "if", "in", "inline", "inout", "InputPatch", "int", "interface", "line", "lineadj",
- "linear", "LineStream", "matrix", "min16float", "min10float", "min16int", "min12int", "min16uint", "namespace", "nointerpolation", "noperspective", "NULL", "out", "OutputPatch", "packoffset",
- "pass", "pixelfragment", "PixelShader", "point", "PointStream", "precise", "RasterizerState", "RenderTargetView", "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer", "RWStructuredBuffer",
- "RWTexture1D", "RWTexture1DArray", "RWTexture2D", "RWTexture2DArray", "RWTexture3D", "sample", "sampler", "SamplerState", "SamplerComparisonState", "shared", "snorm", "stateblock", "stateblock_state",
- "static", "string", "struct", "switch", "StructuredBuffer", "tbuffer", "technique", "technique10", "technique11", "texture", "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray", "Texture2DMS",
- "Texture2DMSArray", "Texture3D", "TextureCube", "TextureCubeArray", "true", "typedef", "triangle", "triangleadj", "TriangleStream", "uint", "uniform", "unorm", "unsigned", "vector", "vertexfragment",
- "VertexShader", "void", "volatile", "while",
- "bool1","bool2","bool3","bool4","double1","double2","double3","double4", "float1", "float2", "float3", "float4", "int1", "int2", "int3", "int4", "in", "out", "inout",
- "uint1", "uint2", "uint3", "uint4", "dword1", "dword2", "dword3", "dword4", "half1", "half2", "half3", "half4",
- "float1x1","float2x1","float3x1","float4x1","float1x2","float2x2","float3x2","float4x2",
- "float1x3","float2x3","float3x3","float4x3","float1x4","float2x4","float3x4","float4x4",
- "half1x1","half2x1","half3x1","half4x1","half1x2","half2x2","half3x2","half4x2",
- "half1x3","half2x3","half3x3","half4x3","half1x4","half2x4","half3x4","half4x4",
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "all", "AllMemoryBarrier", "AllMemoryBarrierWithGroupSync", "any", "asdouble", "asfloat", "asin", "asint", "asint", "asuint",
- "asuint", "atan", "atan2", "ceil", "CheckAccessFullyMapped", "clamp", "clip", "cos", "cosh", "countbits", "cross", "D3DCOLORtoUBYTE4", "ddx",
- "ddx_coarse", "ddx_fine", "ddy", "ddy_coarse", "ddy_fine", "degrees", "determinant", "DeviceMemoryBarrier", "DeviceMemoryBarrierWithGroupSync",
- "distance", "dot", "dst", "errorf", "EvaluateAttributeAtCentroid", "EvaluateAttributeAtSample", "EvaluateAttributeSnapped", "exp", "exp2",
- "f16tof32", "f32tof16", "faceforward", "firstbithigh", "firstbitlow", "floor", "fma", "fmod", "frac", "frexp", "fwidth", "GetRenderTargetSampleCount",
- "GetRenderTargetSamplePosition", "GroupMemoryBarrier", "GroupMemoryBarrierWithGroupSync", "InterlockedAdd", "InterlockedAnd", "InterlockedCompareExchange",
- "InterlockedCompareStore", "InterlockedExchange", "InterlockedMax", "InterlockedMin", "InterlockedOr", "InterlockedXor", "isfinite", "isinf", "isnan",
- "ldexp", "length", "lerp", "lit", "log", "log10", "log2", "mad", "max", "min", "modf", "msad4", "mul", "noise", "normalize", "pow", "printf",
- "Process2DQuadTessFactorsAvg", "Process2DQuadTessFactorsMax", "Process2DQuadTessFactorsMin", "ProcessIsolineTessFactors", "ProcessQuadTessFactorsAvg",
- "ProcessQuadTessFactorsMax", "ProcessQuadTessFactorsMin", "ProcessTriTessFactorsAvg", "ProcessTriTessFactorsMax", "ProcessTriTessFactorsMin",
- "radians", "rcp", "reflect", "refract", "reversebits", "round", "rsqrt", "saturate", "sign", "sin", "sincos", "sinh", "smoothstep", "sqrt", "step",
- "tan", "tanh", "tex1D", "tex1D", "tex1Dbias", "tex1Dgrad", "tex1Dlod", "tex1Dproj", "tex2D", "tex2D", "tex2Dbias", "tex2Dgrad", "tex2Dlod", "tex2Dproj",
- "tex3D", "tex3D", "tex3Dbias", "tex3Dgrad", "tex3Dlod", "tex3Dproj", "texCUBE", "texCUBE", "texCUBEbias", "texCUBEgrad", "texCUBElod", "texCUBEproj", "transpose", "trunc"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
- langDef.mName = "HLSL";
- inited = true;
- }
- return langDef;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::GLSL()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short",
- "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary",
- "_Noreturn", "_Static_assert", "_Thread_local"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph",
- "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[ \\t]*#[ \\t]*[a-zA-Z_]+", PaletteIndex::Preprocessor));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::CharLiteral));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
- langDef.mName = "GLSL";
- inited = true;
- }
- return langDef;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::C()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "auto", "break", "case", "char", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline", "int", "long", "register", "restrict", "return", "short",
- "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while", "_Alignas", "_Alignof", "_Atomic", "_Bool", "_Complex", "_Generic", "_Imaginary",
- "_Noreturn", "_Static_assert", "_Thread_local"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "abort", "abs", "acos", "asin", "atan", "atexit", "atof", "atoi", "atol", "ceil", "clock", "cosh", "ctime", "div", "exit", "fabs", "floor", "fmod", "getchar", "getenv", "isalnum", "isalpha", "isdigit", "isgraph",
- "ispunct", "isspace", "isupper", "kbhit", "log10", "log2", "log", "memcmp", "modf", "pow", "putchar", "putenv", "puts", "rand", "remove", "rename", "sinh", "sqrt", "srand", "strcat", "strcmp", "strerror", "time", "tolower", "toupper"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenize = [](const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex) -> bool
- {
- paletteIndex = PaletteIndex::Max;
- while (in_begin < in_end && isascii(*in_begin) && isblank(*in_begin))
- in_begin++;
- if (in_begin == in_end)
- {
- out_begin = in_end;
- out_end = in_end;
- paletteIndex = PaletteIndex::Default;
- }
- else if (TokenizeCStyleString(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::String;
- else if (TokenizeCStyleCharacterLiteral(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::CharLiteral;
- else if (TokenizeCStyleIdentifier(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Identifier;
- else if (TokenizeCStyleNumber(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Number;
- else if (TokenizeCStylePunctuation(in_begin, in_end, out_begin, out_end))
- paletteIndex = PaletteIndex::Punctuation;
- return paletteIndex != PaletteIndex::Max;
- };
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
- langDef.mName = "C";
- inited = true;
- }
- return langDef;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::SQL()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE",
- "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE",
- "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE",
- "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE",
- "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER",
- "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE",
- "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION",
- "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE",
- "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING","DROP", "OPENROWSET", "VIEW",
- "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "ABS", "ACOS", "ADD_MONTHS", "ASCII", "ASCIISTR", "ASIN", "ATAN", "ATAN2", "AVG", "BFILENAME", "BIN_TO_NUM", "BITAND", "CARDINALITY", "CASE", "CAST", "CEIL",
- "CHARTOROWID", "CHR", "COALESCE", "COMPOSE", "CONCAT", "CONVERT", "CORR", "COS", "COSH", "COUNT", "COVAR_POP", "COVAR_SAMP", "CUME_DIST", "CURRENT_DATE",
- "CURRENT_TIMESTAMP", "DBTIMEZONE", "DECODE", "DECOMPOSE", "DENSE_RANK", "DUMP", "EMPTY_BLOB", "EMPTY_CLOB", "EXP", "EXTRACT", "FIRST_VALUE", "FLOOR", "FROM_TZ", "GREATEST",
- "GROUP_ID", "HEXTORAW", "INITCAP", "INSTR", "INSTR2", "INSTR4", "INSTRB", "INSTRC", "LAG", "LAST_DAY", "LAST_VALUE", "LEAD", "LEAST", "LENGTH", "LENGTH2", "LENGTH4",
- "LENGTHB", "LENGTHC", "LISTAGG", "LN", "LNNVL", "LOCALTIMESTAMP", "LOG", "LOWER", "LPAD", "LTRIM", "MAX", "MEDIAN", "MIN", "MOD", "MONTHS_BETWEEN", "NANVL", "NCHR",
- "NEW_TIME", "NEXT_DAY", "NTH_VALUE", "NULLIF", "NUMTODSINTERVAL", "NUMTOYMINTERVAL", "NVL", "NVL2", "POWER", "RANK", "RAWTOHEX", "REGEXP_COUNT", "REGEXP_INSTR",
- "REGEXP_REPLACE", "REGEXP_SUBSTR", "REMAINDER", "REPLACE", "ROUND", "ROWNUM", "RPAD", "RTRIM", "SESSIONTIMEZONE", "SIGN", "SIN", "SINH",
- "SOUNDEX", "SQRT", "STDDEV", "SUBSTR", "SUM", "SYS_CONTEXT", "SYSDATE", "SYSTIMESTAMP", "TAN", "TANH", "TO_CHAR", "TO_CLOB", "TO_DATE", "TO_DSINTERVAL", "TO_LOB",
- "TO_MULTI_BYTE", "TO_NCLOB", "TO_NUMBER", "TO_SINGLE_BYTE", "TO_TIMESTAMP", "TO_TIMESTAMP_TZ", "TO_YMINTERVAL", "TRANSLATE", "TRIM", "TRUNC", "TZ_OFFSET", "UID", "UPPER",
- "USER", "USERENV", "VAR_POP", "VAR_SAMP", "VARIANCE", "VSIZE "
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
- langDef.mCaseSensitive = false;
- langDef.mAutoIndentation = false;
- langDef.mName = "SQL";
- inited = true;
- }
- return langDef;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::AngelScript()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "and", "abstract", "auto", "bool", "break", "case", "cast", "class", "const", "continue", "default", "do", "double", "else", "enum", "false", "final", "float", "for",
- "from", "funcdef", "function", "get", "if", "import", "in", "inout", "int", "interface", "int8", "int16", "int32", "int64", "is", "mixin", "namespace", "not",
- "null", "or", "out", "override", "private", "protected", "return", "set", "shared", "super", "switch", "this ", "true", "typedef", "uint", "uint8", "uint16", "uint32",
- "uint64", "void", "while", "xor"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "cos", "sin", "tab", "acos", "asin", "atan", "atan2", "cosh", "sinh", "tanh", "log", "log10", "pow", "sqrt", "abs", "ceil", "floor", "fraction", "closeTo", "fpFromIEEE", "fpToIEEE",
- "complex", "opEquals", "opAddAssign", "opSubAssign", "opMulAssign", "opDivAssign", "opAdd", "opSub", "opMul", "opDiv"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\'\\\\?[^\\']\\'", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[0-7]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
- langDef.mCommentStart = "/*";
- langDef.mCommentEnd = "*/";
- langDef.mSingleLineComment = "//";
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = true;
- langDef.mName = "AngelScript";
- inited = true;
- }
- return langDef;
- }
- const TextEditor::LanguageDefinition& TextEditor::LanguageDefinition::Lua()
- {
- static bool inited = false;
- static LanguageDefinition langDef;
- if (!inited)
- {
- static const char* const keywords[] = {
- "and", "break", "do", "", "else", "elseif", "end", "false", "for", "function", "if", "in", "", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while"
- };
- for (auto& k : keywords)
- langDef.mKeywords.insert(k);
- static const char* const identifiers[] = {
- "assert", "collectgarbage", "dofile", "error", "getmetatable", "ipairs", "loadfile", "load", "loadstring", "next", "pairs", "pcall", "print", "rawequal", "rawlen", "rawget", "rawset",
- "select", "setmetatable", "tonumber", "tostring", "type", "xpcall", "_G", "_VERSION","arshift", "band", "bnot", "bor", "bxor", "btest", "extract", "lrotate", "lshift", "replace",
- "rrotate", "rshift", "create", "resume", "running", "status", "wrap", "yield", "isyieldable", "debug","getuservalue", "gethook", "getinfo", "getlocal", "getregistry", "getmetatable",
- "getupvalue", "upvaluejoin", "upvalueid", "setuservalue", "sethook", "setlocal", "setmetatable", "setupvalue", "traceback", "close", "flush", "input", "lines", "open", "output", "popen",
- "read", "tmpfile", "type", "write", "close", "flush", "lines", "read", "seek", "setvbuf", "write", "__gc", "__tostring", "abs", "acos", "asin", "atan", "ceil", "cos", "deg", "exp", "tointeger",
- "floor", "fmod", "ult", "log", "max", "min", "modf", "rad", "random", "randomseed", "sin", "sqrt", "string", "tan", "type", "atan2", "cosh", "sinh", "tanh",
- "pow", "frexp", "ldexp", "log10", "pi", "huge", "maxinteger", "mininteger", "loadlib", "searchpath", "seeall", "preload", "cpath", "path", "searchers", "loaded", "module", "require", "clock",
- "date", "difftime", "execute", "exit", "getenv", "remove", "rename", "setlocale", "time", "tmpname", "byte", "char", "dump", "find", "format", "gmatch", "gsub", "len", "lower", "match", "rep",
- "reverse", "sub", "upper", "pack", "packsize", "unpack", "concat", "maxn", "insert", "pack", "unpack", "remove", "move", "sort", "offset", "codepoint", "char", "len", "codes", "charpattern",
- "coroutine", "table", "io", "os", "string", "utf8", "bit32", "math", "debug", "package"
- };
- for (auto& k : identifiers)
- {
- Identifier id;
- id.mDeclaration = "Built-in function";
- langDef.mIdentifiers.insert(std::make_pair(std::string(k), id));
- }
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("L?\\\"(\\\\.|[^\\\"])*\\\"", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("\\\'[^\\\']*\\\'", PaletteIndex::String));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("0[xX][0-9a-fA-F]+[uU]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[fF]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[+-]?[0-9]+[Uu]?[lL]?[lL]?", PaletteIndex::Number));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[a-zA-Z_][a-zA-Z0-9_]*", PaletteIndex::Identifier));
- langDef.mTokenRegexStrings.push_back(std::make_pair<std::string, PaletteIndex>("[\\[\\]\\{\\}\\!\\%\\^\\&\\*\\(\\)\\-\\+\\=\\~\\|\\<\\>\\?\\/\\;\\,\\.]", PaletteIndex::Punctuation));
- langDef.mCommentStart = "--[[";
- langDef.mCommentEnd = "]]";
- langDef.mSingleLineComment = "--";
- langDef.mCaseSensitive = true;
- langDef.mAutoIndentation = false;
- langDef.mName = "Lua";
- inited = true;
- }
- return langDef;
- }
|