Skip to content

Commit

Permalink
Fixes #13. Adds support of . in LProjectConfigurationPlatforms + te…
Browse files Browse the repository at this point in the history
…sts:

```
Possible symbols for Solution/Project pair includes `.` and `=`:
#13

-_- awesome format as follow:
{A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.Debug.x64.x86|Any.CPU.etc.Build.0 = Debug.x64.x86|Any.CPU.etc
\___________________________________/  \___________/ \_________/ \_____/ ^ \___________/ \_________/

For `=` we will not support this due to errors by VS itself (VS bug from VS2010 to modern VS2019)
#13 (comment)
```
  • Loading branch information
3F committed Jun 16, 2019
1 parent 95194f6 commit c68e79c
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 62 deletions.
175 changes: 114 additions & 61 deletions MvsSln/Core/SlnHandlers/LProjectConfigurationPlatforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,41 @@ namespace net.r_eg.MvsSln.Core.SlnHandlers
{
public class LProjectConfigurationPlatforms: LAbstract, ISlnHandler
{
protected enum LineAttr
{
InvalidOrUnknown,

ActiveCfg,
Build0,
Deploy0
}

protected struct Cortege
{
public string pGuid, csln, cprj;

public override string ToString()
{
return $"`{pGuid}`, `{csln}` = `{cprj}`";
}
}

protected class EqCortegeComparer: IEqualityComparer<Cortege>
{
public bool Equals(Cortege a, Cortege b)
{
if(a.pGuid != b.pGuid
|| a.csln != b.csln
|| a.cprj != b.cprj
)
{
return false;
}
return true;
return a.pGuid == b.pGuid && a.csln == b.csln && a.cprj == b.cprj;
}

public int GetHashCode(Cortege obj)
public int GetHashCode(Cortege x)
{
return 0.CalculateHashCode
(
obj.pGuid.GetHashCode(),
obj.csln.GetHashCode(),
obj.cprj.GetHashCode()
x.pGuid.GetHashCode(), x.csln.GetHashCode(), x.cprj.GetHashCode()
);
}
}

protected struct Cortege
{
public string pGuid;
public string csln;
public string cprj;
}

/// <summary>
/// Checks the readiness to process data.
/// </summary>
Expand Down Expand Up @@ -96,68 +99,118 @@ public override bool Positioned(ISvc svc, RawText line)
svc.Sln.ProjectConfigList = new List<IConfPlatformPrj>();
}

/*
[Projects Guid] [Solution pair] [Project pair]
{A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.CI_Release|Any CPU.ActiveCfg = Release|Any CPU - configuration name
{A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.CI_Release|Any CPU.Build.0 = Release|Any CPU - flag of build (this line exists only when this flag is true)
*/
string _line;
var records = new Dictionary<Cortege, ConfigPrj>(new EqCortegeComparer());

var cortege = new Dictionary<Cortege, ConfigPrj>(new EqCortegeComparer());
string _line;
while((_line = svc.ReadLine(this)) != null && _line.Trim() != "EndGlobalSection")
{
int x, y;

x = _line.IndexOf('.');
var pGuid = _line.Substring(0, x).Trim();

y = _line.IndexOf('.', ++x);
string csln = _line.Substring(x, y - x).Trim();
var v = Parse(ref _line, out LineAttr ltype);

x = _line.IndexOf('=', ++y);
string type = _line.Substring(y, x - y).Trim();

string cprj = _line.Substring(x + 1).Trim();

bool isActiveCfg = type.Equals("ActiveCfg", StringComparison.OrdinalIgnoreCase);
bool isBuild0 = type.Equals("Build.0", StringComparison.OrdinalIgnoreCase);
bool isDeploy0 = type.Equals("Deploy.0", StringComparison.OrdinalIgnoreCase);

if(!isActiveCfg && !isBuild0 && !isDeploy0) {
LSender.Send(this, $"Project Configuration has been ignored for line '{_line}'", Message.Level.Debug);
if(ltype == LineAttr.InvalidOrUnknown)
{
LSender.Send(this, $"Incorrect Project Configuration: {v}; raw: '{_line}'", Message.Level.Warn);
continue;
}

var ident = new Cortege() {
pGuid = pGuid,
csln = csln,
cprj = cprj,
};

if(!cortege.ContainsKey(ident))
//NOTE: Build0 and Deploy0 records are valid too. Even if an ActiveCfg is corrupted and does not exist at all.
if(!records.ContainsKey(v))
{
LSender.Send(this, $"New Project Configuration `{pGuid}`, `{csln}` = `{cprj}` /{type}", Message.Level.Info);
cortege[ident] = new ConfigPrj(cprj, pGuid, isBuild0, new ConfigSln(csln));
svc.Sln.ProjectConfigList.Add(cortege[ident]);
continue;
LSender.Send(this, $"Found Project Configuration: {v}", Message.Level.Info);

records[v] = new ConfigPrj(v.cprj, v.pGuid, false, new ConfigSln(v.csln));
svc.Sln.ProjectConfigList.Add(records[v]);
}

if(isBuild0)
if(ltype == LineAttr.Build0)
{
LSender.Send(this, $"Project Configuration, update Build.0 `{pGuid}`", Message.Level.Debug);
cortege[ident].IncludeInBuild = true;
LSender.Send(this, $"Project Configuration, update Build.0 {v}", Message.Level.Debug);
records[v].IncludeInBuild = true;
continue;
}

if(isDeploy0)
if(ltype == LineAttr.Deploy0)
{
LSender.Send(this, $"Project Configuration, update Deploy.0 `{pGuid}`", Message.Level.Debug);
cortege[ident].IncludeInDeploy = true;
LSender.Send(this, $"Project Configuration, update Deploy.0 {v}", Message.Level.Debug);
records[v].IncludeInDeploy = true;
continue;
}
}

return true;
}

/// <summary>
///
/// [Projects Guid] [Solution pair] [ltype] [Project pair]
/// {A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.CI_Release|Any CPU.ActiveCfg = Release|Any CPU - available configuration
/// {A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.CI_Release|Any CPU.Build.0 = Release|Any CPU - active Build (this line exists only when this flag is true)
/// {A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.CI_Release|Any CPU.Deploy.0 = Release|Any CPU - active Deployment (this line exists only when this flag is true)
///
/// Possible symbols for Solution/Project pair includes `.` and `=`:
/// https://github.com/3F/MvsSln/issues/13
///
/// -_- awesome format as follow:
/// {A7BF1F9C-F18D-423E-9354-859DC3CFAFD4}.Debug.x64.x86|Any.CPU.etc.Build.0 = Debug.x64.x86|Any.CPU.etc
/// \___________________________________/ \___________/ \_________/ \_____/ ^ \___________/ \_________/
///
/// For `=` we will not support this due to errors by VS itself (VS bug from VS2010 to modern VS2019)
/// https://github.com/3F/MvsSln/issues/13#issuecomment-501346079
/// </summary>
/// <param name="raw"></param>
/// <param name="ltype"></param>
/// <returns></returns>
protected Cortege Parse(ref string raw, out LineAttr ltype)
{
int splitter = raw.IndexOf('=');

if(splitter == -1)
{
ltype = LineAttr.InvalidOrUnknown;
return default(Cortege);
}

string cprj = raw.Substring(splitter + 1);

splitter = raw.FirstNonWhiteSpace(splitter - 1, true) + 1;
int rpos = raw.LastIndexOf('.', splitter); // .ActiveCfg =
// .Build.0 =
// ------^

if(splitter - rpos == 2) { // .0
rpos = raw.LastIndexOf('.', rpos - 1);
}

int lpos = raw.IndexOf('.');
string pGuid = raw.Substring(0, lpos);

string csln = raw.Substring(++lpos, rpos - lpos);
string type = raw.Substring(++rpos, splitter - rpos);

ltype = GetAttribute(type.Trim());

return new Cortege()
{
pGuid = pGuid.Trim(),
csln = csln.Trim(),
cprj = cprj.Trim(),
};
}

protected LineAttr GetAttribute(string raw)
{
if(raw.Equals("ActiveCfg", StringComparison.InvariantCulture)) {
return LineAttr.ActiveCfg;
}

if(raw.Equals("Build.0", StringComparison.InvariantCulture)) {
return LineAttr.Build0;
}

if(raw.Equals("Deploy.0", StringComparison.InvariantCulture)) {
return LineAttr.Deploy0;
}

return LineAttr.InvalidOrUnknown;
}
}
}
2 changes: 1 addition & 1 deletion MvsSln/Core/SlnHandlers/LSolutionConfigurationPlatforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public override bool Positioned(ISvc svc, RawText line)
if(left == null
|| String.Compare(left, "DESCRIPTION", StringComparison.OrdinalIgnoreCase) == 0)
{
LSender.Send(this, $"Solution Configuration has been ignored for line '{_line}'", Message.Level.Debug);
LSender.Send(this, $"Solution Configuration has been ignored for line '{_line}'", Message.Level.Warn);
continue;
}

