diff --git a/src/Cody.Core/DocumentSync/DocumentSyncCallback.cs b/src/Cody.Core/DocumentSync/DocumentSyncCallback.cs index cbbcbc50..99620b89 100644 --- a/src/Cody.Core/DocumentSync/DocumentSyncCallback.cs +++ b/src/Cody.Core/DocumentSync/DocumentSyncCallback.cs @@ -7,6 +7,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using static Nerdbank.Streams.MultiplexingStream; namespace Cody.Core.DocumentSync { @@ -29,7 +30,7 @@ private string ToUri(string path) public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange selection, IEnumerable changes) { - logger.Debug($"Sending didChange() for '{fullPath}' changes: {string.Join("|", changes.Select(x => x.Text))}"); + logger.Debug($"Sending didChange() for '{fullPath}', s:{selection}, v:{visibleRange}, c:{string.Join("", changes)}"); Range vRange = null; if (visibleRange != null) @@ -110,7 +111,7 @@ public void OnFocus(string fullPath) public void OnOpened(string fullPath, string content, DocumentRange visibleRange, DocumentRange selection) { - logger.Debug($"Sending DidOpen() for '{fullPath}'"); + logger.Debug($"Sending DidOpen() for '{fullPath}', s:{selection}, v:{visibleRange}"); Range vRange = null; if (visibleRange != null) diff --git a/src/Cody.Core/DocumentSync/IDocumentSyncActions.cs b/src/Cody.Core/DocumentSync/IDocumentSyncActions.cs index 7630adb3..cdd29a3d 100644 --- a/src/Cody.Core/DocumentSync/IDocumentSyncActions.cs +++ b/src/Cody.Core/DocumentSync/IDocumentSyncActions.cs @@ -25,6 +25,8 @@ public class DocumentPosition public int Line { get; set; } public int Column { get; set; } + + public override string ToString() => $"({Line},{Column})"; } public class DocumentRange @@ -32,11 +34,15 @@ public class DocumentRange public DocumentPosition Start { get; set; } public DocumentPosition End { get; set; } + + public override string ToString() => $"{Start}-{End}"; } public class DocumentChange { public string Text { get; set; } public DocumentRange Range { get; set; } + + public override string ToString() => $"['{Text}':{Range}]"; } } diff --git a/src/Cody.VisualStudio/Cody.VisualStudio.csproj b/src/Cody.VisualStudio/Cody.VisualStudio.csproj index 339f1fec..5dbe4bb3 100644 --- a/src/Cody.VisualStudio/Cody.VisualStudio.csproj +++ b/src/Cody.VisualStudio/Cody.VisualStudio.csproj @@ -55,7 +55,7 @@ - + Component diff --git a/src/Cody.VisualStudio/CodyPackage.cs b/src/Cody.VisualStudio/CodyPackage.cs index 88a2b7f5..d822b3e0 100644 --- a/src/Cody.VisualStudio/CodyPackage.cs +++ b/src/Cody.VisualStudio/CodyPackage.cs @@ -69,7 +69,7 @@ public sealed class CodyPackage : AsyncPackage public IVsEditorAdaptersFactoryService VsEditorAdaptersFactoryService; public IVsUIShell VsUIShell; public IAgentClientFactory AgentClientFactory; - public DocumentsSyncManager DocumentsSyncManager; + public DocumentsSyncService DocumentsSyncService; protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { @@ -189,8 +189,8 @@ private async Task InitializeAgent() .ContinueWith(x => { var documentSyncCallback = new DocumentSyncCallback(AgentClientFactory, Logger); - DocumentsSyncManager = new DocumentsSyncManager(VsUIShell, documentSyncCallback, VsEditorAdaptersFactoryService); - DocumentsSyncManager.Initialize(); + DocumentsSyncService = new DocumentsSyncService(VsUIShell, documentSyncCallback, VsEditorAdaptersFactoryService); + DocumentsSyncService.Initialize(); }) .ContinueWith(t => { diff --git a/src/Cody.VisualStudio/Services/DocumentsSyncManager.cs b/src/Cody.VisualStudio/Services/DocumentsSyncManager.cs deleted file mode 100644 index ddef4f3c..00000000 --- a/src/Cody.VisualStudio/Services/DocumentsSyncManager.cs +++ /dev/null @@ -1,234 +0,0 @@ -using Microsoft.VisualStudio.Editor; -using Microsoft.VisualStudio.Shell.Interop; -using Microsoft.VisualStudio.Shell; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.TextManager.Interop; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Documents; -using Cody.Core.DocumentSync; -using Microsoft.VisualStudio; - -namespace Cody.VisualStudio.Services -{ - public class DocumentsSyncManager : IVsRunningDocTableEvents - { - private RunningDocumentTable rdt; - - private readonly IVsUIShell vsUIShell; - private readonly IVsEditorAdaptersFactoryService editorAdaptersFactoryService; - private readonly IDocumentSyncActions documentActions; - - private IVsTextView activeTextView; - private ITextBuffer activeTextBuffer; - private uint activeDocCookie = 0; - private uint lastShowdoc = 0; - - public DocumentsSyncManager(IVsUIShell vsUIShell, IDocumentSyncActions documentActions, IVsEditorAdaptersFactoryService editorAdaptersFactoryService) - { - this.rdt = new RunningDocumentTable(); - this.vsUIShell = vsUIShell; - this.documentActions = documentActions; - - this.editorAdaptersFactoryService = editorAdaptersFactoryService; - } - - public void Initialize() - { - foreach (var frame in GetOpenDocuments()) - { - frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocCookie, out object cookie); - var docCookie = (uint)(int)cookie; - var path = rdt.GetDocumentInfo(docCookie).Moniker; - var content = rdt.GetRunningDocumentContents(docCookie); - var textView = VsShellUtilities.GetTextView(frame); - var docRange = GetDocumentSelection(textView); - var visibleRange = GetVisibleRange(textView); - - documentActions.OnOpened(path, content, visibleRange, docRange); - } - - rdt.Advise(this); - } - - private IEnumerable GetOpenDocuments() - { - var results = new List(); - - vsUIShell.GetDocumentWindowEnum(out IEnumWindowFrames docEnum); - var winFrameArray = new IVsWindowFrame[50]; - - while (true) - { - docEnum.Next((uint)winFrameArray.Length, winFrameArray, out uint fetched); - if (fetched == 0) break; - - results.AddRange(winFrameArray.Take((int)fetched)); - } - - return results; - } - - private ITextBuffer GetTextBuffer(IVsTextView textView) - { - ThreadHelper.ThrowIfNotOnUIThread(); - var wpfTextView = editorAdaptersFactoryService.GetWpfTextView(textView); - return wpfTextView.TextBuffer; - } - - private DocumentRange GetVisibleRange(IVsTextView textView) - { - const int SB_VERT = 1; - int visibleRows = 0, firstVisibleRow = 0; - - if (textView != null) textView.GetScrollInfo(SB_VERT, out _, out _, out visibleRows, out firstVisibleRow); - else return null; - - var range = new DocumentRange - { - Start = new DocumentPosition - { - Line = firstVisibleRow, - Column = 0 - }, - End = new DocumentPosition - { - Line = firstVisibleRow + visibleRows, - Column = 0 - } - }; - - return range; - } - - private DocumentRange GetDocumentSelection(IVsTextView textView) - { - int startLine = 0, startCol = 0, endLine = 0, endCol = 0; - if (textView != null) textView.GetSelection(out startLine, out startCol, out endLine, out endCol); - return new DocumentRange - { - Start = new DocumentPosition - { - Line = startLine, - Column = startCol, - }, - End = new DocumentPosition - { - Line = endLine, - Column = endCol, - } - }; - } - - int IVsRunningDocTableEvents.OnAfterFirstDocumentLock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) => VSConstants.S_OK; - - int IVsRunningDocTableEvents.OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint dwReadLocksRemaining, uint dwEditLocksRemaining) - { - if (dwReadLocksRemaining == 0 && dwEditLocksRemaining == 0) - { - var path = rdt.GetDocumentInfo(docCookie).Moniker; - documentActions.OnClosed(path); - } - return VSConstants.S_OK; - } - - int IVsRunningDocTableEvents.OnAfterSave(uint docCookie) - { - var path = rdt.GetDocumentInfo(docCookie).Moniker; - documentActions.OnSaved(path); - return VSConstants.S_OK; - } - - int IVsRunningDocTableEvents.OnAfterAttributeChange(uint docCookie, uint grfAttribs) => VSConstants.S_OK; - - int IVsRunningDocTableEvents.OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) - { - if (lastShowdoc != docCookie) - { - var path = rdt.GetDocumentInfo(docCookie).Moniker; - - if (fFirstShow == 1) - { - var content = rdt.GetRunningDocumentContents(docCookie); - var textView = VsShellUtilities.GetTextView(pFrame); - var docRange = GetDocumentSelection(textView); - var visibleRange = GetVisibleRange(textView); - - documentActions.OnOpened(path, content, visibleRange, docRange); - } - - - documentActions.OnFocus(path); - - activeTextView = VsShellUtilities.GetTextView(pFrame); - if (activeTextView != null) - { - activeTextBuffer = GetTextBuffer(activeTextView); - activeTextBuffer.ChangedLowPriority += OnTextBufferChanged; - } - else activeTextBuffer = null; - - activeDocCookie = docCookie; - lastShowdoc = docCookie; - } - - return VSConstants.S_OK; - } - - int IVsRunningDocTableEvents.OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) - { - if (activeTextBuffer != null) activeTextBuffer.ChangedLowPriority -= OnTextBufferChanged; - activeTextView = null; - activeTextBuffer = null; - activeDocCookie = 0; - - return VSConstants.S_OK; - } - - private void OnTextBufferChanged(object sender, TextContentChangedEventArgs e) - { - var path = rdt.GetDocumentInfo(activeDocCookie).Moniker; - var selection = GetDocumentSelection(activeTextView); - var changes = GetContentChanges(e.Changes, activeTextView); - var visibleRange = GetVisibleRange(activeTextView); - - documentActions.OnChanged(path, visibleRange, selection, changes); - } - - private IEnumerable GetContentChanges(INormalizedTextChangeCollection textChanges, IVsTextView textView) - { - var results = new List(); - - foreach (var change in textChanges) - { - textView.GetLineAndColumn(change.NewPosition, out int startLine, out int startCol); - textView.GetLineAndColumn(change.NewEnd, out int endLine, out int endCol); - - var contentChange = new DocumentChange - { - Text = change.NewText, - Range = new DocumentRange - { - Start = new DocumentPosition - { - Line = startLine, - Column = startCol - }, - End = new DocumentPosition - { - Line = endLine, - Column = endCol - } - } - }; - - results.Add(contentChange); - } - - return results; - } - } -} diff --git a/src/Cody.VisualStudio/Services/DocumentsSyncService.cs b/src/Cody.VisualStudio/Services/DocumentsSyncService.cs index 498f6b9b..6e77f173 100644 --- a/src/Cody.VisualStudio/Services/DocumentsSyncService.cs +++ b/src/Cody.VisualStudio/Services/DocumentsSyncService.cs @@ -6,13 +6,13 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Documents; +using Cody.Core.DocumentSync; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Text.Editor; namespace Cody.VisualStudio.Services { - public class DocumentsSyncManager : IVsRunningDocTableEvents + public class DocumentsSyncService : IVsRunningDocTableEvents { private RunningDocumentTable rdt; @@ -20,12 +20,10 @@ public class DocumentsSyncManager : IVsRunningDocTableEvents private readonly IVsEditorAdaptersFactoryService editorAdaptersFactoryService; private readonly IDocumentSyncActions documentActions; - private IVsTextView activeTextView; - private ITextBuffer activeTextBuffer; - private uint activeDocCookie = 0; - private uint lastShowdoc = 0; + private ActiveDocument activeDocument; + private uint lastShowDocCookie = 0; - public DocumentsSyncManager(IVsUIShell vsUIShell, IDocumentSyncActions documentActions, IVsEditorAdaptersFactoryService editorAdaptersFactoryService) + public DocumentsSyncService(IVsUIShell vsUIShell, IDocumentSyncActions documentActions, IVsEditorAdaptersFactoryService editorAdaptersFactoryService) { this.rdt = new RunningDocumentTable(); this.vsUIShell = vsUIShell; @@ -70,13 +68,6 @@ private IEnumerable GetOpenDocuments() return results; } - private ITextBuffer GetTextBuffer(IVsTextView textView) - { - ThreadHelper.ThrowIfNotOnUIThread(); - var wpfTextView = editorAdaptersFactoryService.GetWpfTextView(textView); - return wpfTextView.TextBuffer; - } - private DocumentRange GetVisibleRange(IVsTextView textView) { const int SB_VERT = 1; @@ -89,12 +80,12 @@ private DocumentRange GetVisibleRange(IVsTextView textView) { Start = new DocumentPosition { - Line = firstVisibleRow, + Line = Math.Max(firstVisibleRow, 0), Column = 0 }, End = new DocumentPosition { - Line = firstVisibleRow + visibleRows, + Line = Math.Max(firstVisibleRow + visibleRows, 0), Column = 0 } }; @@ -144,33 +135,38 @@ int IVsRunningDocTableEvents.OnAfterSave(uint docCookie) int IVsRunningDocTableEvents.OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame) { - if (lastShowdoc != docCookie) + if (lastShowDocCookie != docCookie) { var path = rdt.GetDocumentInfo(docCookie).Moniker; + var textView = VsShellUtilities.GetTextView(pFrame); if (fFirstShow == 1) { var content = rdt.GetRunningDocumentContents(docCookie); - var textView = VsShellUtilities.GetTextView(pFrame); + var docRange = GetDocumentSelection(textView); var visibleRange = GetVisibleRange(textView); documentActions.OnOpened(path, content, visibleRange, docRange); } - documentActions.OnFocus(path); - activeTextView = VsShellUtilities.GetTextView(pFrame); - if (activeTextView != null) + if (textView != null) { - activeTextBuffer = GetTextBuffer(activeTextView); - activeTextBuffer.ChangedLowPriority += OnTextBufferChanged; + activeDocument = new ActiveDocument + { + DocCookie = docCookie, + TextView = textView, + WpfTextView = editorAdaptersFactoryService.GetWpfTextView(textView) + }; + + activeDocument.TextBuffer.ChangedLowPriority += OnTextBufferChanged; + activeDocument.Selection.SelectionChanged += OnSelectionChanged; } - else activeTextBuffer = null; + else activeDocument = null; - activeDocCookie = docCookie; - lastShowdoc = docCookie; + lastShowDocCookie = docCookie; } return VSConstants.S_OK; @@ -178,24 +174,35 @@ int IVsRunningDocTableEvents.OnBeforeDocumentWindowShow(uint docCookie, int fFir int IVsRunningDocTableEvents.OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) { - if (activeTextBuffer != null) activeTextBuffer.ChangedLowPriority -= OnTextBufferChanged; - activeTextView = null; - activeTextBuffer = null; - activeDocCookie = 0; + if (activeDocument != null) + { + activeDocument.TextBuffer.ChangedLowPriority -= OnTextBufferChanged; + activeDocument.Selection.SelectionChanged -= OnSelectionChanged; + activeDocument = null; + } return VSConstants.S_OK; } private void OnTextBufferChanged(object sender, TextContentChangedEventArgs e) { - var path = rdt.GetDocumentInfo(activeDocCookie).Moniker; - var selection = GetDocumentSelection(activeTextView); - var changes = GetContentChanges(e.Changes, activeTextView); - var visibleRange = GetVisibleRange(activeTextView); + var path = rdt.GetDocumentInfo(activeDocument.DocCookie).Moniker; + var selection = GetDocumentSelection(activeDocument.TextView); + var changes = GetContentChanges(e.Changes, activeDocument.TextView); + var visibleRange = GetVisibleRange(activeDocument.TextView); documentActions.OnChanged(path, visibleRange, selection, changes); } + private void OnSelectionChanged(object sender, EventArgs e) + { + var path = rdt.GetDocumentInfo(activeDocument.DocCookie).Moniker; + var selection = GetDocumentSelection(activeDocument.TextView); + var visibleRange = GetVisibleRange(activeDocument.TextView); + + documentActions.OnChanged(path, visibleRange, selection, Enumerable.Empty()); + } + private IEnumerable GetContentChanges(INormalizedTextChangeCollection textChanges, IVsTextView textView) { var results = new List(); @@ -228,5 +235,22 @@ private IEnumerable GetContentChanges(INormalizedTextChangeColle return results; } + + public class ActiveDocument + { + + public IVsTextView TextView { get; set; } + + public uint DocCookie { get; set; } + + public IWpfTextView WpfTextView { get; set; } + + public ITextBuffer TextBuffer => WpfTextView.TextBuffer; + + public ITextSelection Selection => WpfTextView.Selection; + + } } + + }