private void JoinLine(TextSelection textSelection) { // If the selection has no length, try to pick up the next line. if (textSelection.IsEmpty) { textSelection.LineDown(true); textSelection.EndOfLine(true); } const string fluentPattern = @"[ \t]*\r?\n[ \t]*\."; const string pattern = @"[ \t]*\r?\n[ \t]*"; var selection = textSelection.Text; // do regex replace for fluent style selection = Regex.Replace(selection, fluentPattern, "."); // do regex replace for everything else selection = Regex.Replace(selection, pattern, " "); textSelection.Text = selection; // Move the cursor forward, clearing the selection. textSelection.CharRight(); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gotoes the function header down. /// </summary> /// ------------------------------------------------------------------------------------ public void GotoFunctionHeaderDown() { TextSelection sel = (TextSelection)m_applicationObject.ActiveDocument.Selection; TextPoint curPoint = sel.ActivePoint; try { CodeElement codeElement = GetMethodOrProperty(sel); if (codeElement != null) { sel.MoveToPoint(codeElement.EndPoint, false); } codeElement = null; int prevLine = 0; while (codeElement == null && prevLine != sel.CurrentLine) { prevLine = sel.CurrentLine; sel.LineDown(false, 1); codeElement = GetMethodOrProperty(sel); } if (codeElement != null) { sel.MoveToPoint(codeElement.StartPoint, false); } } catch (Exception e) { System.Diagnostics.Debug.WriteLine("Got exception in GotoFunctionHeaderDown: " + e.Message); } }
/// <summary>Implements the Exec method of the IDTCommandTarget interface. This is called when the command is invoked.</summary> /// <param term='commandName'>The name of the command to execute.</param> /// <param term='executeOption'>Describes how the command should be run.</param> /// <param term='varIn'>Parameters passed from the caller to the command handler.</param> /// <param term='varOut'>Parameters passed from the command handler to the caller.</param> /// <param term='handled'>Informs the caller if the command was handled or not.</param> /// <seealso class='Exec' /> public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled) { handled = false; if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault) { if (commandName == "FormatVariableDefine.Connect.FormatVariableDefine" || commandName == "FormatVariableDefine.Connect.FormatVariableDefineRightClick") { TextSelection select = ((TextSelection)_applicationObject.ActiveDocument.Selection); int nTopLine = select.TopLine; int nBottomLine = select.BottomLine; bool bLastLineEmpty = select.BottomPoint.AtStartOfLine; select.GotoLine(nTopLine, true); select.LineDown(true, nBottomLine - nTopLine); select.EndOfLine(true); if (bLastLineEmpty) { select.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, true); } string selectedCode = select.Text; string outCode = CodeSmart.AlignText(selectedCode); //对齐选中文本 select.Insert(outCode, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); handled = true; return; } } }
/// <summary> /// Removes special characters after inserting header /// </summary> /// <param name="textSelection">Text selection</param> /// <param name="template">Template</param> private void RemoveSpecialCharacters(TextSelection textSelection, string template) { // Remove special characters from beginning of each line in template textSelection.StartOfDocument(); for (int i = 0; i < template.Split('\n').Length; i++) { textSelection.StartOfLine(); textSelection.CharRight(true, SpecialCharacters.Length); textSelection.Delete(); textSelection.LineDown(); } }
/// <summary> /// Scrolls to the beginning of code. Code is searched from below if we are currently on a comment or /// empty line. Otherwise the beginning of code is searched from above. /// </summary> /// <param name="ts"></param> /// <returns></returns> private bool ScrollToCodeStart(TextSelection ts) { ThreadHelper.ThrowIfNotOnUIThread(); string curLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line, ts.ActivePoint.Line + 1); curLine = curLine.TrimStart(); bool codeFound = false; // If we are currently on a comment or empty line, find the first code line from below. if (IsEmptyOrComment(curLine)) { while (!ts.ActivePoint.AtEndOfDocument) { if (!IsEmptyOrComment(curLine)) { codeFound = true; break; } ts.LineDown(); curLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line, ts.ActivePoint.Line + 1); curLine = curLine.TrimStart(); } } else { // Otherwise search from above for the line which begins the code statement. while (ts.ActivePoint.Line > 1) { // Peek previous line and check if it is new code statement, comment or empty. string prevLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line - 1, ts.ActivePoint.Line); prevLine = prevLine.Trim(); if (IsEmptyOrComment(prevLine) || prevLine.EndsWith(";") || prevLine.EndsWith("}")) { codeFound = true; break; } ts.LineUp(); } } return(codeFound); }
/// <summary> /// Joins the text within the specified text selection. /// </summary> /// <param name="textSelection">The text selection.</param> private void JoinText(TextSelection textSelection) { // If the selection has no length, try to pick up the next line. if (textSelection.IsEmpty) { textSelection.LineDown(true); textSelection.EndOfLine(true); } const string pattern = @"[ \t]*\r?\n[ \t]*"; const string replacement = @" "; // Substitute all new lines (and optional surrounding whitespace) with a single space. TextDocumentHelper.SubstituteAllStringMatches(textSelection, pattern, replacement); // Move the cursor forward, clearing the selection. textSelection.CharRight(); }
/// <summary> /// Joins the text within the specified text selection. /// </summary> /// <param name="textSelection">The text selection.</param> private void JoinText(TextSelection textSelection) { // If the selection has no length, try to pick up the next line. if (textSelection.IsEmpty) { textSelection.LineDown(true); textSelection.EndOfLine(true); } const string pattern = @"[ \t]*\r?\n[ \t]*"; const string replacement = @" "; // Substitute all new lines (and optional surrounding whitespace) with a single space. TextDocumentHelper.SubstituteAllStringMatches(textSelection, pattern, replacement); // Move the cursor forward, clearing the selection. textSelection.CharRight(); }
private bool CheckIfInDocumentetFunction(TextSelection ts, int currentLine, int currentOffset, out CodeFunction codeFunction, out int functionLine) { ThreadHelper.ThrowIfNotOnUIThread(); // Get comment beginnings string commentFormat = m_settings.FunctionFormat; string[] formatLines = commentFormat.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); string commentStart = formatLines.First().Trim().Split(' ').First().Trim(); string commentMiddle = formatLines[1].Trim().Split(' ').First().Trim(); string commentEnd = formatLines.Last().Trim().Split(' ').First().Trim(); // Check if in comment bool isComment = false; functionLine = currentLine; string line = m_textView.TextSnapshot.GetLineFromPosition(m_textView.Caret.Position.BufferPosition.Position).GetText().Trim(); if (line.StartsWith(commentStart) || line.StartsWith(commentMiddle) || line.StartsWith(commentEnd)) { while (!ts.ActivePoint.AtEndOfDocument) { // Get the line of the curser string _line = m_textView.TextSnapshot.GetLineFromLineNumber(ts.ActivePoint.Line - 1).GetText(); // Check if the comment ends if (_line.Contains(commentEnd)) { functionLine = ts.ActivePoint.Line + 1; isComment = true; break; } // If the end of the comment was not there, go one line down ts.LineDown(); } // If there is a comment start, but no correct ending, this is not a doxygen documentation if (functionLine == currentLine) { codeFunction = null; return(false); } } codeFunction = null; CodeElement codeElement = null; FileCodeModel fcm = m_dte.ActiveDocument.ProjectItem.FileCodeModel; if (fcm != null) { // Move to end of the current line ts.MoveToLineAndOffset(functionLine, 1); ts.EndOfLine(); // Check if there is a function for (int lineNumber = functionLine; lineNumber <= functionLine + 3; lineNumber++) { codeElement = fcm.CodeElementFromPoint(ts.ActivePoint, vsCMElement.vsCMElementFunction); if (codeElement != null && codeElement.Kind == vsCMElement.vsCMElementFunction) { functionLine = lineNumber; break; } // Only search in the next line if the cursor was in the documentation if (!isComment) { break; } string _line = m_textView.TextSnapshot.GetLineFromLineNumber(lineNumber - 1).GetText().Trim(); // If there was an empty line, check next one if (_line.Length == 0) { ts.LineDown(); ts.EndOfLine(); } // Otherwise the comment is not for a function else { return(false); } } } bool isFunction = codeElement != null && codeElement.Kind == vsCMElement.vsCMElementFunction; if (isFunction) { codeFunction = codeElement as CodeFunction; return(codeFunction != null); } // Return if the line containes a function or not return(isFunction); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Inserts the method header. /// </summary> /// ------------------------------------------------------------------------------------ public void InsertMethodHeader() { TextSelection sel = (TextSelection)m_applicationObject.ActiveDocument.Selection; CodeElement codeElement = GetMethodOrProperty(sel); if (codeElement == null) { codeElement = sel.ActivePoint.get_CodeElement(vsCMElement.vsCMElementClass); if (codeElement == null) { codeElement = sel.ActivePoint.get_CodeElement(vsCMElement.vsCMElementInterface); } if (codeElement == null || codeElement.StartPoint.Line != sel.ActivePoint.Line) { // not a function or property, so just insert /// <summary/> sel.LineUp(false, 1); if (!IsXmlCommentLine) { sel.EndOfLine(false); sel.NewLine(1); sel.Text = "///"; sel.LineDown(true, 1); sel.Delete(1); sel.LineUp(false, 1); sel.EndOfLine(false); sel.WordRight(true, 2); sel.Delete(1); } else { sel.LineDown(false, 1); } return; } } sel.MoveToPoint(codeElement.StartPoint, false); // Figure out indentation and build dashed line sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, false); sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, true); string indent = sel.Text; sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); string dashedLine = indent + "/// " + new string('-', kLineLen - sel.ActivePoint.VirtualDisplayColumn - 4); bool fGhostDoc = true; try { // Use GhostDoc if available string addinName = string.Empty; foreach (AddIn addin in m_applicationObject.AddIns) { if (addin.Name == "GhostDoc") { addinName = (addin.ProgID == "SubMain.GhostDoc.Connect") ? "Tools.SubMain.GhostDoc.DocumentThis" : "Weigelt.GhostDoc.AddIn.DocumentThis"; break; } } if (addinName != string.Empty) { m_applicationObject.ExecuteCommand(addinName, string.Empty); } else { fGhostDoc = false; } } catch { fGhostDoc = false; } if (fGhostDoc) { int nLine = sel.ActivePoint.Line; int nLineOffset = sel.ActivePoint.LineCharOffset; // Check to see if we're in the middle of the comment or at the beginning of // the method. sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); if (GetMethodOrProperty(sel) == null) { // we're in the middle of the comment - move to the end of the comment MoveDownAfterComment(sel); // we're inserting one line (//---) above nLine++; } else { // We are at the beginning of the method. // Check to see if the line above the current line is an attribute. If it is we want to // start there, otherwise we start at the current line. sel.LineUp(false, 1); sel.CharRight(false, 1); if (sel.ActivePoint.get_CodeElement(vsCMElement.vsCMElementAttribute) == null) { sel.MoveToLineAndOffset(nLine, 1, false); } // we're inserting two lines above nLine += 2; } // In case the line is wrapped, we want to go to the real beginning of the line sel.MoveToLineAndOffset(sel.ActivePoint.Line, 1, false); sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, false); // Insert a new line and then insert our dashed line. sel.Insert(dashedLine + Environment.NewLine, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.LineUp(false, 1); sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); MoveUpBeforeComment(sel); sel.Insert(Environment.NewLine + dashedLine, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); // put IP at previous location sel.MoveToLineAndOffset(nLine, nLineOffset, false); } else { // check if we already have a comment sel.LineUp(false, 1); if (!IsXmlCommentLine) { // Insert comment sel.EndOfLine(false); sel.NewLine(1); sel.Text = "///"; } // Insert line above MoveUpBeforeComment(sel); sel.EndOfLine(false); sel.NewLine(1); sel.Text = dashedLine; int upperLine = sel.ActivePoint.Line; sel.LineDown(false, 1); // reformat text for (; IsXmlCommentLine;) { int curLine = sel.CurrentLine; // go through all words in this line for (; sel.CurrentLine == curLine; sel.WordRight(false, 1)) { if (sel.ActivePoint.VirtualDisplayColumn > kLineLen) { // we have to break before this word sel.WordLeft(true, 1); // skip all punctuation characters for (; sel.Text.Length == 1 && char.IsPunctuation(sel.Text[0]);) { sel.CharLeft(false, 1); // removes selection sel.WordLeft(true, 1); } sel.CharLeft(false, 1); // removes selection // break the line sel.NewLine(1); // join next line with remainder of current line sel.EndOfLine(false); sel.LineDown(true, 1); sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, true); sel.WordRight(true, 1); sel.Delete(1); // insert a space between the two lines sel.Text = " "; } } } // Insert line below sel.GotoLine(upperLine + 1, false); MoveDownAfterComment(sel); sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); sel.NewLine(1); sel.LineUp(false, 1); sel.Text = dashedLine; sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); sel.LineDown(false, 1); } }
/// <summary> /// Creates and adds documentation comment blocks when the user types a triple slash. /// </summary> private void HandleTripleSlash() { ThreadHelper.ThrowIfNotOnUIThread(); // Get the original placement of the cursor in the code editor TextSelection ts = (TextSelection)Dte.ActiveDocument.Selection; int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; // Check to see if the previous line starts with a triple-slash; if it does, we should probably // just return because there's most likely a docstring already in place. ts.LineUp(); ts.StartOfLine(); string previousLine = TextView.TextSnapshot.GetLineFromPosition( TextView.Caret.Position.BufferPosition.Position).GetText(); if (previousLine.TrimStart().StartsWith("///")) { ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert("/"); // Add the slash that the user just typed return; } // Get the contents of the next line (the one following the original line) ts.LineDown(); ts.LineDown(); ts.StartOfLine(); int currentCharIndex = TextView.Caret.Position.BufferPosition.Position; string fullText = TextView.TextSnapshot.GetText(); // Check if we just triple-slashed a method (a function or an operation) Match methodMatch = GetMethodSignatureMatch(currentCharIndex, fullText); if (methodMatch != null) { Logger.Debug($"Found a potential method match: [{methodMatch.Value}]"); string signatureString = methodMatch.Groups["Signature"].Value; string leadingSpaces = methodMatch.Groups["Spaces"].Value; // Build the summary section, which is going to go in no matter what StringBuilder commentBuilder = new StringBuilder(); commentBuilder.AppendLine("/ # Summary"); commentBuilder.Append(leadingSpaces + "/// "); // Ask the Q# parser application to pull out all of the method details so we know what to // put into the documentation comments, and add them if parsing succeeded Logger.Debug("Sending a parse request to the Q# parser..."); try { MethodSignatureResponse signature = Messenger.RequestMethodSignatureParse(signatureString); if (signature != null) { Logger.Debug($"Parsing succeeded, method name = [{signature.Name}], " + $"{signature.ParameterNames.Count} parameters, returns something = {signature.HasReturnType}."); BuildMethodCommentBlock(signature, commentBuilder, leadingSpaces); } } catch (Exception ex) { Logger.Error($"Error during method signature request: {ex.GetType().Name} - {ex.Message}"); Logger.Trace(ex.StackTrace); } // Move to the original cursor position and add the comment block to the code ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert(commentBuilder.ToString()); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return; } // Check if we just triple-slashed a new type Match newtypeMatch = GetNewTypeMatch(currentCharIndex, fullText); if (newtypeMatch != null) { Logger.Debug($"Found a newtype match: [{newtypeMatch.Value}]"); string leadingSpaces = newtypeMatch.Groups["Spaces"].Value; // Build the summary section StringBuilder commentBuilder = new StringBuilder(); commentBuilder.AppendLine("/ # Summary"); commentBuilder.Append(leadingSpaces + "/// "); // Move to the original cursor position and add the comment block to the code ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert(commentBuilder.ToString()); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return; } // If this was a triple slash on something else, just add the slash and return. ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert("/"); }
/// <summary> /// Generates a Doxygen comment block to the current caret location. /// </summary> private void GenerateComment() { var currentILine = m_textView.TextSnapshot.GetLineFromPosition(m_textView.Caret.Position.BufferPosition.Position); int len = m_textView.Caret.Position.BufferPosition.Position - currentILine.Start.Position; string currentLine = m_textView.TextSnapshot.GetText(currentILine.Start.Position, len); string spaces = currentLine.Replace(currentLine.TrimStart(), ""); ThreadHelper.ThrowIfNotOnUIThread(); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; // Save current care position. int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; // Check if we're at the beginning of the document and should generate a file comment. if (oldLine == 1) { string fileComment = m_generator.GenerateFileComment(m_dte, out int selectedLine); ts.DeleteLeft(2); // Removing the // part here. ts.Insert(fileComment); // Move the caret. ts.MoveToLineAndOffset(selectedLine + 1, 1); ts.EndOfLine(); return; } // Search for the associated code element for which to generate the comment. CodeElement codeElement = null; ts.LineDown(); ts.EndOfLine(); FileCodeModel fcm = m_dte.ActiveDocument.ProjectItem.FileCodeModel; if (fcm != null) { while (codeElement == null) { codeElement = fcm.CodeElementFromPoint(ts.ActivePoint, vsCMElement.vsCMElementFunction); if (ts.ActivePoint.AtEndOfDocument) { break; } if (codeElement == null) { ts.LineDown(); } } } // Generate the comment and add it to the document. string doxyComment = m_generator.GenerateComment(spaces, codeElement, ""); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.DeleteLeft(2); // Removing the // part here. ts.Insert(doxyComment); // Move caret to the position where the main comment will be written. ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); }
private void method_6(object sender, RoutedEventArgs e) { Func <Document, bool> func = null; if (this.mainViewModel_0 != null && this.mainViewModel_0.SelectedSimilarity != null && this.mainViewModel_0.SelectedSimilarity.OtherFile != null && !string.IsNullOrEmpty(this.mainViewModel_0.SelectedSimilarity.OtherFile.Path)) { if (!Window1.bool_0) { try { System.Diagnostics.Process.Start("\"" + this.mainViewModel_0.SelectedSimilarity.OtherFile.Path + "\""); return; } catch (Exception) { System.Windows.MessageBox.Show("Couldn't open the file"); return; } } try { DTE2 dTE = null; try { System.Diagnostics.Process[] processesByName = System.Diagnostics.Process.GetProcessesByName("devenv"); if (processesByName.Length > 0) { Window1.ShowWindow(processesByName[processesByName.Length - 1].MainWindowHandle, 4); Window1.SetForegroundWindow(processesByName[processesByName.Length - 1].MainWindowHandle); } dTE = (DTE2)Marshal.GetActiveObject(Window1.string_0); } catch (Exception) { System.Diagnostics.Process.Start("\"" + this.mainViewModel_0.SelectedSimilarity.OtherFile.Path + "\""); } if (dTE != null) { System.Diagnostics.Process[] processesByName = System.Diagnostics.Process.GetProcessesByName("devenv"); if (processesByName.Length > 0) { Window1.ShowWindow(processesByName[processesByName.Length - 1].MainWindowHandle, 4); Window1.SetForegroundWindow(processesByName[processesByName.Length - 1].MainWindowHandle); } dTE = (DTE2)Marshal.GetActiveObject(Window1.string_0); } dTE.ItemOperations.OpenFile(this.mainViewModel_0.SelectedSimilarity.OtherFile.Path, "{7651A703-06E5-11D1-8EBD-00A0C90F26EA}"); IEnumerable <Document> enumerable = dTE.Documents.Cast <Document>().ToList <Document>(); foreach (Document current in enumerable) { Console.WriteLine(current.FullName); } IEnumerable <Document> arg_1E4_0 = enumerable; if (func == null) { func = new Func <Document, bool>(this.method_22); } Document document = arg_1E4_0.Where(func).First <Document>(); TextSelection textSelection = (TextSelection)document.Selection; textSelection.GotoLine(this.mainViewModel_0.SelectedSimilarity.OtherRange.Start + 1, false); textSelection.LineDown(true, this.mainViewModel_0.SelectedSimilarity.OtherRange.Length - 1); document.Activate(); } catch { } } }
/// <summary> /// Generates a Doxygen comment block to the current caret location. /// </summary> private void GenerateComment() { var currentILine = m_textView.TextSnapshot.GetLineFromPosition(m_textView.Caret.Position.BufferPosition.Position); int len = m_textView.Caret.Position.BufferPosition.Position - currentILine.Start.Position; string currentLine = m_textView.TextSnapshot.GetText(currentILine.Start.Position, len); string spaces = currentLine.Replace(currentLine.TrimStart(), ""); string next2char = m_textView.TextSnapshot.GetText(currentILine.Start.Position + len, 2); ThreadHelper.ThrowIfNotOnUIThread(); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; // Save current care position. int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; // Removing the auto inserted "*/" if (next2char == "*/") { ts.Delete(2); } // Check if we're at the beginning of the document and should generate a file comment. if (oldLine == 1) { string fileComment = m_generator.GenerateFileComment(m_dte, out int selectedLine); ts.DeleteLeft(2); // Removing the // part here. ts.Insert(fileComment); // Move the caret. ts.MoveToLineAndOffset(selectedLine + 1, 1); ts.EndOfLine(); return; } // Search for the associated code element for which to generate the comment. CodeElement codeElement = null; ts.LineDown(); ts.EndOfLine(); FileCodeModel fcm = this.GetFileCodeModel(m_dte.ActiveDocument); if (fcm != null) { while (codeElement == null) { codeElement = CodeElementFromPoint(fcm, ts.ActivePoint, vsCMElement.vsCMElementNamespace, vsCMElement.vsCMElementClass, vsCMElement.vsCMElementStruct, vsCMElement.vsCMElementEnum, vsCMElement.vsCMElementFunction, vsCMElement.vsCMElementUnion); if (ts.ActivePoint.AtEndOfDocument) { break; } if (codeElement == null) { ts.LineDown(); } } // if active line is in function body, set codeElement to null if (codeElement is CodeFunction function && oldLine > codeElement.StartPoint.Line && oldLine < codeElement.EndPoint.Line) { codeElement = null; } } // Generate the comment and add it to the document. string doxyComment = m_generator.GenerateComment(spaces, codeElement, ""); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.DeleteLeft(2); // Removing the // part here. ts.Insert(doxyComment); if (!m_generator.UseSingleLineComment(codeElement)) { // Move caret to the position where the main comment will be written. ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); } else { ts.MoveToLineAndOffset(oldLine, oldOffset + 2); } }
/// <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> private void Execute(object sender, EventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); var dte = Package.GetGlobalService(typeof(DTE)) as DTE; if (dte == null || dte.ActiveDocument == null) { return; } TextSelection ts = dte.ActiveDocument.Selection as TextSelection; // Check if we're at the beginning of the document and should generate a file comment. if (ts.ActivePoint.Line == 1) { string fileComment = m_generator.GenerateFileComment(dte, out int selectedLine); ts.DeleteLeft(2); // Removing the // part here. ts.Insert(fileComment); // Move the caret. ts.MoveToLineAndOffset(selectedLine + 1, 1); ts.EndOfLine(); return; } ts.EndOfLine(); // Scroll down until we find a non-comment line. if (!ScrollToCodeStart(ts)) { return; } // Save the position so that we know where to place the comment. ts.StartOfLine(); var funcPoint = ts.ActivePoint.CreateEditPoint(); int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; ts.EndOfLine(); // Determine indentation level. string currentLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line, ts.ActivePoint.Line + 1); string spaces = currentLine.Replace(currentLine.TrimStart(), ""); // Search for the associated code element. CodeElement codeElement = null; FileCodeModel fcm = dte.ActiveDocument.ProjectItem.FileCodeModel; if (fcm != null) { while (codeElement == null) { codeElement = fcm.CodeElementFromPoint(ts.ActivePoint, vsCMElement.vsCMElementFunction); if (ts.ActivePoint.AtEndOfDocument) { break; } if (codeElement == null || !(codeElement is CodeFunction)) { codeElement = null; ts.LineDown(); ts.EndOfLine(); } } } // Extract existing comment if found. ts.MoveToLineAndOffset(oldLine, oldOffset); int startLine = ExtractComment(ts, out string existingDoxyComment); // Delete old comment from the text. if (startLine >= 0) { ts.ActivePoint.CreateEditPoint().Delete(funcPoint); oldLine = ts.ActivePoint.Line; oldOffset = ts.ActivePoint.LineCharOffset; } // Generate new comment. string doxyComment = m_generator.GenerateComment(spaces, codeElement, existingDoxyComment); // Write the doxygen comment to the correct position. ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineUp(); // If the upper line is empty, we should go to the start of the line. Otherwise go to the end of the line. currentLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line, ts.ActivePoint.Line + 1); if (currentLine.Trim().Length == 0) { ts.StartOfLine(); } else { ts.EndOfLine(); } ts.Insert("\r\n" + spaces + doxyComment); // If this is a new comment, move to the main comment position immediately. if (startLine < 0) { ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); } }
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { try { if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { return(m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)); } // make a copy of this so we can look at it after forwarding some commands uint commandID = nCmdID; char typedChar = char.MinValue; // make sure the input is a char before getting it if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } // check for the triple slash if (typedChar == '/' && m_dte != null) { string currentLine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position).GetText(); if ((currentLine + "/").Trim() == "///") { // Calculate how many spaces string spaces = currentLine.Replace(currentLine.TrimStart(), ""); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; ts.LineDown(); ts.EndOfLine(); CodeElement codeElement = null; FileCodeModel fcm = m_dte.ActiveDocument.ProjectItem.FileCodeModel; if (fcm != null) { codeElement = fcm.CodeElementFromPoint(ts.ActivePoint, vsCMElement.vsCMElementFunction); } if (codeElement != null && codeElement is CodeFunction) { CodeFunction function = codeElement as CodeFunction; StringBuilder sb = new StringBuilder("/ <summary>\r\n" + spaces + "/// \r\n" + spaces + "/// </summary>"); foreach (CodeElement child in codeElement.Children) { CodeParameter parameter = child as CodeParameter; if (parameter != null) { sb.AppendFormat("\r\n" + spaces + "/// <param name=\"{0}\"></param>", parameter.Name); } } if (function.Type.AsString != "void") { sb.AppendFormat("\r\n" + spaces + "/// <returns></returns>"); } ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert(sb.ToString()); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return(VSConstants.S_OK); } else { ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert("/ <summary>\r\n" + spaces + "/// \r\n" + spaces + "/// </summary>"); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return(VSConstants.S_OK); } } } if (m_session != null && !m_session.IsDismissed) { // check for a commit character if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB || typedChar == '>') { // check for a selection // if the selection is fully selected, commit the current session if (m_session.SelectedCompletionSet.SelectionStatus.IsSelected) { string selectedCompletion = m_session.SelectedCompletionSet.SelectionStatus.Completion.DisplayText; m_session.Commit(); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; switch (selectedCompletion) { case "<!-->": ts.CharLeft(false, 3); break; case "<![CDATA[>": ts.CharLeft(false, 3); break; case "<c>": ts.CharLeft(false, 4); break; case "<code>": ts.CharLeft(false, 7); break; case "<example>": ts.CharLeft(false, 10); break; case "<exception>": ts.CharLeft(false, 14); break; case "<include>": ts.CharLeft(false, 21); break; case "<list>": ts.CharLeft(false, 7); break; case "<para>": ts.CharLeft(false, 7); break; case "<param>": ts.CharLeft(false, 10); break; case "<paramref>": ts.CharLeft(false, 13); break; case "<permission>": ts.CharLeft(false, 15); break; case "<remarks>": ts.CharLeft(false, 10); break; case "<returns>": ts.CharLeft(false, 10); break; case "<see>": ts.CharLeft(false, 3); break; case "<seealso>": ts.CharLeft(false, 3); break; case "<typeparam>": ts.CharLeft(false, 14); break; case "<typeparamref>": ts.CharLeft(false, 3); break; case "<value>": ts.CharLeft(false, 8); break; default: break; } // also, don't add the character to the buffer return(VSConstants.S_OK); } else { // if there is no selection, dismiss the session m_session.Dismiss(); } } } else { if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN) { string currentLine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position).GetText(); if (currentLine.TrimStart().StartsWith("///")) { TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; string spaces = currentLine.Replace(currentLine.TrimStart(), ""); ts.Insert("\r\n" + spaces + "/// "); return(VSConstants.S_OK); } } } // pass along the command so the char is added to the buffer int retVal = m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); if (typedChar == '<') { string currentLine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position).GetText(); if (currentLine.TrimStart().StartsWith("///")) { if (m_session == null || m_session.IsDismissed) // If there is no active session, bring up completion { if (this.TriggerCompletion()) { m_session.SelectedCompletionSet.SelectBestMatch(); m_session.SelectedCompletionSet.Recalculate(); return(VSConstants.S_OK); } } } } else if ( commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE || commandID == (uint)VSConstants.VSStd2KCmdID.DELETE || char.IsLetter(typedChar)) { if (m_session != null && !m_session.IsDismissed) // the completion session is already active, so just filter { m_session.SelectedCompletionSet.SelectBestMatch(); m_session.SelectedCompletionSet.Recalculate(); return(VSConstants.S_OK); } } return(retVal); } catch { } return(VSConstants.E_FAIL); }
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { try { if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { return(m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)); } // make a copy of this so we can look at it after forwarding some commands uint commandID = nCmdID; char typedChar = char.MinValue; // make sure the input is a char before getting it if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } if (m_dte != null) { string currentLine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position).GetText(); // check for the Javadoc slash and two asterisk pattern while compensating for visual studio's block comment closing generation if (typedChar == '*' && currentLine.Trim() == "/**/") { // Calculate how many spaces string spaces = currentLine.Replace(currentLine.TrimStart(), ""); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; //Remember where the cursor was when command was triggered int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; ts.LineDown(); ts.EndOfLine(); ts.SelectLine(); //Detect and skip over Unreal Engine Function Macros string trimmedFuncLine = ts.Text.Trim(); if (trimmedFuncLine != "" && trimmedFuncLine.StartsWith("UFUNCTION(")) { ts.EndOfLine(); } else { ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); } CodeElement codeElement = null; FileCodeModel fcm = m_dte.ActiveDocument.ProjectItem.FileCodeModel; if (fcm != null) { codeElement = fcm.CodeElementFromPoint(ts.ActivePoint, vsCMElement.vsCMElementFunction); } if (codeElement != null && codeElement is CodeFunction) { CodeFunction function = codeElement as CodeFunction; StringBuilder sb = new StringBuilder("*"); bool isNoArgsNoReturn = true; foreach (CodeElement child in codeElement.Children) { CodeParameter parameter = child as CodeParameter; if (parameter != null) { sb.AppendFormat("\r\n" + spaces + " * @param {0} ", parameter.Name); isNoArgsNoReturn = false; } } if (function.Type.AsString != "void") { isNoArgsNoReturn = false; if (function.Type.AsString == "bool") { sb.AppendFormat("\r\n" + spaces + " * @return true \r\n" + spaces + " * @return false "); } else { sb.AppendFormat("\r\n" + spaces + " * @return "); } } //If function has a return type or parameters then we generate them and return, otherwise we skip to generate a single line comment if (!isNoArgsNoReturn) { sb.Insert(1, "\r\n" + spaces + " * "); sb.AppendFormat("\r\n" + spaces + " "); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert(sb.ToString()); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return(VSConstants.S_OK); } } //For variables and void functions with no parameters we can do a single line comment ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert("* "); ts.MoveToLineAndOffset(oldLine, oldOffset + 2); return(VSConstants.S_OK); } else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN) { //Get text on current line before and after cursor TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; ts.EndOfLine(true); string afterCursor = ts.Text; ts.MoveToLineAndOffset(oldLine, oldOffset); ts.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, true); string beforeCursor = ts.Text; string beforeCursorTrimmed = beforeCursor.TrimStart(); ts.MoveToLineAndOffset(oldLine, oldOffset); // Calculate how many spaces string spaces = beforeCursorTrimmed == "" ? beforeCursor : beforeCursor.Replace(beforeCursorTrimmed, ""); bool hasAsteriskBeforeCursor = beforeCursorTrimmed == "" ? false : beforeCursorTrimmed.StartsWith("* "); bool hasBlockTerminatorAfterCursor = afterCursor == "" ? false : afterCursor.EndsWith("*/"); bool hasBlockTerminatorDirectlyAfterCursor = hasBlockTerminatorAfterCursor && afterCursor.Trim() == "*/"; //Add a space to maintain correct asterisk alignment if needed if (beforeCursorTrimmed != "" && beforeCursorTrimmed.StartsWith("/*")) { hasAsteriskBeforeCursor = true; spaces += " "; } if (hasAsteriskBeforeCursor) { ts.Insert("\r\n" + spaces); if (!hasBlockTerminatorAfterCursor) { ts.Insert("* "); } else if (hasBlockTerminatorDirectlyAfterCursor) { ts.Delete(afterCursor.Length); ts.Insert("*/"); ts.MoveToLineAndOffset(ts.ActivePoint.Line, ts.ActivePoint.LineCharOffset - 2); } return(VSConstants.S_OK); } else if (hasBlockTerminatorAfterCursor) { ts.Insert("* \r\n" + spaces); if (hasBlockTerminatorDirectlyAfterCursor) { ts.Delete(afterCursor.Length); ts.Insert("*/"); ts.MoveToLineAndOffset(ts.ActivePoint.Line, ts.ActivePoint.LineCharOffset - 2); } return(VSConstants.S_OK); } } } // pass along the command so the char is added to the buffer return(m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)); } catch { } return(VSConstants.E_FAIL); }
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { try { if (VsShellUtilities.IsInAutomationFunction(m_provider.ServiceProvider)) { return(m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut)); } // make a copy of this so we can look at it after forwarding some commands uint commandID = nCmdID; char typedChar = char.MinValue; // make sure the input is a char before getting it if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.TYPECHAR) { typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); } // check for the triple slash if (typedChar == '!' && m_dte != null) { var currentILine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position); int len = m_textView.Caret.Position.BufferPosition.Position - currentILine.Start.Position; string currentLine = m_textView.TextSnapshot.GetText(currentILine.Start.Position, len); string currentLineFull = currentILine.GetText(); if ((currentLine + typedChar).Trim() == "/*!") { // Calculate how many spaces string spaces = currentLine.Replace(currentLine.TrimStart(), ""); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; if (!currentLineFull.Contains("*/")) { ts.Insert("*/"); } ts.LineDown(); ts.EndOfLine(); CodeElement codeElement = null; FileCodeModel fcm = m_dte.ActiveDocument.ProjectItem.FileCodeModel; if (fcm != null) { while (codeElement == null) { codeElement = fcm.CodeElementFromPoint(ts.ActivePoint, vsCMElement.vsCMElementFunction); if (codeElement == null) { ts.LineDown(); } } } var cls = codeElement as VCCodeClass; var cls2 = codeElement as CodeClass; var fnc = codeElement as VCCodeFunction; var kind = codeElement.Kind; if (codeElement != null && codeElement is CodeFunction) { VCCodeFunction function = codeElement as VCCodeFunction; StringBuilder sb = new StringBuilder("!\r\n" + spaces + " * \r\n" + spaces + " * "); foreach (CodeElement child in codeElement.Children) { CodeParameter parameter = child as CodeParameter; if (parameter != null) { sb.AppendFormat("\r\n" + spaces + " * \\param {0}", parameter.Name); } } if (function.Type.AsString != "void") { sb.AppendFormat("\r\n" + spaces + " * \\return "); } sb.AppendFormat("\r\n" + spaces + " "); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert(sb.ToString()); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return(VSConstants.S_OK); } else if (codeElement != null && codeElement is VCCodeClass) { VCCodeClass function = codeElement as VCCodeClass; StringBuilder sb = new StringBuilder("!\r\n" + spaces + " * \r\n" + spaces + " * "); foreach (CodeElement child in function.TemplateParameters) { CodeParameter parameter = child as CodeParameter; if (parameter != null) { sb.AppendFormat("\r\n" + spaces + " * \\tparam {0}", parameter.Name); } } sb.AppendFormat("\r\n" + spaces + " "); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert(sb.ToString()); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return(VSConstants.S_OK); } else { ts.MoveToLineAndOffset(oldLine, oldOffset); ts.Insert("!\r\n" + spaces + " * \r\n" + spaces + " * \r\n" + spaces + " "); ts.MoveToLineAndOffset(oldLine, oldOffset); ts.LineDown(); ts.EndOfLine(); return(VSConstants.S_OK); } } } if (m_session != null && !m_session.IsDismissed) { // check for a commit character if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB) { // check for a selection // if the selection is fully selected, commit the current session if (m_session.SelectedCompletionSet.SelectionStatus.IsSelected) { string selectedCompletion = m_session.SelectedCompletionSet.SelectionStatus.Completion.DisplayText; m_session.Commit(); // also, don't add the character to the buffer return(VSConstants.S_OK); } else { // if there is no selection, dismiss the session m_session.Dismiss(); } } } else { if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN) { string currentLine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position).GetText(); if (currentLine.TrimStart().StartsWith("*")) { TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; string spaces = currentLine.Replace(currentLine.TrimStart(), ""); ts.Insert("\r\n" + spaces + "* "); return(VSConstants.S_OK); } } } // pass along the command so the char is added to the buffer int retVal = m_nextCommandHandler.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); if (typedChar == '\\') { string currentLine = m_textView.TextSnapshot.GetLineFromPosition( m_textView.Caret.Position.BufferPosition.Position).GetText(); if (currentLine.TrimStart().StartsWith("*")) { if (m_session == null || m_session.IsDismissed) // If there is no active session, bring up completion { if (this.TriggerCompletion()) { m_session.SelectedCompletionSet.SelectBestMatch(); m_session.SelectedCompletionSet.Recalculate(); return(VSConstants.S_OK); } } } } else if ( commandID == (uint)VSConstants.VSStd2KCmdID.BACKSPACE || commandID == (uint)VSConstants.VSStd2KCmdID.DELETE || char.IsLetter(typedChar)) { if (m_session != null && !m_session.IsDismissed) // the completion session is already active, so just filter { m_session.SelectedCompletionSet.SelectBestMatch(); m_session.SelectedCompletionSet.Recalculate(); return(VSConstants.S_OK); } } return(retVal); } catch { } return(VSConstants.E_FAIL); }