Expand Down
29 changes: 29 additions & 0 deletions MvsSln/Extensions/StringExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,35 @@ public static string Before(this string str, params char[] c)
return str.Substring(0, pos);
}

/// <summary>
/// Get position of first non-WhiteSpace character from string.
/// </summary>
/// <param name="str"></param>
/// <param name="offset">Initial position.</param>
/// <param name="rightToLeft">Moving from right to left if true. Otherwise from left to right if false.</param>
/// <returns></returns>
public static int FirstNonWhiteSpace(this string str, int offset = 0, bool rightToLeft = false)
{
if(str == null) {
return -1;
}

int i = offset;

while(true)
{
if(i < 0 || i > str.Length - 1) {
return -1;
}

if(!char.IsWhiteSpace(str[i])) {
return i;
}

i += rightToLeft ? -1 : 1;
}
}

/// <summary>
/// Formatting of the path to directory.
/// </summary>
Expand Down
66 changes: 66 additions & 0 deletions MvsSlnTest/Extensions/StringExtensionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,71 @@ public void MakeRelativePathTest2()

Assert.AreEqual(null, @"path\to\dir1".MakeRelativePath(@"D:\path\to\dir1\bin\Release\file"));
}

[TestMethod]
public void FirstNonWhiteSpaceTest1()
{
Assert.AreEqual(10, " ActiveCfg = ".FirstNonWhiteSpace(12, true));
Assert.AreEqual(10, " ActiveCfg = ".FirstNonWhiteSpace(11, true));

Assert.AreEqual(13, " ActiveCfg = ".FirstNonWhiteSpace(12, false));
Assert.AreEqual(14, " ActiveCfg = ".FirstNonWhiteSpace(12, false));

Assert.AreEqual(2, " A ctiveCfg".FirstNonWhiteSpace(0, false));
Assert.AreEqual(4, " A ctiveCfg".FirstNonWhiteSpace(4, true));
Assert.AreEqual(2, " A ctiveCfg".FirstNonWhiteSpace(3, true));
Assert.AreEqual(0, "A ctiveCfg".FirstNonWhiteSpace(0, false));
}

