| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984 |
- #include <algorithm>
- #include <chrono>
- #include <cmath>
- #include <ctype.h>
- #include <regex>
- #include <string>
- #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::GetScreenCursorPosition() { return Coordinates(mCursorScreenX, mCursorScreenY); }
- 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();
- c.mColumn = std::max(c.mColumn - 1, 0);
- 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(ImGuiFocusedFlags_ChildWindows)) {
- 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::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) {
- 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(ImGuiFocusedFlags_ChildWindows);
- // 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]);
- // store screen cursor pos
- mCursorScreenX = cend.y;
- mCursorScreenY = cend.x;
- // 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_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) {
- if (e == 1 && buf[0] == '\t') {
- for (int i = 0; i < mTabSize; i++)
- buf[i] = ' ';
- e = mTabSize;
- }
- 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();
- }
- }
- TextEditor::Coordinates TextEditor::GetSelectionStart() { return mState.mSelectionStart; }
- 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;
- if (line[cindex].mChar == '\t')
- mState.mCursorPosition.mColumn -= mTabSize;
- else
- --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();
- c.mColumn = std::max(c.mColumn - 1, 0);
- 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)
- 0xFF342C28, // 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 = true;
- 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;
- }
|