TextEditor.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include <array>
  5. #include <memory>
  6. #include <unordered_set>
  7. #include <unordered_map>
  8. #include <map>
  9. #include <regex>
  10. #include <cassert>
  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. std::string GetWordUnderCursor() const;
  173. void SetTextLines(const std::vector<std::string>& aLines);
  174. std::vector<std::string> GetTextLines() const;
  175. std::string GetSelectedText() const;
  176. std::string GetCurrentLineText()const;
  177. int GetTotalLines() const { return (int)mLines.size(); }
  178. bool IsOverwrite() const { return mOverwrite; }
  179. void SetReadOnly(bool aValue);
  180. bool IsReadOnly() const { return mReadOnly; }
  181. bool IsTextChanged() const { return mTextChanged; }
  182. bool IsCursorPositionChanged() const { return mCursorPositionChanged; }
  183. bool IsColorizerEnabled() const { return mColorizerEnabled; }
  184. void SetColorizerEnable(bool aValue);
  185. Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); }
  186. void SetCursorPosition(const Coordinates& aPosition);
  187. Coordinates GetScreenCursorPosition();
  188. inline void SetHandleMouseInputs (bool aValue){ mHandleMouseInputs = aValue;}
  189. inline bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; }
  190. inline void SetHandleKeyboardInputs (bool aValue){ mHandleKeyboardInputs = aValue;}
  191. inline bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; }
  192. inline void SetImGuiChildIgnored (bool aValue){ mIgnoreImGuiChild = aValue;}
  193. inline bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; }
  194. inline void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; }
  195. inline bool IsShowingWhitespaces() const { return mShowWhitespaces; }
  196. void SetTabSize(int aValue);
  197. inline int GetTabSize() const { return mTabSize; }
  198. void InsertText(const std::string& aValue);
  199. void InsertText(const char* aValue);
  200. void MoveUp(int aAmount = 1, bool aSelect = false);
  201. void MoveDown(int aAmount = 1, bool aSelect = false);
  202. void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
  203. void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
  204. void MoveTop(bool aSelect = false);
  205. void MoveBottom(bool aSelect = false);
  206. void MoveHome(bool aSelect = false);
  207. void MoveEnd(bool aSelect = false);
  208. Coordinates GetSelectionStart();
  209. void SetSelectionStart(const Coordinates& aPosition);
  210. void SetSelectionEnd(const Coordinates& aPosition);
  211. void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal);
  212. void SelectWordUnderCursor();
  213. void SelectAll();
  214. bool HasSelection() const;
  215. void Copy();
  216. void Cut();
  217. void Paste();
  218. void Delete();
  219. bool CanUndo() const;
  220. bool CanRedo() const;
  221. void Undo(int aSteps = 1);
  222. void Redo(int aSteps = 1);
  223. static const Palette& GetDarkPalette();
  224. static const Palette& GetLightPalette();
  225. static const Palette& GetRetroBluePalette();
  226. private:
  227. typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList;
  228. struct EditorState
  229. {
  230. Coordinates mSelectionStart;
  231. Coordinates mSelectionEnd;
  232. Coordinates mCursorPosition;
  233. };
  234. class UndoRecord
  235. {
  236. public:
  237. UndoRecord() {}
  238. ~UndoRecord() {}
  239. UndoRecord(
  240. const std::string& aAdded,
  241. const TextEditor::Coordinates aAddedStart,
  242. const TextEditor::Coordinates aAddedEnd,
  243. const std::string& aRemoved,
  244. const TextEditor::Coordinates aRemovedStart,
  245. const TextEditor::Coordinates aRemovedEnd,
  246. TextEditor::EditorState& aBefore,
  247. TextEditor::EditorState& aAfter);
  248. void Undo(TextEditor* aEditor);
  249. void Redo(TextEditor* aEditor);
  250. std::string mAdded;
  251. Coordinates mAddedStart;
  252. Coordinates mAddedEnd;
  253. std::string mRemoved;
  254. Coordinates mRemovedStart;
  255. Coordinates mRemovedEnd;
  256. EditorState mBefore;
  257. EditorState mAfter;
  258. };
  259. typedef std::vector<UndoRecord> UndoBuffer;
  260. void ProcessInputs();
  261. void Colorize(int aFromLine = 0, int aCount = -1);
  262. void ColorizeRange(int aFromLine = 0, int aToLine = 0);
  263. void ColorizeInternal();
  264. float TextDistanceToLineStart(const Coordinates& aFrom) const;
  265. void EnsureCursorVisible();
  266. int GetPageSize() const;
  267. std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
  268. Coordinates GetActualCursorCoordinates() const;
  269. Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
  270. void Advance(Coordinates& aCoordinates) const;
  271. void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
  272. int InsertTextAt(Coordinates& aWhere, const char* aValue);
  273. void AddUndo(UndoRecord& aValue);
  274. Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
  275. Coordinates FindWordStart(const Coordinates& aFrom) const;
  276. Coordinates FindWordEnd(const Coordinates& aFrom) const;
  277. Coordinates FindNextWord(const Coordinates& aFrom) const;
  278. int GetCharacterIndex(const Coordinates& aCoordinates) const;
  279. int GetCharacterColumn(int aLine, int aIndex) const;
  280. int GetLineCharacterCount(int aLine) const;
  281. int GetLineMaxColumn(int aLine) const;
  282. bool IsOnWordBoundary(const Coordinates& aAt) const;
  283. void RemoveLine(int aStart, int aEnd);
  284. void RemoveLine(int aIndex);
  285. Line& InsertLine(int aIndex);
  286. void EnterCharacter(ImWchar aChar, bool aShift);
  287. void Backspace();
  288. void DeleteSelection();
  289. std::string GetWordAt(const Coordinates& aCoords) const;
  290. ImU32 GetGlyphColor(const Glyph& aGlyph) const;
  291. void HandleKeyboardInputs();
  292. void HandleMouseInputs();
  293. void Render();
  294. float mLineSpacing;
  295. Lines mLines;
  296. EditorState mState;
  297. UndoBuffer mUndoBuffer;
  298. int mUndoIndex;
  299. int mTabSize;
  300. bool mOverwrite;
  301. bool mReadOnly;
  302. bool mWithinRender;
  303. bool mScrollToCursor;
  304. bool mScrollToTop;
  305. bool mTextChanged;
  306. bool mColorizerEnabled;
  307. float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor.
  308. int mLeftMargin;
  309. bool mCursorPositionChanged;
  310. int mColorRangeMin, mColorRangeMax;
  311. SelectionMode mSelectionMode;
  312. bool mHandleKeyboardInputs;
  313. bool mHandleMouseInputs;
  314. bool mIgnoreImGuiChild;
  315. bool mShowWhitespaces;
  316. // screen cursor position
  317. float mCursorScreenX;
  318. float mCursorScreenY;
  319. Palette mPaletteBase;
  320. Palette mPalette;
  321. LanguageDefinition mLanguageDefinition;
  322. RegexList mRegexList;
  323. bool mCheckComments;
  324. Breakpoints mBreakpoints;
  325. ErrorMarkers mErrorMarkers;
  326. ImVec2 mCharAdvance;
  327. Coordinates mInteractiveStart, mInteractiveEnd;
  328. std::string mLineBuffer;
  329. uint64_t mStartTime;
  330. float mLastClick;
  331. };