[TestMethod]
public void FirstNonWhiteSpaceTest2()
{
Assert.AreEqual(-1, " ActiveCfg = ".FirstNonWhiteSpace(0, true));
Assert.AreEqual(0, "ActiveCfg = ".FirstNonWhiteSpace(0, true));

Assert.AreEqual(-1, " ActiveCfg = ".FirstNonWhiteSpace(1, true));
Assert.AreEqual(1, "ActiveCfg = ".FirstNonWhiteSpace(1, true));

Assert.AreEqual(-1, " ActiveCfg = ".FirstNonWhiteSpace(13, false));
Assert.AreEqual(-1, " ActiveCfg =".FirstNonWhiteSpace(13, false));

Assert.AreEqual(12, " ActiveCfg = ".FirstNonWhiteSpace(12, false));
Assert.AreEqual(12, " ActiveCfg =".FirstNonWhiteSpace(12, false));
}

[TestMethod]
public void FirstNonWhiteSpaceTest3()
{
Assert.AreEqual(-1, "ActiveCfg".FirstNonWhiteSpace(50, false));
Assert.AreEqual(-1, "ActiveCfg".FirstNonWhiteSpace(50, true));

Assert.AreEqual(-1, " ActiveCfg ".FirstNonWhiteSpace(50, false));
Assert.AreEqual(-1, " ActiveCfg ".FirstNonWhiteSpace(50, true));

Assert.AreEqual(-1, "ActiveCfg".FirstNonWhiteSpace(-50, false));
Assert.AreEqual(-1, "ActiveCfg".FirstNonWhiteSpace(-50, true));

Assert.AreEqual(-1, " ActiveCfg ".FirstNonWhiteSpace(-50, false));
Assert.AreEqual(-1, " ActiveCfg ".FirstNonWhiteSpace(-50, true));
}

[TestMethod]
public void FirstNonWhiteSpaceTest4()
{
Assert.AreEqual(-1, " ".FirstNonWhiteSpace(0, false));
Assert.AreEqual(-1, " ".FirstNonWhiteSpace(0, false));
Assert.AreEqual(-1, String.Empty.FirstNonWhiteSpace(0, false));
Assert.AreEqual(-1, ((string)null).FirstNonWhiteSpace(0, false));

Assert.AreEqual(-1, " ".FirstNonWhiteSpace(0, true));
Assert.AreEqual(-1, " ".FirstNonWhiteSpace(0, true));
Assert.AreEqual(-1, String.Empty.FirstNonWhiteSpace(0, true));
Assert.AreEqual(-1, ((string)null).FirstNonWhiteSpace(0, true));

Assert.AreEqual(-1, " ".FirstNonWhiteSpace(1, true));
Assert.AreEqual(-1, " ".FirstNonWhiteSpace(1, true));
Assert.AreEqual(-1, String.Empty.FirstNonWhiteSpace(1, true));
Assert.AreEqual(-1, ((string)null).FirstNonWhiteSpace(1, true));
}
}
}
20 changes: 20 additions & 0 deletions MvsSlnTest/SlnSamplesResource.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c68e79c

Please sign in to comment.