#include "component/controller/CodeController.h" #include #include "utility/messaging/type/MessageStatus.h" #include "utility/text/TextAccess.h" #include "utility/utility.h" #include "data/access/StorageAccess.h" #include "data/location/TokenLocation.h" #include "data/location/TokenLocationCollection.h" #include "data/location/TokenLocationFile.h" #include "data/location/TokenLocationLine.h" #include "settings/ApplicationSettings.h" CodeController::CodeController(StorageAccess* storageAccess) : m_storageAccess(storageAccess) { } CodeController::~CodeController() { } const uint CodeController::s_lineRadius = 2; void CodeController::handleMessage(MessageActivateTokens* message) { if (message->isEdge && message->isIgnorable()) { return; } std::vector activeTokenIds = message->tokenIds; Id declarationId = 0; // 0 means that no token is found. if (activeTokenIds.size() == 1) { activeTokenIds = m_storageAccess->getActiveTokenIdsForId(activeTokenIds[0], &declarationId); } // TODO: what about declarationId if more than 1 token is active? FIX THIS! CodeView* view = getView(); view->setActiveTokenIds(activeTokenIds); view->setErrorMessages(std::vector()); if (message->isEdge) { view->showFirstActiveSnippet(); return; } std::shared_ptr collection = m_storageAccess->getTokenLocationsForTokenIds(activeTokenIds); view->showCodeSnippets(getSnippetsForActiveTokenLocations(collection.get(), declarationId)); if (!message->isFromSystem) { size_t fileCount = collection->getTokenLocationFileCount(); size_t referenceCount = collection->getTokenLocationCount(); std::stringstream ss; ss << message->tokenIds.size() << ' '; ss << (message->tokenIds.size() == 1 ? "result" : "results"); if (fileCount > 0) { ss << " with " << referenceCount << ' '; ss << (referenceCount == 1 ? "reference" : "references"); ss << " in " << fileCount << ' '; ss << (fileCount == 1 ? "file" : "files"); } MessageStatus(ss.str()).dispatch(); } } void CodeController::handleMessage(MessageFinishedParsing* message) { if (message->errorCount > 0) { std::vector errorMessages; TokenLocationCollection errorCollection = m_storageAccess->getErrorTokenLocations(&errorMessages); std::vector snippets; errorCollection.forEachTokenLocationFile( [&](std::shared_ptr file) -> void { std::vector fileSnippets = getSnippetsForFile(file); snippets.insert(snippets.end(), fileSnippets.begin(), fileSnippets.end()); } ); CodeView* view = getView(); view->setActiveTokenIds(std::vector()); view->setErrorMessages(errorMessages); view->showCodeSnippets(snippets); } } void CodeController::handleMessage(MessageFocusIn* message) { getView()->focusToken(message->tokenId); } void CodeController::handleMessage(MessageFocusOut* message) { getView()->defocusToken(); } void CodeController::handleMessage(MessageShowFile* message) { CodeView::CodeSnippetParams params; params.startLineNumber = message->startLineNumber; params.endLineNumber = message->endLineNumber; std::shared_ptr textAccess = m_storageAccess->getFileContent(message->filePath); params.code = textAccess->getText(); params.locationFile = m_storageAccess->getTokenLocationsForFile(message->filePath.str()); getView()->showCodeFile(params); } void CodeController::handleMessage(MessageShowScope* message) { std::shared_ptr collection = m_storageAccess->getTokenLocationsForLocationIds(std::vector(1, message->scopeLocationId)); TokenLocation* location = collection->findTokenLocationById(message->scopeLocationId); if (!location || !location->isScopeTokenLocation() || !location->getOtherTokenLocation()) { LOG_ERROR("MessageShowScope did not contain a valid scope location id"); return; } std::vector snippets = getSnippetsForActiveTokenLocations(collection.get(), 0); if (snippets.size() != 1) { LOG_ERROR("MessageShowScope didn't result in one single snippet to be created"); return; } getView()->addCodeSnippets(snippets); } void CodeController::handleMessage(MessageShowSnippets* message) { getView()->addCodeSnippets(getSnippetsForActiveTokenLocationsInFile(message->locationFile)); } CodeView* CodeController::getView() { return Controller::getView(); } std::vector CodeController::getSnippetsForActiveTokenLocations( const TokenLocationCollection* collection, Id declarationId ) const { std::vector snippets; collection->forEachTokenLocationFile( [&](std::shared_ptr file) -> void { bool isDeclarationFile = false; file->forEachTokenLocation( [&](TokenLocation* location) { if (location->getTokenId() == declarationId) { isDeclarationFile = true; } } ); if (isDeclarationFile || collection->getTokenLocationFileCount() < 5 || file->isWholeCopy) { std::vector fileSnippets = getSnippetsForActiveTokenLocationsInFile(file); for (CodeView::CodeSnippetParams& snippet : fileSnippets) { snippet.isDeclaration = isDeclarationFile; } utility::append(snippets, fileSnippets); } else { CodeView::CodeSnippetParams params; params.locationFile = file; params.refCount = file->getUnscopedStartTokenLocationCount(); params.isCollapsed = true; snippets.push_back(params); } } ); std::sort(snippets.begin(), snippets.end(), CodeView::CodeSnippetParams::sort); return snippets; } std::vector CodeController::getSnippetsForActiveTokenLocationsInFile( std::shared_ptr file ) const { std::vector fileSnippets = getSnippetsForFile(file); if (!file->isWholeCopy) { for (CodeView::CodeSnippetParams& params : fileSnippets) { params.locationFile = m_storageAccess->getTokenLocationsForLinesInFile( file->getFilePath().str(), params.startLineNumber, params.endLineNumber); } } return fileSnippets; } std::vector CodeController::getSnippetsForFile(std::shared_ptr file) const { std::shared_ptr textAccess = m_storageAccess->getFileContent(file->getFilePath()); std::deque ranges; if (file->isWholeCopy) { ranges.push_back(SnippetMerger::Range( SnippetMerger::Border(1, true), SnippetMerger::Border(textAccess->getLineCount(), true) )); } else { SnippetMerger fileScopedMerger(1, textAccess->getLineCount()); std::map> mergers; file->forEachStartTokenLocation( [&](TokenLocation* location) { buildMergerHierarchy(location, fileScopedMerger, mergers); } ); ranges = fileScopedMerger.merge(); } const int snippetExpandRange = ApplicationSettings::getInstance()->getCodeSnippetExpandRange(); std::vector snippets; for (const SnippetMerger::Range& range: ranges) { CodeView::CodeSnippetParams params; params.locationFile = file; params.refCount = file->getUnscopedStartTokenLocationCount(); params.startLineNumber = std::max(1, range.start.row - (range.start.strong ? 0 : snippetExpandRange)); params.endLineNumber = std::min(textAccess->getLineCount(), range.end.row + (range.end.strong ? 0 : snippetExpandRange)); std::shared_ptr tempFile = m_storageAccess->getTokenLocationsForLinesInFile(file->getFilePath().str(), params.startLineNumber, params.endLineNumber); TokenLocationLine* firstUsedLine = nullptr; for (size_t i = params.startLineNumber; i <= params.endLineNumber && firstUsedLine == nullptr; i++) { firstUsedLine = tempFile->findTokenLocationLineByNumber(i); } if (firstUsedLine && firstUsedLine->getTokenLocations().size()) { m_storageAccess->getTokenLocationOfParentScope(firstUsedLine->getTokenLocations().begin()->second.get())->forEachStartTokenLocation( [&](TokenLocation* location) { params.title = m_storageAccess->getNameForNodeWithId(location->getTokenId()); params.titleId = location->getId(); } ); } for (const std::string& line: textAccess->getLines(params.startLineNumber, params.endLineNumber)) { params.code += line; } snippets.push_back(params); } return snippets; } std::shared_ptr CodeController::buildMergerHierarchy( TokenLocation* location, SnippetMerger& fileScopedMerger, std::map>& mergers) const { const TokenLocation* currentLocation = location; std::shared_ptr currentMerger = std::make_shared( currentLocation->getStartTokenLocation()->getLineNumber(), currentLocation->getEndTokenLocation()->getLineNumber() ); std::shared_ptr locationFile = m_storageAccess->getTokenLocationOfParentScope(currentLocation); if (locationFile->getTokenLocationLineCount() == 0) { fileScopedMerger.addChild(currentMerger); return currentMerger; } std::shared_ptr nextMerger; locationFile->forEachStartTokenLocation( // contains just 1 start location [&](TokenLocation* scopeLocation) { std::map>::iterator it = mergers.find(scopeLocation->getId()); if (it == mergers.end()) { nextMerger = buildMergerHierarchy(scopeLocation, fileScopedMerger, mergers); mergers[scopeLocation->getId()] = nextMerger; } else { nextMerger = it->second; } } ); nextMerger->addChild(currentMerger); return currentMerger; }