From 219f588cbe10c75339865a7c60884c4c2c5085de Mon Sep 17 00:00:00 2001 From: paxcut Date: Fri, 16 Jan 2026 08:25:33 -0700 Subject: [PATCH] Made code faster and cleaned some code. --- .../text_highlighting/pattern_language.hpp | 62 +- .../content/views/view_pattern_editor.hpp | 2 +- .../text_highlighting/pattern_language.cpp | 579 +++++++++--------- .../content/views/view_pattern_editor.cpp | 35 +- plugins/ui/include/ui/text_editor.hpp | 346 ++++++----- .../ui/source/ui/text_editor/codeFolder.cpp | 338 +++++----- plugins/ui/source/ui/text_editor/editor.cpp | 138 ++--- .../ui/source/ui/text_editor/highlighter.cpp | 9 +- plugins/ui/source/ui/text_editor/navigate.cpp | 41 +- plugins/ui/source/ui/text_editor/render.cpp | 244 ++++---- plugins/ui/source/ui/text_editor/support.cpp | 190 ++---- plugins/ui/source/ui/text_editor/utf8.cpp | 29 +- 12 files changed, 928 insertions(+), 1085 deletions(-) diff --git a/plugins/builtin/include/content/text_highlighting/pattern_language.hpp b/plugins/builtin/include/content/text_highlighting/pattern_language.hpp index 9745e01bd..aecc62259 100644 --- a/plugins/builtin/include/content/text_highlighting/pattern_language.hpp +++ b/plugins/builtin/include/content/text_highlighting/pattern_language.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace hex::plugin::builtin { class ViewPatternEditor; @@ -48,13 +49,13 @@ namespace hex::plugin::builtin { bool operator>=(const TokenInterval &other) const { return m_end >= other.m_end; } - bool contains(const TokenInterval &other) const { + [[nodiscard]] bool contains(const TokenInterval &other) const { return other.m_start >= m_start && other.m_end <= m_end; } - bool contains(i32 value) const { + [[nodiscard]] bool contains(i32 value) const { return value >= m_start && value <= m_end; } - bool contiguous(const TokenInterval &other) const { + [[nodiscard]] bool contiguous(const TokenInterval &other) const { auto highEndDiff = m_start - other.m_end; auto lowEndDiff = other.m_start - m_end; return highEndDiff == 0 || highEndDiff == 1 || lowEndDiff == 0 || lowEndDiff == 1; @@ -75,10 +76,11 @@ namespace hex::plugin::builtin { using OrderedBlocks = std::map; using Scopes = std::set; using Location = pl::core::Location; - using VectorString = std::vector; - using TokenIter = pl::hlp::SafeIterator::const_iterator>; + using StringVector = std::vector; + using StringSet = std::set; + using SafeTokenIterator = pl::hlp::SafeIterator::const_iterator>; using VariableScopes = std::map; - using Inheritances = std::map; + using Inheritances = std::map; using IdentifierTypeColor = std::map; using TokenTypeColor = std::map; using TokenColor = std::map; @@ -88,17 +90,18 @@ namespace hex::plugin::builtin { using CompileErrors = std::vector; using TokenSequence = std::vector; using TokenIdVector = std::vector; + using TokenIdSet = std::set; using Instances = std::map>; using CodeFoldBlocks = ui::TextEditor::CodeFoldBlocks; struct ParentDefinition; struct Definition { Definition()= default; - Definition(IdentifierType identifierType, std::string typeStr,i32 tokenId, Location location) : idType(identifierType), typeStr(typeStr), tokenIndex(tokenId),location(location) {} - IdentifierType idType; + Definition(IdentifierType identifierType, std::string typeStr,i32 tokenId, Location location) : idType(identifierType), typeStr(std::move(typeStr)), tokenIndex(tokenId),location(location) {} + IdentifierType idType{}; std::string typeStr; - i32 tokenIndex; - Location location; + i32 tokenIndex{}; + Location location{}; }; struct ParentDefinition { @@ -114,13 +117,13 @@ namespace hex::plugin::builtin { private: TextHighlighter *m_textHighlighter; Types definedTypes; - VectorString usedNamespaces; + StringVector usedNamespaces; ParsedImports parsedImports; Str2StrMap importedHeaders; TokenSequence fullTokens; std::string editedText; CompileErrors compileErrors; - VectorString linesOfColors; + StringVector linesOfColors; public: RequiredInputs() : m_textHighlighter(nullptr) {}; explicit RequiredInputs(TextHighlighter *textHighlighter) : m_textHighlighter(textHighlighter) {} @@ -140,9 +143,9 @@ namespace hex::plugin::builtin { inline static const Coordinates Invalid = Coordinates(0x80000000, 0x80000000); private: - VectorString m_lines; + StringVector m_lines; TokenIdVector m_firstTokenIdOfLine; - ViewPatternEditor *m_viewPatternEditor; + ViewPatternEditor *m_viewPatternEditor{}; TokenColor m_tokenColors; @@ -166,14 +169,15 @@ namespace hex::plugin::builtin { Str2StrMap m_typeDefMap; Str2StrMap m_typeDefInvMap; - VectorString m_UDTs; - std::set m_taggedIdentifiers; - std::set m_memberChains; - std::set m_scopeChains; + StringVector m_UDTs; + TokenIdSet m_taggedIdentifiers; + TokenIdSet m_memberChains; + TokenIdSet m_scopeChains; + TokenIdSet m_identifierTokenIds; RequiredInputs m_requiredInputs; - TokenIter m_curr; - TokenIter m_startToken, m_originalPosition, m_partOriginalPosition; + SafeTokenIterator m_curr; + SafeTokenIterator m_startToken, m_originalPosition, m_partOriginalPosition; VariableScopes m_UDTBlocks; VariableScopes m_functionBlocks; @@ -187,17 +191,13 @@ namespace hex::plugin::builtin { constexpr static u32 Normal = 0; constexpr static u32 Not = 1; - //std::atomic m_needsToUpdateColors = true; - //std::atomic m_wasInterrupted = false; - //std::atomic m_interrupt = false; - //std::atomic m_completed = false; - pl::PatternLanguage *getPatternLanguage(); void updateRequiredInputs(); RequiredInputs& getRequiredInputs(); ViewPatternEditor* getViewPatternEditor(); void setViewPatternEditor(ViewPatternEditor *viewPatternEditor); + void setTokenIds(); TextHighlighter(); ~TextHighlighter(); explicit TextHighlighter(ViewPatternEditor *viewPatternEditor) : m_viewPatternEditor(viewPatternEditor) {} @@ -298,8 +298,8 @@ namespace hex::plugin::builtin { bool findIdentifierDefinition(Definition &result, const std::string &optionalIdentifierName = "", std::string optionalName = "", bool optional = false); /// To deal with the Parent keyword std::optional setChildrenTypes(); - bool findParentTypes(VectorString &parentTypes, const std::string &optionalName=""); - bool findAllParentTypes(VectorString &parentTypes, std::vector &identifiers, std::string &optionalFullName); + bool findParentTypes(StringVector &parentTypes, const std::string &optionalName=""); + bool findAllParentTypes(StringVector &parentTypes, std::vector &identifiers, std::string &optionalFullName); bool tryParentType(const std::string &parentType, std::string &variableName, std::optional &result, std::vector &identifiers); /// Convenience function bool isTokenIdValid(i32 tokenId); @@ -312,6 +312,8 @@ namespace hex::plugin::builtin { pl::core::Location getLocation(i32 tokenId); /// Calculate the token index of a source code, line and column numbers i32 getTokenId(pl::core::Location location); + i32 getTokenId(SafeTokenIterator tokenIterator); + i32 getTokenId(); /// Calculate the function or template argument position from token indices i32 getArgumentNumber(i32 start,i32 arg); /// Calculate the token index of a function or template argument position @@ -322,18 +324,18 @@ namespace hex::plugin::builtin { /// The following functions were copied from the parser and some were modified - template T *getValue(const i32 index); + template T *getValue(i32 index); void next(i32 count = 1); bool begin(); void partBegin(); void reset(); void partReset(); - bool resetIfFailed(const bool value) ; + bool resetIfFailed(bool value) ; template bool sequenceImpl(); template bool matchOne(const Token &token); template bool sequenceImpl(const auto &... args); template bool sequence(const Token &token, const auto &... args); bool isValid(); - bool peek(const Token &token, const i32 index = 0); + bool peek(const Token &token, i32 index = 0); }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 90654c130..70ead21a3 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -140,7 +140,7 @@ namespace hex::plugin::builtin { PerProvider m_cursorPosition; PerProvider m_scroll; PerProvider m_consoleScroll; - + PerProvider m_codeFoldState; PerProvider m_consoleCursorPosition; PerProvider m_selection; PerProvider m_consoleSelection; diff --git a/plugins/builtin/source/content/text_highlighting/pattern_language.cpp b/plugins/builtin/source/content/text_highlighting/pattern_language.cpp index 24b622933..3ed10e55b 100644 --- a/plugins/builtin/source/content/text_highlighting/pattern_language.cpp +++ b/plugins/builtin/source/content/text_highlighting/pattern_language.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -26,6 +25,7 @@ namespace hex::plugin::builtin { using TokenInterval = TextHighlighter::TokenInterval; using CodeFoldBlocks = TextHighlighter::CodeFoldBlocks; using Coordinates = TextHighlighter::Coordinates; + using StringSet = TextHighlighter::StringSet; void TextHighlighter::next(i32 count) { if (m_viewPatternEditor->interrupted()) { @@ -34,7 +34,7 @@ namespace hex::plugin::builtin { } if (count == 0) return; - i32 id = getTokenId(m_curr->location); + i32 id = getTokenId(); i32 maxChange; if (count > 0) maxChange = std::min(count,static_cast(m_requiredInputs.fullTokens.size() - id)); @@ -48,12 +48,12 @@ namespace hex::plugin::builtin { } void TextHighlighter::RequiredInputs::setTypes() { - auto &types = m_textHighlighter->getPatternLanguage()->getInternals().parser.get()->getTypes(); + auto &types = m_textHighlighter->getPatternLanguage()->getInternals().parser->getTypes(); std::ranges::copy(types.begin(), types.end(), std::inserter(definedTypes, definedTypes.begin())); } void TextHighlighter::RequiredInputs::setNamespaces() { - auto &namespaces = m_textHighlighter->getPatternLanguage()->getInternals().preprocessor.get()->getNamespaces(); + auto &namespaces = m_textHighlighter->getPatternLanguage()->getInternals().preprocessor->getNamespaces(); usedNamespaces.resize(namespaces.size()); std::ranges::copy(namespaces, usedNamespaces.begin()); } @@ -78,14 +78,14 @@ namespace hex::plugin::builtin { if (editor == nullptr) return; fullTokens.clear(); - auto &result = m_textHighlighter->getPatternLanguage()->getInternals().preprocessor.get()->getResult(); + auto &result = m_textHighlighter->getPatternLanguage()->getInternals().preprocessor->getResult(); std::ranges::copy(result.begin(),result.end(),std::back_inserter(fullTokens)); editedText = editor->getText(); m_textHighlighter->loadText();; linesOfColors.clear(); for (auto &line : m_textHighlighter->m_lines) - linesOfColors.push_back(std::string(line.size(), ' ')); + linesOfColors.emplace_back(line.size(), ' '); } void TextHighlighter::RequiredInputs::setCompileErrors() { @@ -202,15 +202,13 @@ namespace hex::plugin::builtin { return false; return false; } - if (!isLocationValid(token.location)) - return false; - return true; + return isLocationValid(token.location); } bool TextHighlighter::peek(const Token &token, const i32 index) { if (!isValid()) return false; - i32 id = getTokenId(m_curr->location); + i32 id = getTokenId(); if (id+index < 0 || id+index >= (i32)m_requiredInputs.fullTokens.size()) return false; return m_curr[index].type == token.type && m_curr[index] == token.value; @@ -239,14 +237,14 @@ namespace hex::plugin::builtin { return false; } - TextHighlighter::TextHighlighter() {} - TextHighlighter::~TextHighlighter() {} + TextHighlighter::TextHighlighter() = default; + TextHighlighter::~TextHighlighter() = default; // Returns a chain of identifiers like a.b.c or a::b::c bool TextHighlighter::getFullName(std::string &identifierName, std::vector &identifiers, bool preserveCurr) { Identifier *identifier = nullptr; - if (!peek(tkn::Literal::Identifier) || getTokenId(m_curr->location) < 1) + if (!peek(tkn::Literal::Identifier) || getTokenId() < 1) return getIdentifierName(identifierName, identifier); forwardIdentifierName(identifierName, identifiers, preserveCurr); @@ -374,7 +372,7 @@ namespace hex::plugin::builtin { while (m_curr != m_startToken + interval.m_end) { if (sequence(tkn::Separator::LeftBrace)) { - auto tokenId = getTokenId(m_curr[-1].location); + auto tokenId = getTokenId() - 1; tokenStack.push_back(tokenId); nestedLevel++; } else if (sequence(tkn::Separator::RightBrace)) { @@ -382,7 +380,7 @@ namespace hex::plugin::builtin { if (tokenStack.empty()) return result; - TokenInterval range(tokenStack.back(), getTokenId(m_curr[-1].location)); + TokenInterval range(tokenStack.back(), getTokenId() - 1); tokenStack.pop_back(); result.push_back(range); @@ -405,7 +403,7 @@ namespace hex::plugin::builtin { OrderedBlocks &tokenRangeInv, bool fullName, VariableScopes *blocks) { bool addArgumentBlock = !fullName; - if (getTokenId(m_curr->location) < 1) + if (getTokenId() < 1) return false; std::string name; if (fullName) { @@ -417,7 +415,7 @@ namespace hex::plugin::builtin { if (!getIdentifierName(name, identifier)) return false; std::string nameSpace; - findNamespace(nameSpace, getTokenId(m_curr->location)); + findNamespace(nameSpace, getTokenId()); if (!nameSpace.empty()) name = fmt::format("{}::{}", nameSpace, name); } @@ -433,7 +431,7 @@ namespace hex::plugin::builtin { if (!getFullName(identifierName, identifiers, false)) break; if (std::ranges::find(m_inheritances[name], identifierName) == m_inheritances[name].end()) - m_inheritances[name].push_back(identifierName); + m_inheritances[name].insert(identifierName); skipTemplate(200); next(2); } @@ -442,7 +440,7 @@ namespace hex::plugin::builtin { m_curr = saveCurr; if (peek(tkn::ValueType::Auto)) next(-1); - i32 index1 = getTokenId(m_curr->location); + i32 index1 = getTokenId(); bool result = true; for (const auto &keyword: keywords) result = result && !peek(keyword); @@ -455,7 +453,7 @@ namespace hex::plugin::builtin { //if (peek(tkn::Separator::EndOfProgram),-1) // return false; - i32 index2 = getTokenId(m_curr->location); + i32 index2 = getTokenId(); if (index2 > index1 && index2 < tokenCount) { if (fullName) { @@ -483,42 +481,36 @@ namespace hex::plugin::builtin { Identifier *identifier; IdentifierType identifierType; - m_startToken = TokenIter(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); - auto endToken = TokenIter(m_requiredInputs.fullTokens.end(), m_requiredInputs.fullTokens.end()); - for (m_curr = m_startToken; endToken > m_curr; next()) { - auto curr = m_curr; + m_startToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); + for (auto tokenId : m_identifierTokenIds) { + m_curr = m_startToken + tokenId; + if (identifier = getValue(0); identifier != nullptr) { + identifierType = identifier->getType(); + auto& name = identifier->get(); - if (peek(tkn::Literal::Identifier)) { - if (identifier = getValue(0); identifier != nullptr) { - identifierType = identifier->getType(); - auto& name = identifier->get(); - - if (identifierType == identifierTypeToSearch) { - switch (identifierType) { - case IdentifierType::Function: - if (!m_functionTokenRange.contains(name)) - getTokenRange({tkn::Keyword::Function}, m_functionTokenRange, m_namespaceTokenRange, false, &m_functionBlocks); - break; - case IdentifierType::NameSpace: - if (std::ranges::find(m_requiredInputs.usedNamespaces, name) == m_requiredInputs.usedNamespaces.end()) - m_requiredInputs.usedNamespaces.push_back(name); - getTokenRange({tkn::Keyword::Namespace}, m_functionTokenRange, m_namespaceTokenRange, true, nullptr); - break; - case IdentifierType::UDT: - if (!m_UDTTokenRange.contains(name)) - getTokenRange({tkn::Keyword::Struct, tkn::Keyword::Union, tkn::Keyword::Enum, tkn::Keyword::Bitfield}, m_UDTTokenRange, m_namespaceTokenRange, false, &m_UDTBlocks); - break; - case IdentifierType::Attribute: - linkAttribute(); - break; - default: - break; - } + if (identifierType == identifierTypeToSearch) { + switch (identifierType) { + case IdentifierType::Function: + if (!m_functionTokenRange.contains(name)) + getTokenRange({tkn::Keyword::Function}, m_functionTokenRange, m_namespaceTokenRange, false, &m_functionBlocks); + break; + case IdentifierType::NameSpace: + if (std::ranges::find(m_requiredInputs.usedNamespaces, name) == m_requiredInputs.usedNamespaces.end()) + m_requiredInputs.usedNamespaces.push_back(name); + getTokenRange({tkn::Keyword::Namespace}, m_functionTokenRange, m_namespaceTokenRange, true, nullptr); + break; + case IdentifierType::UDT: + if (!m_UDTTokenRange.contains(name)) + getTokenRange({tkn::Keyword::Struct, tkn::Keyword::Union, tkn::Keyword::Enum, tkn::Keyword::Bitfield}, m_UDTTokenRange, m_namespaceTokenRange, false, &m_UDTBlocks); + break; + case IdentifierType::Attribute: + linkAttribute(); + break; + default: + break; } } - } else if (peek(tkn::Separator::EndOfProgram)) - return; - m_curr = curr; + } } } @@ -529,7 +521,7 @@ namespace hex::plugin::builtin { if (!isValid()) return; - i32 tokenId = getTokenId(m_curr->location); + i32 tokenId = getTokenId(); auto tokenCount = m_requiredInputs.fullTokens.size(); if (tokenId == -1 || tokenId >= (i32) tokenCount-1) @@ -559,12 +551,12 @@ namespace hex::plugin::builtin { if (peek(tkn::Separator::Dot,1) && peek(tkn::Literal::Identifier,2) ) - m_memberChains.insert(getTokenId(m_curr->location)); + m_memberChains.insert(getTokenId()); else if (peek(tkn::Operator::ScopeResolution,1) && peek(tkn::Literal::Identifier,2)) - m_scopeChains.insert(getTokenId(m_curr->location)); + m_scopeChains.insert(getTokenId()); else - m_taggedIdentifiers.insert(getTokenId(m_curr->location)); + m_taggedIdentifiers.insert(getTokenId()); } next(increment); skipCount++; @@ -636,7 +628,7 @@ namespace hex::plugin::builtin { if (findIdentifierDefinition(definition, currentName)) { variableParentType = definition.typeStr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, definition.idType); skipArray(200, true); next(); @@ -651,7 +643,7 @@ namespace hex::plugin::builtin { if (findIdentifierDefinition(result, currentName, variableParentType)) { variableParentType = result.typeStr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, result.idType); skipArray(200, true); next(); @@ -671,7 +663,7 @@ namespace hex::plugin::builtin { variableParentType = currentName; if (!nameSpace.empty() && !variableParentType.contains(nameSpace)) - variableParentType = nameSpace + variableParentType; + variableParentType.insert(0, nameSpace); else if (findNamespace(nameSpace) && !variableParentType.contains(nameSpace)) variableParentType = fmt::format("{}::{}", nameSpace, variableParentType); @@ -680,7 +672,7 @@ namespace hex::plugin::builtin { if (findIdentifierDefinition(result, currentName, variableParentType)) { variableParentType = result.typeStr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, result.idType); skipArray(200, true); next(); @@ -720,7 +712,7 @@ namespace hex::plugin::builtin { bool TextHighlighter::findIdentifierDefinition( Definition &result, const std::string &optionalIdentifierName, std::string optionalName, bool setInstances) { auto curr = m_curr; bool isFunction = false; - auto tokenId = getTokenId(m_curr->location); + auto tokenId = getTokenId(); std::vector definitions; std::string name = optionalName; result.idType = IdentifierType::Unknown; @@ -843,7 +835,7 @@ namespace hex::plugin::builtin { if (auto *keyword = std::get_if(&m_requiredInputs.fullTokens.at(startingLineTokenIndex).value); keyword != nullptr && *keyword == Keyword::Import) { while (index < vectorString.size()) { - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, IdentifierType::NameSpace); next(2); index++; @@ -858,12 +850,12 @@ namespace hex::plugin::builtin { if (findIdentifierDefinition(definition, currentName)) { variableParentType = definition.typeStr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, definition.idType); skipArray(200, true); next(); } else { - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, IdentifierType::Unknown); skipArray(200, true); next(); @@ -878,7 +870,7 @@ namespace hex::plugin::builtin { if (findIdentifierDefinition(result, currentName, variableParentType) && !brokenChain) { variableParentType = result.typeStr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, result.idType); skipArray(200, true); next(); @@ -901,7 +893,7 @@ namespace hex::plugin::builtin { if (!templateName.empty() && findIdentifierDefinition(result, currentName, templateName) ) { variableParentType = result.typeStr; m_curr = saveCurr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, result.idType); skipArray(200, true); next(); @@ -922,7 +914,7 @@ namespace hex::plugin::builtin { if (!typeName.empty() && findIdentifierDefinition(result, currentName, typeName)) { variableParentType = result.typeStr; m_curr = saveCurr; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, result.idType); skipArray(200, true); next(); @@ -931,7 +923,7 @@ namespace hex::plugin::builtin { } } else { brokenChain = true; - auto tokenIndex = getTokenId(m_curr->location); + auto tokenIndex = getTokenId(); setIdentifierColor(tokenIndex, IdentifierType::Unknown); skipArray(200, true); next(); @@ -1036,7 +1028,7 @@ namespace hex::plugin::builtin { return true; } - i32 index = getTokenId(m_curr->location); + i32 index = getTokenId(); if (index < (i32) tokenCount - 1 && index > 2) { auto nextToken = m_curr[1]; @@ -1068,7 +1060,7 @@ namespace hex::plugin::builtin { // finds the name of the token range that the given or the current token index is in. bool TextHighlighter::findScope(std::string &name, const UnorderedBlocks &map, i32 optionalTokenId) { - auto tokenId = optionalTokenId ==-1 ? getTokenId(m_curr->location) : optionalTokenId; + auto tokenId = optionalTokenId ==-1 ? getTokenId() : optionalTokenId; for (const auto &[scopeName, range]: map) { @@ -1085,7 +1077,7 @@ namespace hex::plugin::builtin { nameSpace = ""; for (auto [interval, name]: m_namespaceTokenRange) { - i32 tokenId = optionalTokenId == -1 ? getTokenId(m_curr->location) : optionalTokenId; + i32 tokenId = optionalTokenId == -1 ? getTokenId() : optionalTokenId; if (tokenId > interval.m_start && tokenId < interval.m_end) { @@ -1288,8 +1280,8 @@ namespace hex::plugin::builtin { } else { auto curr = m_curr; for (const auto &[name, range] : m_UDTTokenRange) { - auto startToken = TokenIter(m_requiredInputs.fullTokens.begin()+range.m_start,m_requiredInputs.fullTokens.begin()+range.m_end); - auto endToken = TokenIter(m_requiredInputs.fullTokens.begin()+range.m_end,m_requiredInputs.fullTokens.end()); + auto startToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin() + range.m_start, m_requiredInputs.fullTokens.begin() + range.m_end); + auto endToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin() + range.m_end, m_requiredInputs.fullTokens.end()); for ( m_curr = startToken; endToken > m_curr; next()) { if (auto *identifier = std::get_if(&m_curr->value); identifier != nullptr) { @@ -1467,14 +1459,9 @@ namespace hex::plugin::builtin { // od every instance of the variable name in the code. void TextHighlighter::setInitialColors() { - m_startToken = m_originalPosition = m_partOriginalPosition = TokenIter(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); - auto endToken = TokenIter(m_requiredInputs.fullTokens.end(), m_requiredInputs.fullTokens.end()); - for (m_curr = m_startToken; endToken > m_curr; next()) { - - if (peek(tkn::Separator::EndOfProgram)) - return; - - + m_startToken = m_originalPosition = m_partOriginalPosition = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); + for (auto tokenId : m_identifierTokenIds) { + m_curr = m_startToken + tokenId; if (auto identifier = getValue(0); identifier != nullptr) { if (auto identifierType = identifier->getType(); identifierType != IdentifierType::Unknown && identifierType != IdentifierType::MemberUnknown &&identifierType != IdentifierType::FunctionUnknown && identifierType != IdentifierType::ScopeResolutionUnknown) @@ -1483,104 +1470,111 @@ namespace hex::plugin::builtin { } } + void TextHighlighter::setTokenIds() { + m_identifierTokenIds.clear(); + m_startToken = m_originalPosition = m_partOriginalPosition = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); + auto endToken = SafeTokenIterator(m_requiredInputs.fullTokens.end(), m_requiredInputs.fullTokens.end()); + m_curr = m_startToken; + while (endToken > m_curr) { + if (sequence(tkn::Literal::Identifier)) { + auto tokenId = getTokenId() - 1; + m_identifierTokenIds.insert(tokenId); + } else + next(); + } + } + void TextHighlighter::loadInstances() { std::map> instances; - m_startToken = m_originalPosition = m_partOriginalPosition = TokenIter(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); - auto endToken = TokenIter(m_requiredInputs.fullTokens.end(), m_requiredInputs.fullTokens.end()); - for (m_curr = m_startToken; endToken > m_curr; next()) { + m_startToken = m_originalPosition = m_partOriginalPosition = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); + for (auto identifierTokenId : m_identifierTokenIds) { + m_curr = m_startToken + identifierTokenId; + std::string name; - if (peek(tkn::Literal::Identifier)) { - std::string name; + if (auto identifier = getValue(0); identifier != nullptr) { + auto identifierType = identifier->getType(); - if (auto identifier = getValue(0); identifier != nullptr) { + name = identifier->get(); - if (auto identifierType = identifier->getType(); identifierType != IdentifierType::Unknown && identifierType != IdentifierType::MemberUnknown && - identifierType != IdentifierType::FunctionUnknown && identifierType != IdentifierType::ScopeResolutionUnknown) { - name = identifier->get(); - - if (identifierType == IdentifierType::Typedef) { - auto curr = m_curr; - //std::string typeName = ""; - skipTemplate(200, true); - next(); - if (sequence(tkn::Operator::Assign, tkn::Literal::Identifier)) { - next(-1); - i32 fullNameTokenId = getTokenId(m_curr->location); - std::vector identifiers; - std::string typeName; - if (!getFullName(typeName, identifiers, false)) { - auto identifier2 = getValue(0); - if (identifier2 != nullptr) { - typeName = identifier2->get(); - } - } else { - auto count = std::count(typeName.begin(), typeName.end(), ':') >> 1; - for (auto i = 0; i < count; i++) { - setIdentifierColor(fullNameTokenId, IdentifierType::NameSpace); - fullNameTokenId += 2; - } - } - setIdentifierColor(fullNameTokenId, IdentifierType::UDT); - if (!m_typeDefMap.contains(name) && !typeName.empty()) { - m_typeDefMap[name] = typeName; - m_typeDefInvMap[typeName] = name; - } - auto start = m_curr; - skipTemplate(200, true); - auto end = m_curr; - for (m_curr = start; end > m_curr; next()) { - if (auto identifier2 = getValue(0); identifier2 != nullptr) { - auto tokenId = getTokenId(m_curr->location); - setIdentifierColor(tokenId, IdentifierType::TemplateArgument); - } - } + if (identifierType == IdentifierType::Typedef) { + auto curr = m_curr; + skipTemplate(200, true); + next(); + if (sequence(tkn::Operator::Assign, tkn::Literal::Identifier)) { + next(-1); + i32 fullNameTokenId = getTokenId(); + std::vector identifiers; + std::string typeName; + if (!getFullName(typeName, identifiers, false)) { + auto identifier2 = getValue(0); + if (identifier2 != nullptr) { + typeName = identifier2->get(); } - m_curr = curr; - } - } else { - name = identifier->get(); - auto curr = m_curr; - auto tokenIndex = getTokenId(m_curr->location); - skipArray(200, true); - next(); - bool chainStarted = false; - while (sequence(tkn::Operator::ScopeResolution, tkn::Literal::Identifier)) { - - if (identifier = getValue(-1); identifier != nullptr) - name += "::" + identifier->get(); - std::string nameSpace; - if (!chainStarted) { - chainStarted = true; - m_scopeChains.insert(tokenIndex); - } else if (findNamespace(nameSpace) && !nameSpace.empty()) { - m_scopeChains.insert(tokenIndex); - } - - - curr = m_curr; - } - while (sequence(tkn::Separator::Dot, tkn::Literal::Identifier)) { - - if (identifier = getValue(-1); identifier != nullptr) - name += "." + identifier->get(); - - if (!chainStarted) { - chainStarted = true; - m_memberChains.insert(tokenIndex); - } - skipArray(200, true); - curr = m_curr; - } - if (peek(tkn::Literal::Identifier)) { - std::string nameScape; - if (findNamespace(nameScape) && !nameScape.empty() && std::ranges::find(m_UDTs,(nameScape + "::" + name)) != m_UDTs.end()) { - m_scopeChains.insert(tokenIndex); + } else { + auto count = std::count(typeName.begin(), typeName.end(), ':') >> 1; + for (auto i = 0; i < count; i++) { + setIdentifierColor(fullNameTokenId, IdentifierType::NameSpace); + fullNameTokenId += 2; + } + } + setIdentifierColor(fullNameTokenId, IdentifierType::UDT); + if (!m_typeDefMap.contains(name) && !typeName.empty()) { + m_typeDefMap[name] = typeName; + m_typeDefInvMap[typeName] = name; + } + auto start = m_curr; + skipTemplate(200, true); + auto end = m_curr; + for (m_curr = start; end > m_curr; next()) { + if (auto identifier2 = getValue(0); identifier2 != nullptr) { + auto tokenId = getTokenId(); + setIdentifierColor(tokenId, IdentifierType::TemplateArgument); } } - m_curr = curr; } + m_curr = curr; + } else { + name = identifier->get(); + auto curr = m_curr; + auto tokenIndex = getTokenId(); + skipArray(200, true); + next(); + bool chainStarted = false; + while (sequence(tkn::Operator::ScopeResolution, tkn::Literal::Identifier)) { + + if (identifier = getValue(-1); identifier != nullptr) + name += "::" + identifier->get(); + std::string nameSpace; + if (!chainStarted) { + chainStarted = true; + m_scopeChains.insert(tokenIndex); + } else if (findNamespace(nameSpace) && !nameSpace.empty()) { + m_scopeChains.insert(tokenIndex); + } + + curr = m_curr; + } + while (sequence(tkn::Separator::Dot, tkn::Literal::Identifier)) { + + if (identifier = getValue(-1); identifier != nullptr) + name += "." + identifier->get(); + + if (!chainStarted) { + chainStarted = true; + m_memberChains.insert(tokenIndex); + } + skipArray(200, true); + curr = m_curr; + } + if (peek(tkn::Literal::Identifier)) { + std::string nameScape; + if (findNamespace(nameScape) && !nameScape.empty() && std::ranges::find(m_UDTs, (nameScape + "::" + name)) != m_UDTs.end()) { + m_scopeChains.insert(tokenIndex); + } + } + m_curr = curr; } - auto id = getTokenId(m_curr->location); + auto id = getTokenId(); if (instances.contains(name)) { auto &nameInstances = instances[name]; @@ -1589,8 +1583,7 @@ namespace hex::plugin::builtin { nameInstances.push_back(id); } else instances[name].push_back(id); - } else if (peek(tkn::Separator::EndOfProgram)) - break; + } } m_instances = std::move(instances); } @@ -1603,6 +1596,26 @@ namespace hex::plugin::builtin { return m_requiredInputs.fullTokens.at(tokenId).location; } + i32 TextHighlighter::getTokenId(SafeTokenIterator tokenIterator) { + auto start = &m_requiredInputs.fullTokens[0]; + auto m_start = &tokenIterator.front(); + auto m_end = &tokenIterator.back(); + if (m_start < start || start > m_end) { + throw std::out_of_range("iterator out of range"); + } + return m_start - start; + } + + i32 TextHighlighter::getTokenId() { + auto start = &m_requiredInputs.fullTokens[0]; + auto m_start = &m_curr.front(); + auto m_end = &m_curr.back(); + if (m_start < start || start > m_end) { + throw std::out_of_range("iterator out of range"); + } + return m_start - start; + } + // Get the token index for a given location. i32 TextHighlighter::getTokenId(pl::core::Location location) { @@ -1626,8 +1639,9 @@ namespace hex::plugin::builtin { if (tokenStart == -1 || tokenEnd == -1 || tokenStart >= (i32) tokenCount) return -1; for (i32 i = tokenStart; i <= tokenEnd; i++) { - if (m_requiredInputs.fullTokens.at(i).location.column >= location.column) - return i; + auto location2 = m_requiredInputs.fullTokens[i].location; + if (location2.column <= location.column && location2.column + location2.length >= location.column) + return i + 1; } return -1; } @@ -1637,7 +1651,7 @@ namespace hex::plugin::builtin { if (tokenId == -1) { constToken = &m_curr[0]; - tokenId = getTokenId(m_curr->location); + tokenId = getTokenId(); } else constToken = &m_requiredInputs.fullTokens.at(tokenId); @@ -1650,7 +1664,7 @@ namespace hex::plugin::builtin { void TextHighlighter::setColor(i32 tokenId, const IdentifierType &type) { if (tokenId == -1) - tokenId = getTokenId(m_curr->location); + tokenId = getTokenId(); setIdentifierColor(tokenId, type); } @@ -1661,22 +1675,17 @@ namespace hex::plugin::builtin { taggedIdentifiers.push_back(index); } m_taggedIdentifiers.clear(); - m_startToken = m_originalPosition = m_partOriginalPosition = TokenIter(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); - auto endToken = TokenIter(m_requiredInputs.fullTokens.end(), m_requiredInputs.fullTokens.end()); + m_startToken = m_originalPosition = m_partOriginalPosition = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); m_curr = m_startToken; - - while (endToken > m_curr) { - if (peek(tkn::Separator::EndOfProgram)) - return; - i32 tokenId = getTokenId(m_curr->location); + for (auto tokenId : m_identifierTokenIds) { + m_curr = m_startToken + tokenId; if (!taggedIdentifiers.empty() && tokenId > taggedIdentifiers.back()) { next(taggedIdentifiers.back() - tokenId); taggedIdentifiers.pop_back(); } - if (sequence(tkn::Keyword::Import, tkn::Literal::Identifier)) { - next(-1); + if (peek(tkn::Keyword::Import, -1)) { do { if (auto identifier = const_cast(getValue(0)); identifier != nullptr) { setIdentifierColor(-1, IdentifierType::NameSpace); @@ -1698,97 +1707,81 @@ namespace hex::plugin::builtin { } } } - if (peek(tkn::Separator::EndOfProgram)) - return; - if (peek(tkn::Literal::Identifier)) { - auto identifier = getValue(0); - Token::Identifier::IdentifierType identifierType; - if (identifier == nullptr) { - next(); - continue; - } - identifierType = identifier->getType(); - std::string variableName = identifier->get(); - - if (m_tokenColors.contains(tokenId) && (m_tokenColors.at(tokenId) != ui::TextEditor::PaletteIndex::Default && identifierType != IdentifierType::Unknown)) { - next(); - continue; - } - Definition definition; - std::string nameSpace; - if (peek(tkn::Keyword::Parent, -2)) { - auto save = m_curr; - next(-2); - while (peek(tkn::Keyword::Parent, -2)) - next(-2); - auto optional = setChildrenTypes(); - - if (optional.has_value()) - setIdentifierColor(-1, optional->idType); - else { - m_curr = save; - setIdentifierColor(-1, IdentifierType::Unknown); - next(); - continue; - } - m_curr = save; - next(); - continue; - } - if (peek(tkn::Operator::ScopeResolution, 1)) { - if (std::ranges::find(m_requiredInputs.usedNamespaces, variableName) != m_requiredInputs.usedNamespaces.end()) { - setIdentifierColor(-1, IdentifierType::NameSpace); - next(); - continue; - } - } - if (peek(tkn::Operator::ScopeResolution, -1)) { - auto save = m_curr; - next(-2); - if (auto parentIdentifier = const_cast(getValue(0)); parentIdentifier != nullptr) { - next(2); - if (parentIdentifier->getType() == IdentifierType::UDT) { - auto parentName = parentIdentifier->get(); - auto typeName = findIdentifierType(variableName, parentName); - setIdentifierColor(-1, typeName); - } - } - m_curr = save; - next(); - continue; - } - if (findIdentifierDefinition(definition)) { - identifierType = definition.idType; - setIdentifierColor(-1, identifierType); - next(); - continue; - } - if (findNamespace(nameSpace,tokenId)) { - auto fullName = nameSpace + "::" + variableName; - auto typeName = findIdentifierType(fullName, ""); - if (typeName != IdentifierType::Unknown) { - setIdentifierColor(-1, typeName); - next(); - continue; - } - } - if (std::ranges::find(m_UDTs, variableName) != m_UDTs.end()) { - if (m_typeDefMap.contains(variableName)) - setIdentifierColor(-1, IdentifierType::Typedef); - else - setIdentifierColor(-1, IdentifierType::UDT); - next(); - continue; - } - if (peek(tkn::Keyword::From, -1)) { - setIdentifierColor(-1, IdentifierType::GlobalVariable); - next(); - continue; - } - setIdentifierColor(-1, IdentifierType::Unknown); - next(); + auto identifier = getValue(0); + Token::Identifier::IdentifierType identifierType; + if (identifier == nullptr) { + continue; } - next(); + identifierType = identifier->getType(); + std::string variableName = identifier->get(); + + if (m_tokenColors.contains(tokenId) && (m_tokenColors.at(tokenId) != ui::TextEditor::PaletteIndex::Default && identifierType != IdentifierType::Unknown)) { + continue; + } + Definition definition; + std::string nameSpace; + if (peek(tkn::Keyword::Parent, -2)) { + auto save = m_curr; + next(-2); + while (peek(tkn::Keyword::Parent, -2)) + next(-2); + auto optional = setChildrenTypes(); + + if (optional.has_value()) + setIdentifierColor(-1, optional->idType); + else { + m_curr = save; + setIdentifierColor(-1, IdentifierType::Unknown); + continue; + } + m_curr = save; + continue; + } + if (peek(tkn::Operator::ScopeResolution, 1)) { + if (std::ranges::find(m_requiredInputs.usedNamespaces, variableName) != m_requiredInputs.usedNamespaces.end()) { + setIdentifierColor(-1, IdentifierType::NameSpace); + continue; + } + } + if (peek(tkn::Operator::ScopeResolution, -1)) { + auto save = m_curr; + next(-2); + if (auto parentIdentifier = const_cast(getValue(0)); parentIdentifier != nullptr) { + next(2); + if (parentIdentifier->getType() == IdentifierType::UDT) { + auto parentName = parentIdentifier->get(); + auto typeName = findIdentifierType(variableName, parentName); + setIdentifierColor(-1, typeName); + } + } + m_curr = save; + continue; + } + if (findIdentifierDefinition(definition)) { + identifierType = definition.idType; + setIdentifierColor(-1, identifierType); + continue; + } + if (findNamespace(nameSpace,tokenId)) { + auto fullName = nameSpace + "::" + variableName; + auto typeName = findIdentifierType(fullName, ""); + if (typeName != IdentifierType::Unknown) { + setIdentifierColor(-1, typeName); + continue; + } + } + if (std::ranges::find(m_UDTs, variableName) != m_UDTs.end()) { + if (m_typeDefMap.contains(variableName)) + setIdentifierColor(-1, IdentifierType::Typedef); + else + setIdentifierColor(-1, IdentifierType::UDT); + continue; + } + if (peek(tkn::Keyword::From, -1)) { + setIdentifierColor(-1, IdentifierType::GlobalVariable); + continue; + } + setIdentifierColor(-1, IdentifierType::Unknown); } } @@ -1804,7 +1797,7 @@ namespace hex::plugin::builtin { continue; std::string &lineOfColors = m_requiredInputs.linesOfColors[line];//std::string(m_lines[line].size(), 0); for (auto tokenIndex = m_firstTokenIdOfLine.at(line); tokenIndex < m_firstTokenIdOfLine.at(nextLine(line)); tokenIndex++) { - Token *token = const_cast(&m_requiredInputs.fullTokens.at(tokenIndex)); + auto *token = const_cast(&m_requiredInputs.fullTokens.at(tokenIndex)); if (m_tokenColors.contains(tokenIndex) && token->type == Token::Type::Identifier) { u8 color = (u8) m_tokenColors.at(tokenIndex); u32 tokenLength = token->location.length; @@ -1834,7 +1827,7 @@ namespace hex::plugin::builtin { auto definitions = m_UDTVariables[inheritance]; if (definitions.empty()) definitions = m_ImportedUDTVariables[inheritance]; - for (const auto &[variableName, variableDefinitions]: definitions) { + for (auto [variableName, variableDefinitions]: definitions) { auto tokenRange = m_UDTTokenRange[name]; u32 tokenIndex = tokenRange.m_start; for (auto token = tokenRange.m_start; token < tokenRange.m_end; token++) { @@ -1860,7 +1853,7 @@ namespace hex::plugin::builtin { // Get the string of the argument type. This works on function arguments and non-type template arguments. std::string TextHighlighter::getArgumentTypeName(i32 rangeStart, Token delimiter2) { auto curr = m_curr; - i32 parameterIndex = getArgumentNumber(rangeStart, getTokenId(m_curr->location)); + i32 parameterIndex = getArgumentNumber(rangeStart, getTokenId()); Token delimiter; std::string typeStr; @@ -1918,16 +1911,14 @@ namespace hex::plugin::builtin { } - if (length > (i32) m_lines[line].size()-col && m_firstTokenIdOfLine[line + 1] != -1) - return false; - return true; + return !(length > (i32) m_lines[line].size()-col && m_firstTokenIdOfLine[line + 1] != -1); } // Find the string of the variable type. This works on function variables, views, // local variables as well as on calculated pointers and pattern variables. std::string TextHighlighter::getVariableTypeName() { auto curr = m_curr; - auto varTokenId = getTokenId(m_curr->location); + auto varTokenId = getTokenId(); if (!isTokenIdValid(varTokenId)) return ""; @@ -1983,11 +1974,11 @@ namespace hex::plugin::builtin { // Definitions of global variables and placed variables. void TextHighlighter::loadGlobalDefinitions(Scopes tokenRangeSet, std::vector identifierTypes, Variables &variables) { - m_startToken = m_originalPosition = m_partOriginalPosition = TokenIter(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); + m_startToken = m_originalPosition = m_partOriginalPosition = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); for (auto range: tokenRangeSet) { - auto startToken = TokenIter(m_requiredInputs.fullTokens.begin()+range.m_start,m_requiredInputs.fullTokens.begin()+range.m_end); - auto endToken = TokenIter(m_requiredInputs.fullTokens.begin()+range.m_end,m_requiredInputs.fullTokens.end()); + auto startToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin() + range.m_start, m_requiredInputs.fullTokens.begin() + range.m_end); + auto endToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin() + range.m_end, m_requiredInputs.fullTokens.end()); for ( m_curr = startToken; endToken > m_curr; next()) { @@ -2001,7 +1992,7 @@ namespace hex::plugin::builtin { if (typeStr.empty()) continue; - i32 tokenId = getTokenId(m_curr->location); + i32 tokenId = getTokenId(); Definition definition(identifierType, typeStr, tokenId, m_curr->location); variables[identifierName].push_back(definition); continue; @@ -2077,7 +2068,7 @@ namespace hex::plugin::builtin { if (typeStr.empty()) continue; - Definition definition(identifierType, typeStr, getTokenId(m_curr->location), m_curr->location); + Definition definition(identifierType, typeStr, getTokenId(), m_curr->location); variableMap[name][identifierName].push_back(definition); continue; } @@ -2104,7 +2095,7 @@ namespace hex::plugin::builtin { auto identifierName = identifier->get(); if (!name.ends_with(identifierName)) continue; - types[name] = ParentDefinition(identifierType, getTokenId(m_curr->location), m_curr->location); + types[name] = ParentDefinition(identifierType, getTokenId(), m_curr->location); } } @@ -2167,7 +2158,7 @@ namespace hex::plugin::builtin { } m_lines = wolv::util::splitString(m_requiredInputs.editedText, "\n"); - m_lines.push_back(""); + m_lines.emplace_back(""); m_firstTokenIdOfLine.clear(); u32 tokenId = 0; @@ -2433,10 +2424,10 @@ namespace hex::plugin::builtin { // Parser labels global variables that are not placed as // function variables. void TextHighlighter::fixGlobalVariables() { - m_startToken = m_originalPosition = m_partOriginalPosition = TokenIter(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); + m_startToken = m_originalPosition = m_partOriginalPosition = SafeTokenIterator(m_requiredInputs.fullTokens.begin(), m_requiredInputs.fullTokens.end()); for (auto range: m_globalTokenRange) { - auto startToken = TokenIter(m_requiredInputs.fullTokens.begin() + range.m_start, m_requiredInputs.fullTokens.begin() + range.m_end); - auto endToken = TokenIter(m_requiredInputs.fullTokens.begin() + range.m_end, m_requiredInputs.fullTokens.end()); + auto startToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin() + range.m_start, m_requiredInputs.fullTokens.begin() + range.m_end); + auto endToken = SafeTokenIterator(m_requiredInputs.fullTokens.begin() + range.m_end, m_requiredInputs.fullTokens.end()); for (m_curr = startToken; endToken > m_curr; next()) { @@ -2480,6 +2471,7 @@ namespace hex::plugin::builtin { void TextHighlighter::processSource() { m_UDTVariables.clear(); m_UDTTokenRange.clear(); + setTokenIds(); getTokenRanges(IdentifierType::UDT); loadVariableDefinitions(m_UDTTokenRange, tkn::Operator::BoolLessThan, tkn::Operator::BoolGreaterThan, {IdentifierType::TemplateArgument}, true, m_UDTVariables); @@ -2510,6 +2502,7 @@ namespace hex::plugin::builtin { if (m_requiredInputs.fullTokens.size() > 1) { m_globalTokenRange.insert(TokenInterval(0, m_requiredInputs.fullTokens.size() - 1)); + setTokenIds(); getTokenRanges(IdentifierType::NameSpace); getTokenRanges(IdentifierType::UDT); getTokenRanges(IdentifierType::Function); @@ -2543,5 +2536,7 @@ namespace hex::plugin::builtin { log::debug("TextHighlighter::highlightSourceCode: Out of range error: {}", e.what()); return; } + + return; } } diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index e1a1ccbfd..922a5a853 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -1476,7 +1476,8 @@ namespace hex::plugin::builtin { TaskManager::createBackgroundTask("HighlightSourceCode", [this,provider](auto &) { m_textHighlighter.get(provider).highlightSourceCode(); }); } else if (m_changesWereColored && !m_allStepsCompleted) { m_textHighlighter.get(provider).setRequestedIdentifierColors(); - m_textEditor.get(provider).getLines().readHiddenLines(); + m_textEditor.get(provider).getLines().setAllCodeFolds(); + m_textEditor.get(provider).getLines().applyCodeFoldStates(); m_allStepsCompleted = true; } @@ -1642,7 +1643,7 @@ namespace hex::plugin::builtin { this->evaluatePattern(code, provider); m_textEditor.get(provider).setText(code, true); - m_textEditor.get(provider).readHiddenLines(); + m_textEditor.get(provider).removeHiddenLinesFromPattern(); m_sourceCode.get(provider) = code; if (trackFile) { m_changeTracker.get(provider) = wolv::io::ChangeTracker(file); @@ -1657,7 +1658,7 @@ namespace hex::plugin::builtin { ContentRegistry::PatternLanguage::configureRuntime(*m_editorRuntime, nullptr); const auto &ast = m_editorRuntime->parseString(code, pl::api::Source::DefaultSource); - m_textEditor.get(provider).setLongestLineLength(m_editorRuntime->getInternals().preprocessor.get()->getLongestLineLength()); + m_textEditor.get(provider).setLongestLineLength(m_editorRuntime->getInternals().preprocessor->getLongestLineLength()); auto &patternVariables = m_patternVariables.get(provider); auto oldPatternVariables = std::move(patternVariables); @@ -1840,6 +1841,7 @@ namespace hex::plugin::builtin { return; m_textEditor.get(provider).setText(wolv::util::preprocessText(code)); + m_textEditor.get(provider).removeHiddenLinesFromPattern(); m_sourceCode.get(provider) = code; m_hasUnevaluatedChanges.get(provider) = true; }); @@ -1874,11 +1876,12 @@ namespace hex::plugin::builtin { EventProviderChanged::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) { if (oldProvider != nullptr) { - m_sourceCode.get(oldProvider) = m_textEditor.get(oldProvider).getText(true); + m_sourceCode.get(oldProvider) = m_textEditor.get(oldProvider).getText(); m_scroll.get(oldProvider) = m_textEditor.get(oldProvider).getScroll(); m_cursorPosition.get(oldProvider) = m_textEditor.get(oldProvider).getCursorPosition(); m_selection.get(oldProvider) = m_textEditor.get(oldProvider).getSelection(); m_breakpoints.get(oldProvider) = m_textEditor.get(oldProvider).getBreakpoints(); + m_codeFoldState.get(oldProvider) = m_textEditor.get(oldProvider).getLines().getCodeFoldState(); m_consoleCursorPosition.get(oldProvider) = m_consoleEditor.get(oldProvider).getCursorPosition(); m_consoleSelection.get(oldProvider) = m_consoleEditor.get(oldProvider).getSelection(); m_consoleLongestLineLength.get(oldProvider) = m_consoleEditor.get(oldProvider).getLongestLineLength(); @@ -1891,6 +1894,7 @@ namespace hex::plugin::builtin { m_textEditor.get(newProvider).setScroll(m_scroll.get(newProvider)); m_textEditor.get(newProvider).setSelection(m_selection.get(newProvider)); m_textEditor.get(newProvider).setBreakpoints(m_breakpoints.get(newProvider)); + m_textEditor.get(newProvider).getLines().setCodeFoldState(m_codeFoldState.get(newProvider)); m_textEditor.get(newProvider).setTextChanged(false); m_hasUnevaluatedChanges.get(newProvider) = true; m_consoleEditor.get(newProvider).setText(wolv::util::combineStrings(m_console.get(newProvider), "\n")); @@ -2340,15 +2344,19 @@ namespace hex::plugin::builtin { m_sourceCode.get(provider) = sourceCode; - if (provider == ImHexApi::Provider::get()) + if (provider == ImHexApi::Provider::get()) { m_textEditor.get(provider).setText(sourceCode); + m_textEditor.get(provider).removeHiddenLinesFromPattern(); + } m_hasUnevaluatedChanges.get(provider) = true; return true; }, .store = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) { - if (provider == ImHexApi::Provider::get()) + if (provider == ImHexApi::Provider::get()) { + m_textEditor.get(provider).addHiddenLinesToPattern(); m_sourceCode.get(provider) = m_textEditor.get(provider).getText(); + } const auto &sourceCode = m_sourceCode.get(provider); @@ -2599,12 +2607,12 @@ namespace hex::plugin::builtin { // Wait until evaluation has finished while (m_runningEvaluators > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(100ll)); } auto lock = std::scoped_lock(ContentRegistry::PatternLanguage::getRuntimeLock()); - auto evaluationResult = m_lastEvaluationResult.load(); + int evaluationResult = m_lastEvaluationResult.load(); nlohmann::json result = { { "handle", provider->getID() }, @@ -2623,7 +2631,7 @@ namespace hex::plugin::builtin { // Wait until evaluation has finished while (m_runningEvaluators > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(100ll)); } auto lock = std::scoped_lock(ContentRegistry::PatternLanguage::getRuntimeLock()); @@ -2647,7 +2655,7 @@ namespace hex::plugin::builtin { // Wait until evaluation has finished while (m_runningEvaluators > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(100ll)); } auto lock = std::scoped_lock(ContentRegistry::PatternLanguage::getRuntimeLock()); @@ -2679,6 +2687,7 @@ namespace hex::plugin::builtin { m_changeEventAcknowledgementPending.get(provider) = true; hex::ui::BannerButton::open(ICON_VS_INFO, "hex.builtin.provider.file.reload_changes", ImColor(66, 104, 135), "hex.builtin.provider.file.reload_changes.reload", [this, provider] { m_changeEventAcknowledgementPending.get(provider) = false; + loadPatternFile(m_changeTracker.get(provider).getPath(), provider, true); }); } @@ -2741,7 +2750,8 @@ namespace hex::plugin::builtin { fs::DialogMode::Save, { {"Pattern File", "hexpat"}, {"Pattern Import File", "pat"} }, [this, provider, trackFile](const auto &path) { wolv::io::File file(path, wolv::io::File::Mode::Create); - file.writeString(wolv::util::trim(m_textEditor.get(provider).getText(true))); + m_textEditor.get(provider).addHiddenLinesToPattern(); + file.writeString(wolv::util::trim(m_textEditor.get(provider).getText())); m_patternFileDirty.get(provider) = false; auto loadedPath = m_changeTracker.get(provider).getPath(); if ((loadedPath.empty() && loadedPath != path) || (!loadedPath.empty() && !trackFile) || loadedPath == path) @@ -2764,7 +2774,8 @@ namespace hex::plugin::builtin { wolv::io::File file(path, wolv::io::File::Mode::Create); if (file.isValid() && trackFile) { if (isPatternDirty(provider)) { - file.writeString(wolv::util::trim(m_textEditor.get(provider).getText(true))); + m_textEditor.get(provider).addHiddenLinesToPattern(); + file.writeString(wolv::util::trim(m_textEditor.get(provider).getText())); m_patternFileDirty.get(provider) = false; } return; diff --git a/plugins/ui/include/ui/text_editor.hpp b/plugins/ui/include/ui/text_editor.hpp index 9b9bc6b3e..21f8a8577 100644 --- a/plugins/ui/include/ui/text_editor.hpp +++ b/plugins/ui/include/ui/text_editor.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -62,8 +63,8 @@ namespace hex::ui { bool operator>=(const Coordinates &o) const; Coordinates operator+(const Coordinates &o) const; Coordinates operator-(const Coordinates &o) const; - i32 getLine() const { return m_line; } - i32 getColumn() const { return m_column; } + [[nodiscard]] i32 getLine() const { return m_line; } + [[nodiscard]] i32 getColumn() const { return m_column; } private: i32 m_line, m_column; @@ -84,11 +85,11 @@ namespace hex::ui { Coordinates getEnd() { return m_end; } bool isSingleLine(); enum class EndsInclusive : u8 { None = 0, Start = 2, End = 1, Both = 3 }; - bool contains(const Coordinates &coordinates, EndsInclusive endsInclusive = EndsInclusive::Both) const; - bool contains(const Range &range, EndsInclusive endsInclusive = EndsInclusive::Both) const; - bool containsLine(i32 value, EndsInclusive endsInclusive = EndsInclusive::Both) const; - bool containsColumn(i32 value, EndsInclusive endsInclusive = EndsInclusive::Both) const; - bool overlaps(const Range &o, EndsInclusive endsInclusive = EndsInclusive::Both) const; + [[nodiscard]] bool contains(const Coordinates &coordinates, EndsInclusive endsInclusive = EndsInclusive::Both) const; + [[nodiscard]] bool contains(const Range &range, EndsInclusive endsInclusive = EndsInclusive::Both) const; + [[nodiscard]] bool containsLine(i32 value, EndsInclusive endsInclusive = EndsInclusive::Both) const; + [[nodiscard]] bool containsColumn(i32 value, EndsInclusive endsInclusive = EndsInclusive::Both) const; + [[nodiscard]] bool overlaps(const Range &o, EndsInclusive endsInclusive = EndsInclusive::Both) const; bool operator==(const Range &o) const; bool operator!=(const Range &o) const; bool operator<(const Range &o) const { @@ -118,7 +119,7 @@ namespace hex::ui { Interval() : m_start(0), m_end(0) {} Interval(i32 start, i32 end) : m_start(start), m_end(end) { if (m_start > m_end) std::swap(m_start, m_end);} - Interval(const Interval &other) : m_start(other.m_start), m_end(other.m_end) {} + Interval(const Interval &other) = default; explicit Interval(ImVec2 vec) : m_start((i32)vec.x), m_end((i32)vec.y) { if (m_start > m_end) std::swap(m_start, m_end);} @@ -130,11 +131,11 @@ namespace hex::ui { bool operator!=(const Interval &other) const { return m_start != other.m_start || m_end != other.m_end; } bool operator<=(const Interval &other) const { return other.m_end >= m_end; } bool operator>=(const Interval &other) const { return m_end >= other.m_end; } - bool contains_or_equals(const Interval &other) const { return other.m_start >= m_start && other.m_end <= m_end; } - bool contains(const Interval &other) const { return (other.m_start >= m_start && other.m_end < m_end) || (other.m_start > m_start && other.m_end <= m_end); } - bool contains(i32 value, bool inclusive = true) const; - bool contiguous(const Interval &other) const; - operator ImVec2() const { return ImVec2((float)m_start, (float)m_end); } + [[nodiscard]] bool contains_or_equals(const Interval &other) const { return other.m_start >= m_start && other.m_end <= m_end; } + [[nodiscard]] bool contains(const Interval &other) const { return (other.m_start >= m_start && other.m_end < m_end) || (other.m_start > m_start && other.m_end <= m_end); } + [[nodiscard]] bool contains(i32 value, bool inclusive = true) const; + [[nodiscard]] bool contiguous(const Interval &other) const; + explicit operator ImVec2() const { return {(float)m_start, (float)m_end}; } private: i32 m_start; i32 m_end; @@ -144,8 +145,8 @@ namespace hex::ui { public: friend class TextEditor; bool operator==(const EditorState &o) const; - EditorState() : m_selection(), m_cursorPosition() {} - EditorState(const Range &selection, const Coordinates &cursorPosition) : m_selection(selection), m_cursorPosition(cursorPosition) {} + EditorState() = default; + EditorState(Range selection, Coordinates cursorPosition) : m_selection(selection), m_cursorPosition(cursorPosition) {} private: Range m_selection; Coordinates m_cursorPosition; @@ -153,10 +154,12 @@ namespace hex::ui { class UndoRecord; + using Matches = std::vector; + using UndoRecords = std::vector; + class FindReplaceHandler { public: FindReplaceHandler(); - using Matches = std::vector; Matches &getMatches() { return m_matches; } bool findNext(Lines *lines, u64 &byteIndex); bool findNext(TextEditor *editor, u64 &byteIndex) { return findNext(&editor->m_lines, byteIndex); }; @@ -177,17 +180,17 @@ namespace hex::ui { void findAllMatches(TextEditor *editor, std::string findWord) { findAllMatches(&editor->m_lines, findWord); }; u32 findPosition(Lines *lines, Coordinates pos, bool isNext); u32 findPosition(TextEditor *editor, Coordinates pos, bool isNext) { return findPosition(&editor->m_lines, pos, isNext); }; - bool getMatchCase() const { return m_matchCase; } + [[nodiscard]] bool getMatchCase() const { return m_matchCase; } void setMatchCase(Lines *lines, bool matchCase); void setMatchCase(TextEditor *editor, bool matchCase) { setMatchCase(&editor->m_lines, matchCase); }; - bool getWholeWord() const { return m_wholeWord; } + [[nodiscard]] bool getWholeWord() const { return m_wholeWord; } void setWholeWord(Lines *lines, bool wholeWord); void setWholeWord(TextEditor *editor, bool wholeWord) { setWholeWord(&editor->m_lines, wholeWord); }; - bool getFindRegEx() const { return m_findRegEx; } + [[nodiscard]] bool getFindRegEx() const { return m_findRegEx; } void setFindRegEx(Lines *lines, bool findRegEx); void setFindRegEx(TextEditor *editor, bool findRegEx) { setFindRegEx(&editor->m_lines, findRegEx); }; void resetMatches(); - std::vector m_undoBuffer; + UndoRecords m_undoBuffer; private: std::string m_findWord; std::string m_replaceWord; @@ -198,22 +201,24 @@ namespace hex::ui { Matches m_matches; }; - enum class PaletteIndex { + enum class PaletteIndex : u8 { Default, Identifier, Directive, Operator, Separator, BuiltInType, Keyword, NumericLiteral, StringLiteral, CharLiteral, Cursor, Background, LineNumber, Selection, Breakpoint, ErrorMarker, PreprocessorDeactivated, CurrentLineFill, CurrentLineFillInactive, CurrentLineEdge, ErrorText, WarningText, DebugText, DefaultText, Attribute, PatternVariable, LocalVariable, CalculatedPointer, TemplateArgument, Function, View, FunctionVariable, FunctionParameter, UserDefinedType, PlacedVariable, GlobalVariable, NameSpace, TypeDef, UnkIdentifier, DocComment, DocBlockComment, BlockComment, GlobalDocComment, Comment, PreprocIdentifier, Max }; - using Token = pl::core::Token; - using TokenIter = pl::hlp::SafeIterator::const_iterator>; - using Location = pl::core::Location; - using RegexList = std::vector>; - using Keywords = std::unordered_set; - using ErrorMarkers = std::map>; - using Breakpoints = std::unordered_set; - using Palette = std::array; - using Glyph = u8; - using CodeFoldBlocks = std::map; + using Token = pl::core::Token; + using Tokens = std::vector; + using SafeTokenIterator = pl::hlp::SafeIterator; + using Location = pl::core::Location; + using RegexList = std::vector>; + using Keywords = std::unordered_set; + using ErrorMarkers = std::map>; + using Breakpoints = std::unordered_set; + using Palette = std::array; + using Glyph = u8; + using CodeFoldBlocks = std::map; + using GlobalBlocks = std::set; struct Identifier { Coordinates m_location; std::string m_declaration;}; using Identifiers = std::unordered_map; @@ -223,7 +228,7 @@ namespace hex::ui { ActionableBox() : m_box(ImRect(ImVec2(0, 0), ImVec2(0, 0))) {}; explicit ActionableBox(const ImRect &box) : m_box(box) {} - ImRect &getBox() const { return const_cast(m_box);} + [[nodiscard]] ImRect &getBox() const { return const_cast(m_box);} virtual bool trigger(); virtual void callback() {} virtual ~ActionableBox() = default; @@ -274,12 +279,12 @@ namespace hex::ui { bool startHovered(); bool endHovered(); bool isDetected(); - bool isOpen(); + [[nodiscard]] bool isOpen() const; void open(); void close(); void moveFold(float lineCount, float lineHeight); private: - Lines *lines; + Lines *lines = nullptr; Range key; CursorChangeBox codeFoldStartCursorBox; ActionableBox codeFoldEndActionBox; @@ -302,14 +307,16 @@ namespace hex::ui { using ErrorGotoBoxes = std::map; using CursorBoxes = std::map; using ErrorHoverBoxes = std::map; + using Keys = std::vector; using CodeFoldKeys = std::set; using CodeFoldDelimiters = std::map>; + using Segments = std::vector; using CodeFoldKeyMap = std::map; using CodeFoldKeyLineMap = std::multimap; using CodeFoldState = std::map; - // using RowsToCodeFoldMap = std::map; + using Indices = std::vector; using LineIndexToScreen = std::map; - using MultiLinesToRow = std::map; + using IndexMap = std::map; using RowCodeFoldTooltips = std::map>; enum class TrimMode : u8 { TrimNone = 0, TrimEnd = 1, TrimStart = 2, TrimBoth = 3 }; @@ -322,12 +329,12 @@ namespace hex::ui { public: friend class hex::ui::TextEditor; friend class hex::ui::TextEditor::Lines; - LineIterator(const LineIterator &other) : m_charsIter(other.m_charsIter), m_colorsIter(other.m_colorsIter), m_flagsIter(other.m_flagsIter) {} + LineIterator(const LineIterator &other) = default; LineIterator() = default; char operator*(); LineIterator &operator++(); - LineIterator operator=(const LineIterator &other); + LineIterator &operator=(const LineIterator &other); bool operator!=(const LineIterator &other) const; bool operator==(const LineIterator &other) const; LineIterator operator+(i32 n); @@ -359,20 +366,20 @@ namespace hex::ui { }; union Flags { - Flags(char value) : m_value(value) {} - Flags(FlagBits bits) : m_bits(bits) {} + explicit Flags(char value) : m_value(value) {} + explicit Flags(FlagBits bits) : m_bits(bits) {} FlagBits m_bits; char m_value; }; - enum class LinePart { Chars, Utf8, Colors, Flags }; + enum class LinePart : u8 { Chars, Utf8, Colors, Flags }; - Line() : m_chars(""), m_colors(""), m_flags(""), m_colorized(false), m_lineMaxColumn(-1) {} - explicit Line(const char *line) { Line(std::string(line)); } - explicit Line(const std::string &line) : m_chars(line), m_colors(std::string(line.size(), 0x00)), m_flags(std::string(line.size(), 0x00)), m_colorized(false), m_lineMaxColumn(maxColumn()) {} + Line() : m_lineMaxColumn(-1) {} + explicit Line(const char *line) : Line(std::string(line)) {} + explicit Line(const std::string &line) : m_chars(line), m_colors(std::string(line.size(), 0x00)), m_flags(std::string(line.size(), 0x00)), m_lineMaxColumn(maxColumn()) {} Line(const Line &line) : m_chars(std::string(line.m_chars)), m_colors(std::string(line.m_colors)), m_flags(std::string(line.m_flags)), m_colorized(line.m_colorized), m_lineMaxColumn(line.m_lineMaxColumn) {} Line(Line &&line) noexcept : m_chars(std::move(line.m_chars)), m_colors(std::move(line.m_colors)), m_flags(std::move(line.m_flags)), m_colorized(line.m_colorized), m_lineMaxColumn(line.m_lineMaxColumn) {} - Line(std::string chars, std::string colors, std::string flags) : m_chars(std::move(chars)), m_colors(std::move(colors)), m_flags(std::move(flags)), m_colorized(false), m_lineMaxColumn(maxColumn()) {} + Line(std::string chars, std::string colors, std::string flags) : m_chars(std::move(chars)), m_colors(std::move(colors)), m_flags(std::move(flags)), m_lineMaxColumn(maxColumn()) {} bool operator==(const Line &o) const; bool operator!=(const Line &o) const; @@ -382,7 +389,7 @@ namespace hex::ui { [[nodiscard]] i32 columnIndex(i32 column) const; [[nodiscard]] i32 textSize() const; [[nodiscard]] i32 textSize(u32 index) const; - ImVec2 intervalToScreen(Interval stringIndices) const; + [[nodiscard]] ImVec2 intervalToScreen(Interval stringIndices) const; i32 lineTextSize(TrimMode trimMode = TrimMode::TrimNone); [[nodiscard]] i32 stringTextSize(const std::string &str) const; i32 textSizeIndex(float textSize, i32 position); @@ -403,19 +410,19 @@ namespace hex::ui { [[nodiscard]] std::string substr(u64 start, u64 length = (u64) -1, LinePart part = LinePart::Chars) const; Line subLine(u64 start, u64 length = (u64) -1); char operator[](u64 index) const; - char at(u64 index) const; + [[nodiscard]] char at(u64 index) const; // C++ can't overload functions based on return type, so use any type other // than u64 to avoid ambiguity. std::string operator[](i64 column) const; - std::string at(i64 column) const; + [[nodiscard]] std::string at(i64 column) const; void setNeedsUpdate(bool needsUpdate); void append(const char *text); - void append(const char text); + void append(char text); void append(const std::string &text); void append(const Line &line); void append(LineIterator begin, LineIterator end); void insert(LineIterator iter, const std::string &text); - void insert(LineIterator iter, const char text); + void insert(LineIterator iter, char text); void insert(LineIterator iter, strConstIter beginString, strConstIter endString); void insert(LineIterator iter, const Line &line); void insert(LineIterator iter, LineIterator beginLine, LineIterator endLine); @@ -461,16 +468,16 @@ namespace hex::ui { Range findDelimiterCoordinates(Range key); private: Line m_foldedLine; - Lines *m_lines; + Lines *m_lines{}; Range m_full; - i32 m_row; + i32 m_row{}; FoldType m_type = FoldType::Invalid; std::string m_brackets; - std::vector m_keys; - std::vector m_keysToRemove; - std::vector m_ellipsisIndices; - std::vector m_foldedSegments; - std::vector m_unfoldedSegments; + Keys m_keys; + Keys m_keysToRemove; + Indices m_ellipsisIndices; + Segments m_foldedSegments; + Segments m_unfoldedSegments; Coordinates m_cursorPosition; Range m_selection; bool m_built = false; @@ -480,7 +487,7 @@ namespace hex::ui { public: friend class Lines; friend class TextEditor; - MatchedDelimiter() : m_active(false), m_changed(false), m_nearCursor(0, 0), m_matched(0, 0) {} + MatchedDelimiter() : m_nearCursor(0, 0), m_matched(0, 0) {} MatchedDelimiter(bool active, bool changed, const Coordinates &nearCursor, const Coordinates &matched) : m_active(active), m_changed(changed), m_nearCursor(nearCursor), m_matched(matched) {} bool checkPosition(Lines *lines, Coordinates &from); @@ -494,15 +501,15 @@ namespace hex::ui { private: bool m_active = false; bool m_changed = false; - Coordinates m_nearCursor = {}; - Coordinates m_matched = {}; + Coordinates m_nearCursor{}; + Coordinates m_matched{}; }; - class Segment { + class FoldSegment { public: friend class TextEditor; - Segment(Coordinates foldEnd, const Interval &segment) : m_foldEnd(foldEnd), m_segment(segment) {} - bool operator==(const Segment &o) const { + FoldSegment(Coordinates foldEnd, const Interval &segment) : m_foldEnd(foldEnd), m_segment(segment) {} + bool operator==(const FoldSegment &o) const { return m_foldEnd == o.m_foldEnd && m_segment == o.m_segment; } private: @@ -511,9 +518,9 @@ namespace hex::ui { }; struct LanguageDefinition { - typedef std::pair TokenRegexString; - typedef std::vector TokenRegexStrings; - typedef bool(*TokenizeCallback)(strConstIter in_begin, strConstIter in_end, strConstIter &out_begin, strConstIter &out_end, PaletteIndex &paletteIndex); + using TokenRegexString = std::pair; + using TokenRegexStrings = std::vector; + using TokenizeCallback = bool (*)(strConstIter, strConstIter, strConstIter &, strConstIter &, PaletteIndex &); std::string m_name; Keywords m_keywords; @@ -522,12 +529,11 @@ namespace hex::ui { std::string m_singleLineComment, m_commentEnd, m_commentStart, m_globalDocComment, m_docComment, m_blockDocComment; char m_preprocChar = '#'; bool m_autoIndentation = true; - TokenizeCallback m_tokenize; + TokenizeCallback m_tokenize = {}; TokenRegexStrings m_tokenRegexStrings; bool m_caseSensitive = true; - LanguageDefinition() : m_keywords({}), m_identifiers({}), m_preprocIdentifiers({}), - m_tokenize(nullptr), m_tokenRegexStrings({}) {} + LanguageDefinition() : m_keywords({}), m_identifiers({}), m_preprocIdentifiers({}), m_tokenRegexStrings({}) {} static const LanguageDefinition &CPlusPlus(); static const LanguageDefinition &HLSL(); @@ -544,14 +550,14 @@ namespace hex::ui { class UndoRecord { public: friend class TextEditor; - UndoRecord() {} - ~UndoRecord() {} + UndoRecord() = default; + ~UndoRecord() = default; UndoRecord( std::string added, Range addedRange, std::string removed, Range removedRange, - EditorState &before, - EditorState &after); + EditorState before, + EditorState after); void undo(TextEditor *editor); void redo(TextEditor *editor); @@ -564,13 +570,11 @@ namespace hex::ui { EditorState m_after; }; - using UndoRecords = std::vector; - class UndoAction { public: - UndoAction() {} - ~UndoAction() {} - explicit UndoAction(const UndoRecords &records) : m_records(records) {} + UndoAction() = default; + ~UndoAction() = default; + explicit UndoAction(UndoRecords records) : m_records(std::move(records)) {} void undo(TextEditor *editor); void redo(TextEditor *editor); private: @@ -581,25 +585,31 @@ namespace hex::ui { public: friend class Lines; HiddenLine() = default; - HiddenLine(i32 lineIndex, const std::string &lineContent) : m_lineIndex(lineIndex), m_line(lineContent) {} + HiddenLine(i32 lineIndex, std::string lineContent) : m_lineIndex(lineIndex), m_line(std::move(lineContent)) {} private: - i32 m_lineIndex; + i32 m_lineIndex{}; std::string m_line; }; - using CodeFolds = std::map; - using Segments = std::vector; - using RowToSegments = std::map; - using UndoBuffer = std::vector; - using RowToFoldedLine = std::map; + enum class FoldSymbol : u8 { Line, Up, Down, Square }; + using CodeFolds = std::map; + using FoldSegments = std::vector; + using RowToFoldSegments = std::map; + using UndoBuffer = std::vector; + using FoldedLines = std::map; + using UnfoldedLines = std::vector; + using HiddenLines = std::vector; + using FoldSymbols = std::map; + using StringVector = std::vector; + using RangeFromCoordinates = std::pair; + + bool areEqual(const std::pair &a, const std::pair &b); class Lines { public: friend class TextEditor; - Lines() : m_unfoldedLines({}), m_foldedLines({}), m_hiddenLines({}), m_matchedDelimiter(), m_colorizerEnabled(true), m_defines({}) {} - - enum class FoldSymbol { Line, Up, Down, Square }; + Lines() : m_unfoldedLines({}), m_foldedLines({}), m_hiddenLines({}), m_defines({}) {} Line &at(i32 index); Line &operator[](i32 index); @@ -621,7 +631,6 @@ namespace hex::ui { void clearCursorBoxes() { m_cursorBoxes.clear(); } void clearCodeFolds(); void addClickableText(std::string text) { m_clickableText.push_back(text); } - //void setErrorMarkers(const ErrorMarkers &markers) { m_errorMarkers = markers; } Breakpoints &getBreakpoints() { return m_breakpoints; } void saveCodeFoldStates(); void applyCodeFoldStates(); @@ -642,7 +651,7 @@ namespace hex::ui { void moveUp(i32 amount, bool select); void moveHome(bool select); void moveEnd(bool select); - std::vector removeEmbeddedFolds(); + Keys removeEmbeddedFolds(); bool isLastLine(i32 lineIndex); bool isLastLine(); Coordinates find(const std::string &text, const Coordinates &start); @@ -654,17 +663,17 @@ namespace hex::ui { friend bool Range::Coordinates::isValid(Lines &lines); friend TextEditor::Coordinates Range::Coordinates::sanitize(Lines &lines); void appendLine(const std::string &value); - void readHiddenLines(); - void writeHiddenLines(); + void removeHiddenLinesFromPattern(); + void addHiddenLinesToPattern(); void setSelection(const Range &selection); Range getSelection() const; ImVec2 getLineStartScreenPos(float leftMargin, float lineNumber); ImVec2 &getCharAdvance() { return m_charAdvance; } - std::vector getDeactivatedBlocks(); + Keys getDeactivatedBlocks(); std::string getSelectedText(); void deleteSelection(); - inline void setTextChanged(bool value) { m_textChanged = value; } - inline bool isTextChanged() { return m_textChanged; } + void setTextChanged(bool value) { m_textChanged = value; } + bool isTextChanged() { return m_textChanged; } void setLanguageDefinition(const LanguageDefinition &aLanguageDef); const LanguageDefinition &getLanguageDefinition() const { return m_languageDefinition; } TextEditor::PaletteIndex getColorIndexFromFlags(Line::Flags flags); @@ -681,8 +690,8 @@ namespace hex::ui { void openCodeFold(const Range &key); void removeKeys(); ImVec2 indexCoordsToScreen(Coordinates indexCoords); - inline void setImGuiChildIgnored(bool value) { m_ignoreImGuiChild = value; } - inline bool isImGuiChildIgnored() const { return m_ignoreImGuiChild; } + void setImGuiChildIgnored(bool value) { m_ignoreImGuiChild = value; } + bool isImGuiChildIgnored() const { return m_ignoreImGuiChild; } ImVec2 lineIndexToScreen(i32 lineIndex, Interval stringIndices); void printCodeFold(const Range &key); void resetCursorBlinkTime(); @@ -691,7 +700,7 @@ namespace hex::ui { void setCursorPosition(const Coordinates &position, bool unfoldIfNeeded = true, bool scrollToCursor = true); void setFocusAtCoords(const Coordinates &coords, bool ensureVisible = false); void ensureCursorVisible(); - std::vector unfoldedEllipsisCoordinates(Range delimiterCoordinates); + Segments unfoldedEllipsisCoordinates(Range delimiterCoordinates); Coordinates unfoldedToFoldedCoords(const Coordinates &coords); Coordinates foldedToUnfoldedCoords(const Coordinates &coords); void setScrollY(); @@ -699,59 +708,61 @@ namespace hex::ui { Coordinates findNextWord(const Coordinates &from); Line &insertLine(i32 index); void deleteRange(const Range &rangeToDelete); - inline void clearBreakpointsChanged() { m_breakPointsChanged = false; } - inline bool isBreakpointsChanged() { return m_breakPointsChanged; } + void clearBreakpointsChanged() { m_breakPointsChanged = false; } + bool isBreakpointsChanged() { return m_breakPointsChanged; } Coordinates stringIndexCoords(i32 strIndex, const std::string &input); void refreshSearchResults(); - inline void setReadOnly(bool value) { m_readOnly = value; } + void setReadOnly(bool value) { m_readOnly = value; } void removeLines(i32 start, i32 end); void removeLine(i32 index); float textDistanceToLineStart(const Coordinates &from); - std::string getText(bool addHiddenLines = false); + std::string getText(); void setCursorPosition(); void ensureSelectionNotFolded(); bool hasSelection(); i32 insertTextAtCursor(const std::string &value); - void addUndo(std::vector value); + void addUndo(UndoRecords value); void insertText(const std::string &value); void insertText(const char *value); Interval findBlockInRange(Interval interval); - std::vector searchRangeForBlocks(Interval interval); - std::pair getDelimiterLineNumbers(i32 start, i32 end, const std::string &delimiters); + RangeFromCoordinates getDelimiterLineNumbers(i32 start, i32 end, const std::string &delimiters); void nonDelimitedFolds(); - std::pair convertIndexToLineNumbers(Interval interval); std::pair findMatchingDelimiter(i32 from); CodeFoldBlocks foldPointsFromSource(); Coordinates findCommentEndCoord(i32 tokenId); - std::set blocksFromGlobal(); void skipAttribute(); bool isTokenIdValid(i32 tokenId); bool isLocationValid(Location location); pl::core::Location getLocation(i32 tokenId); i32 getTokenId(pl::core::Location location); + i32 getTokenId(SafeTokenIterator tokenIterator); + i32 getTokenId(); void loadFirstTokenIdOfLine(); i32 nextLine(i32 line); void setAllCodeFolds(); + void setCodeFoldState(CodeFoldState states); + CodeFoldState getCodeFoldState() const; void advanceToNextLine(i32 &lineIndex, i32 ¤tTokenId, Location &location); - void advanceTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location); - void moveToLocationColumn(i32 locationColumn, i32 ¤tTokenId, Location &location); + void incrementTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location); + void moveToStringIndex(i32 stringIndex, i32 ¤tTokenId, Location &location); void resetToTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location); + i32 findNextDelimiter(bool openOnly); constexpr static u32 Normal = 0; constexpr static u32 Not = 1; - template T *getValue(const i32 index); + template T *getValue(i32 index); void next(i32 count = 1); bool begin(); void partBegin(); void reset(); void partReset(); - bool resetIfFailed(const bool value); + bool resetIfFailed(bool value); template bool sequenceImpl(); template bool matchOne(const Token &token); template bool sequenceImpl(const auto &... args); template bool sequence(const Token &token, const auto &... args); bool isValid(); - bool peek(const Token &token, const i32 index = 0); + bool peek(const Token &token, i32 index = 0); friend bool Coordinates::operator==(const Coordinates &o) const; friend bool Coordinates::operator!=(const Coordinates &o) const; @@ -763,53 +774,53 @@ namespace hex::ui { friend Coordinates Coordinates::operator-(const Coordinates &o) const; private: - std::vector m_unfoldedLines; - RowToFoldedLine m_foldedLines; - std::vector m_hiddenLines; - std::map m_rowToFoldSymbol = {}; - MatchedDelimiter m_matchedDelimiter = {}; + UnfoldedLines m_unfoldedLines; + FoldedLines m_foldedLines; + HiddenLines m_hiddenLines; + FoldSymbols m_rowToFoldSymbol; + MatchedDelimiter m_matchedDelimiter{}; bool m_colorizerEnabled = true; - std::vector m_defines; + StringVector m_defines; FindReplaceHandler m_findReplaceHandler; - RowToSegments m_rowToSegments = {}; - EditorState m_state = {}; - UndoBuffer m_undoBuffer = {}; - std::vector m_leadingLineSpaces = {}; + RowToFoldSegments m_rowToFoldSegments; + EditorState m_state; + UndoBuffer m_undoBuffer; + Indices m_leadingLineSpaces; i32 m_undoIndex = 0; bool m_updateFlags = true; - Breakpoints m_breakpoints = {}; - ErrorMarkers m_errorMarkers = {}; - ErrorHoverBoxes m_errorHoverBoxes = {}; - ErrorGotoBoxes m_errorGotoBoxes = {}; - CursorBoxes m_cursorBoxes = {}; - CodeFoldKeys m_codeFoldKeys = {}; - CodeFolds m_codeFolds = {}; - CodeFoldKeyMap m_codeFoldKeyMap = {}; - CodeFoldKeyMap m_codeFoldValueMap = {}; - CodeFoldKeyLineMap m_codeFoldKeyLineMap = {}; - CodeFoldKeyLineMap m_codeFoldValueLineMap = {}; - CodeFoldDelimiters m_codeFoldDelimiters = {}; - Range m_codeFoldHighlighted = {}; - CodeFoldState m_codeFoldState = {}; + Breakpoints m_breakpoints; + ErrorMarkers m_errorMarkers; + ErrorHoverBoxes m_errorHoverBoxes; + ErrorGotoBoxes m_errorGotoBoxes; + CursorBoxes m_cursorBoxes; + CodeFoldKeys m_codeFoldKeys; + CodeFolds m_codeFolds; + CodeFoldKeyMap m_codeFoldKeyMap; + CodeFoldKeyMap m_codeFoldValueMap; + CodeFoldKeyLineMap m_codeFoldKeyLineMap; + CodeFoldKeyLineMap m_codeFoldValueLineMap; + CodeFoldDelimiters m_codeFoldDelimiters; + Range m_codeFoldHighlighted; + CodeFoldState m_codeFoldState; bool m_codeFoldsDisabled = false; - std::map m_rowToLineIndex = {}; - std::map m_lineIndexToRow = {}; - ImVec2 m_cursorScreenPosition = {}; - ImVec2 m_lineNumbersStartPos = {}; - LineIndexToScreen m_lineIndexToScreen = {}; - MultiLinesToRow m_multiLinesToRow = {}; - RowCodeFoldTooltips m_rowCodeFoldTooltips = {}; - Range m_interactiveSelection = {}; - std::vector m_clickableText; + IndexMap m_rowToLineIndex; + IndexMap m_lineIndexToRow; + ImVec2 m_cursorScreenPosition; + ImVec2 m_lineNumbersStartPos; + LineIndexToScreen m_lineIndexToScreen; + IndexMap m_multiLinesToRow; + RowCodeFoldTooltips m_rowCodeFoldTooltips; + Range m_interactiveSelection; + StringVector m_clickableText; float m_topRow = 0.0F; bool m_setTopRow = false; bool m_restoreSavedFolds = true; - ImVec2 m_charAdvance = {}; + ImVec2 m_charAdvance; float m_leftMargin = 0.0F; float m_topMargin = 0.0F; float m_lineNumberFieldWidth = 0.0F; bool m_textChanged = false; - LanguageDefinition m_languageDefinition = {}; + LanguageDefinition m_languageDefinition; RegexList m_regexList; float m_numberOfLinesDisplayed = 0; bool m_withinRender = false; @@ -818,7 +829,7 @@ namespace hex::ui { std::string m_title; bool m_unfoldIfNeeded = false; bool m_scrollToCursor = false; - Coordinates m_focusAtCoords = {}; + Coordinates m_focusAtCoords; bool m_updateFocus = false; float m_oldTopMargin = 0.0F; float m_scrollYIncrement = 0.0F; @@ -826,17 +837,18 @@ namespace hex::ui { bool m_breakPointsChanged = false; bool m_readOnly = false; u64 m_startTime = 0; - bool m_codeFoldStateLoaded = false; + bool m_codeFoldsChanged = false; bool m_saveCodeFoldStateRequested = false; bool m_useSavedFoldStatesRequested = false; - bool m_foldsAreInstalled = false; - std::vector m_tokens; - TokenIter m_curr; - TokenIter m_startToken, m_originalPosition, m_partOriginalPosition; + Tokens m_tokens; + SafeTokenIterator m_curr; + SafeTokenIterator m_startToken, m_originalPosition, m_partOriginalPosition; bool m_interrupt = false; - std::vector m_firstTokenIdOfLine; + Indices m_firstTokenIdOfLine; CodeFoldBlocks m_foldPoints; - std::set m_globalBlocks; + GlobalBlocks m_globalBlocks; + i32 m_cachedGlobalRowMax{}; + bool m_globalRowMaxChanged = true; }; private: @@ -871,11 +883,11 @@ namespace hex::ui { float rowToLineIndex(i32 row); float lineIndexToRow(i32 lineNumber); void clearErrorMarkers(); - void clearActionables() {return m_lines.clearActionables();} + void clearActionables() { m_lines.clearActionables();} void saveCodeFoldStates(); void applyCodeFoldStates(); - void readHiddenLines() { m_lines.readHiddenLines(); }; - void writeHiddenLines() { m_lines.writeHiddenLines(); }; + void removeHiddenLinesFromPattern() { m_lines.removeHiddenLinesFromPattern(); }; + void addHiddenLinesToPattern() { m_lines.addHiddenLinesToPattern(); }; // Highlighting private: @@ -889,7 +901,7 @@ namespace hex::ui { void renderSquare(ImVec2 lineStartScreenPos, ImDrawList *drawList, float boxSize, float verticalMargin, i32 color); void renderMinus(ImVec2 lineStartScreenPos, ImDrawList *drawList, float boxSize, float verticalMargin, i32 color); void renderPlus(ImVec2 lineStartScreenPos, ImDrawList *drawList, float boxSize, float verticalMargin, i32 color); - void renderCodeFolds(i32 row, ImDrawList *drawList, i32 color, Lines::FoldSymbol state); + void renderCodeFolds(i32 row, ImDrawList *drawList, i32 color, FoldSymbol state); void drawLineNumbers(float lineNumber); void drawBreakpoints(float lineIndex, const ImVec2 &contentSize, ImDrawList *drawList, std::string title); void drawCodeFolds(float lineIndex, ImDrawList *drawList); @@ -931,12 +943,12 @@ namespace hex::ui { bool isOverwrite() const { return m_overwrite; } void setText(const std::string &text, bool undo = false); void setImGuiChildIgnored(bool value) { m_lines.setImGuiChildIgnored(value); } - std::vector getTextLines() const; + StringVector getTextLines() const; void setLanguageDefinition(const LanguageDefinition &aLanguageDef) { m_lines.setLanguageDefinition(aLanguageDef); } std::string getLineText(i32 line); void setTextChanged(bool value) { m_lines.setTextChanged(value); } - std::string getText(bool addHiddenLines = false) { return m_lines.getText(addHiddenLines); } - void addUndo(std::vector value) { m_lines.addUndo(value); } + std::string getText() { return m_lines.getText(); } + void addUndo(UndoRecords value) { m_lines.addUndo(value); } bool isTextChanged() { return m_lines.isTextChanged(); } void setHandleMouseInputs(bool value) { m_handleMouseInputs = value; } bool isHandleMouseInputsEnabled() const { return m_handleKeyboardInputs; } @@ -967,7 +979,7 @@ namespace hex::ui { void moveEnd(bool select = false); void moveToMatchedDelimiter(bool select = false); void setCursorPosition(const Coordinates &position, bool unfoldIfNeeded = true, bool scrollToCursor = true) { - return m_lines.setCursorPosition(position, unfoldIfNeeded, scrollToCursor); + m_lines.setCursorPosition(position, unfoldIfNeeded, scrollToCursor); }; void setScroll(ImVec2 scroll); ImVec2 getScroll() const {return m_scroll;} @@ -995,8 +1007,8 @@ namespace hex::ui { void codeFoldCollapse(i32 level=1, bool recursive=false, bool all=false); i32 getCodeFoldLevel(i32 line) const; void resetFoldedSelections(); - void computeLPSArray(const std::string &pattern, std::vector & lps); - std::vector KMPSearch(const std::string& text, const std::string& pattern); + void computeLPSArray(const std::string &pattern, Indices & lps); + Indices KMPSearch(const std::string& text, const std::string& pattern); bool isEmpty(); // utf8 @@ -1011,7 +1023,7 @@ namespace hex::ui { Coordinates lineCoordsToIndexCoords(const Coordinates &coordinates); private: float m_lineSpacing = 1.0F; - Lines m_lines = {}; + Lines m_lines; float m_newTopMargin = 0.0F; bool m_topMarginChanged = false; i32 m_tabSize = 4; @@ -1027,7 +1039,7 @@ namespace hex::ui { TextEditor *m_sourceCodeEditor = nullptr; float m_shiftedScrollY = 0; bool m_setScroll = false; - ImVec2 m_scroll = {}; + ImVec2 m_scroll; float m_scrollOffset = 0; float m_maxScroll =0; bool m_scrollFromLines = false; diff --git a/plugins/ui/source/ui/text_editor/codeFolder.cpp b/plugins/ui/source/ui/text_editor/codeFolder.cpp index ee21b308e..56fb7f757 100644 --- a/plugins/ui/source/ui/text_editor/codeFolder.cpp +++ b/plugins/ui/source/ui/text_editor/codeFolder.cpp @@ -3,21 +3,18 @@ #include #include #include +#include +#include #include namespace hex::ui { using namespace pl::core; - using Interval = TextEditor::Interval; - using Token = pl::core::Token; - using Coordinates = TextEditor::Coordinates; + using Interval = TextEditor::Interval; + using Token = pl::core::Token; + using Coordinates = TextEditor::Coordinates; + using RangeFromCoordinates = TextEditor::RangeFromCoordinates; + using CodeFoldState = TextEditor::CodeFoldState; -/* - std::pair TextEditor::convertIndexToLineNumbers(Interval interval) { - if (m_tokens[interval.m_start].location.source->mainSource && m_tokens[interval.m_end].location.source->mainSource) - return std::make_pair(m_tokens[interval.m_start].location.line, m_tokens[interval.m_end].location.line); - return std::make_pair(0, 0); - } -*/ void TextEditor::Lines::skipAttribute() { if (sequence(tkn::Separator::LeftBracket, tkn::Separator::LeftBracket)) { @@ -26,52 +23,17 @@ namespace hex::ui { } } - std::vector TextEditor::Lines::searchRangeForBlocks(Interval interval) { - m_curr = m_startToken + interval.m_start; - std::vector result; - - u32 nestedLevel = 0; - std::vector tokenStack; - while (m_curr != m_startToken + interval.m_end) { - - if (sequence(tkn::Separator::LeftBrace)) { - auto tokenId = getTokenId(m_curr[-1].location); - tokenStack.push_back(tokenId); - nestedLevel++; - } else if (sequence(tkn::Separator::RightBrace)) { - nestedLevel--; - - if (tokenStack.empty()) - return result; - Interval range(tokenStack.back(), getTokenId(m_curr[-1].location)); - tokenStack.pop_back(); - - result.push_back(range); - - if (nestedLevel == 0) { - skipAttribute(); - break; - } - - } else if (peek(tkn::Separator::EndOfProgram)) - return result; - else - next(); - } - return result; - } - Interval TextEditor::Lines::findBlockInRange(Interval interval) { Interval result = NotValid; - auto tokenStart = TokenIter(m_tokens.begin(), m_tokens.end()); + auto tokenStart = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); bool foundKey = false; bool foundComment = false; m_curr = tokenStart + interval.m_start; - while (interval.m_end >= getTokenId(m_curr->location)) { + while (interval.m_end >= getTokenId()) { if (peek(tkn::Separator::EndOfProgram)) return NotValid; - if (result.m_start = getTokenId(m_curr->location); result.m_start < 0) + if (result.m_start = getTokenId(); result.m_start < 0) return NotValid; while (true) { @@ -115,10 +77,10 @@ namespace hex::ui { break; } if (foundKey || foundComment) { - auto currentId = getTokenId(m_curr->location); + auto currentId = getTokenId(); if (peek(tkn::Separator::EndOfProgram) || (currentId > 0 && currentId < (i32) m_tokens.size())) { next(-1); - if (result.m_end = getTokenId(m_curr->location); result.m_end < 0) + if (result.m_end = getTokenId(); result.m_end < 0) return NotValid; return result; @@ -133,19 +95,19 @@ namespace hex::ui { Coordinates TextEditor::Lines::findCommentEndCoord(i32 tokenId) { Coordinates result = Invalid; auto save = m_curr; - m_curr = TokenIter(m_tokens.begin(), m_tokens.end()) + tokenId; + m_curr = SafeTokenIterator(m_tokens.begin(), m_tokens.end()) + tokenId; if (peek(tkn::Literal::Comment)) { auto comment = getValue(0); if (comment != nullptr) { auto location = m_curr->location; if (comment->singleLine) - return Coordinates(location.line - 1, location.column + location.length - 2); + return {(i32) (location.line - 1), (i32) (location.column + location.length - 2)}; std::string commentText = comment->comment; auto vectorString = wolv::util::splitString(commentText, "\n"); size_t lineCount = vectorString.size(); auto endColumn = (lineCount == 1) ? location.column + location.length - 1 : vectorString.back().length() + 1; - return Coordinates(location.line + lineCount - 2, endColumn); + return {(i32)(location.line + lineCount - 2), (i32)endColumn}; } } else if (peek(tkn::Literal::DocComment)) { @@ -153,57 +115,24 @@ namespace hex::ui { if (docComment != nullptr) { auto location = m_curr->location; if (docComment->singleLine) - return Coordinates(location.line - 1, location.column + location.length - 2); + return {(i32)(location.line - 1), (i32)(location.column + location.length - 2)}; std::string commentText = docComment->comment; auto vectorString = wolv::util::splitString(commentText, "\n"); size_t lineCount = vectorString.size(); auto endColumn = (lineCount == 1) ? location.column + location.length - 1 : vectorString.back().length() + 1; - return Coordinates(location.line + lineCount - 2, endColumn); + return {(i32)(location.line + lineCount - 2), (i32)endColumn}; } } m_curr = save; return result; } - std::set TextEditor::Lines::blocksFromGlobal() { - std::set result; - if (m_globalBlocks.size() == 1) - return m_globalBlocks; - auto globalsIter = m_globalBlocks.begin(); - bool absorbPreviousToken = false; - while (globalsIter != m_globalBlocks.end()) { - if (absorbPreviousToken && globalsIter->m_start > 0) { - result.insert(Interval(globalsIter->m_start - 1, globalsIter->m_end)); - absorbPreviousToken = false; - } else if (globalsIter->m_start == globalsIter->m_end) { - absorbPreviousToken = true; - } else - result.insert(*globalsIter); - auto nextIter = std::next(globalsIter); - - if (nextIter != m_globalBlocks.end() && absorbPreviousToken) { - result.insert(Interval(globalsIter->m_end, nextIter->m_start - 1)); - absorbPreviousToken = false; - } else if (nextIter != m_globalBlocks.end() && globalsIter->m_end + 1 < nextIter->m_start - 1) - result.insert(Interval(globalsIter->m_end + 1, nextIter->m_start - 1)); - else if (nextIter != m_globalBlocks.end() && globalsIter->m_end + 1 == nextIter->m_start - 1) - absorbPreviousToken = true; - else if (globalsIter->m_end + 1 < (i32) m_tokens.size() - 1) - result.insert(Interval(globalsIter->m_end + 1, (i32) m_tokens.size() - 1)); - - globalsIter++; - } - return result; - } - //comments imports and includes void TextEditor::Lines::nonDelimitedFolds() { - //auto allBlocks = blocksFromGlobal(); auto size = m_tokens.size(); if (size > 0) { Interval block = {0,static_cast(size-1)}; - //for (auto block: allBlocks) { while (true) { auto interval = findBlockInRange(block); @@ -227,10 +156,10 @@ namespace hex::ui { } } - std::pair TextEditor::Lines::getDelimiterLineNumbers(i32 start, i32 end, const std::string &delimiters) { - std::pair result = {Invalid, Invalid}; + RangeFromCoordinates TextEditor::Lines::getDelimiterLineNumbers(i32 start, i32 end, const std::string &delimiters) { + RangeFromCoordinates result = {Invalid, Invalid}; Coordinates first = Invalid; - auto tokenStart = TokenIter(m_tokens.begin(), m_tokens.end()); + auto tokenStart = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); m_curr = tokenStart + start; Token::Separator openSeparator = Token::Separator::EndOfProgram; Token::Separator closeSeparator = Token::Separator::EndOfProgram; @@ -261,7 +190,7 @@ namespace hex::ui { Location location2; auto save = m_curr; while (peek(tkn::Literal::Comment, -1) || peek(tkn::Literal::DocComment, -1)) { - if (getTokenId(m_curr->location) == 0) + if (getTokenId() == 0) break; next(-1); } @@ -305,26 +234,43 @@ namespace hex::ui { } void TextEditor::Lines::advanceToNextLine(i32 &lineIndex, i32 ¤tTokenId, Location &location) { - if (lineIndex = nextLine(lineIndex); lineIndex >= size()) + i32 tempLineIndex; + if (tempLineIndex = nextLine(lineIndex); lineIndex == tempLineIndex) { + lineIndex++; + currentTokenId = -1; + location = Location::Empty(); return; + } + lineIndex = tempLineIndex; currentTokenId = m_firstTokenIdOfLine[lineIndex]; m_curr = m_startToken + currentTokenId; location = m_curr->location; } - void TextEditor::Lines::advanceTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { + void TextEditor::Lines::incrementTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { currentTokenId++; m_curr = m_startToken + currentTokenId; location = m_curr->location; lineIndex = location.line - 1; } - void TextEditor::Lines::moveToLocationColumn(i32 locationColumn, i32 ¤tTokenId, Location &location) { - location.column = locationColumn; - location.length = 1; - if (currentTokenId = getTokenId(location); currentTokenId < 0) + void TextEditor::Lines::moveToStringIndex(i32 stringIndex, i32 ¤tTokenId, Location &location) { + auto curr = m_curr; + i32 tempTokenId; + auto &line = operator[](location.line - 1); + while (stringIndex > line.columnIndex(m_curr->location.column) + (i32) m_curr->location.length && m_curr->location.line == location.line) + next(); + if (peek(tkn::Separator::EndOfProgram)) return; - m_curr = m_startToken + currentTokenId; + + if (tempTokenId = getTokenId(); tempTokenId < 0) { + m_curr = curr; + location = curr->location; + } else { + location = m_curr->location; + currentTokenId = tempTokenId; + } + } void TextEditor::Lines::resetToTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { @@ -333,47 +279,55 @@ namespace hex::ui { lineIndex = location.line - 1; } + i32 TextEditor::Lines::findNextDelimiter(bool openOnly) { + while (!peek(tkn::Separator::EndOfProgram)) { + + if (peek(tkn::Separator::LeftBrace) || peek(tkn::Separator::LeftBracket) || peek(tkn::Separator::LeftParenthesis) || peek(tkn::Operator::BoolLessThan)) + return getTokenId(); + if (!openOnly) { + if (peek(tkn::Separator::RightBrace) || peek(tkn::Separator::RightBracket) || peek(tkn::Separator::RightParenthesis) || peek(tkn::Operator::BoolGreaterThan)) + return getTokenId(); + } + next(); + } + return getTokenId(); + } TextEditor::CodeFoldBlocks TextEditor::Lines::foldPointsFromSource() { + auto code = getText(); + if (code.empty()) + return m_foldPoints; + std::unique_ptr runtime = std::make_unique(); + ContentRegistry::PatternLanguage::configureRuntime(*runtime, nullptr); + std::ignore = runtime->preprocessString(code, pl::api::Source::DefaultSource); + m_tokens = runtime->getInternals().preprocessor->getResult(); + const u32 tokenCount = m_tokens.size(); + if (tokenCount == 0) + return m_foldPoints; loadFirstTokenIdOfLine(); if (m_firstTokenIdOfLine.empty()) return m_foldPoints; m_foldPoints.clear(); nonDelimitedFolds(); - std::string blockDelimiters = "{[(<"; + std::string openDelimiters = "{[(<"; size_t topLine = 0; - i32 bottomLine = size(); - m_startToken = TokenIter(m_tokens.begin(), m_tokens.end()); + m_startToken = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); m_curr = m_startToken; auto location = m_curr->location; i32 lineIndex = topLine; i32 currentTokenId = 0; - while (lineIndex < bottomLine) { - auto line = operator[](lineIndex); - if (line.empty()) { - advanceToNextLine(lineIndex, currentTokenId, location); - if (lineIndex >= bottomLine) { - return m_foldPoints; - } - continue; - } + while (currentTokenId < (i32) tokenCount) { - if (size_t columnIndex = line.m_chars.find_first_of(blockDelimiters, location.column - 1); columnIndex != std::string::npos) { - std::string openDelimiter = std::string(1, line[columnIndex]); - moveToLocationColumn(columnIndex + 1, currentTokenId, location); + if (currentTokenId = findNextDelimiter(true); !peek(tkn::Separator::EndOfProgram)) { if (currentTokenId < 0) { return m_foldPoints; } + auto line = operator[](m_curr->location.line - 1); + size_t stringIndex = line.columnIndex(m_curr->location.column); + std::string openDelimiter = std::string(1, line[stringIndex - 1]); + location = m_curr->location; - if (m_curr[0].getFormattedType() != "Operator" && m_curr[0].getFormattedType() != "Separator") { - if (currentTokenId >= (i32) m_tokens.size()) { - return m_foldPoints; - } - advanceTokenId(lineIndex, currentTokenId, location); - continue; - } - - if (auto idx = blockDelimiters.find(openDelimiter); idx != std::string::npos) { + if (auto idx = openDelimiters.find(openDelimiter); idx != std::string::npos) { if (idx == 3) { if (currentTokenId == 0) { return m_foldPoints; @@ -386,7 +340,7 @@ namespace hex::ui { return m_foldPoints; } - if (currentTokenId = getTokenId(m_curr->location); currentTokenId < 0) { + if (currentTokenId = getTokenId(); currentTokenId < 0) { return m_foldPoints; } resetToTokenId(lineIndex, currentTokenId, location); @@ -404,18 +358,15 @@ namespace hex::ui { if (lineBased.first.getLine() != lineBased.second.getLine()) m_foldPoints[lineBased.first] = lineBased.second; - if (currentTokenId = getTokenId(m_tokens[end.first].location); currentTokenId < 0 || currentTokenId >= (i32) m_tokens.size()) { + if (currentTokenId = getTokenId(m_startToken + end.first); currentTokenId < 0 || currentTokenId >= (i32) m_tokens.size()) { return m_foldPoints; } - advanceTokenId(lineIndex, currentTokenId, location); + incrementTokenId(lineIndex, currentTokenId, location); } else { return m_foldPoints; } } else { - advanceToNextLine(lineIndex, currentTokenId, location); - if (lineIndex >= bottomLine) { - return m_foldPoints; - } + return m_foldPoints; } } return m_foldPoints; @@ -425,8 +376,9 @@ namespace hex::ui { std::pair TextEditor::Lines::findMatchingDelimiter(i32 from) { std::string blockDelimiters = "{}[]()<>"; std::pair result = std::make_pair(-1, '\0'); - auto tokenStart = TokenIter(m_tokens.begin(), m_tokens.end()); - if (from >= (i32) m_tokens.size()) + auto tokenStart = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); + const i32 tokenCount = m_tokens.size(); + if (from >= tokenCount) return result; m_curr = tokenStart + from; Location location = m_curr->location; @@ -445,44 +397,19 @@ namespace hex::ui { return result; m_curr = tokenStart + currentTokenId; location = m_curr->location; - size_t lineIndex = location.line - 1; - size_t bottomLine = size(); - while (lineIndex < bottomLine) { - line = operator[](lineIndex); - if (line.empty()) { + i32 lineIndex = location.line - 1; + while (currentTokenId < tokenCount) { - if (lineIndex = nextLine(lineIndex); lineIndex >= bottomLine) + if (currentTokenId = findNextDelimiter(false); !peek(tkn::Separator::EndOfProgram)) { + if (currentTokenId < 0) { return result; - currentTokenId = m_firstTokenIdOfLine[lineIndex]; - m_curr = tokenStart + currentTokenId; - location = m_curr->location; - continue; - } - - if (auto columnIndex = line.m_chars.find_first_of(blockDelimiters, location.column - 1); columnIndex != std::string::npos) { - std::string currentChar = std::string(1, line[columnIndex]); - location.column = columnIndex + 1; - location.length = 1; - - if (currentTokenId = getTokenId(location); currentTokenId < 0) - return result; - m_curr = tokenStart + currentTokenId; - if (m_curr[0].getFormattedType() != "Operator" && m_curr[0].getFormattedType() != "Separator") { - - if (currentTokenId >= (i32) m_tokens.size()) - return result; - currentTokenId++; - m_curr = tokenStart + currentTokenId; - location = m_curr->location; - lineIndex = location.line - 1; - continue; } + line = operator[](m_curr->location.line - 1); + std::string currentChar = std::string(1, line[(u64)(m_curr->location.column - 1)]); + location = m_curr->location; if (auto idx = blockDelimiters.find(currentChar); idx != std::string::npos) { if (currentChar == closeDelimiter) { - - if (currentTokenId = getTokenId(location); currentTokenId < 0) - return result; return std::make_pair(currentTokenId, closeDelimiter[0]); } else { if (idx == 6 || idx == 7) { @@ -494,11 +421,10 @@ namespace hex::ui { return result; } - if (currentTokenId = getTokenId(m_curr->location); currentTokenId < 0) + if (currentTokenId = getTokenId(); currentTokenId < 0) return result; - m_curr = tokenStart + currentTokenId; - location = m_curr->location; - lineIndex = location.line - 1; + + resetToTokenId(lineIndex, currentTokenId, location); continue; } } @@ -512,13 +438,10 @@ namespace hex::ui { if (lineBased.first.getLine() != lineBased.second.getLine()) m_foldPoints[lineBased.first] = lineBased.second; - if (currentTokenId = getTokenId(m_tokens[end.first].location); currentTokenId < 0 || currentTokenId >= (i32) m_tokens.size()) + if (currentTokenId = getTokenId(tokenStart + end.first); currentTokenId < 0 || currentTokenId >= (i32) m_tokens.size()) return result; - currentTokenId++; - m_curr = tokenStart + currentTokenId; - location = m_curr->location; - lineIndex = location.line - 1; + incrementTokenId(lineIndex, currentTokenId, location); } else return result; } @@ -526,23 +449,19 @@ namespace hex::ui { return result; } } else { - - if (lineIndex = nextLine(lineIndex); lineIndex >= bottomLine) - return result; - currentTokenId = m_firstTokenIdOfLine[lineIndex]; - m_curr = tokenStart + currentTokenId; - location = m_curr->location; + return result; } } return result; } + void TextEditor::saveCodeFoldStates() { m_lines.saveCodeFoldStates(); } void TextEditor::Lines::saveCodeFoldStates() { i32 codeFoldIndex = 0; - std::vector closedFoldIncrements; + Indices closedFoldIncrements; for (auto key: m_codeFoldKeys) { if (m_codeFoldState.contains(key) && !m_codeFoldState[key]) { closedFoldIncrements.push_back(codeFoldIndex); @@ -550,6 +469,10 @@ namespace hex::ui { } else codeFoldIndex++; } + if (!m_hiddenLines.empty()) + m_hiddenLines.clear(); + if (closedFoldIncrements.empty()) + return; std::string result = "//+-#:"; for (u32 i = 0; i < closedFoldIncrements.size(); ++i) { result += std::to_string(closedFoldIncrements[i]); @@ -557,37 +480,49 @@ namespace hex::ui { result += ","; } auto lineIndex = 0; - HiddenLine hiddenLine(lineIndex, result); - if (!m_hiddenLines.empty()) { - m_hiddenLines[0] = hiddenLine; - return; - } - m_hiddenLines.push_back(hiddenLine); + m_hiddenLines.emplace_back(lineIndex, result); } void TextEditor::applyCodeFoldStates() { m_lines.applyCodeFoldStates(); } + void TextEditor::Lines::setCodeFoldState(CodeFoldState state) { + m_codeFoldState = state; + } + + CodeFoldState TextEditor::Lines::getCodeFoldState() const { + return m_codeFoldState; + } + void TextEditor::Lines::applyCodeFoldStates() { std::string commentLine; - for (auto line: m_hiddenLines) { + for (const auto& line: m_hiddenLines) { if (line.m_line.starts_with("//+-#:")) { commentLine = line.m_line; break; } } - if (commentLine.size() < 6 || !commentLine.starts_with("//+-#:")) + if (commentLine.size() < 6 || !commentLine.starts_with("//+-#:")) { + for (auto key: m_codeFoldKeys) + m_codeFoldState[key] = true; return; + } auto states = commentLine.substr(6); - auto stringVector = wolv::util::splitString(states, ",", true); - auto count = stringVector.size(); + i32 count; + StringVector stringVector; + if (states.empty()) + count = 0; + else { + stringVector = wolv::util::splitString(states, ",", true); + count = stringVector.size(); + } if (count == 1 && stringVector[0].empty()) return; - std::vector closedFoldIncrements(count); + Indices closedFoldIncrements(count); i32 value = 0; - for (u32 i = 0; i < count; ++i) { + for (i32 i = 0; i < count; ++i) { auto stateStr = stringVector[i]; std::from_chars(stateStr.data(), stateStr.data() + stateStr.size(), value); closedFoldIncrements[i] = value; @@ -607,8 +542,9 @@ namespace hex::ui { void TextEditor::Lines::closeCodeFold(const Range &key, bool userTriggered) { float topRow; - if (userTriggered) + if (userTriggered) { topRow = m_topRow; + } LineIndexToScreen lineIndexToScreen; bool needsDelimiter = lineNeedsDelimiter(key.m_start.m_line); auto lineIter = m_lineIndexToScreen.begin(); @@ -712,7 +648,7 @@ namespace hex::ui { m_foldedLines[newFoldedLine.m_row] = newFoldedLine; currentFoldedLine = m_foldedLines[newFoldedLine.m_row]; } - std::map updatedFoldedLines; + FoldedLines updatedFoldedLines; for (auto &[row, foldedLine] : m_foldedLines) { if (row > currentFoldedLine.m_row) { foldedLine.m_row -= (key.m_end.m_line - key.m_start.m_line); @@ -730,12 +666,13 @@ namespace hex::ui { m_topRow = topRow; m_setTopRow = true; m_saveCodeFoldStateRequested = true; + m_globalRowMaxChanged = true; } m_foldedLines[currentFoldedLine.m_row].loadSegments(); } void TextEditor::Lines::openCodeFold(const Range &key) { - for (auto foldedLine : m_foldedLines) { + for (const auto& foldedLine : m_foldedLines) { for (auto foldKey : foldedLine.second.m_keys) { if (foldKey.contains(key) && foldKey != key) { m_codeFoldState[key] = true; @@ -778,7 +715,7 @@ namespace hex::ui { } } if (erasedRow != -1) { - std::map updatedFoldedLines; + FoldedLines updatedFoldedLines; for (auto &[row, foldedLine] : m_foldedLines) { if (row > erasedRow) { foldedLine.m_row += (key.m_end.m_line - key.m_start.m_line); @@ -790,6 +727,7 @@ namespace hex::ui { m_foldedLines = std::move(updatedFoldedLines); } m_saveCodeFoldStateRequested = true; + m_globalRowMaxChanged = true; } void TextEditor::openCodeFoldAt(Coordinates line) { @@ -814,7 +752,7 @@ namespace hex::ui { } if (count == 0) return; - i32 id = getTokenId(m_curr->location); + i32 id = getTokenId(); if (count > 0) m_curr += std::min(count,static_cast(m_tokens.size() - id)); @@ -904,15 +842,13 @@ namespace hex::ui { return false; return false; } - if (!isLocationValid(token.location)) - return false; - return true; + return isLocationValid(token.location); } bool TextEditor::Lines::peek(const Token &token, const i32 index) { if (!isValid()) return false; - i32 id = getTokenId(m_curr->location); + i32 id = getTokenId(); if (id+index < 0 || id+index >= (i32)m_tokens.size()) return false; return m_curr[index].type == token.type && m_curr[index] == token.value; diff --git a/plugins/ui/source/ui/text_editor/editor.cpp b/plugins/ui/source/ui/text_editor/editor.cpp index c7c4f1adc..ceed9f986 100644 --- a/plugins/ui/source/ui/text_editor/editor.cpp +++ b/plugins/ui/source/ui/text_editor/editor.cpp @@ -3,21 +3,23 @@ #include #include #include +#include #include #include -#include #define IMGUI_DEFINE_MATH_OPERATORS #include "imgui.h" namespace hex::ui { + using StringVector = TextEditor::StringVector; + using Range = TextEditor::Range; + using EditorState = TextEditor::EditorState; - - TextEditor::FindReplaceHandler::FindReplaceHandler() : m_matchCase(false), m_wholeWord(false), m_findRegEx(false) {} + TextEditor::FindReplaceHandler::FindReplaceHandler() : m_matchCase(false), m_wholeWord(false), m_findRegEx(false), m_optionsChanged(false) {} TextEditor::TextEditor() { m_lines.m_startTime = ImGui::GetTime() * 1000; m_lines.setLanguageDefinition(LanguageDefinition::HLSL()); - m_lines.m_unfoldedLines.push_back(Line()); + m_lines.m_unfoldedLines.emplace_back(); m_lineSpacing = 1.0f; m_tabSize = 4; @@ -25,8 +27,7 @@ namespace hex::ui { m_lines.m_state.m_selection.m_start = m_lines.m_state.m_selection.m_end = lineCoordinates( 0, 0); } - TextEditor::~TextEditor() { - } + TextEditor::~TextEditor() = default; std::string TextEditor::Lines::getRange(const Range &rangeToGet) { std::string result; @@ -38,7 +39,7 @@ namespace hex::ui { result = m_unfoldedLines[selection.m_start.m_line].substr(columns.m_line, columns.m_column, Line::LinePart::Utf8); } else { auto lines = selection.getSelectedLines(); - std::vector lineContents; + StringVector lineContents; lineContents.push_back(m_unfoldedLines[lines.m_line].substr(columns.m_line, (u64) -1, Line::LinePart::Utf8)); for (i32 i = lines.m_line + 1; i < lines.m_column; i++) { lineContents.push_back(m_unfoldedLines[i].m_chars); @@ -70,8 +71,8 @@ namespace hex::ui { firstLine.insert(firstLine.end(), lastLine.begin(), lastLine.end()); firstLine.m_colorized = false; } - if (lines.m_line+1 < lines.m_column) - removeLines(lines.m_line+1,lines.m_column); + if (lines.m_line + 1 < lines.m_column) + removeLines(lines.m_line + 1, lines.m_column); else removeLine(lines.m_column); } @@ -88,7 +89,7 @@ namespace hex::ui { m_unfoldedLines[0].m_colors = std::string(text.size(), 0); m_unfoldedLines[0].m_flags = std::string(text.size(), 0); } else { - m_unfoldedLines.push_back(Line(text)); + m_unfoldedLines.emplace_back(text); auto line = m_unfoldedLines.back(); line.m_lineMaxColumn = line.maxColumn(); } @@ -97,7 +98,7 @@ namespace hex::ui { void TextEditor::appendLine(const std::string &value) { m_lines.appendLine(value); - m_lines.setCursorPosition(m_lines.lineCoordinates((i32) m_lines.size() - 1, 0), false); + m_lines.setCursorPosition(m_lines.lineCoordinates(m_lines.size() - 1, 0), false); m_lines.m_unfoldedLines.back().m_colorized = false; m_lines.ensureCursorVisible(); m_lines.m_textChanged = true; @@ -147,7 +148,7 @@ namespace hex::ui { line.m_colorized = false; for (i32 i = 1; i < lineCount; i++) { insertLine(start.m_line + i, stringVector[i]); - m_unfoldedLines[start.m_line + i].m_colorized =false; + m_unfoldedLines[start.m_line + i].m_colorized = false; } m_textChanged = true; return lineCount; @@ -166,7 +167,6 @@ namespace hex::ui { } void TextEditor::Lines::removeLines(i32 lineStart, i32 lineEnd) { - ErrorMarkers errorMarkers; for (auto &errorMarker : m_errorMarkers) { if (errorMarker.first.m_line <= lineStart || errorMarker.first.m_line > lineEnd + 1) { @@ -192,6 +192,7 @@ namespace hex::ui { breakpoints.insert(breakpoint); } } + m_breakpoints = std::move(breakpoints); CodeFoldKeys folds; @@ -224,14 +225,15 @@ namespace hex::ui { } // use clamp to ensure valid results instead of assert. - auto start = std::clamp(lineStart, 0, (i32) size() - 1); - auto end = std::clamp(lineEnd, 0, (i32) size()); + auto start = std::clamp(lineStart, 0, size() - 1); + auto end = std::clamp(lineEnd, 0, size()); if (start > end) std::swap(start, end); m_unfoldedLines.erase(m_unfoldedLines.begin() + lineStart, m_unfoldedLines.begin() + lineEnd + 1); m_textChanged = true; + m_globalRowMaxChanged = true; } void TextEditor::Lines::removeLine(i32 index) { @@ -239,7 +241,7 @@ namespace hex::ui { } void TextEditor::Lines::insertLine(i32 index, const std::string &text) { - if (index < 0 || index > (i32) size()) + if (index < 0 || index > size()) return; auto &line = insertLine(index); line.append(text); @@ -248,14 +250,15 @@ namespace hex::ui { } TextEditor::Line &TextEditor::Lines::insertLine(i32 index) { - + m_globalRowMaxChanged = true; if (isEmpty()) return *m_unfoldedLines.insert(m_unfoldedLines.begin(), Line()); - if (index == (i32)size()) + if (index == size()) return *m_unfoldedLines.insert(m_unfoldedLines.end(), Line()); TextEditor::Line &result = *m_unfoldedLines.insert(m_unfoldedLines.begin() + index, Line()); + result.m_colorized = false; ErrorMarkers errorMarkers; @@ -309,11 +312,10 @@ namespace hex::ui { } void TextEditor::setText(const std::string &text, bool undo) { - UndoRecord u; if (!m_lines.m_readOnly && undo) { u.m_before = m_lines.m_state; - u.m_removed = m_lines.getText(false); + u.m_removed = m_lines.getText(); u.m_removedRange.m_start = m_lines.lineCoordinates(0, 0); u.m_removedRange.m_end = m_lines.lineCoordinates(-1, -1); if (u.m_removedRange.m_start == Invalid || u.m_removedRange.m_end == Invalid) @@ -328,7 +330,7 @@ namespace hex::ui { m_lines.m_hiddenLines.clear(); u64 i = 0; while (vectorString[i].starts_with("//+-")) { - m_lines.m_hiddenLines.push_back(HiddenLine(i, vectorString[i])), i++; + m_lines.m_hiddenLines.emplace_back(i, vectorString[i]), i++; } vectorString.erase(vectorString.begin(), vectorString.begin() + i); lineCount = vectorString.size(); @@ -336,7 +338,7 @@ namespace hex::ui { m_lines.m_unfoldedLines.clear(); m_lines.m_unfoldedLines.resize(lineCount); - for (auto line: vectorString) { + for (const auto &line: vectorString) { auto &unfoldedLine = m_lines.m_unfoldedLines[i]; unfoldedLine.setLine(line); @@ -355,31 +357,29 @@ namespace hex::ui { m_lines.m_textChanged = true; if (!m_lines.m_readOnly && undo) { u.m_after = m_lines.m_state; - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); } - m_lines.setAllCodeFolds(); - applyCodeFoldStates(); - m_lines.m_useSavedFoldStatesRequested = true; m_lines.colorize(); } void TextEditor::enterCharacter(ImWchar character, bool shift) { - if (m_lines.m_readOnly) return; - auto row = lineIndexToRow(m_lines.m_state.m_cursorPosition.m_line); - if (m_lines.m_foldedLines.contains(row)) { - auto foldedLine = m_lines.m_foldedLines[row]; - auto foldedCoords = m_lines.unfoldedToFoldedCoords(m_lines.m_state.m_cursorPosition); - if (foldedLine.m_foldedLine.m_chars[foldedCoords.m_column] == '.') { - auto keyCount = foldedLine.m_keys.size(); - for (u32 i = 0; i < keyCount; i++) { - if (foldedCoords.m_column >= foldedLine.m_ellipsisIndices[i] && - foldedCoords.m_column <= foldedLine.m_ellipsisIndices[i] + 3) { - m_lines.openCodeFold(m_lines.m_foldedLines[row].m_keys[i]); - return; + if (!m_lines.m_codeFoldsDisabled) { + auto row = lineIndexToRow(m_lines.m_state.m_cursorPosition.m_line); + if (m_lines.m_foldedLines.contains(row)) { + auto foldedLine = m_lines.m_foldedLines[row]; + auto foldedCoords = m_lines.unfoldedToFoldedCoords(m_lines.m_state.m_cursorPosition); + if (foldedLine.m_foldedLine.m_chars[foldedCoords.m_column] == '.') { + auto keyCount = foldedLine.m_keys.size(); + for (u32 i = 0; i < keyCount; i++) { + if (foldedCoords.m_column >= foldedLine.m_ellipsisIndices[i] && + foldedCoords.m_column <= foldedLine.m_ellipsisIndices[i] + 3) { + m_lines.openCodeFold(m_lines.m_foldedLines[row].m_keys[i]); + return; + } } } } @@ -454,7 +454,7 @@ namespace hex::ui { u.m_after = m_lines.m_state; m_lines.m_state.m_selection = Range(start, end); - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); @@ -476,19 +476,16 @@ namespace hex::ui { u.m_addedRange.m_start = coord; if (m_lines.m_unfoldedLines.empty()) - m_lines.m_unfoldedLines.push_back(Line()); + m_lines.m_unfoldedLines.emplace_back(); if (character == '\n') { m_lines.insertLine(coord.m_line + 1); auto &line = m_lines.m_unfoldedLines[coord.m_line]; auto &newLine = m_lines.m_unfoldedLines[coord.m_line + 1]; + if (m_lines.m_languageDefinition.m_autoIndentation) newLine.append(std::string(m_lines.m_leadingLineSpaces[coord.m_line], ' ')); - //if (m_languageDefinition.m_autoIndentation) - // for (u64 it = 0; it < line.size() && isascii(line[it]) && isblank(line[it]); ++it) - // newLine.push_back(line[it]); - const u64 whitespaceSize = newLine.size(); i32 charStart; i32 charPosition; @@ -538,9 +535,9 @@ namespace hex::ui { } u.m_addedRange.m_end = m_lines.lineCoordinates(m_lines.m_state.m_cursorPosition); } else { - std::string buf = ""; + std::string buf; imTextCharToUtf8(buf, character); - if (buf.size() > 0) { + if (!buf.empty()) { auto &line = m_lines.m_unfoldedLines[coord.m_line]; auto charIndex = m_lines.lineCoordsIndex(coord); @@ -597,7 +594,7 @@ namespace hex::ui { u.m_after = m_lines.m_state; m_lines.m_textChanged = true; - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); m_lines.colorize(); @@ -659,7 +656,7 @@ namespace hex::ui { auto &line = m_lines.m_unfoldedLines[pos.m_line]; if (pos.m_column == line.maxColumn()) { - if (pos.m_line == (i32) m_lines.size() - 1) + if (pos.m_line == m_lines.size() - 1) return; u.m_removed = '\n'; @@ -688,7 +685,7 @@ namespace hex::ui { } u.m_after = m_lines.m_state; - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); m_lines.refreshSearchResults(); @@ -773,7 +770,7 @@ namespace hex::ui { } u.m_after = m_lines.m_state; - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); m_lines.refreshSearchResults(); @@ -786,7 +783,7 @@ namespace hex::ui { if (!m_lines.isEmpty()) { std::string str; const auto &line = m_lines.m_unfoldedLines[m_lines.lineCoordinates(m_lines.m_state.m_cursorPosition).m_line]; - std::copy(line.m_chars.begin(), line.m_chars.end(), std::back_inserter(str)); + std::ranges::copy(line.m_chars, std::back_inserter(str)); ImGui::SetClipboardText(str.c_str()); } } @@ -798,7 +795,7 @@ namespace hex::ui { } else { if (!m_lines.hasSelection()) { auto lineIndex = m_lines.lineCoordinates(m_lines.m_state.m_cursorPosition).m_line; - if (lineIndex < 0 || lineIndex >= (i32) m_lines.size()) + if (lineIndex < 0 || lineIndex >= m_lines.size()) return; setSelection(Range(m_lines.lineCoordinates(lineIndex, 0), m_lines.lineCoordinates(lineIndex + 1, 0))); } @@ -811,7 +808,7 @@ namespace hex::ui { m_lines.deleteSelection(); u.m_after = m_lines.m_state; - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); } @@ -841,7 +838,7 @@ namespace hex::ui { m_lines.setCursorPosition(u.m_addedRange.m_end, false); setSelection(Range(u.m_addedRange.m_end, u.m_addedRange.m_end)); u.m_after = m_lines.m_state; - std::vector v; + UndoRecords v; v.push_back(u); m_lines.addUndo(v); } @@ -855,7 +852,7 @@ namespace hex::ui { const char *clipText = ImGui::GetClipboardText(); if (clipText != nullptr) { auto stringVector = wolv::util::splitString(clipText, "\n", false); - if (std::any_of(stringVector.begin(), stringVector.end(), [](const std::string &s) { return s.size() > 1024; })) { + if (std::ranges::any_of(stringVector, [](const std::string &s) { return s.size() > 1024; })) { ui::PopupQuestion::open("hex.builtin.view.pattern_editor.warning_paste_large"_lang, [this, clipText]() { this->doPaste(clipText); }, [] {}); @@ -889,25 +886,18 @@ namespace hex::ui { m_lines.refreshSearchResults(); } - std::string TextEditor::Lines::getText(bool includeHiddenLines) { + std::string TextEditor::Lines::getText() { auto start = lineCoordinates(0, 0); auto size = m_unfoldedLines.size(); auto line = m_unfoldedLines[size - 1]; auto end = Coordinates( size - 1, line.m_lineMaxColumn); if (start == Invalid || end == Invalid) return ""; - std::string result; - if (includeHiddenLines) { - for (const auto &hiddenLine: m_hiddenLines) { - result += hiddenLine.m_line + "\n"; - } - } - result += getRange(Range(start, end)); - return result; + return getRange(Range(start, end)); } - std::vector TextEditor::getTextLines() const { - std::vector result; + StringVector TextEditor::getTextLines() const { + StringVector result; result.reserve(m_lines.size()); @@ -933,11 +923,11 @@ namespace hex::ui { TextEditor::UndoRecord::UndoRecord( std::string added, - TextEditor::Range addedRange, + Range addedRange, std::string removed, - TextEditor::Range removedRange, - TextEditor::EditorState &before, - TextEditor::EditorState &after) : m_added(added), m_addedRange(addedRange), m_removed(removed), m_removedRange(removedRange), m_before(before), m_after(after) {} + Range removedRange, + EditorState before, + EditorState after) : m_added(std::move(added)), m_addedRange(addedRange), m_removed(std::move(removed)), m_removedRange(removedRange), m_before(std::move(before)), m_after(std::move(after)) {} void TextEditor::UndoRecord::undo(TextEditor *editor) { if (!m_added.empty()) { @@ -972,13 +962,13 @@ namespace hex::ui { } void TextEditor::UndoAction::undo(TextEditor *editor) { - for (i32 i = (i32) m_records.size() - 1; i >= 0; i--) - m_records.at(i).undo(editor); + for (auto &record : std::ranges::reverse_view(m_records)) + record.undo(editor); } void TextEditor::UndoAction::redo(TextEditor *editor) { - for (i32 i = 0; i < (i32) m_records.size(); i++) - m_records.at(i).redo(editor); + for (auto &record : m_records) + record.redo(editor); } } \ No newline at end of file diff --git a/plugins/ui/source/ui/text_editor/highlighter.cpp b/plugins/ui/source/ui/text_editor/highlighter.cpp index 82f598dbb..5c8fd9782 100644 --- a/plugins/ui/source/ui/text_editor/highlighter.cpp +++ b/plugins/ui/source/ui/text_editor/highlighter.cpp @@ -5,7 +5,7 @@ namespace hex::ui { extern TextEditor::Palette s_paletteBase; - + using Keys = TextEditor::Keys; template bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p) { @@ -41,9 +41,9 @@ namespace hex::ui { } } - std::vector TextEditor::Lines::getDeactivatedBlocks() { + Keys TextEditor::Lines::getDeactivatedBlocks() { colorizeInternal(); - std::vector deactivatedBlocks; + Keys deactivatedBlocks; if (isEmpty()) return deactivatedBlocks; for (i32 i = 0; i < size(); ++i) { @@ -85,7 +85,6 @@ namespace hex::ui { if (isEmpty()) return; - std::smatch results; std::string id; if (m_languageDefinition.m_tokenize == nullptr) { m_languageDefinition.m_tokenize = [](strConstIter, strConstIter, strConstIter &, strConstIter &, PaletteIndex &) { return false; }; @@ -214,7 +213,7 @@ namespace hex::ui { auto withinString = false; auto withinBlockComment = false; auto withinNotDef = false; - auto currentLine = endLine; + i32 currentLine; auto commentLength = 0; auto matchedBracket = false; diff --git a/plugins/ui/source/ui/text_editor/navigate.cpp b/plugins/ui/source/ui/text_editor/navigate.cpp index 7c334a47f..993fb91ca 100644 --- a/plugins/ui/source/ui/text_editor/navigate.cpp +++ b/plugins/ui/source/ui/text_editor/navigate.cpp @@ -32,7 +32,7 @@ namespace hex::ui { TextEditor::Coordinates TextEditor::Lines::rfind( const std::string &text, const Coordinates &from) { Coordinates result = Invalid; - if (text.empty() || isEmpty() || from.m_line >= (i32) size() || from.m_line < 0) + if (text.empty() || isEmpty() || from.m_line >= size() || from.m_line < 0) return result; for (i32 i = from.m_line; i >= 0; --i) { auto &line = m_unfoldedLines[i]; @@ -48,9 +48,9 @@ namespace hex::ui { TextEditor::Coordinates TextEditor::Lines::find(const std::string &text, const Coordinates &from) { Coordinates result = Invalid; - if (text.empty() || isEmpty() || from.m_line >= (i32) size() || from.m_line < 0) + if (text.empty() || isEmpty() || from.m_line >= size() || from.m_line < 0) return result; - for (i32 i = from.m_line; i < (i32) size(); ++i) { + for (i32 i = from.m_line; i < size(); ++i) { auto &line = m_unfoldedLines[i]; auto index = line.m_chars.find(text, (i == from.m_line) ? from.m_column : 0); if (index != std::string::npos) { @@ -429,7 +429,6 @@ namespace hex::ui { m_setScroll = false; ImGui::SetScrollX(scroll.x); ImGui::SetScrollY(scroll.y); - //m_updateFocus = true; } } @@ -461,9 +460,7 @@ namespace hex::ui { if (std::abs(m_line) > maxLine) return false; auto maxColumn = lines.lineMaxColumn(m_line); - if (std::abs(m_column) > maxColumn) - return false; - return true; + return std::abs(m_column) > maxColumn; } TextEditor::Coordinates TextEditor::Coordinates::sanitize(Lines &lines) { @@ -492,7 +489,7 @@ namespace hex::ui { TextEditor::Range::Coordinates TextEditor::Lines::lineCoordinates(i32 lineIndex, i32 column) { if (isEmpty()) - return Coordinates( 0, 0); + return {0, 0}; Coordinates result(lineIndex, column); return result.sanitize(*this); @@ -516,11 +513,11 @@ namespace hex::ui { auto start = lineCoordinates(value.m_start); auto end = lineCoordinates(value.m_end); if (start == Invalid || end == Invalid) - return Range(Invalid, Invalid); + return {Invalid, Invalid}; if (start > end) { std::swap(start, end); } - return Range(start, end); + return {start, end}; } void TextEditor::advance(Coordinates &coordinates) { @@ -542,7 +539,7 @@ namespace hex::ui { TextEditor::Coordinates TextEditor::findWordStart(const Coordinates &from) { Coordinates at = m_lines.lineCoordinates(from); - if (at.m_line >= (i32) m_lines.size()) + if (at.m_line >= m_lines.size()) return at; auto &line = m_lines.m_unfoldedLines[at.m_line]; @@ -564,7 +561,7 @@ namespace hex::ui { TextEditor::Coordinates TextEditor::findWordEnd(const Coordinates &from) { Coordinates at = m_lines.lineCoordinates(from); - if (at.m_line >= (i32) m_lines.size()) + if (at.m_line >= m_lines.size()) return at; auto &line = m_lines.m_unfoldedLines[at.m_line]; @@ -587,7 +584,7 @@ namespace hex::ui { TextEditor::Coordinates TextEditor::Lines::findNextWord(const Coordinates &from) { Coordinates at = unfoldedToFoldedCoords(from); - if (at.m_line >= (i32) size()) + if (at.m_line >= size()) return from; auto &line = operator[](at.m_line); @@ -608,7 +605,7 @@ namespace hex::ui { TextEditor::Coordinates TextEditor::Lines::findPreviousWord(const Coordinates &from) { Coordinates at = unfoldedToFoldedCoords(from); - if (at.m_line >= (i32) size()) + if (at.m_line >= size()) return from; auto &line = operator[](at.m_line); @@ -628,13 +625,9 @@ namespace hex::ui { return foldedToUnfoldedCoords(lineIndexCoords(at.m_line + 1, charIndex)); } - u32 TextEditor::Line::skipSpaces(i32 index) { - auto charIndex = index; - u32 s = 0; - while (charIndex < (i32) m_chars.size() && m_chars[charIndex] == ' ' && m_colors[charIndex] == 0x00) { - ++s; - ++charIndex; - } + u32 TextEditor::Line::skipSpaces(i32 charIndex) { + u32 s; + for (s = 0; charIndex < (i32) m_chars.size() && m_chars[charIndex] == ' ' && m_flags[charIndex] == 0x00; ++s, ++charIndex); return s; } @@ -793,7 +786,7 @@ namespace hex::ui { result = start; auto lineIndex = start.m_line; auto row = lines->lineIndexToRow(lineIndex); - auto maxLineIndex = (i32) lines->size() - 1; + auto maxLineIndex = lines->size() - 1; auto charIndex = lines->lineCoordsIndex(start); std::string line; std::string colors; @@ -888,8 +881,8 @@ namespace hex::ui { else i = 0; } - if ((i32) (direction * i) >= (i32) ((line.size() - 1) * (1 + direction) / 2)) { - if (lines->rowToLineIndex(row) == (i64) maxLineIndex * (1 + direction) / 2) { + if ((direction * i) >= (i32) ((line.size() - 1) * (1 + direction) / 2)) { + if (lines->rowToLineIndex(row) == (i64) maxLineIndex * ((1 + direction) >> 1)) { if (m_active) { m_active = false; m_changed = true; diff --git a/plugins/ui/source/ui/text_editor/render.cpp b/plugins/ui/source/ui/text_editor/render.cpp index 8fe6b99b6..0ee2544cc 100644 --- a/plugins/ui/source/ui/text_editor/render.cpp +++ b/plugins/ui/source/ui/text_editor/render.cpp @@ -2,14 +2,13 @@ #include "fonts/fonts.hpp" #include #include -#include #include #include namespace hex::ui { TextEditor::Palette s_paletteBase = TextEditor::getDarkPalette(); - + using Keys = TextEditor::Keys; inline void TextUnformattedColored(const ImU32 &color, const char *text) { ImGui::PushStyleColor(ImGuiCol_Text, color); @@ -104,7 +103,7 @@ namespace hex::ui { } return !line.ends_with('{'); } - return m_foldedLines[row].firstLineNeedsDelimiter(); + return m_foldedLines.at(row).firstLineNeedsDelimiter(); } bool TextEditor::FoldedLine::firstLineNeedsDelimiter() { @@ -172,14 +171,14 @@ namespace hex::ui { } bool TextEditor::Lines::isEndOfLine(const Coordinates &coordinates) { - if (coordinates.m_line < (i32) size()) + if (coordinates.m_line < size()) return m_unfoldedLines[coordinates.m_line].isEndOfLine(coordinates.m_column); return true; } bool TextEditor::Lines::isEndOfFile(const Coordinates &coordinates) { - if (coordinates.m_line < (i32) size()) + if (coordinates.m_line < size()) return isLastLine(coordinates.m_line) && isEndOfLine(coordinates); return true; @@ -212,29 +211,35 @@ namespace hex::ui { } float TextEditor::Lines::getGlobalRowMax() { - auto maxRow = size() - 1.0f; - std::vector spanningIntervals; - if (m_codeFoldKeys.empty()) + float maxRow = size() - 1.0f; + if (m_codeFoldsDisabled || m_foldedLines.empty() || m_codeFoldKeys.empty()) return std::floor(maxRow); - for (auto key1 = m_codeFoldKeys.begin(); key1 != m_codeFoldKeys.end(); ++key1) { - auto key2 = std::next(key1); - while (key2 != m_codeFoldKeys.end() && (!key2->contains(*key1) || (m_codeFoldState.contains(*key2) && m_codeFoldState[*key2]))) { - ++key2; - } - if (key2 == m_codeFoldKeys.end()) - spanningIntervals.push_back(*key1); - } - for (auto key: spanningIntervals) { - if (m_codeFoldState.contains(key) && !m_codeFoldState[key]) { - if ((key.m_end.m_line - key.m_start.m_line - 1) < maxRow) { - maxRow -= ((key.m_end.m_line - key.m_start.m_line)); + if (m_globalRowMaxChanged) { + Keys spanningIntervals; + + for (auto key1 = m_codeFoldKeys.begin(); key1 != m_codeFoldKeys.end(); ++key1) { + auto key2 = std::next(key1); + while (key2 != m_codeFoldKeys.end() && (!key2->contains(*key1) || (m_codeFoldState.contains(*key2) && m_codeFoldState[*key2]))) { + ++key2; + } + if (key2 == m_codeFoldKeys.end()) + spanningIntervals.push_back(*key1); + } + + for (auto key: spanningIntervals) { + if (m_codeFoldState.contains(key) && !m_codeFoldState[key]) { + if ((key.m_end.m_line - key.m_start.m_line - 1) < maxRow) { + maxRow -= ((key.m_end.m_line - key.m_start.m_line)); + } else + break; } else - break; - } else - m_codeFoldState[key] = true; + m_codeFoldState[key] = true; + } + m_cachedGlobalRowMax = std::floor(maxRow); + m_globalRowMaxChanged = false; } - return std::floor(maxRow); + return m_cachedGlobalRowMax; } float TextEditor::getMaxLineNumber() { @@ -245,7 +250,7 @@ namespace hex::ui { float currentLineNumber = m_topLineNumber; for (auto range: m_lines.m_codeFoldKeys) { - if (m_lines.m_codeFoldState.contains(range) && m_lines.m_codeFoldState[range] == false) { + if (m_lines.m_codeFoldState.contains(range) && !m_lines.m_codeFoldState[range]) { if ((range.m_start.m_line - currentLineNumber) < maxLineNumber) maxLineNumber += ((range.m_end.m_line - range.m_start.m_line)); @@ -264,7 +269,7 @@ namespace hex::ui { if (interval.m_start.m_line > result) break; - if (m_lines.m_codeFoldState.contains(interval) && m_lines.m_codeFoldState[interval] == false) + if (m_lines.m_codeFoldState.contains(interval) && !m_lines.m_codeFoldState[interval]) result += (interval.m_end.m_line- interval.m_start.m_line); else m_lines.m_codeFoldState[interval] = true; @@ -372,12 +377,12 @@ namespace hex::ui { auto row = lineIndexToRow(pos.m_line); if (m_unfoldIfNeeded && m_foldedLines.contains(row) && !m_codeFoldsDisabled) { - auto foldedLine = m_foldedLines[row]; + auto foldedLine = m_foldedLines.at(row); auto foldedCoords = unfoldedToFoldedCoords(pos); auto keyCount = foldedLine.m_keys.size(); for (u32 i = 0; i < keyCount; i++) { if (foldedCoords.m_column >= foldedLine.m_ellipsisIndices[i] && foldedCoords.m_column <= foldedLine.m_ellipsisIndices[i] + 3) { - openCodeFold(m_foldedLines[row].m_keys[i]); + openCodeFold(m_foldedLines.at(row).m_keys[i]); break; } } @@ -468,18 +473,18 @@ namespace hex::ui { } float TextEditor::Lines::rowToLineIndex(i32 row) { - if (m_codeFoldsDisabled) + if (m_codeFoldsDisabled || m_foldedLines.empty() || m_rowToLineIndex.empty()) return row; if (m_rowToLineIndex.contains(row)) - return m_rowToLineIndex[row]; + return m_rowToLineIndex.at(row); return -1.0f; } float TextEditor::Lines::lineIndexToRow(i32 lineIndex) { - if (m_codeFoldsDisabled) + if (m_codeFoldsDisabled || m_foldedLines.empty() || m_lineIndexToRow.empty()) return lineIndex; if (m_lineIndexToRow.contains(lineIndex)) - return m_lineIndexToRow[lineIndex]; + return m_lineIndexToRow.at(lineIndex); return -1.0f; } @@ -495,12 +500,12 @@ namespace hex::ui { } else { auto &rowFoldSymbols = lines->m_rowToFoldSymbol; auto row = lines->lineIndexToRow(key.m_end.m_line); - if (isOpen() && endHovered() && rowFoldSymbols.contains(row) && rowFoldSymbols[row] != Lines::FoldSymbol::Square) { + if (isOpen() && endHovered() && rowFoldSymbols.contains(row) && rowFoldSymbols[row] != FoldSymbol::Square) { lines->m_codeFoldHighlighted = key; codeFoldEndCursorBox.callback(); } row = lines->lineIndexToRow(key.m_start.m_line); - if (startHovered() && rowFoldSymbols.contains(row) && rowFoldSymbols[row] != Lines::FoldSymbol::Square) { + if (startHovered() && rowFoldSymbols.contains(row) && rowFoldSymbols[row] != FoldSymbol::Square) { lines->m_codeFoldHighlighted = key; codeFoldStartCursorBox.callback(); } @@ -534,9 +539,6 @@ namespace hex::ui { m_codeFolds.clear(); m_rowToFoldSymbol.clear(); - //m_foldsAreInstalled = !m_codeFoldKeys.empty(); - - for (auto [key, isOpen]: m_codeFoldState){ auto index = m_codeFoldKeys.find(key); if (index->m_start != key.m_start || index->m_end != key.m_end) @@ -593,11 +595,13 @@ namespace hex::ui { if (m_useSavedFoldStatesRequested) { applyCodeFoldStates(); m_useSavedFoldStatesRequested = false; - } else + } else if (m_saveCodeFoldStateRequested) { saveCodeFoldStates(); + m_saveCodeFoldStateRequested = false; + } m_foldedLines.clear(); - std::vector closedFolds = removeEmbeddedFolds(); + Keys closedFolds = removeEmbeddedFolds(); for (auto closedFold : closedFolds) { closeCodeFold(closedFold, false); auto row = lineIndexToRow(closedFold.m_start.m_line); @@ -667,11 +671,11 @@ namespace hex::ui { bool triggered = false; std::map detectedFolds; - for (auto key = m_codeFoldKeys.rbegin(); key != m_codeFoldKeys.rend(); key++) { - if (m_codeFolds[*key].trigger()) + for (auto key : std::ranges::views::reverse(m_codeFoldKeys)) { + if (m_codeFolds[key].trigger()) triggered = true; - if (m_codeFolds[*key].isDetected()) - detectedFolds.insert({*key, m_codeFolds[*key]}); + if (m_codeFolds[key].isDetected()) + detectedFolds.insert({key, m_codeFolds[key]}); } if (detectedFolds.empty()) { m_codeFoldHighlighted = NoCodeFoldSelected; @@ -697,12 +701,12 @@ namespace hex::ui { return false; } - std::vector TextEditor::Lines::removeEmbeddedFolds() { - std::vector closedFolds; + Keys TextEditor::Lines::removeEmbeddedFolds() { + Keys closedFolds; for (auto key : m_codeFoldKeys) { if (m_codeFoldState.contains(key) && !m_codeFoldState[key]) { bool replace = false; - std::vector keysToErase; + Keys keysToErase; for (auto closedFold : closedFolds) { if (key.contains(closedFold)) { replace = true; @@ -724,30 +728,30 @@ namespace hex::ui { } void TextEditor::Lines::getRowSegments() { - m_rowToSegments.clear(); + m_rowToFoldSegments.clear(); m_multiLinesToRow.clear(); m_rowCodeFoldTooltips.clear(); - std::vector closedFolds = removeEmbeddedFolds(); + Keys closedFolds = removeEmbeddedFolds(); for (auto key : closedFolds) { auto row = lineIndexToRow(key.m_start.m_line); - if (m_rowToSegments.contains(row)) + if (m_rowToFoldSegments.contains(row) || !m_foldedLines.contains(row)) continue; for (i32 i = key.m_start.m_line; i < key.m_end.m_line; i++) m_multiLinesToRow[i] = row; auto lineIndex = rowToLineIndex(row); - auto foldedLine = m_foldedLines[row]; + auto foldedLine = m_foldedLines.at(row); i32 count = foldedLine.m_keys.size(); if (count == 0) continue; for (i32 i = 0; i < count; i++) { Interval sgm = {foldedLine.m_foldedSegments[2 * i].m_column, foldedLine.m_foldedSegments[2 * i + 1].m_column}; - m_rowToSegments[row].push_back({foldedLine.m_keys[i].m_start, indexScreenPosition(lineIndex, sgm)}); + m_rowToFoldSegments[row].push_back({foldedLine.m_keys[i].m_start, indexScreenPosition(lineIndex, sgm)}); ImVec2 screenPosEnd = indexCoordsToScreen(lineCoordinates(lineIndex, foldedLine.m_ellipsisIndices[i])); - m_rowCodeFoldTooltips[row].push_back(TextEditor::CodeFoldTooltip(this, foldedLine.m_keys[i],ImRect(screenPosEnd, screenPosEnd + ImVec2(Ellipsis.lineTextSize(), m_charAdvance.y)))); + m_rowCodeFoldTooltips[row].emplace_back(this, foldedLine.m_keys[i],ImRect(screenPosEnd, screenPosEnd + ImVec2(Ellipsis.lineTextSize(), m_charAdvance.y))); } Interval sgm = {foldedLine.m_foldedSegments[2 * count].m_column, foldedLine.m_foldedSegments[2 * count + 1].m_column}; - m_rowToSegments[row].push_back({foldedLine.m_keys[count - 1].m_end, indexScreenPosition(lineIndex, sgm)}); + m_rowToFoldSegments[row].push_back({foldedLine.m_keys[count - 1].m_end, indexScreenPosition(lineIndex, sgm)}); } } @@ -756,14 +760,14 @@ namespace hex::ui { } ImVec2 TextEditor::Line::intervalToScreen(Interval stringIndices) const { - return ImVec2(textSize(stringIndices.m_start), textSize(stringIndices.m_end)); + return {(float) textSize(stringIndices.m_start), (float) textSize(stringIndices.m_end)}; } ImVec2 TextEditor::Lines::lineIndexToScreen(i32 lineIndex, Interval stringIndices) { auto &line = operator[](lineIndex); auto startPos = m_lineIndexToScreen[lineIndex].x; auto increments = line.intervalToScreen(stringIndices); - return ImVec2(startPos + increments.x, startPos + increments.y); + return {startPos + increments.x, startPos + increments.y}; } ImVec2 TextEditor::Lines::indexCoordsToScreen(Coordinates indexCoords) { @@ -776,7 +780,7 @@ namespace hex::ui { if (hovered && ImGui::IsMouseClicked(0)) { auto codeFoldKeys = m_lines->m_codeFoldKeys; auto codeFoldState = m_lines->m_codeFoldState; - std::vector keysToOpen; + Keys keysToOpen; auto key = codeFoldKeys.begin(); for (; key != codeFoldKeys.end(); key++) { if (*key == m_key) @@ -795,8 +799,8 @@ namespace hex::ui { keysToOpen.push_back(*key); key++; } - for (auto openKey = keysToOpen.rbegin(); openKey != keysToOpen.rend(); openKey++) - m_lines->openCodeFold(*openKey); + for (auto openKey : std::ranges::views::reverse(keysToOpen)) + m_lines->openCodeFold(openKey); return true; } @@ -857,20 +861,18 @@ namespace hex::ui { std::pair delimiters = {' ',' '}; if (m_lines->m_codeFoldDelimiters.contains(key)) delimiters = m_lines->m_codeFoldDelimiters[key]; - std::string delimiterOpen(1,delimiters.first); - std::string delimiterClose(1,delimiters.second); Line lineStart = m_lines->m_unfoldedLines[key.m_start.m_line]; Line lineEnd = m_lines->m_unfoldedLines[key.m_end.m_line]; - bool isIfDef; + std::string lineStartFirstNonSpace = lineStart.m_chars.substr(m_lines->m_leadingLineSpaces[key.m_start.m_line], 2); + bool isSingleLineComment = lineStartFirstNonSpace == "//"; + + bool isIfDef = false; if (key.m_start.m_line > 0 && key.m_end.m_line < m_lines->size()) { std::string prevLine = m_lines->m_unfoldedLines[key.m_start.m_line - 1].m_chars; - if (prevLine.starts_with("#ifdef") || prevLine.starts_with("#ifndef")) { + if (prevLine.starts_with("#ifdef") || prevLine.starts_with("#ifndef")) isIfDef = true; - } else - isIfDef = false; - } else - isIfDef = false; + } bool appendClosingLine = true; Line bracket; @@ -890,9 +892,9 @@ namespace hex::ui { appendClosingLine = false; m_foldedLine = lineStart.subLine(0, 9); m_type = FoldType::AddsFirstLine; - } else if (lineStart.m_chars.starts_with("//")) { + } else if (isSingleLineComment) { appendClosingLine = false; - m_foldedLine = lineStart.subLine(0, 1); + m_foldedLine = lineStart.subLine(m_lines->m_leadingLineSpaces[key.m_start.m_line], 1); m_type = FoldType::AddsFirstLine; }else if (isIfDef) { appendClosingLine = false; @@ -981,12 +983,12 @@ namespace hex::ui { std::string delimiters; delimiters += delimiterPair.first; delimiters += delimiterPair.second; - if (delimiters == "" || (delimiters != "{}" && delimiters != "[]" && delimiters != "()" && delimiters != "<>")) { + if (delimiters.empty() || (delimiters != "{}" && delimiters != "[]" && delimiters != "()" && delimiters != "<>")) { auto lineStart = m_lines->m_unfoldedLines[key.m_start.m_line].m_chars; if (lineStart.starts_with("import") || lineStart.starts_with("#include")) { auto lineEnd = m_lines->m_unfoldedLines[key.m_end.m_line]; - auto columnStart = lineStart.find_first_of(" "); - return Range(m_lines->lineCoordinates(key.m_start.m_line, columnStart), m_lines->lineCoordinates(key.m_end.m_line, lineEnd.maxColumn())); + auto columnStart = lineStart.find(' '); + return {m_lines->lineCoordinates(key.m_start.m_line, columnStart), m_lines->lineCoordinates(key.m_end.m_line, lineEnd.maxColumn())}; } return key; } @@ -1003,7 +1005,6 @@ namespace hex::ui { while (true) { Coordinates nextCoordinates = m_lines->lineCoordinates(openDelimiterCoordinates.m_line, openDelimiterCoordinates.m_column + columnIndex); if (openDelimiterCoordinates.m_column < openDelimiterLine.maxColumn() && openDelimiterLine[(u64) nextCoordinates.m_column] == delimiters[0]) { - //auto saveNearCursor = m_editor->m_lines.m_matchedDelimiter.m_nearCursor; if (m_lines->m_matchedDelimiter.coordinatesNearDelimiter(m_lines, nextCoordinates)) { auto result = m_lines->m_matchedDelimiter.findMatchingDelimiter(m_lines, nextCoordinates, false); if (result.m_line == key.m_end.m_line) { @@ -1020,7 +1021,7 @@ namespace hex::ui { } if (!found) closeDelimiterCoordinates = m_lines->rfind(delimiters.substr(1,1), m_lines->lineCoordinates(key.m_end.m_line, -1)); - return Range(openDelimiterCoordinates, closeDelimiterCoordinates); + return {openDelimiterCoordinates, closeDelimiterCoordinates}; } void TextEditor::FoldedLine::loadSegments() { @@ -1078,8 +1079,8 @@ namespace hex::ui { void TextEditor::Lines::removeKeys() { for (auto &[row,foldedLine] : m_foldedLines) { - for (auto i = foldedLine.m_keysToRemove.rbegin(); i != foldedLine.m_keysToRemove.rend(); i++) { - openCodeFold(*i); + for (auto i : std::ranges::views::reverse(foldedLine.m_keysToRemove)) { + openCodeFold(i); } foldedLine.m_keysToRemove.clear(); if (foldedLine.m_keys.empty()) { @@ -1160,10 +1161,6 @@ namespace hex::ui { m_lines.setRowToLineIndexMap(); m_lines.getRowSegments(); } - if (m_lines.m_saveCodeFoldStateRequested) { - saveCodeFoldStates(); - m_lines.m_saveCodeFoldStateRequested = false; - } bool focused = ImGui::IsWindowFocused(); while (std::floor(row) <= maxDisplayedRow) { @@ -1179,7 +1176,7 @@ namespace hex::ui { } lineIndex = rowToLineIndex((i32) row); - if (lineIndex >= (i32) m_lines.size() || lineIndex < 0) + if (lineIndex >= m_lines.size() || lineIndex < 0) break; if (m_showLineNumbers) { @@ -1212,7 +1209,7 @@ namespace hex::ui { m_topLineNumber = 1; lineIndex = 0; if (m_lines.m_unfoldedLines.empty()) - m_lines.m_unfoldedLines.push_back(Line()); + m_lines.m_unfoldedLines.emplace_back(); m_lines.m_state.m_cursorPosition = lineCoordinates( 0, 0); if (m_showLineNumbers) { if (!m_lines.m_ignoreImGuiChild) @@ -1224,10 +1221,6 @@ namespace hex::ui { if (m_showCursor) drawCursor(0,textEditorSize, true, drawList); ImGui::Dummy(m_lines.m_charAdvance); - - //auto lineStart = m_lines.lineCoordinates(lineIndex, 0); - //drawText(lineStart, 0, 0); - //m_lines.m_rowToLineIndex.clear(); } if (m_lines.m_scrollToCursor) @@ -1238,9 +1231,6 @@ namespace hex::ui { i64 TextEditor::drawColoredText(i32 lineIndex, const ImVec2 &textEditorSize) { auto line = m_lines[lineIndex]; - //if (line.m_chars.starts_with("//+-#:") && lineIndex == (i32) m_lines.size() - 1) { - // return 0; - //} if (line.empty()) { ImGui::Dummy(m_lines.m_charAdvance); @@ -1306,13 +1296,10 @@ namespace hex::ui { } bool TextEditor::Lines::isMultiLineRow(i32 row) { - return (m_foldedLines.contains(row) && m_foldedLines[row].m_keys.size() > 0); + return (m_foldedLines.contains(row) && !m_foldedLines.at(row).m_keys.empty()); } void TextEditor::preRender() { - //static ImVec2 previous = {0,0}; - //static bool update = true; - //if (update) { m_lines.m_charAdvance = calculateCharAdvance(); m_lines.m_leftMargin = m_lines.m_charAdvance.x; for (i32 i = 0; i < (i32) PaletteIndex::Max; ++i) { @@ -1321,12 +1308,6 @@ namespace hex::ui { m_palette[i] = ImGui::ColorConvertFloat4ToU32(color); } m_lines.m_numberOfLinesDisplayed = getPageSize(); - //if (previous == m_lines.m_charAdvance) { - // update = false; - // } else { - // update = true; - // previous = m_lines.m_charAdvance; - // } } void TextEditor::drawSelection(float lineIndex, ImDrawList *drawList) { @@ -1334,8 +1315,8 @@ namespace hex::ui { auto lineStartScreenPos = m_lines.getLineStartScreenPos(0,row); Range lineCoords; if (m_lines.isMultiLineRow(row)) { - lineCoords.m_start = m_lines.lineCoordinates(m_lines.m_foldedLines[row].m_full.m_start.m_line, 0); - lineCoords.m_end = m_lines.lineCoordinates(m_lines.m_foldedLines[row].m_full.m_end.m_line, -1); + lineCoords.m_start = m_lines.lineCoordinates(m_lines.m_foldedLines.at(row).m_full.m_start.m_line, 0); + lineCoords.m_end = m_lines.lineCoordinates(m_lines.m_foldedLines.at(row).m_full.m_end.m_line, -1); } else { lineCoords = Range(m_lines.lineCoordinates(lineIndex, 0), m_lines.lineCoordinates(lineIndex, -1)); } @@ -1367,13 +1348,13 @@ namespace hex::ui { auto start = lineStartScreenPos; ImVec2 end = lineStartScreenPos + ImVec2(m_lines.m_lineNumberFieldWidth + contentSize.x, m_lines.m_charAdvance.y); auto center = lineNumberStartScreenPos + ImVec2(m_lines.m_lineNumberFieldWidth - 2 * m_lines.m_charAdvance.x + 1_scaled, 0); - if (m_lines.m_rowToSegments.contains(row)) { + if (m_lines.m_rowToFoldSegments.contains(row)) { bool circlesDrawn = false; - for (auto segments : m_lines.m_rowToSegments[row]) { - if (segments.m_foldEnd.m_line != lineIndex && m_lines.m_breakpoints.count(segments.m_foldEnd.m_line + 1) > 0) + for (auto segments : m_lines.m_rowToFoldSegments[row]) { + if (segments.m_foldEnd.m_line != lineIndex && m_lines.m_breakpoints.contains(segments.m_foldEnd.m_line + 1)) start.x = segments.m_segment.m_start; - if (m_lines.m_breakpoints.count(segments.m_foldEnd.m_line + 1) > 0) { - if (segments == m_lines.m_rowToSegments[row].back()) + if (m_lines.m_breakpoints.contains(segments.m_foldEnd.m_line + 1)) { + if (segments == m_lines.m_rowToFoldSegments[row].back()) end.x = lineNumberStartScreenPos.x + contentSize.x + m_lines.m_lineNumberFieldWidth; else end.x = segments.m_segment.m_end; @@ -1390,7 +1371,7 @@ namespace hex::ui { auto key = Range(segmentStart, keyValue); if (m_lines.m_codeFoldState.contains(key) && !m_lines.m_codeFoldState[key]) { for (i32 i = key.m_start.m_line + 1; i < key.m_end.m_line; i++) { - if (m_lines.m_breakpoints.count(i + 1) > 0) { + if (m_lines.m_breakpoints.contains(i + 1)) { start.x = segments.m_segment.m_end; end.x = start.x + Ellipsis.lineTextSize(); drawList->AddRectFilled(start, end, m_palette[(i32) PaletteIndex::Breakpoint]); @@ -1404,7 +1385,7 @@ namespace hex::ui { } } } - } else if (m_lines.m_breakpoints.count(lineIndex + 1) > 0) { + } else if (m_lines.m_breakpoints.contains(lineIndex + 1)) { end = ImVec2(lineNumberStartScreenPos.x + contentSize.x + m_lines.m_lineNumberFieldWidth, lineStartScreenPos.y + m_lines.m_charAdvance.y); drawList->AddRectFilled(start, end, m_palette[(i32) PaletteIndex::Breakpoint]); drawList->AddCircleFilled(center + ImVec2(0, m_lines.m_charAdvance.y) / 2, m_lines.m_charAdvance.y / 3, m_palette[(i32) PaletteIndex::Breakpoint]); @@ -1477,8 +1458,8 @@ namespace hex::ui { if (key.contains(lineCoords) && m_lines.m_codeFoldState.contains(key) && !m_lines.m_codeFoldState[key]) { row = m_lines.m_multiLinesToRow[lineIndex + 1]; i32 multilineLineIndex = rowToLineIndex(row); - if (m_lines.m_rowToSegments.contains(row) && m_lines.m_rowToSegments[row].size() > 1) { - Segment result = *std::find_if(m_lines.m_rowToSegments[row].begin(), m_lines.m_rowToSegments[row].end(), [&](const Segment &segment) { + if (m_lines.m_rowToFoldSegments.contains(row) && m_lines.m_rowToFoldSegments[row].size() > 1) { + FoldSegment result = *std::find_if(m_lines.m_rowToFoldSegments[row].begin(), m_lines.m_rowToFoldSegments[row].end(), [&](const FoldSegment &segment) { return segment.m_foldEnd == key.m_end; }); lineStartScreenPos = ImVec2(result.m_segment.m_start + m_lines.m_unfoldedLines[0].stringTextSize(std::string(m_lines.m_leadingLineSpaces[key.m_end.m_line], ' ')), m_lines.m_lineIndexToScreen[multilineLineIndex].y); @@ -1523,8 +1504,8 @@ namespace hex::ui { if (gotoKey != Invalid) { std::string errorLineColumn; bool found = false; - for (auto text: m_lines.m_clickableText) { - if (lineText.find(text) == 0) { + for (const auto &text: m_lines.m_clickableText) { + if (lineText.starts_with(text)) { errorLineColumn = lineText.substr(text.size()); if (!errorLineColumn.empty()) { found = true; @@ -1534,7 +1515,7 @@ namespace hex::ui { } if (found) { i32 currLine = 0, currColumn = 0; - if (auto idx = errorLineColumn.find(":"); idx != std::string::npos) { + if (auto idx = errorLineColumn.find(':'); idx != std::string::npos) { auto errorLine = errorLineColumn.substr(0, idx); if (!errorLine.empty()) currLine = std::stoi(errorLine) - 1; @@ -1684,7 +1665,7 @@ namespace hex::ui { ImVec2 TextEditor::calculateCharAdvance() const { const float fontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x; - return ImVec2(fontSize, GImGui->FontSize * m_lineSpacing); + return {fontSize, GImGui->FontSize * m_lineSpacing}; } float TextEditor::Lines::textDistanceToLineStart(const Coordinates &aFrom) { @@ -1700,7 +1681,6 @@ namespace hex::ui { return line.m_lineMaxColumn - distanceToEnd; } return line.stringTextSize(substr1.c_str()); - //return ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, substr.c_str(), nullptr, nullptr).x; } void TextEditor::drawCodeFolds(float lineIndex, ImDrawList *drawList) { @@ -1711,7 +1691,7 @@ namespace hex::ui { if (m_lines.m_codeFoldHighlighted != NoCodeFoldSelected) { Range key1, key2; if (m_lines.m_foldedLines.contains(row)) { - auto &foldedLine = m_lines.m_foldedLines[row]; + auto &foldedLine = m_lines.m_foldedLines.at(row); if (m_lines.m_codeFoldValueMap.contains(foldedLine.m_full.m_start)) key1 = Range(m_lines.m_codeFoldValueMap[foldedLine.m_full.m_start], foldedLine.m_full.m_start); else @@ -1723,40 +1703,40 @@ namespace hex::ui { if (m_lines.m_codeFoldHighlighted == key1) { if (m_lines.m_codeFoldState.contains(m_lines.m_codeFoldHighlighted) && !m_lines.m_codeFoldState[m_lines.m_codeFoldHighlighted]) - state = Lines::FoldSymbol::Square; + state = FoldSymbol::Square; else { if (codeFoldKeyLine == key1.m_start.m_line) - state = Lines::FoldSymbol::Down; + state = FoldSymbol::Down; else if (codeFoldKeyLine == key1.m_end.m_line) - state = Lines::FoldSymbol::Up; + state = FoldSymbol::Up; } } else if (m_lines.m_codeFoldHighlighted == key2) { if (m_lines.m_codeFoldState.contains(key2) && !m_lines.m_codeFoldState[key2]) - state = Lines::FoldSymbol::Square; + state = FoldSymbol::Square; else { if (lineIndexToRow(codeFoldKeyLine) == lineIndexToRow(key2.m_start.m_line)) - state = Lines::FoldSymbol::Down; + state = FoldSymbol::Down; else if (codeFoldKeyLine == key2.m_end.m_line) - state = Lines::FoldSymbol::Up; + state = FoldSymbol::Up; } } } else if (m_lines.m_codeFoldHighlighted.m_start.m_line == codeFoldKeyLine) { if (m_lines.m_codeFoldState.contains(m_lines.m_codeFoldHighlighted) && m_lines.m_codeFoldState[m_lines.m_codeFoldHighlighted]) - state = Lines::FoldSymbol::Down; + state = FoldSymbol::Down; else - state = Lines::FoldSymbol::Square; + state = FoldSymbol::Square; } else if (m_lines.m_codeFoldHighlighted.m_end.m_line == codeFoldKeyLine) { if (m_lines.m_codeFoldState.contains(m_lines.m_codeFoldHighlighted) && m_lines.m_codeFoldState[m_lines.m_codeFoldHighlighted]) - state = Lines::FoldSymbol::Up; + state = FoldSymbol::Up; else - state = Lines::FoldSymbol::Square; + state = FoldSymbol::Square; } } i32 lineColor; Interval highlightedRowInterval = Interval(m_lines.lineIndexToRow(m_lines.m_codeFoldHighlighted.m_start.m_line), m_lines.lineIndexToRow(m_lines.m_codeFoldHighlighted.m_end.m_line)); - if (highlightedRowInterval.contains(row) && (state == Lines::FoldSymbol::Line || + if (highlightedRowInterval.contains(row) && (state == FoldSymbol::Line || row == highlightedRowInterval.m_start || row == highlightedRowInterval.m_end)) lineColor = ImGui::ColorConvertFloat4ToU32(ImGui::GetStyle().Colors[ImGuiCol_ScrollbarGrabActive]); else @@ -1783,20 +1763,20 @@ namespace hex::ui { ImGui::EndChild(); } - void TextEditor::renderCodeFolds(i32 row, ImDrawList *drawList, i32 color, Lines::FoldSymbol state) { + void TextEditor::renderCodeFolds(i32 row, ImDrawList *drawList, i32 color, FoldSymbol state) { auto boxSize = m_lines.m_charAdvance.x + (((u32)m_lines.m_charAdvance.x % 2) ? 2.0f : 1.0f); auto verticalMargin = m_lines.m_charAdvance.y - boxSize; auto horizontalMargin = m_lines.m_lineNumberFieldWidth - (boxSize - 1) / 2; auto lineStartScreenPos = m_lines.getLineStartScreenPos(horizontalMargin, row); auto numberLineStartScreenPos = ImVec2(m_lines.m_lineNumbersStartPos.x + m_lines.m_lineNumberFieldWidth, lineStartScreenPos.y); - if (state == Lines::FoldSymbol::Square) { + if (state == FoldSymbol::Square) { renderSquare(numberLineStartScreenPos, drawList, boxSize - 1, verticalMargin, color); renderPlus(numberLineStartScreenPos, drawList, boxSize, std::floor(verticalMargin / 2), color); - } else if (state == Lines::FoldSymbol::Down) { + } else if (state == FoldSymbol::Down) { renderPointingDown(numberLineStartScreenPos, drawList, boxSize - 1, verticalMargin, color); renderMinus(numberLineStartScreenPos, drawList, boxSize, std::floor(verticalMargin / 4), color); - } else if (state == Lines::FoldSymbol::Up) { + } else if (state == FoldSymbol::Up) { renderPointingUp(numberLineStartScreenPos, drawList, boxSize - 1, verticalMargin, color); renderMinus(numberLineStartScreenPos, drawList, boxSize, std::floor(3 * verticalMargin / 4), color); } else { @@ -1898,4 +1878,8 @@ namespace hex::ui { drawList->AddLine(p1 + py, p2, color, 1.0f); drawList->AddLine(p1 + px + py, p2, color, 1.0f); } + + bool TextEditor::areEqual(const std::pair &a, const std::pair &b) { + return a.first == b.first && a.second.isOpen() == b.second.isOpen(); + } } \ No newline at end of file diff --git a/plugins/ui/source/ui/text_editor/support.cpp b/plugins/ui/source/ui/text_editor/support.cpp index 39b7a9d05..8c3ce0a0c 100644 --- a/plugins/ui/source/ui/text_editor/support.cpp +++ b/plugins/ui/source/ui/text_editor/support.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -17,6 +16,7 @@ namespace hex::ui { using Range = TextEditor::Range; using FindReplaceHandler = TextEditor::FindReplaceHandler; using CodeFold = TextEditor::CodeFold; + using EditorState = TextEditor::EditorState; bool Interval::contains(i32 value, bool inclusive) const { @@ -30,13 +30,11 @@ namespace hex::ui { if (gap == 0 || gap == 1) return true; gap = other.m_start - m_end; - if (gap == 0 || gap == 1) - return true; - return false; + return gap == 0 || gap == 1; } bool Coordinates::operator==(const Coordinates &o) const { - return m_line == o.m_line && m_column == o.m_column; + return m_line == o.m_line && m_column == o.m_column; } bool Coordinates::operator!=(const Coordinates &o) const { @@ -64,11 +62,11 @@ namespace hex::ui { } Coordinates Coordinates::operator+(const Coordinates &o) const { - return Coordinates(m_line + o.m_line, m_column + o.m_column); + return {m_line + o.m_line, m_column + o.m_column}; } Coordinates Coordinates::operator-(const Coordinates &o) const { - return Coordinates(m_line - o.m_line, m_column - o.m_column); + return {m_line - o.m_line, m_column - o.m_column}; } bool Range::operator==(const Range &o) const { @@ -79,13 +77,13 @@ namespace hex::ui { } Coordinates Range::getSelectedLines() { - return Coordinates(m_start.m_line, m_end.m_line); + return {m_start.m_line, m_end.m_line}; } Coordinates Range::getSelectedColumns() { if (isSingleLine()) - return Coordinates(m_start.m_column, m_end.m_column - m_start.m_column); - return Coordinates(m_start.m_column, m_end.m_column); + return {m_start.m_column, m_end.m_column - m_start.m_column}; + return {m_start.m_column, m_end.m_column}; } bool Range::isSingleLine() { @@ -174,7 +172,7 @@ namespace hex::ui { return *this; } - LineIterator LineIterator::operator=(const LineIterator &other) { + LineIterator &LineIterator::operator=(const LineIterator &other) { m_charsIter = other.m_charsIter; m_colorsIter = other.m_colorsIter; m_flagsIter = other.m_flagsIter; @@ -235,14 +233,7 @@ namespace hex::ui { return iter; } - Line &Line::operator=(const Line &line) { - m_chars = line.m_chars; - m_colors = line.m_colors; - m_flags = line.m_flags; - m_colorized = line.m_colorized; - m_lineMaxColumn = line.m_lineMaxColumn; - return *this; - } + Line &Line::operator=(const Line &line) = default; Line &Line::operator=(Line &&line) noexcept { m_chars = std::move(line.m_chars); @@ -536,24 +527,18 @@ namespace hex::ui { return !m_colorized; } - Interval &Interval::operator=(const Interval &interval) { + Interval &Interval::operator=(const Interval &interval) = default; + + Interval &Interval::operator=(Interval &&interval) noexcept { m_start = interval.m_start; m_end = interval.m_end; return *this; } - Interval &Interval::operator=(Interval &&interval) noexcept { - m_start = std::move(interval.m_start); - m_end = std::move(interval.m_end); - return *this; - } - bool TextEditor::ActionableBox::trigger() { auto mousePos = ImGui::GetMousePos(); - if (mousePos.x <= m_box.Min.x || mousePos.x >= m_box.Max.x || - mousePos.y < m_box.Min.y || mousePos.y > m_box.Max.y) - return false; - return true; + return !(mousePos.x <= m_box.Min.x || mousePos.x >= m_box.Max.x || + mousePos.y < m_box.Min.y || mousePos.y > m_box.Max.y); } void TextEditor::ActionableBox::shiftBoxVertically(float lineCount, float lineHeight) { @@ -639,7 +624,7 @@ namespace hex::ui { if (m_readOnly) return; - m_undoBuffer.resize((u64) (m_undoIndex + 1)); + m_undoBuffer.resize(m_undoIndex + 1); m_undoBuffer.back() = UndoAction(value); m_undoIndex++; } @@ -806,9 +791,7 @@ namespace hex::ui { auto matchedCoords = m_matchedDelimiter.m_matched; Line::Flags nearFlag(m_unfoldedLines[nearCoords.m_line].m_flags[nearCoords.m_column]); Line::Flags matchedFlag(m_unfoldedLines[matchedCoords.m_line].m_flags[matchedCoords.m_column]); - if (nearFlag.m_bits.matchedDelimiter && matchedFlag.m_bits.matchedDelimiter) - return true; - return false; + return nearFlag.m_bits.matchedDelimiter && matchedFlag.m_bits.matchedDelimiter; } // the index here is array index so zero based @@ -1084,7 +1067,7 @@ namespace hex::ui { } if (textLoc == std::string::npos) return false; - TextEditor::EditorState state; + EditorState state; state.m_selection = Range(lines->stringIndexCoords(textLoc, textSrc), lines->stringIndexCoords(textLoc + matchBytes, textSrc)); state.m_cursorPosition = state.m_selection.m_end; if (!m_matches.empty() && state == m_matches.back()) @@ -1122,7 +1105,7 @@ namespace hex::ui { lines->ensureCursorVisible(); return; } - TextEditor::EditorState state = m_matches.back(); + EditorState state = m_matches.back(); while (state.m_cursorPosition < startingPos) { if (!findNext(lines, byteIndex)) { @@ -1138,8 +1121,7 @@ namespace hex::ui { lines->m_state = saveState; lines->ensureCursorVisible(); - return; - } + } bool FindReplaceHandler::replace(Lines *lines, bool right) { @@ -1179,7 +1161,7 @@ namespace hex::ui { ImGui::SetKeyboardFocusHere(0); u.m_after = state; - m_undoBuffer.push_back(u); + m_undoBuffer.emplace_back(std::move(u)); lines->m_textChanged = true; return true; @@ -1225,7 +1207,7 @@ namespace hex::ui { return false; } - bool CodeFold::isOpen() { + bool CodeFold::isOpen() const { return lines->m_codeFoldState[key]; } @@ -1251,11 +1233,11 @@ namespace hex::ui { if (index < 0) index += size(); auto row = lineIndexToRow(index); - if (row < 0 || row >= getGlobalRowMax()) + if (row < 0 || row > getGlobalRowMax()) throw std::out_of_range("Line index out of range"); if (!m_foldedLines.contains(row) || m_foldedLines.at(row).m_full.m_start.m_line != index) return m_unfoldedLines.at(index); - return const_cast(m_foldedLines.at(row).m_foldedLine); + return m_foldedLines.at(row).m_foldedLine; } Line &Lines::operator[](i32 index) { @@ -1266,13 +1248,14 @@ namespace hex::ui { if (index < 0) index += size(); i32 row = lineIndexToRow(index); - if (getGlobalRowMax() != 0) - row = std::clamp(row,0, (i32)(getGlobalRowMax()-1)); + i32 globalRowMax = getGlobalRowMax(); + if (globalRowMax > 0) + row = std::clamp(row,0, globalRowMax); else row = 0; if (!m_foldedLines.contains(row) || m_foldedLines[row].m_full.m_start.m_line != index) return m_unfoldedLines.at(index); - return const_cast(m_foldedLines[row].m_foldedLine); + return m_foldedLines[row].m_foldedLine; } i32 Lines::size() const { @@ -1292,17 +1275,10 @@ namespace hex::ui { } i32 TextEditor::getTotalLines() const { - return (i32) m_lines.size(); + return m_lines.size(); } - using CodeFoldBlocks = TextEditor::CodeFoldBlocks; - //static std::chrono::steady_clock::time_point currentTime1; void TextEditor::Lines::setAllCodeFolds() { - //std::chrono::steady_clock::time_point beforeLoop; - //std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - //std::chrono::duration time_span = now - currentTime1; - //auto lastCharInputTime = time_span.count(); - //log::debug("Before loading 1st id of line : {} ms", lastCharInputTime); CodeFoldBlocks intervals = foldPointsFromSource(); m_codeFoldKeys.clear(); m_codeFolds.clear(); @@ -1341,13 +1317,9 @@ namespace hex::ui { m_codeFoldKeyLineMap.insert(std::make_pair(interval.m_start.m_line,interval.m_start)); m_codeFoldValueLineMap.insert(std::make_pair(interval.m_end.m_line,interval.m_end)); } - //currentTime1 = std::chrono::steady_clock::now(); - //time_span = currentTime1 - now; - //lastCharInputTime = time_span.count(); - // log::debug("After loading 1st id of line : {} ms", lastCharInputTime); } - void TextEditor::Lines::readHiddenLines() { + void TextEditor::Lines::removeHiddenLinesFromPattern() { m_hiddenLines.clear(); i32 lineIndex = 0; const auto totalLines = (i32)m_unfoldedLines.size(); @@ -1359,7 +1331,7 @@ namespace hex::ui { auto lines = wolv::util::splitString(hiddenLinesText, "\n"); for (i32 i = 0; i < lineIndex; i++) { HiddenLine hiddenLine(i, m_unfoldedLines[i].m_chars); - m_hiddenLines.push_back(hiddenLine); + m_hiddenLines.emplace_back(std::move(hiddenLine)); m_useSavedFoldStatesRequested = true; } deleteSelection(); @@ -1367,7 +1339,7 @@ namespace hex::ui { setAllCodeFolds(); } - void TextEditor::Lines::writeHiddenLines() { + void TextEditor::Lines::addHiddenLinesToPattern() { if (m_hiddenLines.empty()) return; for (const auto &hiddenLine : m_hiddenLines) { @@ -1388,7 +1360,7 @@ namespace hex::ui { void TextEditor::codeFoldCollapse(i32 level, bool recursive, bool all) { - for (auto [key, codeFold]: m_lines.m_codeFolds) { + for (const auto& [key, codeFold]: m_lines.m_codeFolds) { if (key.containsLine(m_lines.m_state.m_cursorPosition.m_line) || all) { if (getCodeFoldLevel(key.m_start.m_line) >= level || level == 0) { if (m_lines.m_codeFoldState.contains(key) && m_lines.m_codeFoldState[key]) { @@ -1412,7 +1384,7 @@ namespace hex::ui { } void TextEditor::codeFoldExpand(i32 level, bool recursive, bool all) { - for (auto [key, codeFold]: m_lines.m_codeFolds) { + for (const auto& [key, codeFold]: m_lines.m_codeFolds) { if (key.containsLine(m_lines.m_state.m_cursorPosition.m_line) || all) { if (getCodeFoldLevel(key.m_start.m_line) >= level || level == 0) { if (m_lines.m_codeFoldState.contains(key) && !m_lines.m_codeFoldState[key]) { @@ -1448,42 +1420,11 @@ namespace hex::ui { } if (source == nullptr) return false; - i32 line = location.line - 1; - i32 col = location.column - 1; - i32 length = location.length; - - if ( line < 0 || line >= (i32) size()) - return false; - - if ( col < 0 || col > (i32) operator[](line).size()) - return false; - if (length < 0) - return false; - if (length > (i32) operator[](line).size()-col) - length -= (i32)( operator[](line).size()-col); - while (line + 1 < size() && m_firstTokenIdOfLine[line] == m_firstTokenIdOfLine[line + 1]) { - length -= (i32) operator[](line).size(); - line++; - } - - - if (length > (i32) operator[](line).size()-col && m_firstTokenIdOfLine[line + 1] != -1) - return false; - return true; + return location > m_tokens.front().location && location < m_tokens.back().location; } void TextEditor::Lines::loadFirstTokenIdOfLine() { - auto code = getText(); - if (code.empty()) - return; - std::unique_ptr runtime = std::make_unique(); - ContentRegistry::PatternLanguage::configureRuntime(*runtime, nullptr); - std::ignore = runtime->preprocessString(code, pl::api::Source::DefaultSource); - m_tokens = runtime->getInternals().preprocessor->getResult(); const u32 tokenCount = m_tokens.size(); - if (tokenCount == 0) - return; - m_firstTokenIdOfLine.clear(); u32 tokenId = 0; u32 lineIndex = m_tokens.at(tokenId).location.line - 1; @@ -1512,7 +1453,6 @@ namespace hex::ui { auto commentStartLine = m_tokens.at(tokenId).location.line - 1; std::string value = m_tokens.at(tokenId).getFormattedValue(); auto commentEndLine = commentStartLine + std::count(value.begin(), value.end(), '\n'); - //m_firstTokenIdOfLine.at(commentStartLine) = commentTokenId; for (u32 i = commentStartLine; i <= commentEndLine; i++) { m_firstTokenIdOfLine.at(i) = commentTokenId; } @@ -1525,43 +1465,8 @@ namespace hex::ui { currentLine = lineIndex; } - // if (lineIndex > currentLine) { - // m_firstTokenIdOfLine[lineIndex] = tokenId; - // } - // } - if (tokenCount > 0 && (u32) m_firstTokenIdOfLine.back() != tokenCount - 1) m_firstTokenIdOfLine.push_back(tokenCount - 1); -/* - i32 lastTokenIdRestored; - bool lastTokenIdChanged; - i32 savedLineIndex; - lineIndex = 0; - while (lineIndex < (i32) size()) { - if (m_firstTokenIdOfLine[lineIndex] == -1 && (operator[](lineIndex).empty() || operator[](lineIndex).m_chars.find_first_not_of(" ") == std::string::npos || operator[](lineIndex).m_chars.starts_with("#"))) { - if (lastTokenIdChanged) - savedLineIndex = lineIndex; - lastTokenIdChanged = false; - lineIndex++; - } else if (m_firstTokenIdOfLine[lineIndex] != -1 && !operator[](lineIndex).empty() && operator[](lineIndex).m_chars.find_first_not_of(" ") != std::string::npos && !operator[](lineIndex).m_chars.starts_with("#")) { - tokenId = m_firstTokenIdOfLine[lineIndex]; - if (tokenId != lastTokenIdRestored) - lastTokenIdChanged = true; - lineIndex++; - } else if (m_firstTokenIdOfLine[lineIndex] == -1 && !operator[](lineIndex).empty() && operator[](lineIndex).m_chars.find_first_not_of(" ") != std::string::npos && !operator[](lineIndex).m_chars.starts_with("#")) { - m_firstTokenIdOfLine[lineIndex] = tokenId; - if (!lastTokenIdChanged) { - for (i32 i = savedLineIndex; i < lineIndex; i++) - m_firstTokenIdOfLine[i] = tokenId; - } - if (tokenId != lastTokenIdRestored) { - lastTokenIdRestored = tokenId; - lastTokenIdChanged = true; - } - lineIndex++; - } else - lineIndex ++; - }*/ } @@ -1572,6 +1477,25 @@ namespace hex::ui { return m_tokens[tokenId].location; } + i32 TextEditor::Lines::getTokenId(hex::ui::TextEditor::SafeTokenIterator tokenIterator) { + auto start = m_tokens.data(); + auto m_start = &tokenIterator.front(); + auto m_end = &tokenIterator.back(); + if (m_start < start || start > m_end) { + throw std::out_of_range("iterator out of range"); + } + return m_start - start; + } + + i32 TextEditor::Lines::getTokenId() { + auto start = m_tokens.data(); + auto m_start = &m_curr.front(); + auto m_end = &m_curr.back(); + if (m_start < start || start > m_end) { + throw std::out_of_range("iterator out of range"); + } + return m_start - start; + } // Get the token index for a given location. i32 TextEditor::Lines::getTokenId(pl::core::Location location) { @@ -1597,9 +1521,9 @@ namespace hex::ui { return -1; for (i32 i = tokenStart; i <= tokenEnd; i++) { - auto length = m_tokens[i].location.length; - if (m_tokens[i].location.column + length + (length == 0) > location.column) - return i; + auto location2 = m_tokens[i].location; + if (location2.column <= location.column && location2.column + location2.length >= location.column) + return i + 1; } return -1; } diff --git a/plugins/ui/source/ui/text_editor/utf8.cpp b/plugins/ui/source/ui/text_editor/utf8.cpp index cbf9839a4..068f961e6 100644 --- a/plugins/ui/source/ui/text_editor/utf8.cpp +++ b/plugins/ui/source/ui/text_editor/utf8.cpp @@ -7,7 +7,8 @@ namespace hex::ui { - using Coordinates = TextEditor::Coordinates; + using Coordinates = TextEditor::Coordinates; + using Segments = TextEditor::Segments; TextEditor::Line TextEditor::Line::trim(TrimMode trimMode) { if (m_chars.empty()) @@ -59,12 +60,11 @@ namespace hex::ui { } i32 TextEditor::Line::stringTextSize(const std::string &str) const { - i32 result = 0; if (str.empty()) return 0; if (ImGui::GetFont() == nullptr) { fonts::CodeEditor().push(); - result = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, str.c_str(), nullptr, nullptr).x; + i32 result = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, str.c_str(), nullptr, nullptr).x; fonts::CodeEditor().pop(); return result; } @@ -184,15 +184,13 @@ namespace hex::ui { auto lineSize = m_lines.size(); if (position.y > m_lines.getLineStartScreenPos(0, lineIndexToRow(lineSize - 1)).y + m_lines.m_charAdvance.y) return m_lines.lineCoordinates( -1, -1); - //if (position.y > m_lines.m_lineIndexToScreen[lineSize - 1].y + m_charAdvance.y) - // return m_lines.lineCoordinates( -1, -1); auto local = position - m_lines.m_cursorScreenPosition; auto row = screenPosToRow(position); Coordinates result = lineCoordinates(0,0); i32 lineIndex= rowToLineIndex((i32) std::floor(row)); - if (lineIndex < 0 || lineIndex >= (i32) m_lines.size()) + if (lineIndex < 0 || lineIndex >= m_lines.size()) return Invalid; result.m_line = lineIndex; if (m_lines.m_codeFoldKeyLineMap.contains(lineIndex) || m_lines.m_codeFoldValueLineMap.contains(lineIndex)) { @@ -204,7 +202,6 @@ namespace hex::ui { auto &line = m_lines[result.m_line].m_chars; - //local.x -= (m_leftMargin - 5_scaled); i32 count = 0; u64 length; i32 increase; @@ -218,7 +215,7 @@ namespace hex::ui { result = m_lines.lineIndexCoords(lineIndex + 1, count - increase); result = m_lines.foldedToUnfoldedCoords(result); if (result == Invalid) - return Coordinates(0, 0); + return {0, 0}; return result; } @@ -239,13 +236,13 @@ namespace hex::ui { } Coordinates TextEditor::Lines::lineIndexCoords(i32 lineNumber, i32 stringIndex) { - if (lineNumber < 1 || lineNumber > (i32) size()) + if (lineNumber < 1 || lineNumber > size()) return lineCoordinates( 0, 0); auto &line = operator[](lineNumber - 1); return lineCoordinates(lineNumber - 1, line.indexColumn(stringIndex)); } - std::vector TextEditor::Lines::unfoldedEllipsisCoordinates(Range delimiterCoordinates) { + Segments TextEditor::Lines::unfoldedEllipsisCoordinates(Range delimiterCoordinates) { auto lineStart = m_unfoldedLines[delimiterCoordinates.m_start.m_line]; auto row = lineIndexToRow(delimiterCoordinates.m_start.m_line); @@ -281,7 +278,7 @@ namespace hex::ui { auto totalUnfoldedSpan = unfoldedSpan1 + unfoldedSpan2 + unfoldedSpan3; if (totalUnfoldedSpan < 2.0f) { - std::vector unfoldedEllipsisCoordinates(2); + Segments unfoldedEllipsisCoordinates(2); unfoldedEllipsisCoordinates[0] = lineCoordinates( delimiterCoordinates.m_start.m_line, delimiterCoordinates.m_start.m_column + 1); unfoldedEllipsisCoordinates[1] = delimiterCoordinates.m_end; return unfoldedEllipsisCoordinates; @@ -289,7 +286,7 @@ namespace hex::ui { float spanFragment = totalUnfoldedSpan / 2.0f; - std::vector unfoldedEllipsisCoordinates(4); + Segments unfoldedEllipsisCoordinates(4); if (adddsBothEnds) { unfoldedEllipsisCoordinates[0] = lineCoordinates(delimiterCoordinates.m_start.m_line, delimiterCoordinates.m_start.m_column + 1); unfoldedEllipsisCoordinates[3] = delimiterCoordinates.m_end; @@ -369,7 +366,7 @@ namespace hex::ui { if (foundIndex % 2) { Range delimiterRange = foldedLine.findDelimiterCoordinates(key); - std::vector unfoldedEllipsisCoordinates = this->unfoldedEllipsisCoordinates(delimiterRange); + Segments unfoldedEllipsisCoordinates = this->unfoldedEllipsisCoordinates(delimiterRange); if (unfoldedEllipsisCoordinates.size() > 2) return unfoldedEllipsisCoordinates[coords.m_column - foldedLine.m_ellipsisIndices[foundIndex / 2]]; @@ -401,9 +398,9 @@ namespace hex::ui { Coordinates TextEditor::nextCoordinate(TextEditor::Coordinates coordinate) { auto line = m_lines[coordinate.m_line]; if (line.isEndOfLine(coordinate.m_column)) - return Coordinates(coordinate.m_line + 1, 0); + return {coordinate.m_line + 1, 0}; else - return Coordinates(coordinate.m_line,coordinate.m_column + 1); + return {coordinate.m_line,coordinate.m_column + 1}; } bool TextEditor::testfoldMaps(TextEditor::Range toTest) { bool result = true; @@ -454,7 +451,7 @@ namespace hex::ui { if (foundIndex % 2) { result.m_column = foldedLine.m_ellipsisIndices[foundIndex / 2]; Range delimiterRange = foldedLine.findDelimiterCoordinates(key); - std::vector unfoldedEllipsisCoordinates = this->unfoldedEllipsisCoordinates(delimiterRange); + Segments unfoldedEllipsisCoordinates = this->unfoldedEllipsisCoordinates(delimiterRange); if (unfoldedEllipsisCoordinates.size() > 2) { if (coords == unfoldedEllipsisCoordinates[0])