Skip to content

Commit

Permalink
Bug fix
Browse files Browse the repository at this point in the history
Changes made:
- Fixed loading of code analysis dictionaries with .NET Core/Standard SDK format project files.  Fixes #228.
- Update HtmlAgilityPack NuGet package and fixed up parser file offsets.
  • Loading branch information
EWSoftware committed Mar 1, 2021
1 parent fbe2bef commit f29be90
Show file tree
Hide file tree
Showing 15 changed files with 211 additions and 80 deletions.
3 changes: 3 additions & 0 deletions Docs/Content/Installation.aml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ global spell checker settings.</para>

</list>

<para>A spell checker toolbar is also available. Right click anywhere in the Visual Studio toolbar area
and select the Spell Checker option from the context menu to display it.</para>

</content>
</section>

Expand Down
6 changes: 6 additions & 0 deletions Docs/Content/VersionHistory/VersionHistory.aml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ project. Select a version below to see a description of its changes.</para>
<section>
<content>
<list class="bullet">
<listItem>
<para>
<link xlink:href="e1588046-393b-4864-a3c1-6771b73bf124" />
</para>
</listItem>

<listItem>
<para>
<link xlink:href="bb88f7d5-2491-457e-9ba3-8d7d0bbc8615" />
Expand Down
29 changes: 29 additions & 0 deletions Docs/Content/VersionHistory/v2021.3.1.0.aml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<topic id="e1588046-393b-4864-a3c1-6771b73bf124" revisionNumber="1">
<developerConceptualDocument xmlns="http://ddue.schemas.microsoft.com/authoring/2003/5" xmlns:xlink="http://www.w3.org/1999/xlink">
<introduction>
<para>Changes in this release:</para>
</introduction>

<section>
<content>
<list class="bullet">
<listItem>
<para>Fixed loading of code analysis dictionaries with .NET Core/Standard SDK format project files.</para>
</listItem>

<listItem>
<para>Merged changes from Walter Goodwin to add a spell checker toolbar.</para>
</listItem>

</list>

</content>
</section>

<relatedTopics>
<link xlink:href="548dc6d7-6d08-4006-82b3-d5830be96f04" />
</relatedTopics>

</developerConceptualDocument>
</topic>
9 changes: 7 additions & 2 deletions Docs/ContentLayout.content
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,16 @@
<HelpKeyword index="K" term="submitting changes" />
</HelpKeywords>
</Topic>
<Topic id="548dc6d7-6d08-4006-82b3-d5830be96f04" visible="True" isSelected="true" title="Version History">
<Topic id="548dc6d7-6d08-4006-82b3-d5830be96f04" visible="True" isExpanded="true" title="Version History">
<HelpKeywords>
<HelpKeyword index="K" term="version, history" />
</HelpKeywords>
<Topic id="bb88f7d5-2491-457e-9ba3-8d7d0bbc8615" visible="True" title="Version 2021.1.23.0">
<Topic id="e1588046-393b-4864-a3c1-6771b73bf124" visible="True" title="Version 2021.3.1.0">
<HelpKeywords>
<HelpKeyword index="K" term="versions, 2021.3.1.0" />
</HelpKeywords>
</Topic>
<Topic id="bb88f7d5-2491-457e-9ba3-8d7d0bbc8615" visible="True" isSelected="true" title="Version 2021.1.23.0">
<HelpKeywords>
<HelpKeyword index="K" term="versions, 2021.1.23.0" />
</HelpKeywords>
Expand Down
3 changes: 2 additions & 1 deletion Docs/VSSpellCheckerDocs.shfbproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
</NamespaceSummaries>
<ComponentConfigurations>
</ComponentConfigurations>
<HelpFileVersion>2021.1.23.0</HelpFileVersion>
<HelpFileVersion>2021.3.1.0</HelpFileVersion>
<SaveComponentCacheCapacity>0</SaveComponentCacheCapacity>
<SourceCodeBasePath>..\Source\</SourceCodeBasePath>
<WarnOnMissingSourceContext>True</WarnOnMissingSourceContext>
Expand Down Expand Up @@ -183,6 +183,7 @@
<None Include="Content\VersionHistory\v2020.6.11.0.aml" />
<None Include="Content\VersionHistory\v2020.8.24.0.aml" />
<None Include="Content\VersionHistory\v2021.1.23.0.aml" />
<None Include="Content\VersionHistory\v2021.3.1.0.aml" />
<None Include="Content\VersionHistory\VersionHistory.aml" />
<None Include="Content\VersionHistory\v2015.8.15.0.aml" />
<None Include="Content\VersionHistory\v2015.9.19.0.aml" />
Expand Down
43 changes: 37 additions & 6 deletions Source/VSSpellChecker/ProjectSpellCheck/CodeClassifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// System : Visual Studio Spell Checker Package
// File : CodeClassifier.cs
// Author : Eric Woodruff ([email protected])
// Updated : 09/02/2018
// Note : Copyright 2015-2018, Eric Woodruff, All rights reserved
// Compiler: Microsoft Visual C#
// Updated : 02/28/2021
// Note : Copyright 2015-2021, Eric Woodruff, All rights reserved
//
// This file contains a class used to classify source code file content using a set of regular expressions
//
Expand Down Expand Up @@ -199,41 +198,73 @@ private void ParseNode(HtmlNode node, List<SpellCheckSpan> spans)
var commentNode = (HtmlCommentNode)node;

