ui: vs plugin integration

Reworked vs solution based project setup to utilize new CDB feature
This commit is contained in:
Manuel Dobusch
2016-11-10 17:40:14 +01:00
parent 9aed97eee2
commit 0a3200f8ff
32 changed files with 744 additions and 254 deletions
+2 -2
View File
@@ -32,8 +32,8 @@
.DS_Store
.idea
/ide_plugins/vs/vs2012/CoatiPlugin/CoatiPlugin/bin
/ide_plugins/vs/vs2012/CoatiPlugin/CoatiPlugin/obj
/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/bin
/ide_plugins/vs/vs2015/CoatiPlugin/CoatiPlugin/obj
*.coatidb
*.suo
+1 -1
View File
@@ -83,7 +83,7 @@ Edge.cpp ERROR: Nodes are not plain copies.
INFO: handle TestMessage
INFO: handle TestMessage
INFO: handle TestMessage
NetworkProtocolHelper.cpp ERROR: Failed to parse message, invalid type token
NetworkProtocolHelper.cpp ERROR: Failed to parse message, invalid type token: foo. Expected setActiveToken
NetworkProtocolHelper.cpp ERROR: Failed to parse setActiveToken message, invalid token count
Settings.cpp WARNING: File for Settings not found: data/SettingsTestSuite/wrong_settings.xml
Settings.cpp WARNING: File for Settings not found: data/SettingsTestSuite/wrong_settings.xml
+10
View File
@@ -84,3 +84,13 @@
-Click Create
-Close Progress Bar before CDB is finished
-Check no new CDB was created
-Switch to Coati
-Keep Visual Studio running
-Open the 'New Project From Visual Studio Solution'
-Click 'Create CDB' button
-Check 'Create Compilation Database' dialog opens
-Create a new CDB with Settings of your choice
-Wait for CDB to be finished
-Click 'Yes' in the 'CDB finished' dialog
-Switch back to Coati
-Check prefilled data is correct
Binary file not shown.
@@ -138,7 +138,7 @@
<Compile Include="Logging\VSOutputLogger.cs" />
<Compile Include="Utility\FileUtility.cs" />
<Compile Include="Guids.cs" />
<Compile Include="NetworkProtocolUtility.cs" />
<Compile Include="Utility\NetworkProtocolUtility.cs" />
<Compile Include="Utility\NetworkUtility.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.IO;
using EnvDTE;
using System.Windows.Forms;
namespace CoatiSoftware.CoatiPlugin
{
@@ -109,6 +110,8 @@ namespace CoatiSoftware.CoatiPlugin
private SolutionEvents _solutionEvents = null;
private bool _validSolutionLoaded = false;
public uint ServerPort
{
get
@@ -147,6 +150,8 @@ namespace CoatiSoftware.CoatiPlugin
System.Threading.Thread _serverThread = null;
public CoatiPluginPackage()
{}
@@ -159,16 +164,18 @@ namespace CoatiSoftware.CoatiPlugin
Utility.FileUtility._errorCallback = new Utility.FileUtility.ErrorCallback(OnFileUtilityError);
// register callbacks for changes of plugin settings
OptionPageGrid._serverPortChangeCallback = new OptionPageGrid.Callback(OnServerPortChanged);
OptionPageGrid._clientPortChangeCallback = new OptionPageGrid.Callback(OnClientPortChanged);
OptionPageGrid._loggingToggled = new OptionPageGrid.Callback(OnLoggingToggled);
OptionPageGrid._obfuscationToggled = new OptionPageGrid.Callback(OnObfuscationToggled);
// register the plugin UI elements
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
CommandID setActiveTokenCommandID = new CommandID(GuidList.guidCoatiPluginCmdSet, (int)PkgCmdIDList.cmdidCoatiSetActiveToken);
CommandID createProjectID = new CommandID(GuidList.guidCoatiPluginCmdSet, (int)PkgCmdIDList.cmdidCoatiCreateProject); // cmdidCoatiCreateProject
CommandID createProjectID = new CommandID(GuidList.guidCoatiPluginCmdSet, (int)PkgCmdIDList.cmdidCoatiCreateProject);
CommandID createCDBID = new CommandID(GuidList.guidCoatiPluginCmdSet, (int)PkgCmdIDList.cmdidCoatiCreateCDB);
_menuItemSetActiveToken = new MenuCommand(MenuItemCallback, setActiveTokenCommandID);
@@ -184,8 +191,8 @@ namespace CoatiSoftware.CoatiPlugin
mcs.AddCommand(_menuItemCreateCDB);
}
// register callbacks to enable/disable interaction for eligible solutions
DTE dte = (DTE)GetService(typeof(DTE));
_solutionEvents = dte.Events.SolutionEvents;
_solutionEvents.Opened += OnSolutionOpened;
@@ -200,6 +207,7 @@ namespace CoatiSoftware.CoatiPlugin
try
{
// the coati ui should only be enabled when the solution contains C/C++ projects
DTE dte = (DTE)GetService(typeof(DTE));
List<String> languages = Utility.SolutionUtility.GetSolutionLanguages(dte);
@@ -220,9 +228,13 @@ namespace CoatiSoftware.CoatiPlugin
_menuItemSetActiveToken.Enabled = true;
_menuItemCreateProject.Enabled = true;
_menuItemCreateCDB.Enabled = true;
_validSolutionLoaded = true;
}
else
{
_validSolutionLoaded = false;
Logging.Logging.LogInfo("No C/C++ project was detected");
}
}
@@ -240,6 +252,8 @@ namespace CoatiSoftware.CoatiPlugin
_menuItemSetActiveToken.Enabled = false;
_menuItemCreateProject.Enabled = false;
_menuItemCreateCDB.Enabled = false;
_validSolutionLoaded = false;
}
private void InitNetwork()
@@ -293,11 +307,37 @@ namespace CoatiSoftware.CoatiPlugin
{
if(creationResult._cdb != null && creationResult._cdbDirectory.Length > 0 && creationResult._cdbName.Length > 0)
{
WriteCDBToFile(creationResult._cdb, creationResult._cdbDirectory, creationResult._cdbName);
if(WriteCDBToFile(creationResult._cdb, creationResult._cdbDirectory, creationResult._cdbName))
{
string title = "CDB finished";
string text = "The CDB '" + creationResult._cdbName + "' was created at directory \"" + creationResult._cdbDirectory + "\"\n";
text += "Do you want to auto-import it in Coati now?";
//string message = NetworkProtocolUtility.createCreateProjectMessage(creationResult._cdbDirectory + "\\" + creationResult._cdbName, creationResult._headerDirectories);
DialogResult result = MessageBox.Show(text, title, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
//Utility.AsynchronousClient.Send(message);
if (result == DialogResult.Yes)
{
string message = Utility.NetworkProtocolUtility.CreateCreateProjectMessage(creationResult._cdbDirectory + "\\" + creationResult._cdbName + ".json", creationResult._headerDirectories);
Utility.AsynchronousClient.Send(message);
}
}
else
{
string title = "Error";
string text = "Failed to write CDB '" + creationResult._cdbName + "' to directory \"" + creationResult._cdbDirectory + "\"\n";
if (LoggingEnabled)
{
text += "See log for details.";
}
else
{
text += "Consider enabling logging to provide additional information (Tools->Options->Coati).";
}
DialogResult result = MessageBox.Show(text, title, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
@@ -305,7 +345,7 @@ namespace CoatiSoftware.CoatiPlugin
}
}
private void WriteCDBToFile(SolutionParser.CompilationDatabase cdb, string directory, string fileName)
private bool WriteCDBToFile(SolutionParser.CompilationDatabase cdb, string directory, string fileName)
{
try
{
@@ -314,35 +354,17 @@ namespace CoatiSoftware.CoatiPlugin
}
catch(Exception e)
{
string foo = "Error";
string bar = "Failed to write CDB '" + fileName + "' to directory \"" + directory + "\"\n";
bar += "See log for details.";
Wizard.WindowMessage wm = new Wizard.WindowMessage();
wm.Title = foo;
wm.Message = bar;
wm.RefreshWindow();
wm.ShowDialog();
bar = "Failed to write CDB '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName) + "' to directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(directory) + "\"\n";
Logging.Logging.LogError(bar);
string text = "Failed to write CDB '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName) + "' to directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(directory) + "\"\n";
Logging.Logging.LogError(text);
Logging.Logging.LogError("Exception: " + e.Message);
return;
return false;
}
string title = "CDB finished";
string message = "The CDB '" + fileName + "' was created at directory \"" + directory + "\"\n";
message += "You can now use it in Coati.";
Wizard.WindowMessage windowMessage = new Wizard.WindowMessage();
windowMessage.Title = title;
windowMessage.Message = message;
windowMessage.RefreshWindow();
windowMessage.ShowDialog();
message = "The CDB '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName) + "' was created at directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(directory) + "\"\n";
string message = "The CDB '" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(fileName) + "' was created at directory \"" + Logging.Obfuscation.NameObfuscator.GetObfuscatedName(directory) + "\"\n";
Logging.Logging.LogInfo(message);
return true;
}
private void MenuItemCallback(object sender, EventArgs e)
@@ -361,7 +383,7 @@ namespace CoatiSoftware.CoatiPlugin
int lineNumber = Utility.FileUtility.GetActiveLineNumber(dte);
int columnNumber = Utility.FileUtility.GetActiveColumnNumber(dte);
string message = NetworkProtocolUtility.createActivateTokenMessage(filePath + fileName, lineNumber, columnNumber);
string message = Utility.NetworkProtocolUtility.CreateActivateTokenMessage(filePath + fileName, lineNumber, columnNumber);
Utility.AsynchronousClient.Send(message);
}
@@ -371,8 +393,7 @@ namespace CoatiSoftware.CoatiPlugin
}
else if(menuCommand.CommandID.ID == (int)PkgCmdIDList.cmdidCoatiCreateProject)
{
// CreateCoatiProjectOld();
// show hint to use CDB methad (only for CDB beta) and create project on ok
Wizard.WindowMessage windowMessage = new Wizard.WindowMessage();
windowMessage.Title = "Hint";
windowMessage.Message = "Consider using 'Create CDB' if errors arise during Coati's indexing. This will become standard in the future.";
@@ -383,6 +404,7 @@ namespace CoatiSoftware.CoatiPlugin
}
}
// will be removed once the CDB project creation is fully integrated
private void CreateCoatiProjectOld()
{
DTE dte = (DTE)GetService(typeof(DTE));
@@ -401,7 +423,7 @@ namespace CoatiSoftware.CoatiPlugin
if (solutionName.Length > 0)
{
string message = NetworkProtocolUtility.createCreateProjectMessage(solutionName);
string message = Utility.NetworkProtocolUtility.CreateCreateProjectMessage(solutionName);
Utility.AsynchronousClient.Send(message);
}
@@ -413,16 +435,30 @@ namespace CoatiSoftware.CoatiPlugin
private void OnNetworkReadCallback(string message)
{
NetworkProtocolUtility.CursorPosition cursorPosition = NetworkProtocolUtility.parseSetCursorMessage(message);
if (cursorPosition.Valid)
{
cursorPosition.ColumnNumber += 1; // VS counts columns starting at 1, coati starts at 0
DTE dte = (DTE)GetService(typeof(DTE));
if (Utility.FileUtility.OpenSourceFile(dte, cursorPosition.FilePath))
{
Utility.FileUtility.GoToLine(dte, cursorPosition.LineNumber, cursorPosition.ColumnNumber);
Utility.NetworkProtocolUtility.MESSAGE_TYPE messageType = Utility.NetworkProtocolUtility.GetMessageType(message);
Utility.SystemUtility.GetWindowFocus();
if(messageType == Utility.NetworkProtocolUtility.MESSAGE_TYPE.MOVE_CURSOR)
{
Utility.NetworkProtocolUtility.CursorPosition cursorPosition = Utility.NetworkProtocolUtility.ParseSetCursorMessage(message);
if (cursorPosition.Valid)
{
cursorPosition.ColumnNumber += 1; // VS counts columns starting at 1, coati starts at 0
DTE dte = (DTE)GetService(typeof(DTE));
if (Utility.FileUtility.OpenSourceFile(dte, cursorPosition.FilePath))
{
Utility.FileUtility.GoToLine(dte, cursorPosition.LineNumber, cursorPosition.ColumnNumber);
Utility.SystemUtility.GetWindowFocus();
}
}
}
else if(messageType == Utility.NetworkProtocolUtility.MESSAGE_TYPE.CREATE_CDB)
{
if(_validSolutionLoaded)
{
DTE dte = (DTE)GetService(typeof(DTE));
CreateCompilationDatabase(dte);
}
}
}
@@ -521,7 +557,7 @@ namespace CoatiSoftware.CoatiPlugin
string solutionName = System.IO.Path.GetFileNameWithoutExtension(dte.Solution.FullName);
window.m_solutionFileName = solutionName;
bool containsCFiles = true; // Utility.SolutionUtility.ContainsCFiles(dte); // takes ridiculously long
bool containsCFiles = true; // Utility.SolutionUtility.ContainsCFiles(dte); // takes ridiculously long, I'd rather just display the option by default
window.m_containsCFiles = containsCFiles;
window.UpdateGUI();
@@ -1,172 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CoatiSoftware.CoatiPlugin
{
class NetworkProtocolUtility
{
private static string s_divider = ">>";
private static string s_setActiveTokenPrefix = "setActiveToken";
private static string s_moveCursorPrefix = "moveCursor";
private static string s_endOfMessageToken = "<EOM>";
private static string s_createProjectPrefix = "createProject";
private static string s_createCDBProjectPrefix = "createCDBProject";
private static string s_ideId = "vs";
public class CursorPosition
{
private string _filePath = "";
private int _lineNumber = 0;
private int _columnNumber = 0;
private bool _valid = false;
public string FilePath
{
get { return _filePath; }
set { _filePath = value; }
}
public int LineNumber
{
get { return _lineNumber; }
set { _lineNumber = value; }
}
public int ColumnNumber
{
get { return _columnNumber; }
set { _columnNumber = value; }
}
public bool Valid
{
get { return _valid; }
set { _valid = value; }
}
}
public static string createActivateTokenMessage(string filePath, int lineNumber, int columnNumber)
{
string message = s_setActiveTokenPrefix;
message += s_divider;
message += filePath;
message += s_divider;
message += lineNumber.ToString();
message += s_divider;
message += columnNumber.ToString();
message += s_endOfMessageToken;
return message;
}
public static string createCreateProjectMessage(string solutionPath)
{
string message = s_createProjectPrefix;
message += s_divider;
message += solutionPath;
message += s_divider;
message += s_ideId;
message += s_endOfMessageToken;
return message;
}
public static string createCreateProjectMessage(string cdbPath, List<string> headerPaths)
{
string message = s_createCDBProjectPrefix;
message += s_divider;
message += cdbPath;
message += s_divider;
foreach(string path in headerPaths)
{
message += path;
message += s_divider;
}
message += s_endOfMessageToken;
return message;
}
public static CursorPosition parseSetCursorMessage(string message)
{
CursorPosition result = new CursorPosition();
// remove eof token right away
if(message.IndexOf(s_endOfMessageToken) > -1)
{
message = message.Substring(0, message.IndexOf(s_endOfMessageToken));
}
int pos = message.IndexOf(s_moveCursorPrefix);
if (pos < 0)
{
return result;
}
message = message.Substring(pos + s_moveCursorPrefix.Length + s_divider.Length);
pos = message.IndexOf(s_divider);
if (pos < 0)
{
return result;
}
string filePath = message.Substring(0, pos);
result.FilePath = filePath;
message = message.Substring(pos+2);
pos = message.IndexOf(s_divider);
if (pos < 0)
{
return result;
}
string sLineNumber = message.Substring(0, pos);
int lineNumber = 0;
bool valid = int.TryParse(sLineNumber, out lineNumber);
if (valid)
{
result.LineNumber = lineNumber;
}
message = message.Substring(pos+2);
string sColumnNumber = message;
int columnNumber = 0;
valid = int.TryParse(sColumnNumber, out columnNumber);
if (valid)
{
result.ColumnNumber = columnNumber;
result.Valid = true;
}
return result;
}
}
}
@@ -0,0 +1,237 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CoatiSoftware.CoatiPlugin.Utility
{
class NetworkProtocolUtility
{
private static string s_divider = ">>";
private static string s_setActiveTokenPrefix = "setActiveToken";
private static string s_moveCursorPrefix = "moveCursor";
private static string s_endOfMessageToken = "<EOM>";
private static string s_createProjectPrefix = "createProject";
private static string s_createCDBProjectPrefix = "createCDBProject";
private static string s_ideId = "vs";
private static string s_createCDB = "createCDB";
public enum MESSAGE_TYPE
{
UNKNOWN = 0,
MOVE_CURSOR,
CREATE_CDB
}
public class CursorPosition
{
private string _filePath = "";
private int _lineNumber = 0;
private int _columnNumber = 0;
private bool _valid = false;
public string FilePath
{
get { return _filePath; }
set { _filePath = value; }
}
public int LineNumber
{
get { return _lineNumber; }
set { _lineNumber = value; }
}
public int ColumnNumber
{
get { return _columnNumber; }
set { _columnNumber = value; }
}
public bool Valid
{
get { return _valid; }
set { _valid = value; }
}
}
public static string CreateActivateTokenMessage(string filePath, int lineNumber, int columnNumber)
{
string message = s_setActiveTokenPrefix;
message += s_divider;
message += filePath;
message += s_divider;
message += lineNumber.ToString();
message += s_divider;
message += columnNumber.ToString();
message += s_endOfMessageToken;
return message;
}
public static string CreateCreateProjectMessage(string solutionPath)
{
string message = s_createProjectPrefix;
message += s_divider;
message += solutionPath;
message += s_divider;
message += s_ideId;
message += s_endOfMessageToken;
return message;
}
public static string CreateCreateProjectMessage(string cdbPath, List<string> headerPaths)
{
string message = s_createCDBProjectPrefix;
message += s_divider;
message += cdbPath;
message += s_divider;
foreach(string path in headerPaths)
{
message += path;
message += s_divider;
}
message += s_ideId;
message += s_endOfMessageToken;
return message;
}
public static MESSAGE_TYPE GetMessageType(string message)
{
List<string> tokens = GetMessageTokens(message);
if (tokens.Count > 0)
{
if(tokens[0] == s_createCDB)
{
return MESSAGE_TYPE.CREATE_CDB;
}
else if(tokens[0] == s_moveCursorPrefix)
{
return MESSAGE_TYPE.MOVE_CURSOR;
}
else
{
return MESSAGE_TYPE.UNKNOWN;
}
}
return MESSAGE_TYPE.UNKNOWN;
}
public static CursorPosition ParseSetCursorMessage(string message)
{
CursorPosition result = new CursorPosition();
List<string> tokens = GetMessageTokens(message);
if(tokens.Count != 4)
{
Logging.Logging.LogError("Invalid message: " + message);
Logging.Logging.LogError("Invalid token count for 'move cursor' message. Expected 4, but got " + tokens.Count.ToString());
return result;
}
if(tokens[0] != s_moveCursorPrefix)
{
Logging.Logging.LogError("Invalid message: " + message);
Logging.Logging.LogError("Invalid message type. Expected '" + s_moveCursorPrefix + "' but got '" + tokens[0] + "'");
return result;
}
result.FilePath = tokens[1];
int lineNumber = 0;
if(int.TryParse(tokens[2], out lineNumber))
{
result.LineNumber = lineNumber;
}
else
{
Logging.Logging.LogError("Invalid message: " + message);
Logging.Logging.LogError("Failed to parse line number");
return result;
}
int columnNumber = 0;
if(int.TryParse(tokens[3], out columnNumber))
{
result.ColumnNumber = columnNumber;
}
else
{
Logging.Logging.LogError("Invalid message: " + message);
Logging.Logging.LogError("Failed to parse column number");
return result;
}
result.Valid = true;
return result;
}
private static List<string> GetMessageTokens(string message)
{
List<string> tokens = new List<string>();
if(RemoveEOMString(ref message))
{
tokens = message.Split(s_divider.ToCharArray()).ToList();
// removing empty strings
List<string> cleanTokens = new List<string>();
foreach(string token in tokens)
{
if(token.Length > 0)
{
cleanTokens.Add(token);
}
}
tokens = cleanTokens;
}
else
{
Logging.Logging.LogError("");
}
return tokens;
}
// returns false if no EOM string was found
private static bool RemoveEOMString(ref string message)
{
if (message.IndexOf(s_endOfMessageToken) > -1)
{
message = message.Substring(0, message.IndexOf(s_endOfMessageToken));
return true;
}
return false;
}
}
}
@@ -173,23 +173,35 @@ namespace CoatiSoftware.CoatiPlugin.Utility
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult ar = client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
if (!connectDone.WaitOne(2000))
try
{
client.EndConnect(ar);
client.Shutdown(SocketShutdown.Both);
client.Close();
IAsyncResult ar = client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
if (!connectDone.WaitOne(2000))
{
client.EndConnect(ar);
client.Shutdown(SocketShutdown.Both);
client.Close();
Logging.Logging.LogWarning("Connection timed out, message was not sent");
Logging.Logging.LogWarning("Connection timed out, message was not sent");
return;
return;
}
Send(client, message);
sendDone.WaitOne();
}
catch(Exception e)
{
Logging.Logging.LogError("Exception: " + e.Message);
}
finally
{
if(client.Connected)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
Send(client, message);
sendDone.WaitOne();
client.Shutdown(SocketShutdown.Both);
client.Close();
}
private static void ConnectCallback(IAsyncResult ar)
@@ -31,7 +31,7 @@ namespace CoatiSoftware.CoatiPlugin.Utility
public string Name = "";
public Project Project = null;
public Object Foo = null;
public Object UserData = null;
public virtual NodeType GetNodeType() { throw (new NotImplementedException()); }
}
@@ -108,14 +108,14 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
if(node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.PROJECT)
{
TreeNode treeNode = new TreeNode(node.Name);
node.Foo = treeNode;
node.UserData = treeNode;
treeViewProjects.Nodes.Add(treeNode);
}
else if(node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.FOLDER)
{
TreeNode[] subNodes = GetSubNodes(node as Utility.SolutionUtility.SolutionStructure.FolderNode);
TreeNode treeNode = new TreeNode(node.Name, subNodes);
node.Foo = treeNode;
node.UserData = treeNode;
treeViewProjects.Nodes.Add(treeNode);
}
}
@@ -130,14 +130,14 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
if(node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.PROJECT)
{
TreeNode treeNode = new TreeNode(node.Name);
node.Foo = treeNode;
node.UserData = treeNode;
result.Add(treeNode);
}
else if(node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.FOLDER)
{
TreeNode[] subNodes = GetSubNodes(node as Utility.SolutionUtility.SolutionStructure.FolderNode);
TreeNode treeNode = new TreeNode(node.Name, subNodes);
node.Foo = treeNode;
node.UserData = treeNode;
result.Add(treeNode);
}
}
@@ -297,12 +297,12 @@ namespace CoatiSoftware.CoatiPlugin.Wizard
{
Utility.SolutionUtility.SolutionStructure.Node node = nodeStack.Pop();
bool include = (node.Foo as TreeNode).Checked;
bool include = (node.UserData as TreeNode).Checked;
string name = node.Name;
if(node.GetNodeType() == Utility.SolutionUtility.SolutionStructure.Node.NodeType.PROJECT
&& (node.Foo as TreeNode).Checked == true)
&& (node.UserData as TreeNode).Checked == true)
{
solutionProjects.Add(node.Project);
}
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="acf15780-03b5-440e-a41e-db79b7043fc2" Version="0.8.18" Language="en-US" Publisher="Coati Software OG" />
<Identity Id="acf15780-03b5-440e-a41e-db79b7043fc2" Version="0.8.25" Language="en-US" Publisher="Coati Software OG" />
<DisplayName>CoatiPlugin</DisplayName>
<Description xml:space="preserve">This package allows Coati to communicate with Visual Studio and vice versa.</Description>
<MoreInfo>https://www.coati.io/</MoreInfo>
+2 -1
View File
@@ -281,6 +281,7 @@ add_files(
utility/messaging/type/MessageGraphNodeBundleSplit.h
utility/messaging/type/MessageGraphNodeExpand.h
utility/messaging/type/MessageGraphNodeMove.h
utility/messaging/type/MessageIDECreateCDB.h
utility/messaging/type/MessageInterruptTasks.h
utility/messaging/type/MessageLoadProject.h
utility/messaging/type/MessageMoveIDECursor.h
@@ -307,7 +308,7 @@ add_files(
utility/messaging/type/MessageWindowClosed.h
utility/messaging/type/MessageWindowFocus.h
utility/messaging/type/MessageZoom.h
utility/messaging/Message.h
utility/messaging/MessageBase.h
utility/messaging/MessageInterruptTasksCounter.cpp
@@ -44,6 +44,10 @@ void IDECommunicationController::handleIncomingMessage(const std::string& messag
{
handleSetActiveTokenMessage(NetworkProtocolHelper::parseSetActiveTokenMessage(message));
}
else if (type == NetworkProtocolHelper::MESSAGE_TYPE::CREATE_CDB_MESSAGE)
{
handleCreateCDBProjectMessage(NetworkProtocolHelper::parseCreateCDBProjectMessage(message));
}
else
{
handleCreateProjectMessage(NetworkProtocolHelper::parseCreateProjectMessage(message));
@@ -139,9 +143,37 @@ void IDECommunicationController::handleCreateProjectMessage(const NetworkProtoco
}
}
void IDECommunicationController::handleCreateCDBProjectMessage(const NetworkProtocolHelper::CreateCDBProjectMessage& message)
{
if (message.valid)
{
std::shared_ptr<MessageProjectNew> msg = std::make_shared<MessageProjectNew>();
msg->setSolutionPath(message.cdbFileLocation);
msg->setHeaderPaths(message.headerPaths);
msg->ideId = message.ideId;
bool foo = msg->fromCDB();
MessageDispatchWhenLicenseValid(msg).dispatch();
}
else
{
LOG_ERROR_STREAM(<< "Unable to parse provided CDB, invalid data received");
}
}
void IDECommunicationController::handleMessage(MessageIDECreateCDB* message)
{
std::string networkMessage = NetworkProtocolHelper::buildCreateCDBMessage();
MessageStatus("Requesting IDE to create CDB.").dispatch();
sendMessage(networkMessage);
}
void IDECommunicationController::handleMessage(MessageMoveIDECursor* message)
{
std::string networkMessage = NetworkProtocolHelper::buildMessage(
std::string networkMessage = NetworkProtocolHelper::buildSetIDECursorMessage(
message->FilePosition, message->Row, message->Column
);
@@ -7,6 +7,7 @@
#include "component/controller/helper/NetworkProtocolHelper.h"
#include "utility/messaging/MessageListener.h"
#include "utility/messaging/type/MessageIDECreateCDB.h"
#include "utility/messaging/type/MessageMoveIDECursor.h"
#include "utility/messaging/type/MessagePluginPortChange.h"
@@ -14,6 +15,7 @@ class StorageAccess;
class IDECommunicationController
: public Controller
, public MessageListener<MessageIDECreateCDB>
, public MessageListener<MessageMoveIDECursor>
, public MessageListener<MessagePluginPortChange>
{
@@ -35,7 +37,9 @@ public:
private:
void handleSetActiveTokenMessage(const NetworkProtocolHelper::SetActiveTokenMessage& message);
void handleCreateProjectMessage(const NetworkProtocolHelper::CreateProjectMessage& message);
void handleCreateCDBProjectMessage(const NetworkProtocolHelper::CreateCDBProjectMessage& message);
virtual void handleMessage(MessageIDECreateCDB* message);
virtual void handleMessage(MessageMoveIDECursor* message);
virtual void handleMessage(MessagePluginPortChange* message);
virtual void sendMessage(const std::string& message) const = 0;
@@ -14,6 +14,8 @@ std::string NetworkProtocolHelper::m_setActiveTokenPrefix = "setActiveToken";
std::string NetworkProtocolHelper::m_moveCursorPrefix = "moveCursor";
std::string NetworkProtocolHelper::m_endOfMessageToken = "<EOM>";
std::string NetworkProtocolHelper::m_createProjectPrefix = "createProject";
std::string NetworkProtocolHelper::m_createCDBProjectPrefix = "createCDBProject";
std::string NetworkProtocolHelper::m_createCDBPrefix = "createCDB";
NetworkProtocolHelper::MESSAGE_TYPE NetworkProtocolHelper::getMessageType(const std::string& message)
{
@@ -29,6 +31,10 @@ NetworkProtocolHelper::MESSAGE_TYPE NetworkProtocolHelper::getMessageType(const
{
return MESSAGE_TYPE::CREATE_PROJECT;
}
else if (subMessages[0] == m_createCDBProjectPrefix)
{
return MESSAGE_TYPE::CREATE_CDB_MESSAGE;
}
else
{
return MESSAGE_TYPE::UNKNOWN;
@@ -74,7 +80,7 @@ NetworkProtocolHelper::SetActiveTokenMessage NetworkProtocolHelper::parseSetActi
}
else
{
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token");
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token: " << subMessages[0] << ". Expected " << m_setActiveTokenPrefix);
}
}
@@ -111,18 +117,88 @@ NetworkProtocolHelper::CreateProjectMessage NetworkProtocolHelper::parseCreatePr
networkMessage.valid = true;
}
else
{
LOG_WARNING_STREAM(<< "Failed to parse ide ID string. Is " << ideId);
}
}
}
else
{
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token");
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token: " << subMessages[0] << ". Expected " << m_createProjectPrefix);
}
}
return networkMessage;
}
std::string NetworkProtocolHelper::buildMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column)
NetworkProtocolHelper::CreateCDBProjectMessage NetworkProtocolHelper::parseCreateCDBProjectMessage(const std::string& message)
{
std::vector<std::string> subMessages = divideMessage(message);
NetworkProtocolHelper::CreateCDBProjectMessage networkMessage;
if (subMessages.size() > 0)
{
if (subMessages[0] == m_createCDBProjectPrefix)
{
if (subMessages.size() < 4)
{
LOG_ERROR_STREAM(<< "Failed to parse createCDBProject message, too few tokens");
}
else
{
int subMessageCount = subMessages.size();
std::string cdbPath = subMessages[1];
if (cdbPath.length() > 0)
{
networkMessage.cdbFileLocation = cdbPath;
}
else
{
LOG_WARNING_STREAM(<< "CDB file path is not set.");
}
std::vector<std::string> headerPaths;
for (int i = 2; i < subMessageCount - 2; i++)
{
if (subMessages[i].length() > 0)
{
headerPaths.push_back(subMessages[i]);
}
}
networkMessage.headerPaths = headerPaths;
std::string ideId = subMessages[subMessageCount - 2];
if (ideId.length() > 0)
{
std::string nonConstId = ideId;
boost::algorithm::to_lower(nonConstId);
networkMessage.ideId = nonConstId;
}
else
{
LOG_WARNING_STREAM(<< "Failed to parse ide ID string. Is " << ideId);
}
if (networkMessage.cdbFileLocation.length() > 0 && networkMessage.ideId.length() > 0)
{
networkMessage.valid = true;
}
}
}
else
{
LOG_ERROR_STREAM(<< "Failed to parse message, invalid type token: " << subMessages[0] << ". Expected " << m_createCDBProjectPrefix);
}
}
return networkMessage;
}
std::string NetworkProtocolHelper::buildSetIDECursorMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column)
{
std::stringstream messageStream;
@@ -138,6 +214,16 @@ std::string NetworkProtocolHelper::buildMessage(const std::string& fileLocation,
return messageStream.str();
}
std::string NetworkProtocolHelper::buildCreateCDBMessage()
{
std::stringstream messageStream;
messageStream << m_createCDBPrefix;
messageStream << m_endOfMessageToken;
return messageStream.str();
}
std::vector<std::string> NetworkProtocolHelper::divideMessage(const std::string& message)
{
std::vector<std::string> result;
@@ -37,19 +37,38 @@ public:
bool valid;
};
struct CreateCDBProjectMessage
{
public:
CreateCDBProjectMessage()
: cdbFileLocation("")
, headerPaths()
, ideId("")
, valid(false)
{}
std::string cdbFileLocation;
std::vector<std::string> headerPaths;
std::string ideId;
bool valid;
};
enum MESSAGE_TYPE
{
UNKNOWN = 0,
SET_ACTIVE_TOKEN,
CREATE_PROJECT
CREATE_PROJECT,
CREATE_CDB_MESSAGE
};
static MESSAGE_TYPE getMessageType(const std::string& message);
static SetActiveTokenMessage parseSetActiveTokenMessage(const std::string& message);
static CreateProjectMessage parseCreateProjectMessage(const std::string& message);
static CreateCDBProjectMessage parseCreateCDBProjectMessage(const std::string& message);
static std::string buildMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column);
static std::string buildSetIDECursorMessage(const std::string& fileLocation, const unsigned int row, const unsigned int column);
static std::string buildCreateCDBMessage();
private:
static std::vector<std::string> divideMessage(const std::string& message);
@@ -64,6 +83,8 @@ private:
static std::string m_moveCursorPrefix;
static std::string m_endOfMessageToken;
static std::string m_createProjectPrefix;
static std::string m_createCDBProjectPrefix;
static std::string m_createCDBPrefix;
};
#endif // NETWORK_PROTOCOL_HELPER_H
@@ -0,0 +1,24 @@
#ifndef MESSAGE_IDE_CREATE_CDB_H
#define MESSAGE_IDE_CREATE_CDB_H
#include "utility/messaging/Message.h"
class MessageIDECreateCDB : public Message<MessageIDECreateCDB>
{
public:
MessageIDECreateCDB()
{
}
static const std::string getStaticType()
{
return "MessageIDECreateCDB";
}
virtual void print(std::ostream& os) const
{
os << "Create CDB from current solution";
}
};
#endif // MESSAGE_IDE_CREATE_CDB_H
@@ -9,6 +9,7 @@ class MessageProjectNew
public:
MessageProjectNew()
: solutionPath("")
, headerPaths()
, ideId("")
{
}
@@ -23,12 +24,38 @@ public:
return solutionPath.size() > 0;
}
bool fromCDB() const
{
if (solutionPath.length() > 0)
{
size_t pos = solutionPath.find_last_of('.');
if (pos != std::string::npos)
{
std::string extension = solutionPath.substr(pos + 1);
return (extension == "json");
}
else
{
return false;
}
}
return false;
}
void setSolutionPath(const std::string& path)
{
solutionPath = path;
}
void setHeaderPaths(const std::vector<std::string>& headerPaths)
{
this->headerPaths = headerPaths;
}
std::string solutionPath;
std::vector<std::string> headerPaths;
std::string ideId;
};
+23 -2
View File
@@ -1,4 +1,5 @@
#include "QtTcpWrapper.h"
#include "qdatastream.h"
#include "utility/logging/logging.h"
@@ -100,12 +101,32 @@ void QtTcpWrapper::acceptConnection()
void QtTcpWrapper::startRead()
{
char buffer[1024] = { 0 };
QByteArray byteArray;
while (m_tcpClient->atEnd() == false)
{
QByteArray data = m_tcpClient->read(128);
byteArray += data;
}
/*QDataStream stream(&byteArray, QIODevice::ReadOnly);
QString string;
stream >> string;*/
QString string = QString::fromUtf8(byteArray);
if (m_readCallback != NULL)
{
std::string message = string.toStdString();
m_readCallback(message);
}
/*char buffer[1024] = { 0 };
m_tcpClient->read(buffer, m_tcpClient->bytesAvailable());
m_tcpClient->close();
if (m_readCallback != NULL)
{
m_readCallback(buffer);
}
}*/
}
+14 -1
View File
@@ -5,6 +5,7 @@
QtMainView::QtMainView()
: m_editProjectFunctor(std::bind(&QtMainView::doEditProject, this))
, m_createNewProjectFromSolutionFunctor(std::bind(&QtMainView::doCreateNewProjectFromSolution, this, std::placeholders::_1, std::placeholders::_2))
, m_createNewProjectFromCDBFunctor(std::bind(&QtMainView::doCreateNewProjectFromCDB, this, std::placeholders::_1, std::placeholders::_2))
, m_showStartScreenFunctor(std::bind(&QtMainView::doShowStartScreen, this))
, m_hideStartScreenFunctor(std::bind(&QtMainView::doHideStartScreen, this))
, m_setTitleFunctor(std::bind(&QtMainView::doSetTitle, this, std::placeholders::_1))
@@ -117,7 +118,14 @@ void QtMainView::handleMessage(MessageProjectNew* message)
{
if (message->ideId.size() != 0 && message->solutionPath.size() != 0)
{
m_createNewProjectFromSolutionFunctor(message->ideId, message->solutionPath);
if (message->fromCDB() == false)
{
m_createNewProjectFromSolutionFunctor(message->ideId, message->solutionPath);
}
else
{
m_createNewProjectFromCDBFunctor(message->solutionPath, message->headerPaths);
}
}
}
@@ -136,6 +144,11 @@ void QtMainView::doCreateNewProjectFromSolution(const std::string& ideId, const
m_window->newProjectFromSolution(ideId, solutionPath);
}
void QtMainView::doCreateNewProjectFromCDB(const std::string& filePath, const std::vector<std::string>& headerPaths)
{
m_window->newProjectFromCDB(filePath, headerPaths);
}
void QtMainView::doShowStartScreen()
{
m_window->showStartScreen();
+2
View File
@@ -58,6 +58,7 @@ private:
void doEditProject();
void doCreateNewProjectFromSolution(const std::string& ideId, const std::string& solutionPath);
void doCreateNewProjectFromCDB(const std::string& filePath, const std::vector<std::string>& headerPaths);
void doShowStartScreen();
void doHideStartScreen();
void doSetTitle(const std::string& title);
@@ -70,6 +71,7 @@ private:
QtThreadedFunctor<> m_editProjectFunctor;
QtThreadedFunctor<const std::string&, const std::string&> m_createNewProjectFromSolutionFunctor;
QtThreadedFunctor<const std::string&, const std::vector<std::string>&> m_createNewProjectFromCDBFunctor;
QtThreadedFunctor<> m_showStartScreenFunctor;
QtThreadedFunctor<> m_hideStartScreenFunctor;
QtThreadedFunctor<const std::string&> m_setTitleFunctor;
+6
View File
@@ -436,6 +436,12 @@ void QtMainWindow::newProjectFromSolution(const std::string& ideId, const std::s
wizzard->newProjectFromSolution(ideId, solutionPath);
}
void QtMainWindow::newProjectFromCDB(const std::string& filePath, const std::vector<std::string>& headerPaths)
{
QtProjectWizzard* wizzard = createWindow<QtProjectWizzard>();
wizzard->newProjectFromCDB(filePath, headerPaths);
}
void QtMainWindow::openProject()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "Coati Project Files (*.coatiproject)");
+1
View File
@@ -110,6 +110,7 @@ public slots:
void newProject();
void newProjectFromSolution(const std::string& ideId, const std::string& solutionPath);
void newProjectFromCDB(const std::string& filePath, const std::vector<std::string>& headerPaths);
void openProject();
void editProject();
@@ -116,6 +116,26 @@ void QtProjectWizzard::newProjectFromSolution(const std::string& ideId, const st
}
}
void QtProjectWizzard::newProjectFromCDB(const std::string& filePath, const std::vector<std::string>& headerPaths)
{
FilePath fp(filePath);
std::vector<FilePath> hp;
for (int i = 0; i < headerPaths.size(); i++)
{
hp.push_back(FilePath(headerPaths[i]));
}
std::shared_ptr<CxxProjectSettings> settings = std::make_shared<CxxProjectSettings>();
settings->setLanguage(LanguageType::LANGUAGE_CPP);
settings->setProjectName(fp.withoutExtension().fileName());
settings->setProjectFileLocation(fp.parentDirectory());
settings->setCompilationDatabasePath(fp);
settings->setSourcePaths(hp);
m_settings = settings;
emptyProjectCDBVS();
}
void QtProjectWizzard::refreshProjectFromSolution(const std::string& ideId, const std::string& visualStudioSolutionPath)
{
if (m_parserManager->canParseSolution(ideId))
@@ -323,7 +343,7 @@ void QtProjectWizzard::selectedProjectType(LanguageType languageType, QtProjectW
break;
case QtProjectWizzardContentSelect::PROJECT_MANAGED:
{
/*{
std::string fileEndings = "(";
for (unsigned int i = 0; i < m_parserManager->getParserCount(); i++)
{
@@ -346,7 +366,12 @@ void QtProjectWizzard::selectedProjectType(LanguageType languageType, QtProjectW
}
}
break;
}
}*/
m_settings = std::make_shared<CxxProjectSettings>();
m_settings->setLanguage(languageType);
emptyProjectCDBVS();
break;
case QtProjectWizzardContentSelect::PROJECT_CDB:
m_settings = std::make_shared<CxxProjectSettings>();
@@ -428,6 +453,13 @@ void QtProjectWizzard::frameworkSearchPaths()
connect(window, SIGNAL(next()), this, SLOT(showSummary()));
}
void QtProjectWizzard::emptyProjectCDBVS()
{
QtProjectWizzardWindow* window = createWindowWithContent<QtProjectWizzardContentDataCDBVS>();
connect(window, SIGNAL(next()), this, SLOT(headerPathsCDB()));
}
void QtProjectWizzard::emptyProjectCDB()
{
QtProjectWizzardWindow* window = createWindowWithContent<QtProjectWizzardContentDataCDB>();
@@ -34,6 +34,7 @@ public slots:
void newProject();
void newProjectFromSolution(const std::string& ideId, const std::string& visualStudioSolutionPath);
void newProjectFromCDB(const std::string& filePath, const std::vector<std::string>& headerPaths);
void refreshProjectFromSolution(const std::string& ideId, const std::string& visualStudioSolutionPath);
void editProject(const FilePath& settingsPath);
@@ -72,6 +73,8 @@ private slots:
void headerSearchPathsDone();
void frameworkSearchPaths();
void emptyProjectCDBVS();
void emptyProjectCDB();
void headerPathsCDB();
@@ -5,6 +5,7 @@
#include "settings/CxxProjectSettings.h"
#include "utility/messaging/type/MessageIDECreateCDB.h"
#include "utility/logging/logging.h"
QtProjectWizzardContentData::QtProjectWizzardContentData(std::shared_ptr<ProjectSettings> settings, QtProjectWizzardWindow* window)
@@ -257,3 +258,81 @@ bool QtProjectWizzardContentDataCDB::check()
void QtProjectWizzardContentDataCDB::refreshClicked()
{
}
QtProjectWizzardContentDataCDBVS::QtProjectWizzardContentDataCDBVS(std::shared_ptr<ProjectSettings> settings, QtProjectWizzardWindow* window)
: QtProjectWizzardContentDataCDB(settings, window)
{
}
void QtProjectWizzardContentDataCDBVS::populate(QGridLayout* layout, int& row)
{
if (!isInForm())
{
layout->setRowMinimumHeight(row, 15);
row++;
}
QLabel* nameLabel = createFormLabel("Create Compilation Database");
layout->addWidget(nameLabel, row, QtProjectWizzardWindow::FRONT_COL);
addHelpButton("To create a new Compilation Database from a Visual Studio Solution, this Solution has to be open in Visual Studio.\n\
Coati will call Visual Studio to open the 'Create Compilation Database' dialog.\
Please follow the instructions in Visual Studio to complete the process.\n\
Note: Coati's Visual Studio plugin has to be installed. Visual Studio has to be running with an eligible Solution, containing C/C++ projects, loaded.", layout, row);
QLabel* descriptionLabel = createFormLabel("Call Visual Studio to create a Compilation Database from the loaded Solution.");
descriptionLabel->setObjectName("description");
descriptionLabel->setAlignment(Qt::AlignmentFlag::AlignLeft);
layout->addWidget(descriptionLabel, row, QtProjectWizzardWindow::BACK_COL);
row++;
QPushButton* button = new QPushButton("Create CDB");
button->setObjectName("windowButton");
layout->addWidget(button, row, QtProjectWizzardWindow::BACK_COL);
row++;
QLabel* skipLabel = createFormLabel("*Skip this step if you already have a Compilation Database for your Solution.");
skipLabel->setObjectName("description");
skipLabel->setAlignment(Qt::AlignmentFlag::AlignLeft);
layout->addWidget(skipLabel, row, QtProjectWizzardWindow::BACK_COL);
row++;
QFrame* separator = new QFrame();
separator->setFrameShape(QFrame::HLine);
QPalette palette = separator->palette();
palette.setColor(QPalette::WindowText, Qt::lightGray);
separator->setPalette(palette);
layout->addWidget(separator, row++, 0, 1, -1);
connect(button, SIGNAL(clicked()), this, SLOT(handleVSCDBClicked()));
addNameAndLocation(layout, row);
layout->setRowMinimumHeight(row++, 20);
QString name = "Compilation Database";
QString filter = "JSON Compilation Database (*.json)";
addBuildFilePicker(layout, row, name, filter);
if (!isInForm())
{
layout->setRowMinimumHeight(row, 15);
layout->setRowStretch(row, 1);
}
}
void QtProjectWizzardContentDataCDBVS::refreshClicked()
{
}
void QtProjectWizzardContentDataCDBVS::handleVSCDBClicked()
{
MessageIDECreateCDB().dispatch();
}
@@ -55,4 +55,19 @@ private slots:
void refreshClicked();
};
class QtProjectWizzardContentDataCDBVS
: public QtProjectWizzardContentDataCDB
{
Q_OBJECT
public:
QtProjectWizzardContentDataCDBVS(std::shared_ptr<ProjectSettings> settings, QtProjectWizzardWindow* window);
virtual void populate(QGridLayout* layout, int& row) override;
private slots:
void refreshClicked();
void handleVSCDBClicked();
};
#endif // QT_PROJECT_WIZZARD_CONTENT_DATA_H
@@ -44,7 +44,7 @@ void QtProjectWizzardWindow::populateWindow(QWidget* widget)
{
QGridLayout* layout = new QGridLayout();
layout->setContentsMargins(0, 0, 0, 0);
layout->setColumnStretch(QtProjectWizzardWindow::FRONT_COL, 1);
layout->setColumnStretch(QtProjectWizzardWindow::BACK_COL, 3);
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB