From a79542efb962d55968c3b811a59a6acfc37b6231 Mon Sep 17 00:00:00 2001 From: XperiAndri Date: Mon, 26 Oct 2026 19:29:32 +0100 Subject: [PATCH 1/2] Watch .slnx solution files as well as .sln The watcher of the solution file was set up only when the name of the solution ended in ".sln", and its rename handler checked the same. A solution in the newer, XML based, .slnx format got no watcher, so a change of the solution (such as adding a project) did not reload the list of .resx files. The project file watcher was not affected. IsSolutionFileName recognizes both extensions, without regard to case, and both checks use it. The check in the rename handler was case sensitive before and is not any more. Co-Authored-By: Claude Sonnet 5.5 --- src/StringExtensions.cs | 10 ++++++++++ src/StringResVizPackage.cs | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/StringExtensions.cs b/src/StringExtensions.cs index b4d5665..31b2480 100644 --- a/src/StringExtensions.cs +++ b/src/StringExtensions.cs @@ -11,6 +11,16 @@ namespace StringResourceVisualizer { public static class StringExtensions { + /// + /// Whether a file name is that of a Visual Studio solution file: the .sln format or the newer, XML based, .slnx format. + /// + public static bool IsSolutionFileName(this string fileName) + { + return !string.IsNullOrEmpty(fileName) + && (fileName.EndsWith(".sln", StringComparison.InvariantCultureIgnoreCase) + || fileName.EndsWith(".slnx", StringComparison.InvariantCultureIgnoreCase)); + } + public static async Task IndexOfAnyAsync(this string source, params string[] values) { try diff --git a/src/StringResVizPackage.cs b/src/StringResVizPackage.cs index 2f5100d..0ff024c 100644 --- a/src/StringResVizPackage.cs +++ b/src/StringResVizPackage.cs @@ -270,7 +270,7 @@ private async Task SetUpRunningDocumentTableEventsAsync(CancellationToken cancel private void WatchForSolutionOrProjectChanges(string solutionFileName) { // It might actually be the project file name if no solution file exists - if (solutionFileName.EndsWith(".sln", StringComparison.InvariantCultureIgnoreCase)) + if (solutionFileName.IsSolutionFileName()) { this.SlnWatcher.Filter = Path.GetFileName(solutionFileName); this.SlnWatcher.Path = Path.GetDirectoryName(solutionFileName); @@ -315,7 +315,7 @@ private async void SlnWatcher_Renamed(object sender, RenamedEventArgs e) try { // Don't want to know about temporary files created during save. - if (e.FullPath.EndsWith(".sln")) + if (e.FullPath.IsSolutionFileName()) { await this.SetOrUpdateListOfResxFilesAsync(Path.GetDirectoryName(e.FullPath)); } From 88fdb1bb26317a287d6a17b8cc83b1f77e20a745 Mon Sep 17 00:00:00 2001 From: XperiAndri Date: Mon, 26 Oct 2026 19:29:32 +0100 Subject: [PATCH 2/2] Test the detection of solution files Nine tests for IsSolutionFileName: the .sln and .slnx formats, different case, a project file and a solution filter, an extension in the middle of the path, an empty name and null. Co-Authored-By: Claude Sonnet 5.5 --- .../StringExtensionsTests.cs | 73 +++++++++++++++++++ .../StringResourceVisualizer.Tests.csproj | 1 + 2 files changed, 74 insertions(+) create mode 100644 src/StringResourceVisualizer.Tests/StringExtensionsTests.cs diff --git a/src/StringResourceVisualizer.Tests/StringExtensionsTests.cs b/src/StringResourceVisualizer.Tests/StringExtensionsTests.cs new file mode 100644 index 0000000..466c279 --- /dev/null +++ b/src/StringResourceVisualizer.Tests/StringExtensionsTests.cs @@ -0,0 +1,73 @@ +// +// Copyright (c) Matt Lacey. All rights reserved. +// + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace StringResourceVisualizer.Tests +{ + [TestClass] + public class StringExtensionsTests + { + [TestMethod] + public void IsSolutionFileName_Sln() + { + TestIt(@"C:\Source\MyApp\MyApp.sln", true); + } + + [TestMethod] + public void IsSolutionFileName_Slnx() + { + TestIt(@"C:\Source\MyApp\MyApp.slnx", true); + } + + [TestMethod] + public void IsSolutionFileName_Sln_UpperCase() + { + TestIt(@"C:\Source\MyApp\MyApp.SLN", true); + } + + [TestMethod] + public void IsSolutionFileName_Slnx_MixedCase() + { + TestIt(@"C:\Source\MyApp\MyApp.SlnX", true); + } + + [TestMethod] + public void IsSolutionFileName_ProjectFile() + { + TestIt(@"C:\Source\MyApp\MyApp.csproj", false); + } + + [TestMethod] + public void IsSolutionFileName_SolutionFilter() + { + TestIt(@"C:\Source\MyApp\MyApp.slnf", false); + } + + [TestMethod] + public void IsSolutionFileName_ExtensionInTheMiddleOfThePath() + { + TestIt(@"C:\Source\MyApp.sln\readme.txt", false); + } + + [TestMethod] + public void IsSolutionFileName_Empty() + { + TestIt(string.Empty, false); + } + + [TestMethod] + public void IsSolutionFileName_Null() + { + TestIt(null, false); + } + + private void TestIt(string input, bool expected) + { + var actual = input.IsSolutionFileName(); + + Assert.AreEqual(expected, actual); + } + } +} \ No newline at end of file diff --git a/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj b/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj index 82e550c..d77d350 100644 --- a/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj +++ b/src/StringResourceVisualizer.Tests/StringResourceVisualizer.Tests.csproj @@ -44,6 +44,7 @@ +