VSE-FormatDocumentOnSave
VSE-FormatDocumentOnSave copied to clipboard
Document.Saved is true even when it shouldn't be
I am on VS17.3.0 Preview 2.0. The extension does not work. When I ran it in the debugger, I was able to discover that Document.Saved is true, even though the document is dirty before saving. I have a coworker with the same version of VS who is not experiencing the same issue. I have tried uninstalling and reinstalling the extension.
Which version of the extension you are using?
3.2
FYI, Preview 3.0 has the same issues. Given my coworker is not having the same issue on the same version of VS, is it possible that I am in some AB testing group that he isn't in? Do you know how to see that?
I am not sure what is happening. I had exactly the same issue with one of my colleagues. When he updated the VS version the plugin started working again.
I just tested again in preview 3 after a reboot and it works now. Must be a thing with some specific configuration of 2.0. Anyone looking at this issue should update to preview 3 and reboot and see if that solves the issue.
Scratch that, it stopped working again.
I guess there is another extension which grabs the save operation and swallows it. Can you isolate it somehow?
Extensions installed:
- Visual Studio Theme Pack 1.2
- VSBlockJumper 1.1.5
- Test adapter for Google test 0.17.0.9
- Format Document on Save 3.2
- Test adapter for Boost.Test 1.1.0.4
- NuGetRecommender 1.700
Also of note is that the plugin appears to work for the first little while after installing a new preview version. After some time it appears to stop functioning again. I disabled all these extensions except for format on save and was still unable to format.
For which files it is not working? I have disabled xml files (razor, html, chhtml) because there is huge breaking change in vs2022
C++ files.
Bug still present in preview 6.0
I am doing some more research. It looks like the dirty flag is being cleared before calling the save handler. Call stack for the dirty flag clear:
Elders.VSE_FormatDocumentOnSave.dll!Elders.VSE_FormatDocumentOnSave.FormatDocumentOnBeforeSave.OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, Microsoft.VisualStudio.Shell.Interop.IVsHierarchy pHierOld, uint itemidOld, string pszMkDocumentOld, Microsoft.VisualStudio.Shell.Interop.IVsHierarchy pHierNew, uint itemidNew, string pszMkDocumentNew) Line 55 C#
[Native to Managed Transition]
msenv.dll!<lambda>(void)() Unknown
msenv.dll!CCookieTable<ATL::CComPtr<IVsRunningDocTableEvents>,DefaultCookieTraits<unsigned long,1,4294967295,0,1>,DefaultValueTraits<ATL::CComPtr<IVsRunningDocTableEvents>>>::for_each<<lambda>(void)>() Unknown
msenv.dll!CRunningDocTable::Impl::NotifyOnAfterAttributeChange(unsigned long,unsigned long,struct IVsHierarchy *,unsigned long,unsigned short const *,struct IVsHierarchy *,unsigned long,unsigned short const *) Unknown
msenv.dll!<lambda>(void)() Unknown
msenv.dll!FreeThreadingHelpers::UIThreadSynchronizedFunc<<lambda>(void)>() Unknown
msenv.dll!CRunningDocTable::NotifyOnAfterAttributeChange(unsigned long,unsigned long,struct IVsHierarchy *,unsigned long,unsigned short const *,struct IVsHierarchy *,unsigned long,unsigned short const *) Unknown
msenv.dll!CRunningDocInfo::IsDocumentDirty(void) Unknown
msenv.dll!CRunningDocTable::Impl::UpdateDirtyState(unsigned long) Unknown
msenv.dll!FreeThreadingHelpers::UIThreadSynchronizedFunc<<lambda_47a9be1b53fe414670aecddaf18a786e>>() Unknown
msenv.dll!CRunningDocTable::UpdateDirtyState(unsigned long) Unknown
[Managed to Native Transition]
Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Utilities.GuardedOperations.CallExtensionPoint(object errorSource, System.Action call) Unknown
Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.TextDocData.OnDirtyStateChanged(object sender, System.EventArgs e) Unknown
Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Utilities.GuardedOperations.RaiseEvent(object sender, System.EventHandler eventHandlers) Unknown
Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Implementation.TextDocument.RaiseDirtyStateChangedEvent(bool newDirtyState) Unknown
Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Implementation.TextDocument.UpdateDirtyState(bool isDirtied, System.DateTime lastContentModifiedTimeUtc) Unknown
Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.TextDocData.TextBufferState.set(uint value) Unknown
Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.TextDocData.SetDocDataDirty(int fDirty) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem.SetDocumentDirtyStateAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider asp, object docData, string moniker, bool dirty, System.Threading.CancellationToken token) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem.BeforeSaveAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider asp, Microsoft.Internal.VisualStudio.Shell.Interop.IVsSavePrimitives primitives, System.Threading.CancellationToken token) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTree.BeforeSaveAsync.AnonymousMethod__0(Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem item, int _, object _) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem.VisitItemsAsync<object>(System.Func<Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem, int, object, System.Threading.Tasks.Task> action, object state, int depth, bool visitChildrenFirst) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem.VisitItemsAsync<object>(System.Func<Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem, int, object, System.Threading.Tasks.Task> action, object state, int depth, bool visitChildrenFirst) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTree.BeforeSaveAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider asp, Microsoft.Internal.VisualStudio.Shell.Interop.IVsSavePrimitives primitives, System.Collections.Generic.Dictionary<Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem, object> saveContexts, System.Threading.CancellationToken token) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTree.SaveChangesAsync(Microsoft.VisualStudio.Shell.IAsyncServiceProvider asp, Microsoft.Internal.VisualStudio.Shell.Interop.IVsSavePrimitives primitives, Microsoft.VisualStudio.Shell.Interop.IVsProgress progress, System.Threading.CancellationToken token) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTree.PromptSaveChangesAsync(Microsoft.VisualStudio.Threading.JoinableTaskFactory jtf, Microsoft.VisualStudio.Shell.IAsyncServiceProvider asp, Microsoft.Internal.VisualStudio.Shell.Interop.IVsSavePrimitives primitives, Microsoft.VisualStudio.Shell.Interop.IVsProgress progress, System.Threading.CancellationToken token) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.SaveDocumentCoreAsync(Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveDocumentsInfo saveDocumentsInfo) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.SaveDocumentAsync(Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveDocumentsInfo saveDocumentsInfo) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.SaveDocumentsAsync(Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveDocumentsInfo saveDocumentsInfo) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.SaveDocumentsAsync.AnonymousMethod__1(Microsoft.VisualStudio.Telemetry.TelemetryEvent telemetryEvent, System.Threading.CancellationToken innerToken) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.RunWithTelemetryAsync(System.Func<Microsoft.VisualStudio.Telemetry.TelemetryEvent, System.Threading.CancellationToken, System.Threading.Tasks.Task<bool>> func, System.Threading.CancellationToken token) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.SaveDocumentsAsync.AnonymousMethod__0(System.Threading.CancellationToken outerToken) Unknown
Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.ExecuteJob<bool>(System.Func<System.Threading.Tasks.Task> asyncMethod, Microsoft.VisualStudio.Threading.JoinableTask job) Unknown
Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.RunAsync<bool>(System.Func<System.Threading.Tasks.Task<bool>> asyncMethod, bool synchronouslyBlocking, Microsoft.VisualStudio.Threading.JoinableTaskCreationOptions creationOptions) Unknown
Microsoft.VisualStudio.Shell.15.0.dll!Microsoft.VisualStudio.Shell.VsTaskLibraryHelper.RunAsync<bool>(Microsoft.VisualStudio.Threading.JoinableTaskFactory joinableTaskFactory, Microsoft.VisualStudio.Shell.VsTaskRunContext priority, System.Func<System.Threading.Tasks.Task<bool>> asyncMethod) Unknown
Microsoft.VisualStudio.Shell.15.0.dll!Microsoft.VisualStudio.Shell.VsTaskLibraryHelper.RunAsyncAsVsTask<bool>(Microsoft.VisualStudio.Threading.JoinableTaskFactory joinableTaskFactory, Microsoft.VisualStudio.Shell.VsTaskRunContext priority, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.Task<bool>> asyncMethod) Unknown
[Native to Managed Transition]
msenv.dll!CRunningDocTable::Impl::SaveDocumentsAsync(unsigned long,struct IVsHierarchy *,unsigned long,unsigned long,struct IVsProgress *,struct IVsSavePrimitives *,struct IVsTask * *) Unknown
msenv.dll!<lambda>(void)() Unknown
msenv.dll!FreeThreadingHelpers::UIThreadSynchronizedFunc<<lambda>(void)>() Unknown
msenv.dll!CRunningDocTable::SaveDocumentsAsync(unsigned long,struct IVsHierarchy *,unsigned long,unsigned long,struct IVsProgress *,struct IVsSavePrimitives *,struct IVsTask * *) Unknown
msenv.dll!CRunningDocTable::SaveDocumentsAsync(unsigned long,struct IVsHierarchy *,unsigned long,unsigned long,struct IVsProgress *,struct IVsTask * *) Unknown
msenv.dll!CAsyncSave::SaveItemAsync(bool,struct IVsTask * *) Unknown
msenv.dll!HrShellExec(struct _GUID const *,unsigned long,unsigned long,struct tagVARIANT *,struct tagVARIANT *) Unknown
msenv.dll!CVSCommandTarget::ExecCmd(class CIcmdGuidCmdId const *,struct _GUID const *,unsigned long,unsigned long,struct tagVARIANT *,struct tagVARIANT *,struct _GUID *) Unknown
msenv.dll!FTranslateAcceleratorEx(struct tagMSG *,int,unsigned long *,unsigned long *,int,int,unsigned long const *,int *) Unknown
msenv.dll!FTranslateAccelerator(struct tagMSG *,int,unsigned long *,unsigned long *) Unknown
msenv.dll!CMsoComponent::MainFTranslateMessage(struct tagMSG *,unsigned long) Unknown
msenv.dll!CMsoComponent::FPreTranslateMessage(struct tagMSG *) Unknown
msenv.dll!SCMI::FPreTranslateMessage(struct tagMSG *) Unknown
msenv.dll!SCM_MsoStdCompMgr::FPreTranslateMessage(struct tagMSG *) Unknown
msenv.dll!MainMessageLoop::ProcessMessage(struct IMsoStdComponentMgr *,struct IVsWindowManager *,struct tagMSG &) Unknown
msenv.dll!CMsoCMHandler::EnvironmentMsgLoop(void) Unknown
msenv.dll!CMsoCMHandler::FPushMessageLoop(unsigned long) Unknown
msenv.dll!SCM::FPushMessageLoop(class SCMI *,unsigned long,void *) Unknown
msenv.dll!SCM_MsoCompMgr::FPushMessageLoop(unsigned long,unsigned long,void *) Unknown
msenv.dll!CMsoComponent::PushMsgLoop(unsigned long) Unknown
msenv.dll!VStudioMainLogged(void) Unknown
msenv.dll!VStudioMain() Unknown
devenv.exe!util_CallVsMain(struct MAINPARAM *,int *) Unknown
devenv.exe!CDevEnvAppId::Run(unsigned short *,int) Unknown
devenv.exe!WinMain() Unknown
devenv.exe!__scrt_common_main_seh() Unknown
kernel32.dll!BaseThreadInitThunk() Unknown
ntdll.dll!RtlUserThreadStart() Unknown
And for the actual save event:
Elders.VSE_FormatDocumentOnSave.dll!Elders.VSE_FormatDocumentOnSave.FormatDocumentOnBeforeSave.OnBeforeSave(uint docCookie) Line 62 C#
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.NotifyOnBeforeSave.AnonymousMethod__0(Microsoft.VisualStudio.Shell.Interop.IVsRunningDocTableEvents sink) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.RunningDocumentTable.NotifySafely(System.Func<Microsoft.VisualStudio.Shell.Interop.IVsRunningDocTableEvents, Microsoft.VisualStudio.Shell.Interop.IVsTask> notify) Unknown
[Native to Managed Transition]
msenv.dll!CRunningDocTable::Impl::NotifyOnBeforeSave(unsigned long,unsigned long,struct IVsTask *) Unknown
msenv.dll!FreeThreadingHelpers::UIThreadSynchronizedFunc<<lambda_f3e5ed5f27221d9351fc5dbe0ad65b84>>() Unknown
msenv.dll!CRunningDocTable::NotifyOnBeforeSave(unsigned long,unsigned long,struct IVsTask *) Unknown
[Managed to Native Transition]
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTreeItem.SaveCoreAsync(Microsoft.VisualStudio.PlatformUI.Packages.Rdt.SaveTree savetree, Microsoft.VisualStudio.Shell.Interop.IVsTaskSchedulerService taskScheduler, Microsoft.Internal.VisualStudio.Shell.Interop.IVsRdtBackChannel backChannel, Microsoft.Internal.VisualStudio.Shell.Interop.IVsSavePrimitives primitives, Microsoft.VisualStudio.Shell.Interop.IVsProgress progress, System.Threading.CancellationToken token) Unknown
[Resuming Async Method]
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() Unknown
mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.OutputAsyncCausalityEvents.AnonymousMethod__0() Unknown
Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.SingleExecuteProtector.TryExecute() Unknown
mscorlib.dll!System.Threading.Tasks.Task.Execute() Unknown
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) Unknown
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.Services.TaskSchedulerService.VsUIThreadBlockableTaskScheduler.DoOneTask(out int dequeuedTaskCount) Unknown
Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.Services.TaskSchedulerService.VsUINormalPriorityScheduler.OnTaskQueued.AnonymousMethod__2_0() Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl() Unknown
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke() Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue() Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) Unknown
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler) Unknown
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) Unknown
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Unknown
[Native to Managed Transition]
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!DispatchMessageWorker() Unknown
msenv.dll!MainMessageLoop::ProcessMessage(struct IMsoStdComponentMgr *,struct IVsWindowManager *,struct tagMSG &) Unknown
msenv.dll!CMsoCMHandler::EnvironmentMsgLoop(void) Unknown
msenv.dll!CMsoCMHandler::FPushMessageLoop(unsigned long) Unknown
msenv.dll!SCM::FPushMessageLoop(class SCMI *,unsigned long,void *) Unknown
msenv.dll!SCM_MsoCompMgr::FPushMessageLoop(unsigned long,unsigned long,void *) Unknown
msenv.dll!CMsoComponent::PushMsgLoop(unsigned long) Unknown
msenv.dll!VStudioMainLogged(void) Unknown
msenv.dll!VStudioMain() Unknown
devenv.exe!util_CallVsMain(struct MAINPARAM *,int *) Unknown
devenv.exe!CDevEnvAppId::Run(unsigned short *,int) Unknown
devenv.exe!WinMain() Unknown
devenv.exe!__scrt_common_main_seh() Unknown
kernel32.dll!BaseThreadInitThunk() Unknown
ntdll.dll!RtlUserThreadStart() Unknown
[Async Call Stack]
[Async] Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.ActiveTaskCollection<string>.RunAsync.AnonymousMethod__0() Unknown
[Async] Microsoft.VisualStudio.Shell.UI.Internal.dll!Microsoft.VisualStudio.PlatformUI.Packages.Rdt.ActiveTaskCollection<string>.TaskCompletionState<int>.ContinueFrom.__AfterAsyncWork|6_1(System.Threading.Tasks.Task<int> antecedent) Unknown
I went ahead and put in a feedback item for this: https://developercommunity.visualstudio.com/t/Visual-Studio-clears-dirty-flag-before-c/10124978. I have had trouble getting feedback through Microsoft's triage before, so I would appreciate it if @mynkow you could get your colleague to chime in there
Auch, on which line (or call stack line) did you figure out that the flag has been cleared?
FormatDocumentOnBeforeSave::OnAfterAttributeChangeEx is the callback where it happens. If the flag variable is 16 then the file is having its dirty flag cleared. A quick test reveals that this is happening before the save command is called.
I tested this with c++ files and it is working for me.
VS version: 17.3.1 Extension version: 3.4
Maybe the issue is when visual studio is set up to use clang-format on Edit.DocumentSave? That's my setup anyway, which is why maybe its only working in some circumstances?
What are the steps to setup the clang-format?
test.zip
Minimal cmake project which I can repro the issue with. To enable clang format support, Options->Text Editor->C/C++->Code Style->Formatting->General->Enable ClangFormat support. That said, I tried disabling Clang-Format and still have the same issue. I also tested in a non-C++ project and had the same problem.
We have the same issue here => https://github.com/Elders/VSE-FormatDocumentOnSave/issues/47