| #pragma once | |
| #include <string> | |
| #include <vector> | |
| #include <array> | |
| #include <memory> | |
| #include <unordered_set> | |
| #include <unordered_map> | |
| #include <map> | |
| #include <regex> | |
| #include "imgui.h" | |
| class TextEditor | |
| { | |
| public: | |
| enum class PaletteIndex | |
| { | |
| Default, | |
| Keyword, | |
| Number, | |
| String, | |
| CharLiteral, | |
| Punctuation, | |
| Preprocessor, | |
| Identifier, | |
| KnownIdentifier, | |
| PreprocIdentifier, | |
| Comment, | |
| MultiLineComment, | |
| Background, | |
| Cursor, | |
| Selection, | |
| ErrorMarker, | |
| Breakpoint, | |
| LineNumber, | |
| CurrentLineFill, | |
| CurrentLineFillInactive, | |
| CurrentLineEdge, | |
| Max | |
| }; | |
| enum class SelectionMode | |
| { | |
| Normal, | |
| Word, | |
| Line | |
| }; | |
| struct Breakpoint | |
| { | |
| int mLine; | |
| bool mEnabled; | |
| std::string mCondition; | |
| Breakpoint() | |
| : mLine(-1) | |
| , mEnabled(false) | |
| {} | |
| }; | |
| struct Coordinates | |
| { | |
| int mLine, mColumn; | |
| Coordinates() : mLine(0), mColumn(0) {} | |
| Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn) | |
| { | |
| assert(aLine >= 0); | |
| assert(aColumn >= 0); | |
| } | |
| static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; } | |
| bool operator ==(const Coordinates& o) const | |
| { | |
| return | |
| mLine == o.mLine && | |
| mColumn == o.mColumn; | |
| } | |
| bool operator !=(const Coordinates& o) const | |
| { | |
| return | |
| mLine != o.mLine || | |
| mColumn != o.mColumn; | |
| } | |
| bool operator <(const Coordinates& o) const | |
| { | |
| if (mLine != o.mLine) | |
| return mLine < o.mLine; | |
| return mColumn < o.mColumn; | |
| } | |
| bool operator >(const Coordinates& o) const | |
| { | |
| if (mLine != o.mLine) | |
| return mLine > o.mLine; | |
| return mColumn > o.mColumn; | |
| } | |
| bool operator <=(const Coordinates& o) const | |
| { | |
| if (mLine != o.mLine) | |
| return mLine < o.mLine; | |
| return mColumn <= o.mColumn; | |
| } | |
| bool operator >=(const Coordinates& o) const | |
| { | |
| if (mLine != o.mLine) | |
| return mLine > o.mLine; | |
| return mColumn >= o.mColumn; | |
| } | |
| }; | |
| struct Identifier | |
| { | |
| Coordinates mLocation; | |
| std::string mDeclaration; | |
| }; | |
| typedef std::string String; | |
| typedef std::unordered_map<std::string, Identifier> Identifiers; | |
| typedef std::unordered_set<std::string> Keywords; | |
| typedef std::map<int, std::string> ErrorMarkers; | |
| typedef std::unordered_set<int> Breakpoints; | |
| typedef std::array<ImU32, (unsigned)PaletteIndex::Max> Palette; | |
| typedef char Char; | |
| struct Glyph | |
| { | |
| Char mChar; | |
| PaletteIndex mColorIndex = PaletteIndex::Default; | |
| bool mMultiLineComment : 1; | |
| Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex), mMultiLineComment(false) {} | |
| }; | |
| typedef std::vector<Glyph> Line; | |
| typedef std::vector<Line> Lines; | |
| struct LanguageDefinition | |
| { | |
| typedef std::pair<std::string, PaletteIndex> TokenRegexString; | |
| typedef std::vector<TokenRegexString> TokenRegexStrings; | |
| typedef bool (*TokenizeCallback)(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex); | |
| std::string mName; | |
| Keywords mKeywords; | |
| Identifiers mIdentifiers; | |
| Identifiers mPreprocIdentifiers; | |
| std::string mCommentStart, mCommentEnd; | |
| bool mAutoIndentation; | |
| TokenizeCallback mTokenize; | |
| TokenRegexStrings mTokenRegexStrings; | |
| bool mCaseSensitive; | |
| LanguageDefinition() | |
| : mTokenize(nullptr) | |
| { | |
| } | |
| static const LanguageDefinition& CPlusPlus(); | |
| static const LanguageDefinition& HLSL(); | |
| static const LanguageDefinition& GLSL(); | |
| static const LanguageDefinition& C(); | |
| static const LanguageDefinition& SQL(); | |
| static const LanguageDefinition& AngelScript(); | |
| static const LanguageDefinition& Lua(); | |
| }; | |
| TextEditor(); | |
| ~TextEditor(); | |
| void SetLanguageDefinition(const LanguageDefinition& aLanguageDef); | |
| const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; } | |
| const Palette& GetPalette() const { return mPalette; } | |
| void SetPalette(const Palette& aValue); | |
| void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; } | |
| void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; } | |
| void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false); | |
| void SetText(const std::string& aText); | |
| std::string GetText() const; | |
| std::string GetSelectedText() const; | |
| std::string GetCurrentLineText()const; | |
| int GetTotalLines() const { return (int)mLines.size(); } | |
| bool IsOverwrite() const { return mOverwrite; } | |
| void SetReadOnly(bool aValue); | |
| bool IsReadOnly() const { return mReadOnly; } | |
| bool IsTextChanged() const { return mTextChanged; } | |
| bool IsCursorPositionChanged() const { return mCursorPositionChanged; } | |
| Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); } | |
| void SetCursorPosition(const Coordinates& aPosition); | |
| void InsertText(const std::string& aValue); | |
| void InsertText(const char* aValue); | |
| void MoveUp(int aAmount = 1, bool aSelect = false); | |
| void MoveDown(int aAmount = 1, bool aSelect = false); | |
| void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false); | |
| void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false); | |
| void MoveTop(bool aSelect = false); | |
| void MoveBottom(bool aSelect = false); | |
| void MoveHome(bool aSelect = false); | |
| void MoveEnd(bool aSelect = false); | |
| void SetSelectionStart(const Coordinates& aPosition); | |
| void SetSelectionEnd(const Coordinates& aPosition); | |
| void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal); | |
| void SelectWordUnderCursor(); | |
| void SelectAll(); | |
| bool HasSelection() const; | |
| void Copy(); | |
| void Cut(); | |
| void Paste(); | |
| void Delete(); | |
| bool CanUndo() const; | |
| bool CanRedo() const; | |
| void Undo(int aSteps = 1); | |
| void Redo(int aSteps = 1); | |
| static const Palette& GetDarkPalette(); | |
| static const Palette& GetLightPalette(); | |
| static const Palette& GetRetroBluePalette(); | |
| private: | |
| typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList; | |
| struct EditorState | |
| { | |
| Coordinates mSelectionStart; | |
| Coordinates mSelectionEnd; | |
| Coordinates mCursorPosition; | |
| }; | |
| class UndoRecord | |
| { | |
| public: | |
| UndoRecord() {} | |
| ~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); | |
| void Undo(TextEditor* aEditor); | |
| void Redo(TextEditor* aEditor); | |
| std::string mAdded; | |
| Coordinates mAddedStart; | |
| Coordinates mAddedEnd; | |
| std::string mRemoved; | |
| Coordinates mRemovedStart; | |
| Coordinates mRemovedEnd; | |
| EditorState mBefore; | |
| EditorState mAfter; | |
| }; | |
| typedef std::vector<UndoRecord> UndoBuffer; | |
| void ProcessInputs(); | |
| void Colorize(int aFromLine = 0, int aCount = -1); | |
| void ColorizeRange(int aFromLine = 0, int aToLine = 0); | |
| void ColorizeInternal(); | |
| float TextDistanceToLineStart(const Coordinates& aFrom) const; | |
| void EnsureCursorVisible(); | |
| int GetPageSize() const; | |
| int AppendBuffer(std::string& aBuffer, char chr, int aIndex); | |
| std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const; | |
| Coordinates GetActualCursorCoordinates() const; | |
| Coordinates SanitizeCoordinates(const Coordinates& aValue) const; | |
| void Advance(Coordinates& aCoordinates) const; | |
| void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd); | |
| int InsertTextAt(Coordinates& aWhere, const char* aValue); | |
| void AddUndo(UndoRecord& aValue); | |
| Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const; | |
| Coordinates FindWordStart(const Coordinates& aFrom) const; | |
| Coordinates FindWordEnd(const Coordinates& aFrom) const; | |
| bool IsOnWordBoundary(const Coordinates& aAt) const; | |
| void RemoveLine(int aStart, int aEnd); | |
| void RemoveLine(int aIndex); | |
| Line& InsertLine(int aIndex); | |
| void EnterCharacter(Char aChar); | |
| void BackSpace(); | |
| void DeleteSelection(); | |
| std::string GetWordUnderCursor() const; | |
| std::string GetWordAt(const Coordinates& aCoords) const; | |
| float mLineSpacing; | |
| Lines mLines; | |
| EditorState mState; | |
| UndoBuffer mUndoBuffer; | |
| int mUndoIndex; | |
| int mTabSize; | |
| bool mOverwrite; | |
| bool mReadOnly; | |
| bool mWithinRender; | |
| bool mScrollToCursor; | |
| bool mTextChanged; | |
| float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor. | |
| int mLeftMargin; | |
| bool mCursorPositionChanged; | |
| int mColorRangeMin, mColorRangeMax; | |
| SelectionMode mSelectionMode; | |
| Palette mPalette; | |
| LanguageDefinition mLanguageDefinition; | |
| RegexList mRegexList; | |
| bool mCheckMultilineComments; | |
| Breakpoints mBreakpoints; | |
| ErrorMarkers mErrorMarkers; | |
| ImVec2 mCharAdvance; | |
| Coordinates mInteractiveStart, mInteractiveEnd; | |
| }; |