11using EnvDTE ;
22using Microsoft . VisualStudio ;
3- using Microsoft . VisualStudio . OLE . Interop ;
3+ using Microsoft . VisualStudio . ComponentModelHost ;
4+ using Microsoft . VisualStudio . Editor ;
45using Microsoft . VisualStudio . Shell ;
56using Microsoft . VisualStudio . Shell . Interop ;
7+ using Microsoft . VisualStudio . Text ;
8+ using Microsoft . VisualStudio . Text . Editor ;
69using Microsoft . VisualStudio . TextManager . Interop ;
710using System ;
811using System . ComponentModel ;
912using System . Diagnostics . CodeAnalysis ;
13+ using System . Runtime . CompilerServices ;
1014using System . Runtime . InteropServices ;
1115using System . Threading ;
1216using Process = System . Diagnostics . Process ;
@@ -33,20 +37,18 @@ namespace GtmExtension
3337 /// </remarks>
3438 [ PackageRegistration ( UseManagedResourcesOnly = true , AllowsBackgroundLoading = true ) ]
3539 [ InstalledProductRegistration ( "#110" , "#112" , "1.0" , IconResourceID = 400 ) ] // Info on this package for Help/About
36- [ Guid ( GtmPackage . PackageGuidString ) ]
40+ [ Guid ( PackageGuidString ) ]
3741 [ SuppressMessage ( "StyleCop.CSharp.DocumentationRules" , "SA1650:ElementDocumentationMustBeSpelledCorrectly" , Justification = "pkgdef, VS and vsixmanifest are valid VS terms" ) ]
3842 [ ProvideAutoLoad ( UIContextGuids80 . SolutionExists , PackageAutoLoadFlags . BackgroundLoad ) ] // Load the extension when a solution is open.
39- public sealed class GtmPackage : AsyncPackage , IVsTextViewEvents
43+ public sealed class GtmPackage : AsyncPackage
4044 {
4145 private string gtmExe ;
4246 private IVsStatusbar statusBar ;
43- private TextEditorEvents textEditorEvents ;
47+ private IVsEditorAdaptersFactoryService editor ;
4448 private WindowEvents windowEvents ;
4549 private DocumentEvents documentEvents ;
46- private Window previousWindow ;
47- private IVsTextView previousTextView ;
48- private uint previousCookie ;
4950 private IVsTextManager textManager ;
51+ private IWpfTextView wpfTextView ;
5052
5153 /// <summary>
5254 /// GtmPackage GUID string.
@@ -173,74 +175,63 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke
173175 textManager = ( IVsTextManager ) await GetServiceAsync ( typeof ( SVsTextManager ) ) ;
174176 if ( textManager == null ) { throw new InvalidOperationException ( "No TextManager." ) ; }
175177
176- // Subscribe to events.
177- textEditorEvents = dte . Events . TextEditorEvents ; // Don't get GC'ed!
178- textEditorEvents . LineChanged += TextEditorEvents_LineChanged ;
178+ // Get editor adapters.
179+ var componentModel = ( IComponentModel ) await GetServiceAsync ( typeof ( SComponentModel ) ) ;
180+ if ( componentModel == null ) { throw new InvalidOperationException ( "No ComponentModel." ) ; }
181+ editor = componentModel . GetService < IVsEditorAdaptersFactoryService > ( ) ;
179182
183+ // Subscribe to events. We keep the events objects so that they don't get GC'ed.
180184 windowEvents = dte . Events . WindowEvents ;
181185 windowEvents . WindowActivated += WindowEvents_WindowActivated ;
182186
183187 documentEvents = dte . Events . DocumentEvents ;
184188 documentEvents . DocumentSaved += DocumentEvents_DocumentSaved ;
189+
190+ Subscribe ( ) ;
185191 }
186192
187- private void TextEditorEvents_LineChanged ( TextPoint StartPoint , TextPoint EndPoint , int Hint )
193+ private void WindowEvents_WindowActivated ( Window GotFocus , Window LostFocus )
188194 {
189- statusBar . SetText ( "Text changed: " + StartPoint . Parent . Parent . FullName + " (" + DateTime . Now . ToLongTimeString ( ) + ")." ) ;
195+ Subscribe ( ) ;
190196 }
191- private IConnectionPoint GetConnectionPoint ( IVsTextView view )
197+ private string GetFilePath ( ITextView textView )
192198 {
193- if ( view is IConnectionPointContainer cpc )
194- {
195- Guid riid = typeof ( IVsTextViewEvents ) . GUID ;
196- cpc . FindConnectionPoint ( ref riid , out IConnectionPoint cp ) ;
197- return cp ;
198- }
199- else
200- {
201- throw new InvalidOperationException ( "No IConnectionPointContainer." ) ;
202- }
199+ return textView . TextBuffer . Properties . GetProperty < ITextDocument > ( typeof ( ITextDocument ) ) . FilePath ;
203200 }
204- private void WindowEvents_WindowActivated ( Window GotFocus , Window LostFocus )
201+ private void Subscribe ( )
205202 {
206203 // Unsubscribe the previously focused window.
207- if ( LostFocus != null && previousWindow != null )
204+ if ( wpfTextView != null )
208205 {
209- if ( previousWindow != LostFocus )
210- {
211- throw new InvalidOperationException ( "Unknown previous window." ) ;
212- }
213-
214- GetConnectionPoint ( previousTextView ) . Unadvise ( previousCookie ) ;
206+ wpfTextView . Caret . PositionChanged -= Caret_PositionChanged ;
207+ wpfTextView . LayoutChanged -= WpfTextView_LayoutChanged ;
208+ wpfTextView = null ;
215209 }
216210
217211 // Subsribe the currently focused window.
218- if ( GotFocus != null )
219- {
220- previousWindow = GotFocus ;
221- ErrorHandler . ThrowOnFailure ( textManager . GetActiveView ( 0 , null , out previousTextView ) ) ;
222- GetConnectionPoint ( previousTextView ) . Advise ( this , out previousCookie ) ;
223- }
212+ ErrorHandler . ThrowOnFailure ( textManager . GetActiveView ( 0 , null , out IVsTextView textView ) ) ;
213+ wpfTextView = editor . GetWpfTextView ( textView ) ;
214+ wpfTextView . Caret . PositionChanged += Caret_PositionChanged ;
215+ wpfTextView . LayoutChanged += WpfTextView_LayoutChanged ;
216+
217+ Update ( GetFilePath ( wpfTextView ) ) ;
224218 }
225- private void DocumentEvents_DocumentSaved ( Document Document )
219+
220+ private void WpfTextView_LayoutChanged ( object sender , TextViewLayoutChangedEventArgs e )
226221 {
227- statusBar . SetText ( "Document saved: " + Document . FullName + " (" + DateTime . Now . ToLongTimeString ( ) + ")." ) ;
222+ Update ( GetFilePath ( wpfTextView ) ) ;
228223 }
229- #endregion
230-
231- #region Implementation of `IVsTextViewEvents`
232- public void OnSetFocus ( IVsTextView pView ) { }
233- public void OnKillFocus ( IVsTextView pView ) { }
234- public void OnSetBuffer ( IVsTextView pView , IVsTextLines pBuffer ) { }
235- public void OnChangeScrollInfo ( IVsTextView pView , int iBar , int iMinUnit , int iMaxUnits , int iVisibleUnits , int iFirstVisibleUnit )
224+ private void Caret_PositionChanged ( object sender , CaretPositionChangedEventArgs e )
225+ {
226+ Update ( GetFilePath ( e . TextView ) ) ;
227+ }
228+ private void DocumentEvents_DocumentSaved ( Document Document )
236229 {
237- // TODO: Doesn't fire.
238- statusBar . SetText ( "Scrolling..." ) ;
230+ Update ( Document . FullName ) ;
239231 }
240- public void OnChangeCaretLine ( IVsTextView pView , int iNewLine , int iOldLine )
232+ private void Update ( string path , [ CallerMemberName ] string message = null )
241233 {
242- // TODO: Doesn't fire.
243- statusBar . SetText ( "Changing caret..." ) ;
234+ statusBar . SetText ( message + ": " + path + " (" + DateTime . Now . ToString ( "o" ) + ")." ) ;
244235 }
245236 #endregion
246237 }
0 commit comments