609 ImGuiIO& io = ImGui::GetIO();
610 auto shift = io.KeyShift;
611 auto ctrl = io.ConfigMacOSXBehaviors ? io.KeySuper : io.KeyCtrl;
612 auto alt = io.ConfigMacOSXBehaviors ? io.KeyCtrl : io.KeyAlt;
614 if (ImGui::IsWindowFocused()) {
615 if (ImGui::IsWindowHovered())
616 ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput);
619 io.WantCaptureKeyboard =
true;
620 io.WantTextInput =
true;
622 if (!
IsReadOnly() && ctrl && !shift && !alt &&
623 ImGui::IsKeyPressed(ImGuiKey_Z))
625 else if (!
IsReadOnly() && !ctrl && !shift && alt &&
626 ImGui::IsKeyPressed(ImGuiKey_Backspace))
628 else if (!
IsReadOnly() && ctrl && !shift && !alt &&
629 ImGui::IsKeyPressed(ImGuiKey_Y))
631 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_UpArrow))
633 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_DownArrow))
635 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
637 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_RightArrow))
639 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageUp))
641 else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageDown))
643 else if (!alt && ctrl && ImGui::IsKeyPressed(ImGuiKey_Home))
645 else if (ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
647 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Home))
649 else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
651 else if (!
IsReadOnly() && !ctrl && !shift && !alt &&
652 ImGui::IsKeyPressed(ImGuiKey_Delete))
654 else if (!
IsReadOnly() && !ctrl && !shift && !alt &&
655 ImGui::IsKeyPressed(ImGuiKey_Backspace))
657 else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
659 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
661 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C))
663 else if (!
IsReadOnly() && !ctrl && shift && !alt &&
664 ImGui::IsKeyPressed(ImGuiKey_Insert))
666 else if (!
IsReadOnly() && ctrl && !shift && !alt &&
667 ImGui::IsKeyPressed(ImGuiKey_V))
669 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X))
671 else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
673 else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_A))
675 else if (!
IsReadOnly() && !ctrl && !shift && !alt &&
676 ImGui::IsKeyPressed(ImGuiKey_Enter))
679 ImGui::IsKeyPressed(ImGuiKey_Tab))
682 if (!
IsReadOnly() && !io.InputQueueCharacters.empty()) {
683 for (
int i = 0; i < io.InputQueueCharacters.Size; i++) {
684 auto c = io.InputQueueCharacters[i];
687 io.InputQueueCharacters.resize(0);
767 const float fontSize = ImGui::GetFont()
768 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX,
769 -1.0f,
"#",
nullptr,
nullptr)
772 ImVec2(fontSize, ImGui::GetTextLineHeightWithSpacing() *
mLineSpacing);
776 auto color = ImGui::ColorConvertU32ToFloat4(
mPaletteBase[i]);
777 color.w *= ImGui::GetStyle().Alpha;
778 mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
783 auto contentSize = ImGui::GetWindowContentRegionMax();
784 auto drawList = ImGui::GetWindowDrawList();
789 ImGui::SetScrollY(0.f);
792 ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos();
793 auto scrollX = ImGui::GetScrollX();
794 auto scrollY = ImGui::GetScrollY();
797 auto globalLineMax = (int)
mLines.size();
798 auto lineMax = std::max(
801 lineNo + (
int)floor((scrollY + contentSize.y) /
mCharAdvance.y)));
806 snprintf(buf, 16,
" %d ", globalLineMax);
808 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf,
814 float spaceSize = ImGui::GetFont()
815 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f,
816 " ",
nullptr,
nullptr)
819 while (lineNo <= lineMax) {
820 ImVec2 lineStartScreenPos = ImVec2(
821 cursorScreenPos.x, cursorScreenPos.y + lineNo *
mCharAdvance.y);
822 ImVec2 textScreenPos =
823 ImVec2(lineStartScreenPos.x +
mTextStart, lineStartScreenPos.y);
825 auto& line =
mLines[lineNo];
834 float sstart = -1.0f;
838 if (
mState.mSelectionStart <= lineEndCoord)
839 sstart =
mState.mSelectionStart > lineStartCoord
842 if (
mState.mSelectionEnd > lineStartCoord)
849 if (sstart != -1 && ssend != -1 && sstart < ssend) {
850 ImVec2 vstart(lineStartScreenPos.x +
mTextStart + sstart,
851 lineStartScreenPos.y);
852 ImVec2 vend(lineStartScreenPos.x +
mTextStart + ssend,
854 drawList->AddRectFilled(vstart, vend,
859 auto start = ImVec2(lineStartScreenPos.x + scrollX, lineStartScreenPos.y);
862 auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX,
864 drawList->AddRectFilled(start, end,
871 auto end = ImVec2(lineStartScreenPos.x + contentSize.x + 2.0f * scrollX,
873 drawList->AddRectFilled(start, end,
876 if (ImGui::IsMouseHoveringRect(lineStartScreenPos, end)) {
877 ImGui::BeginTooltip();
878 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.2f, 0.2f, 1.0f));
879 ImGui::Text(
"Error at line %d:", errorIt->first);
880 ImGui::PopStyleColor();
882 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.2f, 1.0f));
883 ImGui::Text(
"%s", errorIt->second.c_str());
884 ImGui::PopStyleColor();
890 snprintf(buf, 16,
"%d ", lineNo + 1);
892 auto lineNoWidth = ImGui::GetFont()
893 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX,
894 -1.0f, buf,
nullptr,
nullptr)
896 drawList->AddText(ImVec2(lineStartScreenPos.x +
mTextStart - lineNoWidth,
897 lineStartScreenPos.y),
900 if (
mState.mCursorPosition.mLine == lineNo) {
901 auto focused = ImGui::IsWindowFocused();
905 auto end = ImVec2(start.x + contentSize.x + scrollX,
907 drawList->AddRectFilled(
911 drawList->AddRect(start, end,
918 std::chrono::duration_cast<std::chrono::milliseconds>(
919 std::chrono::system_clock::now().time_since_epoch())
927 if (
mOverwrite && cindex < (
int)line.size()) {
928 auto c = line[cindex].mChar;
930 auto x = (1.0f + std::floor((1.0f + cx) /
936 buf2[0] = line[cindex].mChar;
938 width = ImGui::GetFont()
939 ->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX,
944 ImVec2 cstart(textScreenPos.x + cx, lineStartScreenPos.y);
945 ImVec2 cend(textScreenPos.x + cx + width,
947 drawList->AddRectFilled(cstart, cend,
959 for (
int i = 0; i < line.size();) {
960 auto& glyph = line[i];
963 if ((color != prevColor || glyph.mChar ==
'\t' || glyph.mChar ==
' ') &&
965 const ImVec2 newOffset(textScreenPos.x + bufferOffset.x,
966 textScreenPos.y + bufferOffset.y);
967 drawList->AddText(newOffset, prevColor,
mLineBuffer.c_str());
968 auto textSize = ImGui::GetFont()->CalcTextSizeA(
969 ImGui::GetFontSize(), FLT_MAX, -1.0f,
mLineBuffer.c_str(),
971 bufferOffset.x += textSize.x;
976 if (glyph.mChar ==
'\t') {
977 auto oldX = bufferOffset.x;
978 bufferOffset.x = (1.0f + std::floor((1.0f + bufferOffset.x) /
984 const auto s = ImGui::GetFontSize();
985 const auto x1 = textScreenPos.x + oldX + 1.0f;
986 const auto x2 = textScreenPos.x + bufferOffset.x - 1.0f;
987 const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f;
988 const ImVec2 p1(x1, y);
989 const ImVec2 p2(x2, y);
990 const ImVec2 p3(x2 - s * 0.2f, y - s * 0.2f);
991 const ImVec2 p4(x2 - s * 0.2f, y + s * 0.2f);
992 drawList->AddLine(p1, p2, 0x90909090);
993 drawList->AddLine(p2, p3, 0x90909090);
994 drawList->AddLine(p2, p4, 0x90909090);
996 }
else if (glyph.mChar ==
' ') {
998 const auto s = ImGui::GetFontSize();
999 const auto x = textScreenPos.x + bufferOffset.x + spaceSize * 0.5f;
1000 const auto y = textScreenPos.y + bufferOffset.y + s * 0.5f;
1001 drawList->AddCircleFilled(ImVec2(x, y), 1.5f, 0x80808080, 4);
1003 bufferOffset.x += spaceSize;
1006 auto l = UTF8CharLength(glyph.mChar);
1007 while (l-- > 0)
mLineBuffer.push_back(line[i++].mChar);
1013 const ImVec2 newOffset(textScreenPos.x + bufferOffset.x,
1014 textScreenPos.y + bufferOffset.y);
1015 drawList->AddText(newOffset, prevColor,
mLineBuffer.c_str());
1023 if (ImGui::IsMousePosValid()) {
1028 ImGui::BeginTooltip();
1029 ImGui::TextUnformatted(it->second.mDeclaration.c_str());
1030 ImGui::EndTooltip();
1034 ImGui::BeginTooltip();
1035 ImGui::TextUnformatted(pi->second.mDeclaration.c_str());
1036 ImGui::EndTooltip();
1047 ImGui::SetWindowFocus();
1143 if (aChar ==
'\t' &&
1144 mState.mSelectionStart.mLine !=
mState.mSelectionEnd.mLine) {
1145 auto start =
mState.mSelectionStart;
1146 auto end =
mState.mSelectionEnd;
1147 auto originalEnd = end;
1149 if (start > end) std::swap(start, end);
1153 if (end.mColumn == 0 && end.mLine > 0) --end.mLine;
1154 if (end.mLine >= (
int)
mLines.size())
1155 end.mLine =
mLines.empty() ? 0 : (int)
mLines.size() - 1;
1165 bool modified =
false;
1167 for (
int i = start.mLine; i <= end.mLine; i++) {
1170 if (!line.empty()) {
1171 if (line.front().mChar ==
'\t') {
1172 line.erase(line.begin());
1176 j <
mTabSize && !line.empty() && line.front().mChar ==
' ';
1178 line.erase(line.begin());
1184 line.insert(line.begin(),
1193 if (originalEnd.mColumn != 0) {
1208 mState.mSelectionStart = start;
1209 mState.mSelectionEnd = end;
1232 if (aChar ==
'\n') {
1234 auto& line =
mLines[coord.mLine];
1235 auto& newLine =
mLines[coord.mLine + 1];
1238 for (
size_t it = 0; it < line.size() && isascii(line[it].mChar) &&
1239 isblank(line[it].mChar);
1241 newLine.push_back(line[it]);
1243 const size_t whitespaceSize = newLine.size();
1245 newLine.insert(newLine.end(), line.begin() + cindex, line.end());
1246 line.erase(line.begin() + cindex, line.begin() + line.size());
1253 int e = ImTextCharToUtf8(buf, 7, aChar);
1256 auto& line =
mLines[coord.mLine];
1259 if (
mOverwrite && cindex < (
int)line.size()) {
1260 auto d = UTF8CharLength(line[cindex].mChar);
1266 while (d-- > 0 && cindex < (
int)line.size()) {
1268 line.erase(line.begin() + cindex);
1272 for (
auto p = buf; *p !=
'\0'; p++, ++cindex)
1935 if (
mLines.empty() || aFromLine >= aToLine)
return;
1938 std::cmatch results;
1941 int endLine = std::max(0, std::min((
int)
mLines.size(), aToLine));
1942 for (
int i = aFromLine; i < endLine; ++i) {
1945 if (line.empty())
continue;
1947 buffer.resize(line.size());
1948 for (
size_t j = 0; j < line.size(); ++j) {
1949 auto& col = line[j];
1950 buffer[j] = col.mChar;
1954 const char* bufferBegin = &buffer.front();
1955 const char* bufferEnd = bufferBegin + buffer.size();
1957 auto last = bufferEnd;
1959 for (
auto first = bufferBegin; first != last;) {
1960 const char* token_begin =
nullptr;
1961 const char* token_end =
nullptr;
1964 bool hasTokenizeResult =
false;
1969 hasTokenizeResult =
true;
1972 if (hasTokenizeResult ==
false) {
1978 if (std::regex_search(first, last, results, p.first,
1979 std::regex_constants::match_continuous)) {
1980 hasTokenizeResult =
true;
1982 auto& v = *results.begin();
1983 token_begin = v.first;
1984 token_end = v.second;
1985 token_color = p.second;
1991 if (hasTokenizeResult ==
false) {
1994 const size_t token_length = token_end - token_begin;
1997 id.assign(token_begin, token_end);
2002 std::transform(
id.begin(),
id.end(),
id.begin(), ::toupper);
2004 if (!line[first - bufferBegin].mPreprocessor) {
2017 for (
size_t j = 0; j < token_length; ++j)
2018 line[(token_begin - bufferBegin) + j].mColorIndex = token_color;
2030 auto endLine =
mLines.size();
2032 auto commentStartLine = endLine;
2033 auto commentStartIndex = endIndex;
2034 auto withinString =
false;
2035 auto withinSingleLineComment =
false;
2036 auto withinPreproc =
false;
2039 auto concatenate =
false;
2040 auto currentLine = 0;
2041 auto currentIndex = 0;
2042 while (currentLine < endLine || currentIndex < endIndex) {
2043 auto& line =
mLines[currentLine];
2045 if (currentIndex == 0 && !concatenate) {
2046 withinSingleLineComment =
false;
2047 withinPreproc =
false;
2051 concatenate =
false;
2053 if (!line.empty()) {
2054 auto& g = line[currentIndex];
2060 if (currentIndex == (
int)line.size() - 1 &&
2061 line[line.size() - 1].mChar ==
'\\')
2064 bool inComment = (commentStartLine < currentLine ||
2065 (commentStartLine == currentLine &&
2066 commentStartIndex <= currentIndex));
2069 line[currentIndex].mMultiLineComment = inComment;
2072 if (currentIndex + 1 < (
int)line.size() &&
2073 line[currentIndex + 1].mChar ==
'\"') {
2075 if (currentIndex < (
int)line.size())
2076 line[currentIndex].mMultiLineComment = inComment;
2078 withinString =
false;
2079 }
else if (c ==
'\\') {
2081 if (currentIndex < (
int)line.size())
2082 line[currentIndex].mMultiLineComment = inComment;
2086 withinPreproc =
true;
2089 withinString =
true;
2090 line[currentIndex].mMultiLineComment = inComment;
2092 auto pred = [](
const char& a,
const Glyph& b) {
2093 return a == b.mChar;
2095 auto from = line.begin() + currentIndex;
2099 if (singleStartStr.size() > 0 &&
2100 currentIndex + singleStartStr.size() <= line.size() &&
2101 equals(singleStartStr.begin(), singleStartStr.end(), from,
2102 from + singleStartStr.size(), pred)) {
2103 withinSingleLineComment =
true;
2104 }
else if (!withinSingleLineComment &&
2105 currentIndex + startStr.size() <= line.size() &&
2106 equals(startStr.begin(), startStr.end(), from,
2107 from + startStr.size(), pred)) {
2108 commentStartLine = currentLine;
2109 commentStartIndex = currentIndex;
2112 inComment = inComment = (commentStartLine < currentLine ||
2113 (commentStartLine == currentLine &&
2114 commentStartIndex <= currentIndex));
2116 line[currentIndex].mMultiLineComment = inComment;
2117 line[currentIndex].mComment = withinSingleLineComment;
2120 if (currentIndex + 1 >= (
int)endStr.size() &&
2121 equals(endStr.begin(), endStr.end(), from + 1 - endStr.size(),
2123 commentStartIndex = endIndex;
2124 commentStartLine = endLine;
2128 line[currentIndex].mPreprocessor = withinPreproc;
2129 currentIndex += UTF8CharLength(c);
2130 if (currentIndex >= (
int)line.size()) {
2143 const int increment =
void SetSelection(const Coordinates &aStart, const Coordinates &aEnd, SelectionMode aMode=SelectionMode::Normal)
bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p)