#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; | |
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; | |
}; |