2
0

TextEditor.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. //https://github.com/BalazsJako/ImGuiColorTextEdit
  2. #pragma once
  3. #include <string>
  4. #include <vector>
  5. #include <array>
  6. #include <memory>
  7. #include <unordered_set>
  8. #include <unordered_map>
  9. #include <map>
  10. #include <regex>
  11. #include "imgui.h"
  12. class TextEditor
  13. {
  14. public:
  15. enum class PaletteIndex
  16. {
  17. Default,
  18. Keyword,
  19. Number,
  20. String,
  21. CharLiteral,
  22. Punctuation,
  23. Preprocessor,
  24. Identifier,
  25. KnownIdentifier,
  26. PreprocIdentifier,
  27. Comment,
  28. MultiLineComment,
  29. Background,
  30. Cursor,
  31. Selection,
  32. ErrorMarker,
  33. Breakpoint,
  34. LineNumber,
  35. CurrentLineFill,
  36. CurrentLineFillInactive,
  37. CurrentLineEdge,
  38. Max
  39. };
  40. enum class SelectionMode
  41. {
  42. Normal,
  43. Word,
  44. Line
  45. };
  46. struct Breakpoint
  47. {
  48. int mLine;
  49. bool mEnabled;
  50. std::string mCondition;
  51. Breakpoint()
  52. : mLine(-1)
  53. , mEnabled(false)
  54. {}
  55. };
  56. // Represents a character coordinate from the user's point of view,
  57. // i. e. consider an uniform grid (assuming fixed-width font) on the
  58. // screen as it is rendered, and each cell has its own coordinate, starting from 0.
  59. // Tabs are counted as [1..mTabSize] count empty spaces, depending on
  60. // how many space is necessary to reach the next tab stop.
  61. // For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4,
  62. // because it is rendered as " ABC" on the screen.
  63. struct Coordinates
  64. {
  65. int mLine, mColumn;
  66. Coordinates() : mLine(0), mColumn(0) {}
  67. Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn)
  68. {
  69. assert(aLine >= 0);
  70. assert(aColumn >= 0);
  71. }
  72. static Coordinates Invalid() { static Coordinates invalid(-1, -1); return invalid; }
  73. bool operator ==(const Coordinates& o) const
  74. {
  75. return
  76. mLine == o.mLine &&
  77. mColumn == o.mColumn;
  78. }
  79. bool operator !=(const Coordinates& o) const
  80. {
  81. return
  82. mLine != o.mLine ||
  83. mColumn != o.mColumn;
  84. }
  85. bool operator <(const Coordinates& o) const
  86. {
  87. if (mLine != o.mLine)
  88. return mLine < o.mLine;
  89. return mColumn < o.mColumn;
  90. }
  91. bool operator >(const Coordinates& o) const
  92. {
  93. if (mLine != o.mLine)
  94. return mLine > o.mLine;
  95. return mColumn > o.mColumn;
  96. }
  97. bool operator <=(const Coordinates& o) const
  98. {
  99. if (mLine != o.mLine)
  100. return mLine < o.mLine;
  101. return mColumn <= o.mColumn;
  102. }
  103. bool operator >=(const Coordinates& o) const
  104. {
  105. if (mLine != o.mLine)
  106. return mLine > o.mLine;
  107. return mColumn >= o.mColumn;
  108. }
  109. };
  110. struct Identifier
  111. {
  112. Coordinates mLocation;
  113. std::string mDeclaration;
  114. };
  115. typedef std::string String;
  116. typedef std::unordered_map<std::string, Identifier> Identifiers;
  117. typedef std::unordered_set<std::string> Keywords;
  118. typedef std::map<int, std::string> ErrorMarkers;
  119. typedef std::unordered_set<int> Breakpoints;
  120. typedef std::array<ImU32, (unsigned)PaletteIndex::Max> Palette;
  121. typedef uint8_t Char;
  122. struct Glyph
  123. {
  124. Char mChar;
  125. PaletteIndex mColorIndex = PaletteIndex::Default;
  126. bool mComment : 1;
  127. bool mMultiLineComment : 1;
  128. bool mPreprocessor : 1;
  129. Glyph(Char aChar, PaletteIndex aColorIndex) : mChar(aChar), mColorIndex(aColorIndex),
  130. mComment(false), mMultiLineComment(false), mPreprocessor(false) {}
  131. };
  132. typedef std::vector<Glyph> Line;
  133. typedef std::vector<Line> Lines;
  134. struct LanguageDefinition
  135. {
  136. typedef std::pair<std::string, PaletteIndex> TokenRegexString;
  137. typedef std::vector<TokenRegexString> TokenRegexStrings;
  138. typedef bool(*TokenizeCallback)(const char * in_begin, const char * in_end, const char *& out_begin, const char *& out_end, PaletteIndex & paletteIndex);
  139. std::string mName;
  140. Keywords mKeywords;
  141. Identifiers mIdentifiers;
  142. Identifiers mPreprocIdentifiers;
  143. std::string mCommentStart, mCommentEnd, mSingleLineComment;
  144. char mPreprocChar;
  145. bool mAutoIndentation;
  146. TokenizeCallback mTokenize;
  147. TokenRegexStrings mTokenRegexStrings;
  148. bool mCaseSensitive;
  149. LanguageDefinition()
  150. : mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true)
  151. {
  152. }
  153. static const LanguageDefinition& CPlusPlus();
  154. static const LanguageDefinition& HLSL();
  155. static const LanguageDefinition& GLSL();
  156. static const LanguageDefinition& C();
  157. static const LanguageDefinition& SQL();
  158. static const LanguageDefinition& AngelScript();
  159. static const LanguageDefinition& Lua();
  160. };
  161. TextEditor();
  162. ~TextEditor();
  163. void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
  164. const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
  165. const Palette& GetPalette() const { return mPaletteBase; }
  166. void SetPalette(const Palette& aValue);
  167. void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
  168. void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
  169. void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
  170. void SetText(const std::string& aText);
  171. std::string GetText() const;
  172. void SetTextLines(const std::vector<std::string>& aLines);
  173. std::vector<std::string> GetTextLines() const;
  174. std::string GetSelectedText() const;
  175. std::string GetCurrentLineText()const;
  176. int GetTotalLines() const { return (int)mLines.size(); }
  177. bool IsOverwrite() const { return mOverwrite; }
  178. void SetReadOnly(bool aValue);
  179. bool IsReadOnly() const { return mReadOnly; }
  180. bool IsTextChanged() const { return mTextChanged; }
  181. bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
  182. bool IsColorizerEnabled() const { return mColorizerEnabled; }
  183. void SetColorizerEnable(bool aValue);
  184. Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
  185. void SetCursorPosition(const Coordinates& aPosition);
  186. inline void SetHandleMouseInputs (bool aValue){ mHandleMouseInputs = aValue;}
  187. inline bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; }
  188. inline void SetHandleKeyboardInputs (bool aValue){ mHandleKeyboardInputs = aValue;}
  189. inline bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; }
  190. inline void SetImGuiChildIgnored (bool aValue){ mIgnoreImGuiChild = aValue;}
  191. inline bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; }
  192. inline void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; }
  193. inline bool IsShowingWhitespaces() const { return mShowWhitespaces; }
  194. void SetTabSize(int aValue);
  195. inline int GetTabSize() const { return mTabSize; }
  196. void InsertText(const std::string& aValue);
  197. void InsertText(const char* aValue);
  198. void MoveUp(int aAmount = 1, bool aSelect = false);
  199. void MoveDown(int aAmount = 1, bool aSelect = false);
  200. void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
  201. void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
  202. void MoveTop(bool aSelect = false);
  203. void MoveBottom(bool aSelect = false);
  204. void MoveHome(bool aSelect = false);
  205. void MoveEnd(bool aSelect = false);
  206. void SetSelectionStart(const Coordinates& aPosition);
  207. void SetSelectionEnd(const Coordinates& aPosition);
  208. void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal);
  209. void SelectWordUnderCursor();
  210. void SelectAll();
  211. bool HasSelection() const;
  212. void Copy();
  213. void Cut();
  214. void Paste();
  215. void Delete();
  216. bool CanUndo() const;
  217. bool CanRedo() const;
  218. void Undo(int aSteps = 1);
  219. void Redo(int aSteps = 1);
  220. static const Palette& GetDarkPalette();
  221. static const Palette& GetLightPalette();
  222. static const Palette& GetRetroBluePalette();
  223. private:
  224. typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList;
  225. struct EditorState
  226. {
  227. Coordinates mSelectionStart;
  228. Coordinates mSelectionEnd;
  229. Coordinates mCursorPosition;
  230. };
  231. class UndoRecord
  232. {
  233. public:
  234. UndoRecord() {}
  235. ~UndoRecord() {}
  236. UndoRecord(
  237. const std::string& aAdded,
  238. const TextEditor::Coordinates aAddedStart,
  239. const TextEditor::Coordinates aAddedEnd,
  240. const std::string& aRemoved,
  241. const TextEditor::Coordinates aRemovedStart,
  242. const TextEditor::Coordinates aRemovedEnd,
  243. TextEditor::EditorState& aBefore,
  244. TextEditor::EditorState& aAfter);
  245. void Undo(TextEditor* aEditor);
  246. void Redo(TextEditor* aEditor);
  247. std::string mAdded;
  248. Coordinates mAddedStart;
  249. Coordinates mAddedEnd;
  250. std::string mRemoved;
  251. Coordinates mRemovedStart;
  252. Coordinates mRemovedEnd;
  253. EditorState mBefore;
  254. EditorState mAfter;
  255. };
  256. typedef std::vector<UndoRecord> UndoBuffer;
  257. void ProcessInputs();
  258. void Colorize(int aFromLine = 0, int aCount = -1);
  259. void ColorizeRange(int aFromLine = 0, int aToLine = 0);
  260. void ColorizeInternal();
  261. float TextDistanceToLineStart(const Coordinates& aFrom) const;
  262. void EnsureCursorVisible();
  263. int GetPageSize() const;
  264. std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
  265. Coordinates GetActualCursorCoordinates() const;
  266. Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
  267. void Advance(Coordinates& aCoordinates) const;
  268. void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
  269. int InsertTextAt(Coordinates& aWhere, const char* aValue);
  270. void AddUndo(UndoRecord& aValue);
  271. Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
  272. Coordinates FindWordStart(const Coordinates& aFrom) const;
  273. Coordinates FindWordEnd(const Coordinates& aFrom) const;
  274. Coordinates FindNextWord(const Coordinates& aFrom) const;
  275. int GetCharacterIndex(const Coordinates& aCoordinates) const;
  276. int GetCharacterColumn(int aLine, int aIndex) const;
  277. int GetLineCharacterCount(int aLine) const;
  278. int GetLineMaxColumn(int aLine) const;
  279. bool IsOnWordBoundary(const Coordinates& aAt) const;
  280. void RemoveLine(int aStart, int aEnd);
  281. void RemoveLine(int aIndex);
  282. Line& InsertLine(int aIndex);
  283. void EnterCharacter(ImWchar aChar, bool aShift);
  284. void Backspace();
  285. void DeleteSelection();
  286. std::string GetWordUnderCursor() const;
  287. std::string GetWordAt(const Coordinates& aCoords) const;
  288. ImU32 GetGlyphColor(const Glyph& aGlyph) const;
  289. void HandleKeyboardInputs();
  290. void HandleMouseInputs();
  291. void Render();
  292. float mLineSpacing;
  293. Lines mLines;
  294. EditorState mState;
  295. UndoBuffer mUndoBuffer;
  296. int mUndoIndex;
  297. int mTabSize;
  298. bool mOverwrite;
  299. bool mReadOnly;
  300. bool mWithinRender;
  301. bool mScrollToCursor;
  302. bool mScrollToTop;
  303. bool mTextChanged;
  304. bool mColorizerEnabled;
  305. float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
  306. int mLeftMargin;
  307. bool mCursorPositionChanged;
  308. int mColorRangeMin, mColorRangeMax;
  309. SelectionMode mSelectionMode;
  310. bool mHandleKeyboardInputs;
  311. bool mHandleMouseInputs;
  312. bool mIgnoreImGuiChild;
  313. bool mShowWhitespaces;
  314. Palette mPaletteBase;
  315. Palette mPalette;
  316. LanguageDefinition mLanguageDefinition;
  317. RegexList mRegexList;
  318. bool mCheckComments;
  319. Breakpoints mBreakpoints;
  320. ErrorMarkers mErrorMarkers;
  321. ImVec2 mCharAdvance;
  322. Coordinates mInteractiveStart, mInteractiveEnd;
  323. std::string mLineBuffer;
  324. uint64_t mStartTime;
  325. float mLastClick;
  326. };