Skip to content

Commit 1a66253

Browse files
Tell people to update at start, end and when there's an error
1 parent ed4544a commit 1a66253

2 files changed

Lines changed: 46 additions & 33 deletions

File tree

Vsix/CodeConversion.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,9 @@ private async Task<string> GetConversionSummaryAsync(IReadOnlyCollection<string>
229229
oneLine += $" with {errors.Count} error" + (errors.Count == 1 ? "" : "s");
230230
}
231231

232-
if (files.Count > errors.Count * 2) {
232+
if (VisualStudioInteraction.GetUpdateWarningsOrNull() is { } warnings) {
233+
successSummary += Environment.NewLine + warnings;
234+
} else if (files.Count > errors.Count * 2) {
233235
successSummary += Environment.NewLine + "Please report issues at https://github.com/icsharpcode/CodeConverter/issues and consider rating at https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.CodeConverter#review-details";
234236
} else {
235237
successSummary += Environment.NewLine + "Please report issues at https://github.com/icsharpcode/CodeConverter/issues";

Vsix/VisualStudioInteraction.cs

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ namespace ICSharpCode.CodeConverter.VsExtension;
3030
/// </remarks>
3131
internal static class VisualStudioInteraction
3232
{
33-
private static DTE2 m_Dte;
33+
private static DTE2 _dte;
3434

3535
/// <remarks>All calls and usages must be from the main thread</remarks>>
36-
internal static DTE2 Dte => m_Dte ??= Package.GetGlobalService(typeof(DTE)) as DTE2;
36+
internal static DTE2 Dte => _dte ??= Package.GetGlobalService(typeof(DTE)) as DTE2;
3737

38-
private static CancellationToken CancelAllToken;
39-
private static readonly Version m_LowestSupportedVersion = new(15, 7, 0, 0);
40-
private static readonly Version m_FullVsVersion = GetFullVsVersion();
41-
private static readonly string m_Title = "Code converter " + new AssemblyName(typeof(ProjectConversion).Assembly.FullName).Version.ToString(3) + " - Visual Studio " + (m_FullVsVersion?.ToString() ?? "unknown version");
38+
private static CancellationToken _cancelAllToken;
39+
private static readonly Version LowestSupportedVersion = new(16, 10, 0, 0);
40+
private static readonly Version FullVsVersion = GetFullVsVersion();
41+
private static readonly string Title = "Code converter " + new AssemblyName(typeof(ProjectConversion).Assembly.FullName).Version.ToString(3) + " - Visual Studio " + (FullVsVersion?.ToString() ?? "unknown version");
42+
private static readonly int WeeksUpdatesStoppedFor = (int) (DateTime.Now - new DateTime(2022, 05, 01)).TotalDays / 7;
4243

4344
private static Version GetFullVsVersion()
4445
{
@@ -56,12 +57,12 @@ private static Version GetFullVsVersion()
5657

5758
internal static void Initialize(Cancellation packageCancellation)
5859
{
59-
CancelAllToken = packageCancellation.CancelAll;
60+
_cancelAllToken = packageCancellation.CancelAll;
6061
}
6162

6263
public static async Task<List<string>> GetSelectedItemsPathAsync(Func<string, bool> fileFilter)
6364
{
64-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
65+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
6566
const string folderKind = "{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}";
6667
const string fileKind = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}";
6768

@@ -85,22 +86,22 @@ public static async Task<List<string>> GetSelectedItemsPathAsync(Func<string, bo
8586

8687
public static async Task<Window> OpenFileAsync(FileInfo fileInfo)
8788
{
88-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
89+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
8990
var window = Dte.ItemOperations.OpenFile(fileInfo.FullName, Constants.vsViewKindTextView);
9091
await TaskScheduler.Default;
9192
return window;
9293
}
9394

9495
public static async Task SelectAllAsync(this Window window)
9596
{
96-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
97+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
9798
((TextSelection)window?.Document?.Selection)?.SelectAll(); // https://github.com/icsharpcode/CodeConverter/issues/770
9899
await TaskScheduler.Default;
99100
}
100101

101102
public static async Task<IReadOnlyCollection<Project>> GetSelectedProjectsAsync(string projectExtension)
102103
{
103-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
104+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
104105

105106
#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
106107
var projects = GetSelectedSolutionExplorerItems<Solution>().SelectMany(s => s.GetAllProjects())
@@ -115,28 +116,24 @@ public static async Task<IReadOnlyCollection<Project>> GetSelectedProjectsAsync(
115116

116117
public static async Task<ITextDocument> GetTextDocumentAsync(this IWpfTextViewHost viewHost)
117118
{
118-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
119+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
119120
viewHost.TextView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out ITextDocument textDocument);
120121
await TaskScheduler.Default;
121122
return textDocument;
122123
}
123124

124125
public static async Task ShowExceptionAsync(this AsyncPackage asyncPackage, Exception ex)
125126
{
126-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
127-
if (CancelAllToken.IsCancellationRequested) {
127+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
128+
if (_cancelAllToken.IsCancellationRequested) {
128129
return;
129130
}
130131

131132
string mainMessage = ex.ToString();
132133
var messageSuffix = "";
133134

134-
if (m_FullVsVersion < m_LowestSupportedVersion) {
135-
messageSuffix = $"{Environment.NewLine}This extension only supports VS {m_LowestSupportedVersion}+, you are currently using {m_FullVsVersion}";
136-
}
137-
138-
if (m_FullVsVersion.Major < 16) {
139-
messageSuffix = $"{Environment.NewLine}Support for VS2017 (15.*) is likely to end this year. You're using: {m_FullVsVersion}";
135+
if (FullVsVersion < LowestSupportedVersion) {
136+
messageSuffix = $"{Environment.NewLine}This extension only receives updates for VS {LowestSupportedVersion}+, you are currently using {FullVsVersion}";
140137
}
141138

142139
if (ex is FileNotFoundException fnf && !string.IsNullOrEmpty(fnf.FusionLog)) {
@@ -158,7 +155,7 @@ public static async Task ShowExceptionAsync(this AsyncPackage asyncPackage, Exce
158155
}
159156

160157
MessageBox.Show($"An error has occurred during conversion - press Ctrl+C to copy the details: {mainMessage}{messageSuffix}",
161-
m_Title, MessageBoxButton.OK, MessageBoxImage.Error);
158+
Title, MessageBoxButton.OK, MessageBoxImage.Error);
162159
}
163160

164161
private static string GetShortStackTrace(Exception ex)
@@ -175,24 +172,26 @@ private static string GetShortStackTrace(Exception ex)
175172
/// <returns>true iff the user answers "OK"</returns>
176173
public static async Task<bool> ShowMessageBoxAsync(string title, string msg, bool showCancelButton, bool defaultOk = true)
177174
{
178-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
179-
if (CancelAllToken.IsCancellationRequested) return false;
175+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
176+
if (_cancelAllToken.IsCancellationRequested) return false;
180177
var userAnswer = MessageBox.Show(msg, title,
181178
showCancelButton ? MessageBoxButton.OKCancel : MessageBoxButton.OK,
182179
MessageBoxImage.Information,
183180
defaultOk || !showCancelButton ? MessageBoxResult.OK : MessageBoxResult.Cancel);
184181
return userAnswer == MessageBoxResult.OK;
185182
}
186183

187-
public static async Task ShowMessageBoxAsync(string msg) => await ShowMessageBoxAsync(m_Title, msg, showCancelButton: false);
184+
public static async Task ShowMessageBoxAsync(string msg) => await ShowMessageBoxAsync(Title, msg, showCancelButton: false);
188185

189186
public static async Task EnsureBuiltAsync(IReadOnlyCollection<Project> projects, Func<string, Task> writeMessageAsync)
190187
{
191-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
188+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
192189
var build = Dte.Solution.SolutionBuild;
193190
if (build.BuildState == vsBuildState.vsBuildStateInProgress) {
194191
throw new InvalidOperationException("Build in progress, please wait for it to complete before conversion.");
195192
}
193+
194+
if (GetUpdateWarningsOrNull() is {} warning) await writeMessageAsync(warning);
196195
if (projects.Count == 1 && build.ActiveConfiguration?.Name is { } configuration && projects.Single().UniqueName is {} uniqueName) {
197196
await writeMessageAsync($"Building project '{uniqueName}' prior to conversion for maximum accuracy...");
198197
build.BuildProject(configuration, uniqueName);
@@ -204,9 +203,21 @@ public static async Task EnsureBuiltAsync(IReadOnlyCollection<Project> projects,
204203
await TaskScheduler.Default;
205204
}
206205

206+
public static string GetUpdateWarningsOrNull()
207+
{
208+
if (FullVsVersion < LowestSupportedVersion && WeeksUpdatesStoppedFor > 0)
209+
{
210+
return
211+
$"Deprecated: Code Converter no longer receives updates for Visual Studio {FullVsVersion}. Please update to the latest version of Visual Studio ({LowestSupportedVersion} at minimum).{Environment.NewLine}" +
212+
$"See the {WeeksUpdatesStoppedFor} weeks of improvements you're missing at https://github.com/icsharpcode/CodeConverter/blob/master/CHANGELOG.md";
213+
}
214+
215+
return null;
216+
}
217+
207218
public static async Task WriteStatusBarTextAsync(IAsyncServiceProvider serviceProvider, string text)
208219
{
209-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
220+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
210221
var statusBar = await serviceProvider.GetServiceAsync<SVsStatusbar, IVsStatusbar>();
211222
if (statusBar == null)
212223
return;
@@ -224,7 +235,7 @@ public static async Task WriteStatusBarTextAsync(IAsyncServiceProvider servicePr
224235
public static async Task<Span?> GetFirstSelectedSpanInCurrentViewAsync(IAsyncServiceProvider serviceProvider,
225236
Func<string, bool> predicate, bool mustHaveFocus)
226237
{
227-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
238+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
228239
var span = await FirstSelectedSpanInCurrentViewPrivateAsync(serviceProvider, predicate, mustHaveFocus);
229240
await TaskScheduler.Default;
230241
return span;
@@ -233,7 +244,7 @@ public static async Task WriteStatusBarTextAsync(IAsyncServiceProvider servicePr
233244
public static async Task<(string FilePath, Span? Selection)> GetCurrentFilenameAndSelectionAsync(
234245
IAsyncServiceProvider asyncServiceProvider, Func<string, bool> predicate, bool mustHaveFocus)
235246
{
236-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
247+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
237248

238249
var span = await GetFirstSelectedSpanInCurrentViewAsync(asyncServiceProvider, predicate, mustHaveFocus);
239250
var currentViewHostAsync =
@@ -250,7 +261,7 @@ public static async Task WriteStatusBarTextAsync(IAsyncServiceProvider servicePr
250261

251262
public static async Task<CaretPosition> GetCaretPositionAsync(IAsyncServiceProvider serviceProvider)
252263
{
253-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
264+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
254265
var viewHost = await GetCurrentViewHostAsync(serviceProvider,false);
255266
ITextEdit edit = viewHost.TextView.TextBuffer.CreateEdit();
256267
var caretPositionAsync = new CaretPosition(edit, viewHost.TextView.Caret.Position.BufferPosition.Position);
@@ -260,7 +271,7 @@ public static async Task<CaretPosition> GetCaretPositionAsync(IAsyncServiceProvi
260271

261272
public static async Task<Project> GetFirstProjectContainingAsync(string documentFilePath)
262273
{
263-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
274+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
264275
var containingProject = Dte.Solution.FindProjectItem(documentFilePath)?.ContainingProject;
265276
await TaskScheduler.Default;
266277
return containingProject;
@@ -279,7 +290,7 @@ public CaretPosition(ITextEdit textEdit, int position)
279290

280291
public async Task InsertAsync(string text)
281292
{
282-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
293+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
283294
_textEdit.Insert(_position, text);
284295
_textEdit.Apply();
285296
_textEdit.Dispose();
@@ -305,7 +316,7 @@ private static IEnumerable<T> ObjectOfType<T>(IReadOnlyCollection<UIHierarchyIte
305316

306317
private static async Task<IWpfTextViewHost> GetCurrentViewHostAsync(IAsyncServiceProvider serviceProvider, bool mustHaveFocus)
307318
{
308-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(CancelAllToken);
319+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(_cancelAllToken);
309320
var txtMgr = await serviceProvider.GetServiceAsync<SVsTextManager, IVsTextManager>();
310321
if (txtMgr == null) {
311322
return null;

0 commit comments

Comments
 (0)