@@ -30,15 +30,16 @@ namespace ICSharpCode.CodeConverter.VsExtension;
3030/// </remarks>
3131internal 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