logic: visual studio solution parsing

Can now parse visual studio solutions. VS Plugin can send a command, parsing is implemented in Coati.
Some minor changes: added project file icon, added language check to vs plugin
This commit is contained in:
Manuel Dobusch
2016-02-08 15:58:25 +01:00
parent 29149f313a
commit e13eaa85da
46 changed files with 5139 additions and 253 deletions
+3
View File
@@ -18,6 +18,9 @@
#include "version.h"
#include "utility/solution/SolutionParserVisualStudio.h"
#include "settings/ProjectSettings.h"
void init()
{
std::shared_ptr<ConsoleLogger> consoleLogger = std::make_shared<ConsoleLogger>();
+6
View File
@@ -237,6 +237,7 @@ add_files(
utility/messaging/type/MessageInterruptTasks.h
utility/messaging/type/MessageLoadProject.h
utility/messaging/type/MessageMoveIDECursor.h
utility/messaging/type/MessageNewProject.h
utility/messaging/type/MessageRedo.h
utility/messaging/type/MessageRefresh.h
utility/messaging/type/MessageResetZoom.h
@@ -273,6 +274,11 @@ add_files(
utility/scheduling/TaskScheduler.cpp
utility/scheduling/TaskScheduler.h
utility/solution/ISolutionParser.cpp
utility/solution/ISolutionParser.h
utility/solution/SolutionParserVisualStudio.cpp
utility/solution/SolutionParserVisualStudio.h
utility/text/Dictionary.cpp
utility/text/Dictionary.h
utility/text/TextAccess.cpp
@@ -1,14 +1,18 @@
#include "IDECommunicationController.h"
#include "component/controller/helper/NetworkProtocolHelper.h"
#include "data/access/StorageAccess.h"
#include "data/location/TokenLocationFile.h"
#include "data/location/TokenLocation.h"
#include "utility/messaging/type/MessageActivateTokenLocations.h"
#include "utility/messaging/type/MessageActivateWindow.h"
#include "utility/messaging/type/MessageLoadProject.h"
#include "utility/messaging/type/MessageStatus.h"
#include "utility/messaging/type/MessageNewProject.h"
#include "utility/logging/logging.h"
#include "utility/solution/SolutionParserVisualStudio.h"
#include "settings/ProjectSettings.h"
IDECommunicationController::IDECommunicationController(StorageAccess* storageAccess)
: m_storageAccess(storageAccess)
@@ -21,30 +25,44 @@ IDECommunicationController::~IDECommunicationController()
void IDECommunicationController::handleIncomingMessage(const std::string& message)
{
LOG_WARNING_STREAM(<< message);
NetworkProtocolHelper::MESSAGE_TYPE type = NetworkProtocolHelper::getMessageType(message);
NetworkProtocolHelper::NetworkMessage parsedMessage = NetworkProtocolHelper::parseMessage(message);
if (parsedMessage.valid)
if (type == NetworkProtocolHelper::MESSAGE_TYPE::UNKNOWN)
{
const unsigned int cursorColumn = parsedMessage.column;
LOG_ERROR_STREAM(<< "Invalid message type");
}
else if (type == NetworkProtocolHelper::MESSAGE_TYPE::SET_ACTIVE_TOKEN)
{
handleSetActiveTokenMessage(NetworkProtocolHelper::parseSetActiveTokenMessage(message));
}
else
{
handleCreateProjectMessage(NetworkProtocolHelper::parseCreateProjectMessage(message));
}
}
void IDECommunicationController::handleSetActiveTokenMessage(const NetworkProtocolHelper::SetActiveTokenMessage& message)
{
if (message.valid)
{
const unsigned int cursorColumn = message.column;
std::shared_ptr<TokenLocationFile> tokenLocationFile = m_storageAccess->getTokenLocationsForLinesInFile(
parsedMessage.fileLocation, parsedMessage.row, parsedMessage.row
);
message.fileLocation, message.row, message.row
);
std::vector<Id> selectedLocationIds;
tokenLocationFile->forEachStartTokenLocation(
[&](TokenLocation* startLocation)
{
TokenLocation* endLocation = startLocation->getEndTokenLocation();
{
TokenLocation* endLocation = startLocation->getEndTokenLocation();
if (!startLocation->isScopeTokenLocation() &&
startLocation->getColumnNumber() <= cursorColumn && endLocation->getColumnNumber() + 1 >= cursorColumn)
{
selectedLocationIds.push_back(startLocation->getId());
}
if (!startLocation->isScopeTokenLocation() &&
startLocation->getColumnNumber() <= cursorColumn && endLocation->getColumnNumber() + 1 >= cursorColumn)
{
selectedLocationIds.push_back(startLocation->getId());
}
}
);
if (selectedLocationIds.size() > 0)
@@ -57,7 +75,53 @@ void IDECommunicationController::handleIncomingMessage(const std::string& messag
{
MessageStatus(
"Activating a source location from external failed. No symbol(s) have been found at the selected location."
).dispatch();
).dispatch();
}
}
}
void IDECommunicationController::handleCreateProjectMessage(const NetworkProtocolHelper::CreateProjectMessage& message)
{
if (message.valid)
{
if (message.ideId == NetworkProtocolHelper::CreateProjectMessage::IDE_ID::VS)
{
SolutionParserVisualStudio parser;
parser.openSolutionFile(message.solutionFileLocation);
std::vector<std::string> includePaths = parser.getIncludePaths();
std::vector<std::string> projectItems = parser.getProjectItems();
std::vector<FilePath> projectFPs;
std::vector<FilePath> includeFPs;
for (unsigned int i = 0; i < projectItems.size(); i++)
{
projectFPs.push_back(FilePath(projectItems[i]));
}
for (unsigned int i = 0; i < includePaths.size(); i++)
{
includeFPs.push_back(FilePath(includePaths[i]));
}
/*ProjectSettings* projSettings = ProjectSettings::getInstance().get();
projSettings->clear();
projSettings->setLanguage("c++");
projSettings->setStandard("11");
projSettings->setSourcePaths(projectFPs);
projSettings->setHeaderSearchPaths(includeFPs);
std::string filePath = parser.getSolutionPath() + parser.getSolutionName() + ".coatiproject";
projSettings->save(filePath);*/
MessageNewProject(parser.getSolutionName(), parser.getSolutionPath(), projectItems, includePaths).dispatch();
}
else
{
LOG_ERROR_STREAM(<< "Unable to parse provided solution, unknown format");
}
}
}
@@ -5,6 +5,8 @@
#include "component/controller/Controller.h"
#include "component/controller/helper/NetworkProtocolHelper.h"
#include "utility/messaging/MessageListener.h"
#include "utility/messaging/type/MessageMoveIDECursor.h"
@@ -21,6 +23,9 @@ public:
void handleIncomingMessage(const std::string& message);
private:
void handleSetActiveTokenMessage(const NetworkProtocolHelper::SetActiveTokenMessage& message);
void handleCreateProjectMessage(const NetworkProtocolHelper::CreateProjectMessage& message);
virtual void handleMessage(MessageMoveIDECursor* message);
virtual void sendMessage(const std::string& message) const = 0;
@@ -3,38 +3,119 @@
#include <sstream>
#include <string>
#include "utility/logging/logging.h"
std::string NetworkProtocolHelper::m_divider = ">>";
std::string NetworkProtocolHelper::m_setActiveTokenPrefix = "setActiveToken";
std::string NetworkProtocolHelper::m_moveCursorPrefix = "moveCursor";
std::string NetworkProtocolHelper::m_endOfMessageToken = "<EOM>";
std::string NetworkProtocolHelper::m_createProjectPrefix = "createProject";
NetworkProtocolHelper::NetworkMessage NetworkProtocolHelper::parseMessage(const std::string& message)
NetworkProtocolHelper::MESSAGE_TYPE NetworkProtocolHelper::getMessageType(const std::string& message)
{
NetworkMessage networkMessage;
size_t pos = message.find(m_setActiveTokenPrefix);
std::vector<std::string> subMessages = divideMessage(message);
if(pos != std::string::npos)
if (subMessages.size() > 0)
{
std::string tmpMessage = "";
getSubstringAfterString(message, m_divider, tmpMessage); // just get rid of message type
tmpMessage = removeEndOfMessageToken(tmpMessage);
if (subMessages[0] == m_setActiveTokenPrefix)
{
return MESSAGE_TYPE::SET_ACTIVE_TOKEN;
}
else if (subMessages[0] == m_createProjectPrefix)
{
return MESSAGE_TYPE::CREATE_PROJECT;
}
else
{
return MESSAGE_TYPE::UNKNOWN;
}
}
return MESSAGE_TYPE::UNKNOWN;
}
std::string fileLocation = getSubstringAfterString(tmpMessage, m_divider, tmpMessage);
std::string row = getSubstringAfterString(tmpMessage, m_divider, tmpMessage);
std::string column = tmpMessage; // there should be nothing left in the message but the column number
NetworkProtocolHelper::SetActiveTokenMessage NetworkProtocolHelper::parseSetActiveTokenMessage(const std::string& message)
{
std::vector<std::string> subMessages = divideMessage(message);
if(
fileLocation.length() > 0
&& row.length() > 0
&& column.length() > 0
&& isDigits(row)
&& isDigits(column)
){
networkMessage.fileLocation = fileLocation;
networkMessage.row = std::stoi(row);
networkMessage.column = std::stoi(column);
networkMessage.valid = true;
SetActiveTokenMessage networkMessage;
if (subMessages.size() > 0)
{
if (subMessages[0] == m_setActiveTokenPrefix)
{
if (subMessages.size() != 5)
{
LOG_ERROR_STREAM(<< "Failed to parse setActiveToken message, invalid token count");
}
else
{
std::string fileLocation = subMessages[1];
std::string row = subMessages[2];
std::string column = subMessages[3];
if(
fileLocation.length() > 0
&& row.length() > 0
&& column.length() > 0
&& isDigits(row)
&& isDigits(column)
){
networkMessage.fileLocation = fileLocation;
networkMessage.row = std::stoi(row);
networkMessage.column = std::stoi(column);
networkMessage.valid = true;
}
}
}
else
{
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token");
}
}
return networkMessage;
}
NetworkProtocolHelper::CreateProjectMessage NetworkProtocolHelper::parseCreateProjectMessage(const std::string& message)
{
std::vector<std::string> subMessages = divideMessage(message);
NetworkProtocolHelper::CreateProjectMessage networkMessage;
if (subMessages.size() > 0)
{
if (subMessages[0] == m_createProjectPrefix)
{
if (subMessages.size() != 4)
{
LOG_ERROR_STREAM(<< "Failed to parse createProject message, invalid token count");
}
else
{
std::string fileLocation = subMessages[1];
std::string ideId = subMessages[2];
if (fileLocation.length() > 0
&& ideId.length() > 0)
{
networkMessage.solutionFileLocation = fileLocation;
if (ideId == "vs")
{
networkMessage.ideId = CreateProjectMessage::IDE_ID::VS;
}
else
{
networkMessage.ideId = CreateProjectMessage::IDE_ID::UNKNOWN;
}
networkMessage.valid = true;
}
}
}
else
{
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token");
}
}
@@ -57,6 +138,36 @@ std::string NetworkProtocolHelper::buildMessage(const std::string& fileLocation,
return messageStream.str();
}
std::vector<std::string> NetworkProtocolHelper::divideMessage(const std::string& message)
{
std::vector<std::string> result;
std::string msg = message;
size_t pos = msg.find(m_divider);
while (pos != std::string::npos)
{
std::string subMessage = msg.substr(0, pos);
result.push_back(subMessage);
msg = msg.substr(pos + m_divider.size());
pos = msg.find(m_divider);
}
if (msg.size() > 0)
{
pos = msg.find(m_endOfMessageToken);
if (pos != std::string::npos)
{
std::string subMessage = msg.substr(0, pos);
result.push_back(subMessage);
msg = msg.substr(pos);
result.push_back(msg);
}
}
return result;
}
std::string NetworkProtocolHelper::removeEndOfMessageToken(const std::string& message)
{
size_t pos = message.find(m_endOfMessageToken);
@@ -2,14 +2,15 @@
#define NETWORK_PROTOCOL_HELPER_H
#include <string>
#include <vector>
class NetworkProtocolHelper
{
public:
struct NetworkMessage
struct SetActiveTokenMessage
{
public:
NetworkMessage()
SetActiveTokenMessage()
: fileLocation("")
, row(0)
, column(0)
@@ -22,10 +23,43 @@ public:
bool valid;
};
static NetworkMessage parseMessage(const std::string& message);
struct CreateProjectMessage
{
public:
CreateProjectMessage()
: solutionFileLocation("")
, ideId(IDE_ID::UNKNOWN)
, valid(false)
{}
enum IDE_ID
{
UNKNOWN = 0,
VS
};
std::string solutionFileLocation;
IDE_ID ideId;
bool valid;
};
enum MESSAGE_TYPE
{
UNKNOWN = 0,
SET_ACTIVE_TOKEN,
CREATE_PROJECT
};
static MESSAGE_TYPE getMessageType(const std::string& message);
static SetActiveTokenMessage parseSetActiveTokenMessage(const std::string& message);
static CreateProjectMessage parseCreateProjectMessage(const std::string& message);
static std::string buildMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column);
private:
static std::vector<std::string> divideMessage(const std::string& message);
static std::string removeEndOfMessageToken(const std::string& message);
static std::string getSubstringAfterString(const std::string& message, const std::string& searchString, std::string& subMessage);
@@ -35,6 +69,7 @@ private:
static std::string m_setActiveTokenPrefix;
static std::string m_moveCursorPrefix;
static std::string m_endOfMessageToken;
static std::string m_createProjectPrefix;
};
#endif // NETWORK_PROTOCOL_HELPER_H
@@ -0,0 +1,33 @@
#ifndef MESSAGE_NEW_PROJECT_H
#define MESSAGE_NEW_PROJECT_H
#include "utility/messaging/Message.h"
class MessageNewProject : public Message<MessageNewProject>
{
public:
MessageNewProject(const std::string& projectName, const std::string projectLocation,
const std::vector<std::string>& sourceFiles, const std::vector<std::string>& includePaths)
: projectName(projectName)
, projectLocation(projectLocation)
, projectSourceFiles(sourceFiles)
, projectIncludePaths(includePaths)
{
}
static const std::string getStaticType()
{
return "MessageNewProject";
}
virtual void print(std::ostream& os) const
{
}
const std::string projectName;
const std::string projectLocation;
const std::vector<std::string> projectSourceFiles;
const std::vector<std::string> projectIncludePaths;
};
#endif // MESSAGE_NEW_PROJECT_H
@@ -0,0 +1,48 @@
#include "ISolutionParser.h"
std::string ISolutionParser::getSolutionPath()
{
return m_solutionPath;
}
void ISolutionParser::openSolutionFile(const std::string& solutionFilePath)
{
m_solution = loadFile(solutionFilePath);
size_t pos = solutionFilePath.find_last_of("/");
if (pos == std::string::npos)
{
pos = solutionFilePath.find_last_of("\\");
}
if (pos != std::string::npos)
{
if (pos > 0)
{
pos += 1;
}
m_solutionPath = solutionFilePath.substr(0, pos);
m_solutionName = solutionFilePath.substr(pos);
}
}
unsigned int ISolutionParser::getSolutionCharCount() const
{
return m_solution.size();
}
std::string ISolutionParser::loadFile(const std::string& filePath)
{
std::string file = "";
std::ifstream ifstream;
ifstream.open(filePath);
if (ifstream.is_open())
{
file = std::string(std::istreambuf_iterator<char>(ifstream), std::istreambuf_iterator<char>());
}
return file;
}
@@ -0,0 +1,34 @@
#ifndef I_SOLUTION_PARSER_H
#define I_SOLUTION_PARSER_H
#include <fstream>
#include <vector>
class ISolutionParser
{
public:
ISolutionParser()
: m_solutionPath("")
, m_solution("")
{};
virtual ~ISolutionParser(){};
void openSolutionFile(const std::string& solutionFilePath);
unsigned int getSolutionCharCount() const;
virtual std::string getSolutionName() = 0; // to be overwritten to account for different file endings
std::string getSolutionPath();
virtual std::vector<std::string> getProjects() = 0;
virtual std::vector<std::string> getProjectFiles() = 0;
virtual std::vector<std::string> getProjectItems() = 0;
protected:
std::string loadFile(const std::string& filePath);
std::string m_solutionName;
std::string m_solutionPath;
std::string m_solution;
};
#endif // I_SOLUTION_PARSER_H
@@ -0,0 +1,18 @@
#include "SolutionParserCMake.h"
SolutionParserCMake::SolutionParserCMake()
{
}
SolutionParserCMake::~SolutionParserCMake()
{
}
std::vector<std::string> SolutionParserCMake::getProjects()
{
std::vector<std::string> projects;
return projects;
}
@@ -0,0 +1,16 @@
#ifndef SOLUTION_PARSER_C_MAKE_H
#define SOLUTION_PARSER_C_MAKE_H
#include "ISolutionParser.h"
class SolutionParserCMake : public ISolutionParser
{
public:
SolutionParserCMake();
virtual ~SolutionParserCMake();
virtual std::vector<std::string> getProjects();
virtual std::vector<std::string> getProjectFiles();
};
#endif // SOLUTION_PARSER_C_MAKE_H
@@ -0,0 +1,604 @@
#include "SolutionParserVisualStudio.h"
#include <algorithm>
#include <cstdlib>
#include <set>
#include "boost/filesystem/path.hpp"
#include "boost/filesystem.hpp"
#include "utility/logging/logging.h"
SolutionParserVisualStudio::SolutionParserVisualStudio()
{
}
SolutionParserVisualStudio::~SolutionParserVisualStudio()
{
}
std::string SolutionParserVisualStudio::getSolutionName()
{
std::string result = "";
if (m_solutionName.size() > 0)
{
size_t pos = m_solutionName.find(".sln");
if (pos != std::string::npos)
{
result = m_solutionName.substr(0, pos);
}
else
{
result = m_solution;
}
}
return result;
}
std::vector<std::string> SolutionParserVisualStudio::getProjects()
{
std::vector<std::string> projectFiles;
if (m_solution.size() > 0)
{
std::vector<std::string> blocks = getProjectBlocks(m_solution);
for (unsigned int i = 0; i < blocks.size(); i++)
{
projectFiles.push_back(getProjectFilePath(blocks[i]));
}
}
return projectFiles;
}
std::vector<std::string> SolutionParserVisualStudio::getProjectFiles()
{
std::vector<std::string> projectFiles;
std::vector<std::string> projectFilesNames = getProjects();
for (unsigned int i = 0; i < projectFilesNames.size(); i++)
{
projectFiles.push_back(loadFile(m_solutionPath + projectFilesNames[i]));
}
//projectFiles.push_back(loadFile(m_solutionPath + "foo.xml"));
return projectFiles;
}
std::vector<std::string> SolutionParserVisualStudio::getProjectItems()
{
std::vector<std::string> projectItems;
std::vector<std::string> projectFilesNames = getProjects();
std::vector<std::string> projectFiles = getProjectFiles();
std::vector<std::string> relativeProjectPaths;
for (unsigned int i = 0; i < projectFilesNames.size(); i++)
{
size_t pos = projectFilesNames[i].find_last_of("/");
if (pos == std::string::npos)
{
pos = projectFilesNames[i].find_last_of("\\");
}
if (pos != std::string::npos)
{
relativeProjectPaths.push_back(projectFilesNames[i].substr(0, pos));
}
else
{
relativeProjectPaths.push_back("");
}
}
for (unsigned int i = 0; i < projectFiles.size(); i++)
{
TiXmlDocument doc;
doc.Parse(projectFiles[i].c_str(), 0, TIXML_ENCODING_UTF8);
std::string error = doc.ErrorDesc();
if (error.length() > 0)
{
LOG_ERROR_STREAM(<< "Failed to parse project file " << i << ": " << error);
continue;
}
TiXmlElement* root = getFirstTagByNameWithAttribute(doc.RootElement(), "ClCompile", "Include");
if (root != NULL)
{
// std::string text(root->GetText());
std::string tag = root->Value();
std::string text = "";
if (root->Attribute("Include") != NULL)
{
text = root->Attribute("Include");
}
if (text.find(".cpp") == std::string::npos)
{
root = NULL;
}
else
{
root = root->Parent()->ToElement();
}
}
if (root == NULL)
{
TiXmlElement* root = getFirstTagByNameWithAttribute(doc.RootElement(), "ClInclude", "Include");
if (root != NULL)
{
root = root->Parent()->ToElement();
}
else
{
root = NULL;
}
}
if (root != NULL)
{
for (TiXmlElement* child = root->FirstChildElement(); child != NULL; child = child->NextSiblingElement())
{
std::string filePath = child->Attribute("Include");
if (relativeProjectPaths[i].size() > 0)
{
filePath = relativeProjectPaths[i] + "/" + filePath;
}
projectItems.push_back(filePath);
}
}
}
std::set<std::string> s(projectItems.begin(), projectItems.end());
projectItems.assign(s.begin(), s.end());
projectItems = resolveEnvironmentVariables(projectItems);
projectItems = makePathsAbsolute(projectItems);
projectItems = makePathsCanonical(projectItems);
return projectItems;
}
std::vector<std::string> SolutionParserVisualStudio::getIncludePaths()
{
std::vector<std::string> includePaths;
std::vector<std::string> projectFiles = getProjectFiles();
for (unsigned int i = 0; i < projectFiles.size(); i++)
{
TiXmlDocument doc;
doc.Parse(projectFiles[i].c_str(), 0, TIXML_ENCODING_UTF8);
std::string error = doc.ErrorDesc();
if (error.length() > 0)
{
LOG_ERROR_STREAM(<< "Failed to parse project file " << i << ": " << error);
continue;
}
std::vector<TiXmlElement*> nodes = getAllTagsByName(doc.RootElement(), "AdditionalIncludeDirectories");
for (unsigned int j = 0; j < nodes.size(); j++)
{
includePaths.push_back(nodes[j]->GetText());
}
}
includePaths = seperateIncludePaths(includePaths);
std::set<std::string> s(includePaths.begin(), includePaths.end());
includePaths.assign(s.begin(), s.end());
includePaths = resolveEnvironmentVariables(includePaths);
includePaths = makePathsAbsolute(includePaths);
includePaths = makePathsCanonical(includePaths);
return includePaths;
}
std::vector<std::string> SolutionParserVisualStudio::getProjectBlocks(const std::string& solution) const
{
std::vector<std::string> blocks;
std::string subSolution = solution;
std::string solutionOpenTag = "\nProject";
std::string solutionCloseTag = "\nEndProject";
size_t blockStart = subSolution.find(solutionOpenTag, 0);
size_t blockEnd = subSolution.find(solutionCloseTag, 0);
while (blockStart != std::string::npos && blockEnd != std::string::npos)
{
std::string block = subSolution.substr(blockStart, blockEnd - blockStart + solutionCloseTag.size());
if (subSolution.size() > blockEnd + solutionCloseTag.size())
{
subSolution = subSolution.substr(blockEnd + solutionCloseTag.size());
}
else
{
subSolution = "";
}
blockStart = subSolution.find(solutionOpenTag);
blockEnd = subSolution.find(solutionCloseTag);
blocks.push_back(block);
}
return blocks;
}
std::string SolutionParserVisualStudio::getProjectFilePath(const std::string& projectBlock) const
{
std::string projectFilePath;
std::string fileEnding = "vcxproj";
size_t pos = projectBlock.find(fileEnding);
if (pos != std::string::npos)
{
std::string searchArea = projectBlock.substr(0, pos + fileEnding.size());
pos = searchArea.find_last_of("\"");
projectFilePath = searchArea.substr(pos + 1);
}
return projectFilePath;
}
std::vector<std::string> SolutionParserVisualStudio::seperateIncludePaths(const std::vector<std::string>& includePaths) const
{
std::vector<std::string> seperatedPaths;
for (unsigned int i = 0; i < includePaths.size(); i++)
{
std::vector<std::string> paths = seperateIncludePaths(includePaths[i]);
for (unsigned int j = 0; j < paths.size(); j++)
{
seperatedPaths.push_back(paths[j]);
}
}
return seperatedPaths;
}
std::vector<std::string> SolutionParserVisualStudio::seperateIncludePaths(const std::string& includePaths) const
{
std::string paths = includePaths;
std::string seperator = ";";
std::vector<std::string> seperatedPaths;
size_t pos = includePaths.find(seperator);
while (pos != std::string::npos)
{
std::string path = paths.substr(0, pos);
paths = paths.substr(pos + 1);
seperatedPaths.push_back(path);
pos = paths.find(seperator);
}
return seperatedPaths;
}
TiXmlElement* SolutionParserVisualStudio::getFirstTagByName(TiXmlElement* root, const std::string& tag)
{
TiXmlElement* element = root;
while (element)
{
if (element == NULL)
{
int foo = 0;
}
std::string value = element->Value();
if (value == tag) // "ClInclude") // || value == "ClCompile")
{
if (element->Parent() != NULL)
{
return element; // ->Parent()->ToElement();
}
}
if (element->FirstChildElement() != NULL)
{
element = element->FirstChildElement();
}
else if (element->NextSiblingElement() != NULL)
{
element = element->NextSiblingElement();
}
else
{
if (element == NULL)
{
int foo = 0;
}
while (element->Parent()->ToElement() != NULL && element->Parent()->NextSiblingElement() == NULL)
{
TiXmlElement* newElement = element->Parent()->ToElement();
if (newElement == NULL)
{
int foo = 0;
}
element = newElement;
}
if (element->Parent() != NULL && element->Parent()->NextSiblingElement() != NULL)
{
element = element->Parent()->NextSiblingElement();
}
else
{
return NULL;
}
}
}
return NULL;
}
std::vector<TiXmlElement*> SolutionParserVisualStudio::getAllTagsByName(TiXmlElement* root, const std::string& tag)
{
std::vector<TiXmlElement*> nodes;
TiXmlElement* element = root;
while (element)
{
std::string value = element->Value();
if (value == tag)
{
nodes.push_back(element);
}
if (element->FirstChildElement() != NULL)
{
element = element->FirstChildElement();
}
else if (element->NextSiblingElement() != NULL)
{
element = element->NextSiblingElement();
}
else
{
if (element == NULL)
{
int foo = 0;
}
while (element->Parent()->ToElement() != NULL && element->Parent()->NextSiblingElement() == NULL)
{
TiXmlElement* newElement = element->Parent()->ToElement();
if (newElement == NULL)
{
int foo = 0;
}
element = newElement;
}
if (element->Parent() != NULL && element->Parent()->NextSiblingElement() != NULL)
{
element = element->Parent()->NextSiblingElement();
}
else
{
break;
}
}
}
return nodes;
}
TiXmlElement* SolutionParserVisualStudio::getFirstTagByNameWithAttribute(TiXmlElement* root, const std::string& tag, const std::string& attribute)
{
TiXmlElement* element = root;
while (element)
{
if (element == NULL)
{
int foo = 0;
}
std::string value = element->Value();
bool hasAttribute = false;
if (element->Attribute(attribute.c_str()) != NULL)
{
hasAttribute = true;
}
if (value == tag && hasAttribute) // "ClInclude") // || value == "ClCompile")
{
if (element->Parent() != NULL)
{
return element; // ->Parent()->ToElement();
}
}
if (element->FirstChildElement() != NULL)
{
element = element->FirstChildElement();
}
else if (element->NextSiblingElement() != NULL)
{
element = element->NextSiblingElement();
}
else
{
while (element->Parent()->ToElement() != NULL && element->Parent()->NextSiblingElement() == NULL)
{
TiXmlElement* newElement = element->Parent()->ToElement();
element = newElement;
}
if (element->Parent() != NULL && element->Parent()->NextSiblingElement() != NULL)
{
element = element->Parent()->NextSiblingElement();
}
else
{
return NULL;
}
}
}
return NULL;
}
std::vector<TiXmlElement*> SolutionParserVisualStudio::getAllTagsByNameWithAttribute(TiXmlElement* root, const std::string& tag, const std::string& attribute)
{
std::vector<TiXmlElement*> nodes;
TiXmlElement* element = root;
while (element)
{
std::string value = element->Value();
bool hasAttribute = false;
if (element->Attribute(attribute.c_str()) != NULL)
{
hasAttribute = true;
}
if (value == tag && hasAttribute)
{
nodes.push_back(element);
}
if (element->FirstChildElement() != NULL)
{
element = element->FirstChildElement();
}
else if (element->NextSiblingElement() != NULL)
{
element = element->NextSiblingElement();
}
else
{
while (element->Parent()->ToElement() != NULL && element->Parent()->NextSiblingElement() == NULL)
{
TiXmlElement* newElement = element->Parent()->ToElement();
element = newElement;
}
if (element->Parent() != NULL && element->Parent()->NextSiblingElement() != NULL)
{
element = element->Parent()->NextSiblingElement();
}
else
{
break;
}
}
}
return nodes;
}
std::vector<std::string> SolutionParserVisualStudio::resolveEnvironmentVariables(const std::vector<std::string>& paths)
{
std::vector<std::string> resolvedPaths;
for (unsigned int i = 0; i < paths.size(); i++)
{
resolvedPaths.push_back(findAndResolveEnvironmentVariable(paths[i]));
}
return resolvedPaths;
}
std::string SolutionParserVisualStudio::findAndResolveEnvironmentVariable(const std::string& path)
{
std::string resolvedPath;
size_t pos = path.find("$(");
if (pos != std::string::npos)
{
size_t endPos = path.substr(pos).find(")");
std::string envVariable = path.substr(pos+2, (endPos-2) - pos);
std::string envPath = getenv(envVariable.c_str());
std::string prePath = path.substr(0, pos);
std::string postPath = path.substr(endPos + 1);
resolvedPath = prePath + envPath + postPath;
}
else
{
resolvedPath = path;
}
return resolvedPath;
}
std::vector<std::string> SolutionParserVisualStudio::makePathsAbsolute(const std::vector<std::string>& paths)
{
std::vector<std::string> absolutePaths;
for (unsigned int i = 0; i < paths.size(); i++)
{
std::string path = paths[i];
boost::filesystem::path boostPath(path);
if (boostPath.is_relative())
{
path = m_solutionPath + path;
}
absolutePaths.push_back(path);
}
return absolutePaths;
}
std::vector<std::string> SolutionParserVisualStudio::makePathsCanonical(const std::vector<std::string>& paths)
{
std::vector<std::string> canonicalPaths;
for (unsigned int i = 0; i < paths.size(); i++)
{
try
{
boost::filesystem::path canonicalPath = boost::filesystem::canonical(boost::filesystem::path(paths[i]));
canonicalPaths.push_back(canonicalPath.string());
}
catch (std::exception& e)
{
LOG_WARNING_STREAM(<< e.what());
}
}
return canonicalPaths;
}
@@ -0,0 +1,40 @@
#ifndef SOLUTION_PARSER_VISUAL_STUDIO_H
#define SOLUTION_PARSER_VISUAL_STUDIO_H
#include "ISolutionParser.h"
#include "tinyxml/tinyxml.h"
class SolutionParserVisualStudio : public ISolutionParser
{
public:
SolutionParserVisualStudio();
virtual ~SolutionParserVisualStudio();
virtual std::string getSolutionName();
virtual std::vector<std::string> getProjects();
virtual std::vector<std::string> getProjectFiles();
virtual std::vector<std::string> getProjectItems();
virtual std::vector<std::string> getIncludePaths();
private:
std::vector<std::string> getProjectBlocks(const std::string& solution) const;
std::string getProjectFilePath(const std::string& projectBlock) const;
std::vector<std::string> seperateIncludePaths(const std::vector<std::string>& includePaths) const;
std::vector<std::string> seperateIncludePaths(const std::string& includePaths) const;
TiXmlElement* getFirstTagByName(TiXmlElement* root, const std::string& tag);
std::vector<TiXmlElement*> getAllTagsByName(TiXmlElement* root, const std::string& tag);
TiXmlElement* getFirstTagByNameWithAttribute(TiXmlElement* root, const std::string& tag, const std::string& attribute);
std::vector<TiXmlElement*> getAllTagsByNameWithAttribute(TiXmlElement* root, const std::string& tag, const std::string& attribute);
std::vector<std::string> resolveEnvironmentVariables(const std::vector<std::string>& paths);
std::string findAndResolveEnvironmentVariable(const std::string& path);
std::vector<std::string> makePathsAbsolute(const std::vector<std::string>& paths);
std::vector<std::string> makePathsCanonical(const std::vector<std::string>& paths);
};
#endif // SOLUTION_PARSER_VISUAL_STUDIO_H
+13
View File
@@ -106,6 +106,7 @@ bool MouseWheelFilter::eventFilter(QObject* obj, QEvent* event)
QtMainWindow::QtMainWindow()
: m_showDockWidgetTitleBars(true)
, m_createNewProjectFunctor(std::bind(&QtMainWindow::doCreateNewProject, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4))
{
setObjectName("QtMainWindow");
setCentralWidget(nullptr);
@@ -252,6 +253,11 @@ void QtMainWindow::forceEnterLicense()
m_enterLicenseWindow->setEnabled(true);
}
void QtMainWindow::handleMessage(MessageNewProject* message)
{
m_createNewProjectFunctor(message->projectName, message->projectLocation, message->projectSourceFiles, message->projectIncludePaths);
}
bool QtMainWindow::event(QEvent* event)
{
if (event->type() == QEvent::WindowActivate)
@@ -599,6 +605,13 @@ void QtMainWindow::toggleShowDockWidgetTitleBars()
setShowDockWidgetTitleBars(!m_showDockWidgetTitleBars);
}
void QtMainWindow::doCreateNewProject(const std::string& name, const std::string& location,
const std::vector<std::string>& sourceFiles, const std::vector<std::string>& includePaths)
{
newProject();
m_newProjectDialog->setPresets(name, location, sourceFiles, includePaths);
}
void QtMainWindow::setupEditMenu()
{
QMenu *menu = new QMenu(tr("&Edit"), this);
+11
View File
@@ -8,6 +8,10 @@
#include <QMainWindow>
#include <QShortcut>
#include "utility/messaging/MessageListener.h"
#include "utility/messaging/type/MessageNewProject.h"
#include "qt/utility/QtThreadedFunctor.h"
#include "qt/window/QtApplicationSettingsScreen.h"
#include "qt/window/QtStartScreen.h"
#include "qt/window/QtProjectSetupScreen.h"
@@ -66,6 +70,7 @@ protected:
class QtMainWindow
: public QMainWindow
, public MessageListener<MessageNewProject>
{
Q_OBJECT
@@ -86,6 +91,8 @@ public:
void forceEnterLicense();
void handleMessage(MessageNewProject* message);
protected:
bool event(QEvent* event);
void keyPressEvent(QKeyEvent* event);
@@ -143,6 +150,8 @@ private:
QtViewToggle* toggle;
};
void doCreateNewProject(const std::string& name, const std::string& location,
const std::vector<std::string>& sourceFiles, const std::vector<std::string>& includePaths);
void setupEditMenu();
void setupProjectMenu();
@@ -174,6 +183,8 @@ private:
QShortcut* m_escapeShortcut;
static std::string m_windowSettingsPath;
QtThreadedFunctor<std::string, std::string, std::vector<std::string>, std::vector<std::string>> m_createNewProjectFunctor;
};
#endif // QT_MAIN_WINDOW_H
@@ -142,6 +142,28 @@ void QtProjectSetupScreen::loadProjectSettings()
}
}
void QtProjectSetupScreen::setPresets(const std::string& name, const std::string& location,
const std::vector<std::string>& sourceFiles, const std::vector<std::string>& includePaths)
{
m_projectName->setText(QString::fromStdString(name));
m_projectFileLocation->setText(QString::fromStdString(location));
std::vector<FilePath> sourceFilePaths;
for (unsigned int i = 0; i < sourceFiles.size(); i++)
{
sourceFilePaths.push_back(FilePath(sourceFiles[i]));
}
std::vector<FilePath> includePathsPaths;
for (unsigned int i = 0; i < includePaths.size(); i++)
{
includePathsPaths.push_back(FilePath(sourceFiles[i]));
}
m_sourcePaths->setList(sourceFilePaths);
m_includePaths->setList(includePathsPaths);
}
void QtProjectSetupScreen::populateForm(QFormLayout* layout)
{
int minimumWidthForSecondCol = 360;
@@ -49,6 +49,10 @@ public:
void projectSetupScreen();
// fill screen without having to set project setting beforehand (e.g. when creating a new project)
void setPresets(const std::string& name, const std::string& location,
const std::vector<std::string>& sourceFiles, const std::vector<std::string>& includePaths);
signals:
void showPreferences();
+1
View File
@@ -31,4 +31,5 @@ add_files(
TokenLocationCollectionTestSuite.h
UtilityStringTestSuite.h
Vector2TestSuite.h
VsSolutionParserTestSuite.h
)
+5 -5
View File
@@ -18,7 +18,7 @@ public:
std::stringstream message;
message << type << divider << filePath << divider << row << divider << column << endOfMessageToken;
NetworkProtocolHelper::NetworkMessage networkMessage = NetworkProtocolHelper::parseMessage(message.str());
NetworkProtocolHelper::SetActiveTokenMessage networkMessage = NetworkProtocolHelper::parseSetActiveTokenMessage(message.str());
TS_ASSERT_EQUALS(networkMessage.fileLocation, filePath);
TS_ASSERT_EQUALS(networkMessage.row, row);
@@ -28,7 +28,7 @@ public:
// invalid type
message.str("");
message << "foo" << divider << filePath << divider << row << divider << column << endOfMessageToken;
networkMessage = NetworkProtocolHelper::parseMessage(message.str());
networkMessage = NetworkProtocolHelper::parseSetActiveTokenMessage(message.str());
TS_ASSERT_EQUALS(networkMessage.fileLocation, "");
TS_ASSERT_EQUALS(networkMessage.row, 0);
@@ -38,7 +38,7 @@ public:
// missing divider
message.str("");
message << type << divider << filePath << row << divider << column << endOfMessageToken;
networkMessage = NetworkProtocolHelper::parseMessage(message.str());
networkMessage = NetworkProtocolHelper::parseSetActiveTokenMessage(message.str());
TS_ASSERT_EQUALS(networkMessage.fileLocation, "");
TS_ASSERT_EQUALS(networkMessage.row, 0);
@@ -48,7 +48,7 @@ public:
// invalid row
message.str("");
message << type << divider << filePath << divider << "potato" << divider << column << endOfMessageToken;
networkMessage = NetworkProtocolHelper::parseMessage(message.str());
networkMessage = NetworkProtocolHelper::parseSetActiveTokenMessage(message.str());
TS_ASSERT_EQUALS(networkMessage.fileLocation, "");
TS_ASSERT_EQUALS(networkMessage.row, 0);
@@ -58,7 +58,7 @@ public:
// invalid column
message.str("");
message << type << divider << filePath << divider << row << divider << "laz0r" << endOfMessageToken;
networkMessage = NetworkProtocolHelper::parseMessage(message.str());
networkMessage = NetworkProtocolHelper::parseSetActiveTokenMessage(message.str());
TS_ASSERT_EQUALS(networkMessage.fileLocation, "");
TS_ASSERT_EQUALS(networkMessage.row, 0);
+61
View File
@@ -0,0 +1,61 @@
#include "cxxtest/TestSuite.h"
#include "utility/logging/logging.h"
#include "utility/solution/SolutionParserVisualStudio.h"
class VsSolutionParserTestSuite : public CxxTest::TestSuite
{
public:
void test_load_solution()
{
SolutionParserVisualStudio parser;
parser.openSolutionFile("data/vsSolutionParserTestSuite/Coati.sln");
// TS_ASSERT_EQUALS(10186, parser.getSolutionCharCount());
}
void test_get_project_files()
{
SolutionParserVisualStudio parser;
parser.openSolutionFile("data/vsSolutionParserTestSuite/Coati.sln");
std::vector<std::string> projects = parser.getProjects();
TS_ASSERT_EQUALS(9, projects.size());
TS_ASSERT_EQUALS("ALL_BUILD.vcxproj", projects[0]);
TS_ASSERT_EQUALS("Coati.vcxproj", projects[1]);
TS_ASSERT_EQUALS("Coati_lib.vcxproj", projects[2]);
TS_ASSERT_EQUALS("Coati_lib_gui.vcxproj", projects[3]);
TS_ASSERT_EQUALS("Coati_lib_parser.vcxproj", projects[4]);
TS_ASSERT_EQUALS("Coati_test.vcxproj", projects[5]);
TS_ASSERT_EQUALS("Coati_trial.vcxproj", projects[6]);
TS_ASSERT_EQUALS("ZERO_CHECK.vcxproj", projects[7]);
TS_ASSERT_EQUALS("versionnumber.vcxproj", projects[8]);
}
void test_get_solution_name()
{
SolutionParserVisualStudio parser;
parser.openSolutionFile("data/vsSolutionParserTestSuite/Coati.sln");
std::string solutionName = parser.getSolutionName();
TS_ASSERT_EQUALS("Coati", solutionName);
}
void test_get_include_paths()
{
SolutionParserVisualStudio parser;
parser.openSolutionFile("data/vsSolutionParserTestSuite/Coati.sln");
std::vector<std::string> includePaths = parser.getIncludePaths();
TS_ASSERT_EQUALS(23, includePaths.size());
}
void test_get_()
{
SolutionParserVisualStudio parser;
parser.openSolutionFile("data/vsSolutionParserTestSuite/Coati.sln");
std::vector<std::string> projectItems = parser.getProjectItems();
TS_ASSERT_EQUALS(447, projectItems.size());
}
};