#pragma once #include #include #include #include #include #include #include #include #include "../imgui/imgui.h" namespace tracy { 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 Identifiers; typedef std::unordered_set Keywords; typedef std::map ErrorMarkers; typedef std::unordered_set Breakpoints; typedef std::array Palette; typedef char Char; struct Glyph { Char mChar; PaletteIndex mColorIndex : 7; bool mMultiLineComment : 1; Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex), mMultiLineComment(false) {} }; typedef std::vector Line; typedef std::vector Lines; struct LanguageDefinition { typedef std::pair TokenRegexString; typedef std::vector TokenRegexStrings; std::string mName; Keywords mKeywords; Identifiers mIdentifiers; Identifiers mPreprocIdentifiers; std::string mCommentStart, mCommentEnd; TokenRegexStrings mTokenRegexStrings; bool mCaseSensitive; static LanguageDefinition CPlusPlus(); static LanguageDefinition HLSL(); static LanguageDefinition GLSL(); static LanguageDefinition C(); static LanguageDefinition SQL(); static LanguageDefinition AngelScript(); static 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; 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; } 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> 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 UndoBuffer; void ProcessInputs(); void Colorize(int aFromLine = 0, int aCount = -1); void ColorizeRange(int aFromLine = 0, int aToLine = 0); void ColorizeInternal(); int 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; int mColorRangeMin, mColorRangeMax; SelectionMode mSelectionMode; Palette mPalette; LanguageDefinition mLanguageDefinition; RegexList mRegexList; bool mCheckMultilineComments; Breakpoints mBreakpoints; ErrorMarkers mErrorMarkers; ImVec2 mCharAdvance; Coordinates mInteractiveStart, mInteractiveEnd; }; }