/// <summary> /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> protected override void MenuItemCallback(object sender, EventArgs e) { var settings = (FormatterOptionsPage)Package.GetDialogPage(typeof(FormatterOptionsPage)); // Try to find absolute paths var document = VSUtils.GetDTE().ActiveDocument; var project = document.ProjectItem?.ContainingProject; if (project == null) { Output.Instance.WriteLine("The document '{0}' is not part of a project.", document.Name); } var includeDirectories = VSUtils.GetProjectIncludeDirectories(project); // Read. var viewHost = VSUtils.GetCurrentTextViewHost(); var selectionSpan = GetSelectionSpan(viewHost); // Format string formatedText = Formatter.IncludeFormatter.FormatIncludes(selectionSpan.GetText(), document.FullName, includeDirectories, settings); // Overwrite. using (var edit = viewHost.TextView.TextBuffer.CreateEdit()) { edit.Replace(selectionSpan, formatedText); edit.Apply(); } }
private void UpdateVisibility(object sender, EventArgs e) { // Check whether any includes are selected. var viewHost = VSUtils.GetCurrentTextViewHost(); var selectionSpan = GetSelectionSpan(viewHost); var lines = Formatter.IncludeLineInfo.ParseIncludes(selectionSpan.GetText(), Formatter.ParseOptions.RemoveEmptyLines); menuCommand.Visible = lines.Any(x => x.ContainsActiveInclude); }
/// <summary> /// Parses a given source file using cl.exe with the /showIncludes option and adds the output to the original graph. /// </summary> /// <remarks> /// If this is the first file, the graph is necessarily a tree after this operation. /// </remarks> /// <returns>true if successful, false otherwise.</returns> public static async Task <bool> AddIncludesRecursively_ShowIncludesCompilation(this IncludeGraph graph, Document document, OnCompleteCallback onCompleted) { var canPerformShowIncludeCompilation = await CanPerformShowIncludeCompilation(document); if (!canPerformShowIncludeCompilation.Result) { await Output.Instance.ErrorMsg(canPerformShowIncludeCompilation.Reason); return(false); } try { var dte = VSUtils.GetDTE(); if (dte == null) { await Output.Instance.ErrorMsg("Failed to acquire dte object."); return(false); } try { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); showIncludeSettingBefore = VSUtils.VCUtils.GetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject); VSUtils.VCUtils.SetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject, true); } catch (VCQueryFailure queryFailure) { await Output.Instance.ErrorMsg("Can't compile with show includes: {0}.", queryFailure.Message); return(false); } // Only after we're through all early out error cases, set static compilation infos. dte.Events.BuildEvents.OnBuildDone += OnBuildConfigFinished; CompilationBasedGraphParser.onCompleted = onCompleted; CompilationBasedGraphParser.documentBeingCompiled = document; CompilationBasedGraphParser.graphBeingExtended = graph; // Even with having the config changed and having compile force==true, we still need to make a dummy change in order to enforce recompilation of this file. { document.Activate(); var documentTextView = VSUtils.GetCurrentTextViewHost(); var textBuffer = documentTextView.TextView.TextBuffer; using (var edit = textBuffer.CreateEdit()) { edit.Insert(0, " "); edit.Apply(); } using (var edit = textBuffer.CreateEdit()) { edit.Replace(new Microsoft.VisualStudio.Text.Span(0, 1), ""); edit.Apply(); } } await VSUtils.VCUtils.CompileSingleFile(document); } catch (Exception e) { await ResetPendingCompilationInfo(); await Output.Instance.ErrorMsg("Compilation of file '{0}' with /showIncludes failed: {1}.", document.FullName, e); return(false); } return(true); }
static private void ApplyTasks(Dictionary <string, FormatTask> tasks, bool applyFormatting, FormatterOptionsPage formatSettings) { var dte = VSUtils.GetDTE(); foreach (KeyValuePair <string, FormatTask> entry in tasks) { string filename = entry.Key.Replace('/', '\\'); // Classy. But Necessary. EnvDTE.Window fileWindow = dte.ItemOperations.OpenFile(filename); if (fileWindow == null) { Output.Instance.ErrorMsg("Failed to open File {0}", filename); continue; } fileWindow.Activate(); var viewHost = VSUtils.GetCurrentTextViewHost(); using (var edit = viewHost.TextView.TextBuffer.CreateEdit()) { var originalLines = edit.Snapshot.Lines.ToArray(); // Determine which line ending to use by majority. string lineEndingToBeUsed = Utils.GetDominantNewLineSeparator(edit.Snapshot.GetText()); // Add lines. { // Find last include. // Will find even if commented out, but we don't care. int lastIncludeLine = -1; for (int line = originalLines.Length - 1; line >= 0; --line) { if (originalLines[line].GetText().Contains("#include")) { lastIncludeLine = line; break; } } // Build replacement string StringBuilder stringToInsertBuilder = new StringBuilder(); foreach (string lineToAdd in entry.Value.linesToAdd) { stringToInsertBuilder.Append(lineToAdd); stringToInsertBuilder.Append(lineEndingToBeUsed); } string stringToInsert = stringToInsertBuilder.ToString(); // optional, format before adding. if (applyFormatting) { var includeDirectories = VSUtils.GetProjectIncludeDirectories(fileWindow.Document.ProjectItem?.ContainingProject); stringToInsert = Formatter.IncludeFormatter.FormatIncludes(stringToInsert, fileWindow.Document.FullName, includeDirectories, formatSettings); // Add a newline if we removed it. if (formatSettings.RemoveEmptyLines) { stringToInsert += lineEndingToBeUsed; } } // Insert. int insertPosition = 0; if (lastIncludeLine >= 0 && lastIncludeLine < originalLines.Length) { insertPosition = originalLines[lastIncludeLine].EndIncludingLineBreak; } edit.Insert(insertPosition, stringToInsert.ToString()); } // Remove lines. // It should safe to do that last since we added includes at the bottom, this way there is no confusion with the text snapshot. { foreach (int lineToRemove in entry.Value.linesToRemove.Reverse()) { if (!Formatter.IncludeLineInfo.ContainsPreserveFlag(originalLines[lineToRemove].GetText())) { edit.Delete(originalLines[lineToRemove].ExtentIncludingLineBreak); } } } edit.Apply(); } // For Debugging: //Output.Instance.WriteLine(""); //Output.Instance.WriteLine(entry.Key); //Output.Instance.WriteLine(entry.Value.ToString()); } }
/// <summary> /// Parses a given source file using cl.exe with the /showIncludes option and adds the output to the original graph. /// </summary> /// <remarks> /// If this is the first file, the graph is necessarily a tree after this operation. /// </remarks> /// <returns>true if successful, false otherwise.</returns> public static bool AddIncludesRecursively_ShowIncludesCompilation(this IncludeGraph graph, Document document, OnCompleteCallback onCompleted) { if (!CanPerformShowIncludeCompilation(document, out string reasonForFailure)) { Output.Instance.ErrorMsg(reasonForFailure); return(false); } try { var dte = VSUtils.GetDTE(); if (dte == null) { Output.Instance.ErrorMsg("Failed to acquire dte object."); return(false); } { bool?setting = VSUtils.VCUtils.GetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject, out reasonForFailure); if (!setting.HasValue) { Output.Instance.ErrorMsg("Can't compile with show includes: {0}.", reasonForFailure); return(false); } else { showIncludeSettingBefore = setting.Value; } VSUtils.VCUtils.SetCompilerSetting_ShowIncludes(document.ProjectItem?.ContainingProject, true, out reasonForFailure); if (!string.IsNullOrEmpty(reasonForFailure)) { Output.Instance.ErrorMsg("Can't compile with show includes: {0}.", reasonForFailure); return(false); } } // Only after we're through all early out error cases, set static compilation infos. dte.Events.BuildEvents.OnBuildDone += OnBuildConfigFinished; CompilationBasedGraphParser.onCompleted = onCompleted; CompilationBasedGraphParser.documentBeingCompiled = document; CompilationBasedGraphParser.graphBeingExtended = graph; // Even with having the config changed and having compile force==true, we still need to make a dummy change in order to enforce recompilation of this file. { document.Activate(); var documentTextView = VSUtils.GetCurrentTextViewHost(); var textBuffer = documentTextView.TextView.TextBuffer; using (var edit = textBuffer.CreateEdit()) { edit.Insert(0, " "); edit.Apply(); } using (var edit = textBuffer.CreateEdit()) { edit.Replace(new Microsoft.VisualStudio.Text.Span(0, 1), ""); edit.Apply(); } } VSUtils.VCUtils.CompileSingleFile(document); } catch (Exception e) { ResetPendingCompilationInfo(); Output.Instance.ErrorMsg("Compilation of file '{0}' with /showIncludes failed: {1}.", document.FullName, e); return(false); } return(true); }