You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

text_editor.h 11 kB

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