├── .gitignore ├── LICENSE ├── CONTRIBUTING ├── README.md └── TextEditor.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | TextEditor.cpp.bak 34 | *.bak 35 | Save/TextEditor.h 36 | Save/TextEditor.cpp 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 BalazsJako 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Pull requests are welcome, feel free to contribute if you have implemented something which might be useful for the general audience of this little piece of software. Apparently, it became kind of a community project now. :) 3 | 4 | Whem contributing, please follow the following guidelines. I will keep it updated as we bump into something which worth doing better. 5 | - Try to follow the same coding and naming conventions you find in the source already. I know that everyone has its own preference/taste in coding, but please keep the source consistent in style. 6 | - Please submit to the 'dev' branch first for testing, and it will be merged to 'main' if it seems to work fine. I would like try keep 'master' in a good working condition, as more and more people are using it. 7 | - Please send your submissions in small, well defined requests, i. e. do not accumulate many unrelated changes in one large pull request. Keep your submissions as small as possible, it will make everyone's life easier. 8 | - Avoid using ImGui internal since it would make the source fragile against internal changes in ImGui. 9 | - Try to keep the perormance high within the render function. Try to avoid doing anything which leads to memory allocations (like using temporary std::string, std::vector variables), or complex algorithm. If you really have to, try to amortise it between frames. 10 | 11 | Thank you. :) 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImGuiColorTextEdit 2 | Syntax highlighting text editor for ImGui 3 | 4 | ![Screenshot](https://github.com/BalazsJako/ImGuiColorTextEdit/wiki/ImGuiTextEdit.png "Screenshot") 5 | 6 | Demo project: https://github.com/BalazsJako/ColorTextEditorDemo 7 | 8 | This started as my attempt to write a relatively simple widget which provides text editing functionality with syntax highlighting. Now there are other contributors who provide valuable additions. 9 | 10 | While it relies on Omar Cornut's https://github.com/ocornut/imgui, it does not follow the "pure" one widget - one function approach. Since the editor has to maintain a relatively complex and large internal state, it did not seem to be practical to try and enforce fully immediate mode. It stores its internal state in an object instance which is reused across frames. 11 | 12 | The code is (still) work in progress, please report if you find any issues. 13 | 14 | # Main features 15 | - approximates typical code editor look and feel (essential mouse/keyboard commands work - I mean, the commands _I_ normally use :)) 16 | - undo/redo 17 | - UTF-8 support 18 | - works with both fixed and variable-width fonts 19 | - extensible syntax highlighting for multiple languages 20 | - identifier declarations: a small piece of description can be associated with an identifier. The editor displays it in a tooltip when the mouse cursor is hovered over the identifier 21 | - error markers: the user can specify a list of error messages together the line of occurence, the editor will highligh the lines with red backround and display error message in a tooltip when the mouse cursor is hovered over the line 22 | - large files: there is no explicit limit set on file size or number of lines (below 2GB, performance is not affected when large files are loaded (except syntax coloring, see below) 23 | - color palette support: you can switch between different color palettes, or even define your own 24 | - whitespace indicators (TAB, space) 25 | 26 | # Known issues 27 | - syntax highligthing of most languages - except C/C++ - is based on std::regex, which is diasppointingly slow. Because of that, the highlighting process is amortized between multiple frames. C/C++ has a hand-written tokenizer which is much faster. 28 | 29 | Please post your screenshots if you find this little piece of software useful. :) 30 | 31 | # Contribute 32 | 33 | If you want to contribute, please refer to CONTRIBUTE file. 34 | -------------------------------------------------------------------------------- /TextEditor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | class TextEditor { 17 | public: 18 | enum class PaletteIndex { 19 | Default, 20 | Keyword, 21 | Number, 22 | String, 23 | CharLiteral, 24 | Punctuation, 25 | Preprocessor, 26 | Identifier, 27 | KnownIdentifier, 28 | PreprocIdentifier, 29 | Comment, 30 | MultiLineComment, 31 | Background, 32 | Cursor, 33 | Selection, 34 | ErrorMarker, 35 | Breakpoint, 36 | BreakpointOutline, 37 | CurrentLineIndicator, 38 | CurrentLineIndicatorOutline, 39 | LineNumber, 40 | CurrentLineFill, 41 | CurrentLineFillInactive, 42 | CurrentLineEdge, 43 | ErrorMessage, 44 | BreakpointDisabled, 45 | UserFunction, 46 | UserType, 47 | UniformVariable, 48 | GlobalVariable, 49 | LocalVariable, 50 | FunctionArgument, 51 | Max 52 | }; 53 | 54 | enum class ShortcutID { 55 | Undo, 56 | Redo, 57 | MoveUp, 58 | SelectUp, 59 | MoveDown, 60 | SelectDown, 61 | MoveLeft, 62 | SelectLeft, 63 | MoveWordLeft, 64 | SelectWordLeft, 65 | MoveRight, 66 | SelectRight, 67 | MoveWordRight, 68 | SelectWordRight, 69 | MoveUpBlock, 70 | SelectUpBlock, 71 | MoveDownBlock, 72 | SelectDownBlock, 73 | MoveTop, 74 | SelectTop, 75 | MoveBottom, 76 | SelectBottom, 77 | MoveStartLine, 78 | SelectStartLine, 79 | MoveEndLine, 80 | SelectEndLine, 81 | ForwardDelete, 82 | ForwardDeleteWord, 83 | DeleteRight, 84 | BackwardDelete, 85 | BackwardDeleteWord, 86 | DeleteLeft, 87 | OverwriteCursor, 88 | Copy, 89 | Paste, 90 | Cut, 91 | SelectAll, 92 | AutocompleteOpen, 93 | AutocompleteSelect, 94 | AutocompleteSelectActive, 95 | AutocompleteUp, 96 | AutocompleteDown, 97 | NewLine, 98 | Indent, 99 | Unindent, 100 | Find, 101 | Replace, 102 | FindNext, 103 | DebugStep, 104 | DebugStepInto, 105 | DebugStepOut, 106 | DebugContinue, 107 | DebugJumpHere, 108 | DebugBreakpoint, 109 | DebugStop, 110 | DuplicateLine, 111 | CommentLines, 112 | UncommentLines, 113 | Count 114 | }; 115 | 116 | static const int LineNumberSpace = 20; 117 | static const int DebugDataSpace = 10; 118 | 119 | struct Shortcut { 120 | // 0 - not used, 1 - used 121 | bool Alt; 122 | bool Ctrl; 123 | bool Shift; 124 | 125 | // -1 - not used, everything else: Win32 VK_ code 126 | int Key1; 127 | int Key2; 128 | 129 | Shortcut(int vk1 = -1, int vk2 = -2, bool alt = 0, bool ctrl = 0, bool shift = 0) 130 | : Key1(vk1) 131 | , Key2(vk2) 132 | , Alt(alt) 133 | , Ctrl(ctrl) 134 | , Shift(shift) 135 | { 136 | } 137 | }; 138 | 139 | enum class SelectionMode { 140 | Normal, 141 | Word, 142 | Line 143 | }; 144 | 145 | struct Breakpoint { 146 | int mLine; 147 | bool mEnabled; 148 | bool mUseCondition; 149 | std::string mCondition; 150 | 151 | Breakpoint() 152 | : mLine(-1) 153 | , mEnabled(false) 154 | { 155 | } 156 | }; 157 | 158 | // Represents a character coordinate from the user's point of view, 159 | // i. e. consider an uniform grid (assuming fixed-width font) on the 160 | // screen as it is rendered, and each cell has its own coordinate, starting from 0. 161 | // Tabs are counted as [1..mTabSize] count empty spaces, depending on 162 | // how many space is necessary to reach the next tab stop. 163 | // For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize = 4, 164 | // because it is rendered as " ABC" on the screen. 165 | struct Coordinates { 166 | int mLine, mColumn; 167 | Coordinates() 168 | : mLine(0) 169 | , mColumn(0) 170 | { 171 | } 172 | Coordinates(int aLine, int aColumn) 173 | : mLine(aLine) 174 | , mColumn(aColumn) 175 | { 176 | assert(aLine >= 0); 177 | assert(aColumn >= 0); 178 | } 179 | static Coordinates Invalid() 180 | { 181 | static Coordinates invalid(-1, -1); 182 | return invalid; 183 | } 184 | 185 | bool operator==(const Coordinates& o) const 186 | { 187 | return mLine == o.mLine && mColumn == o.mColumn; 188 | } 189 | 190 | bool operator!=(const Coordinates& o) const 191 | { 192 | return mLine != o.mLine || mColumn != o.mColumn; 193 | } 194 | 195 | bool operator<(const Coordinates& o) const 196 | { 197 | if (mLine != o.mLine) 198 | return mLine < o.mLine; 199 | return mColumn < o.mColumn; 200 | } 201 | 202 | bool operator>(const Coordinates& o) const 203 | { 204 | if (mLine != o.mLine) 205 | return mLine > o.mLine; 206 | return mColumn > o.mColumn; 207 | } 208 | 209 | bool operator<=(const Coordinates& o) const 210 | { 211 | if (mLine != o.mLine) 212 | return mLine < o.mLine; 213 | return mColumn <= o.mColumn; 214 | } 215 | 216 | bool operator>=(const Coordinates& o) const 217 | { 218 | if (mLine != o.mLine) 219 | return mLine > o.mLine; 220 | return mColumn >= o.mColumn; 221 | } 222 | }; 223 | 224 | struct Identifier { 225 | Identifier() {} 226 | Identifier(const std::string& declr) 227 | : mDeclaration(declr) 228 | { 229 | } 230 | 231 | Coordinates mLocation; 232 | std::string mDeclaration; 233 | }; 234 | 235 | typedef std::string String; 236 | typedef std::unordered_map Identifiers; 237 | typedef std::unordered_set Keywords; 238 | typedef std::map ErrorMarkers; 239 | typedef std::array Palette; 240 | typedef uint8_t Char; 241 | 242 | struct Glyph { 243 | Char mChar; 244 | PaletteIndex mColorIndex = PaletteIndex::Default; 245 | bool mComment : 1; 246 | bool mMultiLineComment : 1; 247 | bool mPreprocessor : 1; 248 | 249 | Glyph(Char aChar, PaletteIndex aColorIndex) 250 | : mChar(aChar) 251 | , mColorIndex(aColorIndex) 252 | , mComment(false) 253 | , mMultiLineComment(false) 254 | , mPreprocessor(false) 255 | { 256 | } 257 | }; 258 | 259 | typedef std::vector Line; 260 | typedef std::vector Lines; 261 | 262 | struct LanguageDefinition { 263 | typedef std::pair TokenRegexString; 264 | typedef std::vector TokenRegexStrings; 265 | typedef bool (*TokenizeCallback)(const char* in_begin, const char* in_end, const char*& out_begin, const char*& out_end, PaletteIndex& paletteIndex); 266 | 267 | std::string mName; 268 | Keywords mKeywords; 269 | Identifiers mIdentifiers; 270 | Identifiers mPreprocIdentifiers; 271 | std::string mCommentStart, mCommentEnd, mSingleLineComment; 272 | char mPreprocChar; 273 | bool mAutoIndentation; 274 | 275 | TokenizeCallback mTokenize; 276 | 277 | TokenRegexStrings mTokenRegexStrings; 278 | 279 | bool mCaseSensitive; 280 | 281 | LanguageDefinition() 282 | : mPreprocChar('#') 283 | , mAutoIndentation(true) 284 | , mTokenize(nullptr) 285 | , mCaseSensitive(true) 286 | { 287 | } 288 | 289 | static const LanguageDefinition& CPlusPlus(); 290 | static const LanguageDefinition& HLSL(); 291 | static const LanguageDefinition& GLSL(); 292 | static const LanguageDefinition& SPIRV(); 293 | static const LanguageDefinition& C(); 294 | static const LanguageDefinition& SQL(); 295 | static const LanguageDefinition& AngelScript(); 296 | static const LanguageDefinition& Lua(); 297 | 298 | private: 299 | static void m_HLSLDocumentation(Identifiers& idents); 300 | static void m_GLSLDocumentation(Identifiers& idents); 301 | }; 302 | 303 | TextEditor(); 304 | ~TextEditor(); 305 | 306 | void SetLanguageDefinition(const LanguageDefinition& aLanguageDef); 307 | const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; } 308 | 309 | const Palette& GetPalette() const { return mPaletteBase; } 310 | void SetPalette(const Palette& aValue); 311 | 312 | void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; } 313 | 314 | bool HasBreakpoint(int line); 315 | void AddBreakpoint(int line, bool useCondition = false, std::string condition = "", bool enabled = true); 316 | void RemoveBreakpoint(int line); 317 | void SetBreakpointEnabled(int line, bool enable); 318 | Breakpoint& GetBreakpoint(int line); 319 | inline const std::vector& GetBreakpoints() { return mBreakpoints; } 320 | void SetCurrentLineIndicator(int line, bool displayBar = true); 321 | inline int GetCurrentLineIndicator() { return mDebugCurrentLine; } 322 | 323 | inline bool IsDebugging() { return mDebugCurrentLine > 0; } 324 | 325 | void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false); 326 | void SetText(const std::string& aText); 327 | std::string GetText() const; 328 | 329 | void SetTextLines(const std::vector& aLines); 330 | void GetTextLines(std::vector& out) const; 331 | 332 | std::string GetSelectedText() const; 333 | std::string GetCurrentLineText() const; 334 | 335 | int GetTotalLines() const { return (int)mLines.size(); } 336 | bool IsOverwrite() const { return mOverwrite; } 337 | 338 | bool IsFocused() const { return mFocused; } 339 | void SetReadOnly(bool aValue); 340 | bool IsReadOnly() { return mReadOnly || IsDebugging(); } 341 | bool IsTextChanged() const { return mTextChanged; } 342 | bool IsCursorPositionChanged() const { return mCursorPositionChanged; } 343 | inline void ResetTextChanged() 344 | { 345 | mTextChanged = false; 346 | mChangedLines.clear(); 347 | } 348 | 349 | bool IsColorizerEnabled() const { return mColorizerEnabled; } 350 | void SetColorizerEnable(bool aValue); 351 | 352 | Coordinates GetCorrectCursorPosition(); // The GetCursorPosition() returns the cursor pos where \t == 4 spaces 353 | Coordinates GetCursorPosition() const { return GetActualCursorCoordinates(); } 354 | void SetCursorPosition(const Coordinates& aPosition); 355 | 356 | inline void SetHandleMouseInputs(bool aValue) { mHandleMouseInputs = aValue; } 357 | inline bool IsHandleMouseInputsEnabled() const { return mHandleKeyboardInputs; } 358 | 359 | inline void SetHandleKeyboardInputs(bool aValue) { mHandleKeyboardInputs = aValue; } 360 | inline bool IsHandleKeyboardInputsEnabled() const { return mHandleKeyboardInputs; } 361 | 362 | inline void SetImGuiChildIgnored(bool aValue) { mIgnoreImGuiChild = aValue; } 363 | inline bool IsImGuiChildIgnored() const { return mIgnoreImGuiChild; } 364 | 365 | inline void SetShowWhitespaces(bool aValue) { mShowWhitespaces = aValue; } 366 | inline bool IsShowingWhitespaces() const { return mShowWhitespaces; } 367 | 368 | void InsertText(const std::string& aValue, bool indent = false); 369 | void InsertText(const char* aValue, bool indent = false); 370 | 371 | void MoveUp(int aAmount = 1, bool aSelect = false); 372 | void MoveDown(int aAmount = 1, bool aSelect = false); 373 | void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false); 374 | void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false); 375 | void MoveTop(bool aSelect = false); 376 | void MoveBottom(bool aSelect = false); 377 | void MoveHome(bool aSelect = false); 378 | void MoveEnd(bool aSelect = false); 379 | 380 | void SetSelectionStart(const Coordinates& aPosition); 381 | void SetSelectionEnd(const Coordinates& aPosition); 382 | void SetSelection(const Coordinates& aStart, const Coordinates& aEnd, SelectionMode aMode = SelectionMode::Normal); 383 | void SelectWordUnderCursor(); 384 | void SelectAll(); 385 | bool HasSelection() const; 386 | 387 | void Copy(); 388 | void Cut(); 389 | void Paste(); 390 | void Delete(); 391 | 392 | bool CanUndo(); 393 | bool CanRedo(); 394 | void Undo(int aSteps = 1); 395 | void Redo(int aSteps = 1); 396 | 397 | std::vector GetRelevantExpressions(int line); 398 | 399 | inline void SetHighlightedLines(const std::vector& lines) { mHighlightedLines = lines; } 400 | inline void ClearHighlightedLines() { mHighlightedLines.clear(); } 401 | 402 | inline void SetTabSize(int s) { mTabSize = std::max(0, std::min(32, s)); } 403 | inline int GetTabSize() { return mTabSize; } 404 | 405 | inline void SetInsertSpaces(bool s) { mInsertSpaces = s; } 406 | inline int GetInsertSpaces() { return mInsertSpaces; } 407 | 408 | inline void SetSmartIndent(bool s) { mSmartIndent = s; } 409 | inline void SetAutoIndentOnPaste(bool s) { mAutoindentOnPaste = s; } 410 | inline void SetHighlightLine(bool s) { mHighlightLine = s; } 411 | inline void SetCompleteBraces(bool s) { mCompleteBraces = s; } 412 | inline void SetHorizontalScroll(bool s) { mHorizontalScroll = s; } 413 | inline void SetSmartPredictions(bool s) { mAutocomplete = s; } 414 | inline void SetFunctionDeclarationTooltip(bool s) { mFunctionDeclarationTooltipEnabled = s; } 415 | inline void SetFunctionTooltips(bool s) { mFuncTooltips = s; } 416 | inline void SetActiveAutocomplete(bool cac) { mActiveAutocomplete = cac; } 417 | inline void SetScrollbarMarkers(bool markers) { mScrollbarMarkers = markers; } 418 | inline void SetSidebarVisible(bool s) { mSidebar = s; } 419 | inline void SetSearchEnabled(bool s) { mHasSearch = s; } 420 | inline void SetHiglightBrackets(bool s) { mHighlightBrackets = s; } 421 | inline void SetFoldEnabled(bool s) { mFoldEnabled = s; } 422 | 423 | inline void SetUIScale(float scale) { mUIScale = scale; } 424 | inline void SetUIFontSize(float size) { mUIFontSize = size; } 425 | inline void SetEditorFontSize(float size) { mEditorFontSize = size; } 426 | 427 | void SetShortcut(TextEditor::ShortcutID id, Shortcut s); 428 | 429 | inline void SetShowLineNumbers(bool s) 430 | { 431 | mShowLineNumbers = s; 432 | mTextStart = (s ? 20 : 6); 433 | mLeftMargin = (s ? (DebugDataSpace + LineNumberSpace) : (DebugDataSpace - LineNumberSpace)); 434 | } 435 | inline int GetTextStart() const { return mShowLineNumbers ? 7 : 3; } 436 | 437 | void Colorize(int aFromLine = 0, int aCount = -1); 438 | void ColorizeRange(int aFromLine = 0, int aToLine = 0); 439 | void ColorizeInternal(); 440 | 441 | inline void ClearAutocompleteData() 442 | { 443 | mACFunctions.clear(); 444 | mACUserTypes.clear(); 445 | mACUniforms.clear(); 446 | mACGlobals.clear(); 447 | } 448 | inline void ClearAutocompleteEntries() 449 | { 450 | mACEntries.clear(); 451 | mACEntrySearch.clear(); 452 | } 453 | inline const std::unordered_map& GetAutocompleteFunctions() { return mACFunctions; } 454 | inline const std::unordered_map>& GetAutocompleteUserTypes() { return mACUserTypes; } 455 | inline const std::vector& GetAutocompleteUniforms() { return mACUniforms; } 456 | inline const std::vector& GetAutocompleteGlobals() { return mACGlobals; } 457 | inline void SetAutocompleteFunctions(const std::unordered_map& funcs) 458 | { 459 | mACFunctions = funcs; 460 | } 461 | inline void SetAutocompleteUserTypes(const std::unordered_map>& utypes) 462 | { 463 | mACUserTypes = utypes; 464 | } 465 | inline void SetAutocompleteUniforms(const std::vector& unis) 466 | { 467 | mACUniforms = unis; 468 | } 469 | inline void SetAutocompleteGlobals(const std::vector& globs) 470 | { 471 | mACGlobals = globs; 472 | } 473 | inline void AddAutocompleteEntry(const std::string& search, const std::string& display, const std::string& value) 474 | { 475 | mACEntrySearch.push_back(search); 476 | mACEntries.push_back(std::make_pair(display, value)); 477 | } 478 | 479 | static const std::vector GetDefaultShortcuts(); 480 | static const Palette& GetDarkPalette(); 481 | static const Palette& GetLightPalette(); 482 | static const Palette& GetRetroBluePalette(); 483 | 484 | enum class DebugAction 485 | { 486 | Step, 487 | StepInto, 488 | StepOut, 489 | Continue, 490 | Stop 491 | }; 492 | 493 | std::function OnDebuggerJump; 494 | std::function OnDebuggerAction; 495 | std::function OnIdentifierHover; 496 | std::function HasIdentifierHover; 497 | std::function OnExpressionHover; 498 | std::function HasExpressionHover; 499 | std::function OnBreakpointRemove; 500 | std::function OnBreakpointUpdate; 501 | 502 | std::function OnCtrlAltClick; 503 | std::function RequestOpen; 504 | std::function OnContentUpdate; 505 | 506 | inline void SetPath(const std::string& path) { mPath = path; } 507 | inline const std::string& GetPath() { return mPath; } 508 | 509 | private: 510 | std::string mPath; 511 | 512 | typedef std::vector> RegexList; 513 | 514 | struct EditorState 515 | { 516 | Coordinates mSelectionStart; 517 | Coordinates mSelectionEnd; 518 | Coordinates mCursorPosition; 519 | }; 520 | 521 | class UndoRecord 522 | { 523 | public: 524 | UndoRecord() {} 525 | ~UndoRecord() {} 526 | 527 | UndoRecord( 528 | const std::string& aAdded, 529 | const TextEditor::Coordinates aAddedStart, 530 | const TextEditor::Coordinates aAddedEnd, 531 | 532 | const std::string& aRemoved, 533 | const TextEditor::Coordinates aRemovedStart, 534 | const TextEditor::Coordinates aRemovedEnd, 535 | 536 | TextEditor::EditorState& aBefore, 537 | TextEditor::EditorState& aAfter); 538 | 539 | void Undo(TextEditor* aEditor); 540 | void Redo(TextEditor* aEditor); 541 | 542 | std::string mAdded; 543 | Coordinates mAddedStart; 544 | Coordinates mAddedEnd; 545 | 546 | std::string mRemoved; 547 | Coordinates mRemovedStart; 548 | Coordinates mRemovedEnd; 549 | 550 | EditorState mBefore; 551 | EditorState mAfter; 552 | }; 553 | 554 | typedef std::vector UndoBuffer; 555 | 556 | void ProcessInputs(); 557 | float TextDistanceToLineStart(const Coordinates& aFrom) const; 558 | void EnsureCursorVisible(); 559 | int GetPageSize() const; 560 | std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const; 561 | Coordinates GetActualCursorCoordinates() const; 562 | Coordinates SanitizeCoordinates(const Coordinates& aValue) const; 563 | void Advance(Coordinates& aCoordinates) const; 564 | void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd); 565 | int InsertTextAt(Coordinates& aWhere, const char* aValue, bool indent = false); 566 | void AddUndo(UndoRecord& aValue); 567 | Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const; 568 | Coordinates MousePosToCoordinates(const ImVec2& aPosition) const; 569 | ImVec2 CoordinatesToScreenPos(const TextEditor::Coordinates& aPosition) const; 570 | Coordinates FindWordStart(const Coordinates& aFrom) const; 571 | Coordinates FindWordEnd(const Coordinates& aFrom) const; 572 | Coordinates FindNextWord(const Coordinates& aFrom) const; 573 | int GetCharacterIndex(const Coordinates& aCoordinates) const; 574 | int GetCharacterColumn(int aLine, int aIndex) const; 575 | int GetLineCharacterCount(int aLine) const; 576 | int GetLineMaxColumn(int aLine) const; 577 | bool IsOnWordBoundary(const Coordinates& aAt) const; 578 | void RemoveLine(int aStart, int aEnd); 579 | void RemoveLine(int aIndex); 580 | Line& InsertLine(int aIndex, int column); 581 | void EnterCharacter(ImWchar aChar, bool aShift); 582 | void Backspace(); 583 | void DeleteSelection(); 584 | std::string GetWordUnderCursor() const; 585 | std::string GetWordAt(const Coordinates& aCoords) const; 586 | ImU32 GetGlyphColor(const Glyph& aGlyph) const; 587 | 588 | Coordinates FindFirst(const std::string& what, const Coordinates& fromWhere); 589 | 590 | void HandleKeyboardInputs(); 591 | void HandleMouseInputs(); 592 | void RenderInternal(const char* aTitle); 593 | 594 | bool mFuncTooltips; 595 | 596 | float mUIScale, mUIFontSize, mEditorFontSize; 597 | inline float mUICalculateSize(float h) 598 | { 599 | return h * (mUIScale + mUIFontSize / 18.0f - 1.0f); 600 | } 601 | inline float mEditorCalculateSize(float h) 602 | { 603 | return h * (mUIScale + mEditorFontSize / 18.0f - 1.0f); 604 | } 605 | 606 | bool mFunctionDeclarationTooltipEnabled; 607 | TextEditor::Coordinates mFunctionDeclarationCoord; 608 | bool mFunctionDeclarationTooltip; 609 | std::string mFunctionDeclaration; 610 | void mOpenFunctionDeclarationTooltip(const std::string& obj, TextEditor::Coordinates coord); 611 | 612 | std::string mBuildFunctionDef(const std::string& func, const std::string& lang); 613 | std::string mBuildVariableType(const ed::SPIRVParser::Variable& var, const std::string& lang); 614 | 615 | float mLineSpacing; 616 | Lines mLines; 617 | EditorState mState; 618 | UndoBuffer mUndoBuffer; 619 | int mUndoIndex; 620 | int mReplaceIndex; 621 | 622 | bool mSidebar; 623 | bool mHasSearch; 624 | 625 | char mFindWord[256]; 626 | bool mFindOpened; 627 | bool mFindJustOpened; 628 | bool mFindNext; 629 | bool mFindFocused, mReplaceFocused; 630 | bool mReplaceOpened; 631 | char mReplaceWord[256]; 632 | 633 | bool mFoldEnabled; 634 | std::vector mFoldBegin, mFoldEnd; 635 | std::vector mFoldConnection; 636 | std::vector mFold; 637 | bool mFoldSorted; 638 | void mRemoveFolds(const Coordinates& start, const Coordinates& end); 639 | void mRemoveFolds(std::vector& folds, const Coordinates& start, const Coordinates& end); 640 | uint64_t mFoldLastIteration; 641 | float mLastScroll; 642 | 643 | std::vector mACEntrySearch; 644 | std::vector> mACEntries; 645 | 646 | bool mIsSnippet; 647 | std::vector mSnippetTagStart, mSnippetTagEnd; 648 | std::vector mSnippetTagID; 649 | std::vector mSnippetTagHighlight; 650 | int mSnippetTagSelected, mSnippetTagLength, mSnippetTagPreviousLength; 651 | std::string mAutcompleteParse(const std::string& str, const Coordinates& start); 652 | void mAutocompleteSelect(); 653 | 654 | bool m_requestAutocomplete, m_readyForAutocomplete; 655 | void m_buildMemberSuggestions(bool* keepACOpened = nullptr); 656 | void m_buildSuggestions(bool* keepACOpened = nullptr); 657 | bool mActiveAutocomplete; 658 | bool mAutocomplete; 659 | std::unordered_map mACFunctions; 660 | std::unordered_map> mACUserTypes; 661 | std::vector mACUniforms; 662 | std::vector mACGlobals; 663 | std::string mACWord; 664 | std::vector> mACSuggestions; 665 | int mACIndex; 666 | bool mACOpened; 667 | bool mACSwitched; // if == true then allow selection with enter 668 | std::string mACObject; // if mACObject is not empty, it means user typed '.' -> suggest struct members and methods for mACObject 669 | Coordinates mACPosition; 670 | 671 | std::vector m_shortcuts; 672 | 673 | bool mScrollbarMarkers; 674 | std::vector mChangedLines; 675 | 676 | std::vector mHighlightedLines; 677 | 678 | bool mHorizontalScroll; 679 | bool mCompleteBraces; 680 | bool mShowLineNumbers; 681 | bool mHighlightLine; 682 | bool mHighlightBrackets; 683 | bool mInsertSpaces; 684 | bool mSmartIndent; 685 | bool mFocused; 686 | int mTabSize; 687 | bool mOverwrite; 688 | bool mReadOnly; 689 | bool mWithinRender; 690 | bool mScrollToCursor; 691 | bool mScrollToTop; 692 | bool mTextChanged; 693 | bool mColorizerEnabled; 694 | float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor. 695 | int mLeftMargin; 696 | bool mCursorPositionChanged; 697 | int mColorRangeMin, mColorRangeMax; 698 | SelectionMode mSelectionMode; 699 | bool mHandleKeyboardInputs; 700 | bool mHandleMouseInputs; 701 | bool mIgnoreImGuiChild; 702 | bool mShowWhitespaces; 703 | bool mAutoindentOnPaste; 704 | 705 | Palette mPaletteBase; 706 | Palette mPalette; 707 | LanguageDefinition mLanguageDefinition; 708 | RegexList mRegexList; 709 | 710 | float mDebugBarWidth, mDebugBarHeight; 711 | 712 | bool mDebugBar; 713 | bool mDebugCurrentLineUpdated; 714 | int mDebugCurrentLine; 715 | ImVec2 mUICursorPos, mFindOrigin; 716 | float mWindowWidth; 717 | std::vector mBreakpoints; 718 | ImVec2 mRightClickPos; 719 | 720 | int mPopupCondition_Line; 721 | bool mPopupCondition_Use; 722 | char mPopupCondition_Condition[512]; 723 | 724 | bool mCheckComments; 725 | ErrorMarkers mErrorMarkers; 726 | ImVec2 mCharAdvance; 727 | Coordinates mInteractiveStart, mInteractiveEnd; 728 | std::string mLineBuffer; 729 | uint64_t mStartTime; 730 | 731 | Coordinates mLastHoverPosition; 732 | std::chrono::steady_clock::time_point mLastHoverTime; 733 | 734 | float mLastClick; 735 | }; --------------------------------------------------------------------------------