if(commentNode.OuterHtml.StartsWith("<!--", StringComparison.Ordinal))
{
#if DEBUG
// The parser offsets changed in an update to the HtmlAgilityPack. Catch any further
// changes as we'll need to fix our computed offsets again.
if(!this.Text.Substring(this.GetOffset(commentNode.Line, commentNode.LinePosition + 1),
commentNode.OuterHtml.Length).Equals(commentNode.OuterHtml, StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(new SpellCheckSpan
{
Span = new Span(this.AdjustedOffset(this.GetOffset(commentNode.Line,
commentNode.LinePosition) - 1, commentNode.OuterHtml),
commentNode.LinePosition + 1), commentNode.OuterHtml),
commentNode.OuterHtml.Length),
Text = commentNode.OuterHtml,
Classification = RangeClassification.XmlFileComment
});
}
break;

case HtmlNodeType.Text:
var textNode = (HtmlTextNode)node;

if(!HtmlNode.IsOverlappedClosingElement(textNode.Text) && textNode.Text.Trim().Length != 0)
{
#if DEBUG
// See above
if(!this.Text.Substring(this.GetOffset(textNode.Line, textNode.LinePosition + 1),
textNode.Text.Length).Equals(textNode.Text, StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(new SpellCheckSpan
{
Span = new Span(this.GetOffset(textNode.Line, textNode.LinePosition),
Span = new Span(this.GetOffset(textNode.Line, textNode.LinePosition + 1),
textNode.Text.Length),
Text = textNode.Text,
Classification = RangeClassification.XmlCommentsInnerText
});
}
break;

case HtmlNodeType.Element:
foreach(var attribute in node.Attributes)
if(this.SpellCheckConfiguration.SpellCheckedXmlAttributes.Contains(attribute.Name) &&
!String.IsNullOrWhiteSpace(attribute.Value))
{
#if DEBUG
// See above
if(!this.Text.Substring(this.GetOffset(attribute.Line, attribute.LinePosition +
attribute.Name.Length + 3), attribute.Value.Length).Equals(attribute.Value,
StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(new SpellCheckSpan
{
Span = new Span(this.AdjustedOffset(this.GetOffset(attribute.Line,
attribute.LinePosition + attribute.Name.Length + 1), attribute.Value),
attribute.LinePosition + attribute.Name.Length + 3), attribute.Value),
attribute.Value.Length),
Text = attribute.Value,
Classification = RangeClassification.AttributeValue
});
}

if(!this.SpellCheckConfiguration.IgnoredXmlElements.Contains(node.Name) && node.HasChildNodes)
foreach(HtmlNode subnode in node.ChildNodes)
Expand Down
83 changes: 66 additions & 17 deletions Source/VSSpellChecker/ProjectSpellCheck/HtmlClassifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// System : Visual Studio Spell Checker Package
// File : HtmlClassifier.cs
// Author : Eric Woodruff ([email protected])
// Updated : 09/17/2018
// Note : Copyright 2015-2018, Eric Woodruff, All rights reserved
// Compiler: Microsoft Visual C#
// Updated : 02/28/2021
// Note : Copyright 2015-2021, Eric Woodruff, All rights reserved
//
// This file contains a class used to classify HTML file content
//
Expand Down Expand Up @@ -132,11 +131,19 @@ private void ParseNode(HtmlNode node, List<SpellCheckSpan> spans)
// by the node parser but we don't want to include them.
if(commentNode.OuterHtml.StartsWith("<!--", StringComparison.Ordinal))
{
#if DEBUG
// The parser offsets changed in an update to the HtmlAgilityPack. Catch any further
// changes as we'll need to fix our computed offsets again.
if(!this.Text.Substring(this.GetOffset(commentNode.Line, commentNode.LinePosition + 1),
commentNode.OuterHtml.Length).Equals(commentNode.OuterHtml, StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(new SpellCheckSpan
{
Span = new Span(this.AdjustedOffset(this.GetOffset(commentNode.Line,
commentNode.LinePosition) - 1, commentNode.OuterHtml),
commentNode.OuterHtml.Length),
commentNode.LinePosition + 1), commentNode.OuterHtml), commentNode.OuterHtml.Length),
Text = commentNode.OuterHtml,
Classification = RangeClassification.XmlFileComment
});
Expand All @@ -148,8 +155,20 @@ private void ParseNode(HtmlNode node, List<SpellCheckSpan> spans)

if(!HtmlNode.IsOverlappedClosingElement(textNode.Text) && textNode.Text.Trim().Length != 0)
{
if(!this.DeterminePageLanguage(textNode.Text, this.GetOffset(textNode.Line, textNode.LinePosition), spans))
this.ParseScriptBlocks(textNode.Text, this.GetOffset(textNode.Line, textNode.LinePosition), spans);
if(!this.DeterminePageLanguage(textNode.Text, this.GetOffset(textNode.Line,
textNode.LinePosition + 1), spans))
{
#if DEBUG
// See above
if(!this.Text.Substring(this.GetOffset(textNode.Line, textNode.LinePosition + 1),
textNode.Text.Length).Equals(textNode.Text, StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
this.ParseScriptBlocks(textNode.Text, this.GetOffset(textNode.Line,
textNode.LinePosition + 1), spans);
}
}
break;

Expand All @@ -158,10 +177,19 @@ private void ParseNode(HtmlNode node, List<SpellCheckSpan> spans)
if(this.SpellCheckConfiguration.SpellCheckedXmlAttributes.Contains(attribute.Name) &&
!String.IsNullOrWhiteSpace(attribute.Value))
{
#if DEBUG
// See above
if(!this.Text.Substring(this.GetOffset(attribute.Line, attribute.LinePosition +
attribute.Name.Length + 3), attribute.Value.Length).Equals(attribute.Value,
StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(new SpellCheckSpan
{
Span = new Span(this.AdjustedOffset(this.GetOffset(attribute.Line,
attribute.LinePosition + attribute.Name.Length + 1), attribute.Value),
attribute.LinePosition + attribute.Name.Length + 3), attribute.Value),
attribute.Value.Length),
Text = attribute.Value,
Classification = RangeClassification.AttributeValue
Expand All @@ -171,7 +199,18 @@ private void ParseNode(HtmlNode node, List<SpellCheckSpan> spans)
if(!this.SpellCheckConfiguration.IgnoredXmlElements.Contains(node.Name) && node.HasChildNodes)
{
if(node.Name == "script")
this.ParseScriptElement(node.OuterHtml, this.GetOffset(node.Line, node.LinePosition), spans);
{
#if DEBUG
// See above
if(!this.Text.Substring(this.GetOffset(node.Line, node.LinePosition + 1),
node.OuterHtml.Length).Equals(node.OuterHtml, StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
this.ParseScriptElement(node.OuterHtml, this.GetOffset(node.Line,
node.LinePosition + 1), spans);
}
else
foreach(HtmlNode subnode in node.ChildNodes)
this.ParseNode(subnode, spans);
Expand Down Expand Up @@ -248,10 +287,15 @@ private void ParseScriptBlocks(string text, int offset, List<SpellCheckSpan> spa
{
// Adjust the span to set the position relative to the start of the block within this file
s.Span = new Span(s.Span.Start + offset, s.Span.Length);

System.Diagnostics.Debug.Assert(this.Text.Substring(s.Span.Start, s.Span.Length) ==
s.Text.Replace('<', '\xFE').Replace('>', '\xFF'));

#if DEBUG
// The parser offsets changed in an update to the HtmlAgilityPack. Catch any further
// changes as we'll need to fix our computed offsets again.
if(!this.Text.Substring(s.Span.Start, s.Span.Length).Equals(
s.Text.Replace('<', '\xFE').Replace('>', '\xFF'), StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(s);
}
}
Expand Down Expand Up @@ -295,9 +339,14 @@ private void ParseScriptElement(string script, int offset, List<SpellCheckSpan>
{
// Adjust the span to set the position relative to the start of the block within this file
s.Span = new Span(s.Span.Start + offset + scriptElement.Index + scriptElement.Length, s.Span.Length);

System.Diagnostics.Debug.Assert(this.Text.Substring(s.Span.Start, s.Span.Length) == s.Text);

#if DEBUG
// The parser offsets changed in an update to the HtmlAgilityPack. Catch any further
// changes as we'll need to fix our computed offsets again.
if(!this.Text.Substring(s.Span.Start, s.Span.Length).Equals(s.Text, StringComparison.OrdinalIgnoreCase))
{
System.Diagnostics.Debugger.Break();
}
#endif
spans.Add(s);
}
}
Expand Down Expand Up @@ -336,6 +385,6 @@ private TextClassifier GetClassifier(string language)

return c;
}
#endregion
#endregion
}
}
34 changes: 28 additions & 6 deletions Source/VSSpellChecker/ProjectSpellCheck/SpellCheckFileInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// System : Visual Studio Spell Checker Package
// File : SpellCheckFileInfo.cs
// Author : Eric Woodruff ([email protected])
// Updated : 03/17/2020
// Note : Copyright 2015-2020, Eric Woodruff, All rights reserved
// Compiler: Microsoft Visual C#
// Updated : 02/28/2021
// Note : Copyright 2015-2021, Eric Woodruff, All rights reserved
//
// This file contains a class used to hold information about a file that will be spell checked
//
Expand Down Expand Up @@ -89,6 +88,11 @@ internal class SpellCheckFileInfo
/// </summary>
public string DependencyConfigurationFile { get; private set; }

/// <summary>
/// This read-only property returns true if this item represents a code analysis dictionary, false if not
/// </summary>
public bool IsCodeAnalysisDictionary { get; private set; }

/// <summary>
/// This returns a description of the item with the solution and relative path to the file
/// </summary>
Expand Down Expand Up @@ -145,6 +149,18 @@ public static SpellCheckFileInfo ForOpenDocument(string filename)
};
}

/// <summary>
/// This is used to get the code analysis dictionaries from the named project
/// </summary>
/// <param name="projectName">The project from which to get code analysis dictionaries</param>
/// <returns>An enumerable list of the code analysis dictionary files if any</returns>
public static IEnumerable<SpellCheckFileInfo> ProjectCodeAnalysisDictionaries(string projectName)
{
Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();

return AllProjectFiles(projectName).Where(f => f.IsCodeAnalysisDictionary);
}

/// <summary>
/// This is used to get information for all files in the solution or a specific project
/// </summary>
Expand Down Expand Up @@ -507,9 +523,9 @@ private static void ProcessHierarchyNodeRecursively(IVsHierarchy hierarchy, uint
result = hierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_FirstVisibleChild,
out object value);

while(result == VSConstants.S_OK && value != null && value is int)
while(result == VSConstants.S_OK && value != null && value is int nodeId)
{
uint visibleChildNode = (uint)(int)value;
uint visibleChildNode = (uint)nodeId;

if(visibleChildNode == VSConstants.VSITEMID_NIL)
break;
Expand Down Expand Up @@ -564,11 +580,17 @@ private static SpellCheckFileInfo DetermineProjectFileInformation(IVsHierarchy h
Path.IsPathRooted(canonicalName) && !canonicalName.EndsWith("\\", StringComparison.Ordinal) &&
!canonicalName.Equals(projectName, StringComparison.OrdinalIgnoreCase))
{
result = hierarchy.GetProperty(itemId, (int)__VSHPROPID4.VSHPROPID_BuildAction, out value);

bool isCodeAnalysisDictionary = (result == VSConstants.S_OK && value != null &&
((string)value).Equals("CodeAnalysisDictionary", StringComparison.OrdinalIgnoreCase));

return new SpellCheckFileInfo
{
ProjectFile = projectName,
Filename = name,
CanonicalName = canonicalName
CanonicalName = canonicalName,
IsCodeAnalysisDictionary = isCodeAnalysisDictionary
};
}
}
Expand Down
Loading

0 comments on commit f29be90

Please sign in to comment.