/// ------------------------------------------------------------------------------------ /// <summary> /// Goes to the previous function header. /// </summary> /// ------------------------------------------------------------------------------------ public void GotoFunctionHeaderUp() { TextSelection sel = (TextSelection)m_applicationObject.ActiveDocument.Selection; TextPoint curPoint = sel.ActivePoint; CodeElement codeElement = GetMethodOrProperty(sel); bool fGotoPrevMethod = true; if (codeElement != null) { TextPoint startPoint = codeElement.StartPoint; if (curPoint.AbsoluteCharOffset != startPoint.AbsoluteCharOffset) { fGotoPrevMethod = false; } curPoint = startPoint; } if (fGotoPrevMethod) { CodeElement newElement = codeElement; while ((newElement == codeElement || newElement == null) && sel.CurrentLine > 1) { sel.LineUp(false, 1); newElement = GetMethodOrProperty(sel); } if (newElement != null) { curPoint = newElement.StartPoint; } } sel.MoveToPoint(curPoint, false); }
/// <summary> /// Creates a new comment line based on the position of the caret and Doxygen configuration. /// </summary> /// <param name="currentLine">Current line for reference.</param> private void NewCommentLine(string currentLine) { ThreadHelper.ThrowIfNotOnUIThread(); string startSpaces = currentLine.Replace(currentLine.TrimStart(), ""); string endSpaces = currentLine.Replace(currentLine.TrimEnd(), ""); TextSelection ts = m_dte.ActiveDocument.Selection as TextSelection; // Try to also guess proper indentation level based on the current line. int oldLine = ts.ActivePoint.Line; int oldOffset = ts.ActivePoint.LineCharOffset; int extraIndent = 0; while (!currentLine.StartsWith("/*!")) { if (m_regexTagSection.IsMatch(currentLine)) { extraIndent = m_configService.Config.TagIndentation; break; } ts.LineUp(); currentLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line, ts.ActivePoint.Line + 1); currentLine = currentLine.TrimStart(); } // Remove extra spaces from the previous line and add tag start line. ts.MoveToLineAndOffset(oldLine, oldOffset); ts.DeleteLeft(endSpaces.Length); // TODO: This adds trailing space. Get rid of it similarly to SmartIndent(). ts.Insert(m_generator.GenerateTagStartLine(startSpaces) + new string(' ', extraIndent)); }
/// <summary> /// Extracts comment from the current text selection location. /// </summary> /// <param name="ts">Text selection.</param> /// <param name="comment">Extracted comment</param> /// <returns>The start line of the comment. -1, if no comment was found.</returns> private int ExtractComment(TextSelection ts, out string comment) { ThreadHelper.ThrowIfNotOnUIThread(); comment = ""; string curLine = ""; int startLine = -1; int endLine = -1; do { ts.LineUp(); curLine = ts.ActivePoint.CreateEditPoint().GetLines(ts.ActivePoint.Line, ts.ActivePoint.Line + 1); curLine = curLine.TrimStart(); // Check if we found the beginning of the comment. if (curLine.StartsWith("/*!")) { startLine = ts.ActivePoint.Line; break; } // Check for the end of the comment. else if (curLine.StartsWith("*/")) { endLine = ts.ActivePoint.Line; } } while (curLine.Length == 0 || curLine.StartsWith("*")); if (startLine >= 0 && endLine >= ts.ActivePoint.Line) { comment = ts.ActivePoint.CreateEditPoint().GetLines(startLine, endLine + 1); } return(startLine); }
/// <summary> /// Adds the header comment. /// </summary> /// <param name="instance">The instance.</param> /// <param name="headerComment">The header comment.</param> public static void AddHeaderComment( this ProjectItem instance, string headerComment) { TextSelection selection = (TextSelection)instance.Document.Selection; selection.StartOfDocument(); selection.NewLine(); selection.LineUp(); selection.Text = headerComment; }
/// <summary> /// Adds the header comment. /// </summary> /// <param name="instance">The instance.</param> /// <param name="headerComment">The header comment.</param> public static void AddHeaderComment( this ProjectItem instance, string headerComment) { TraceService.WriteLine("ProjectItemExtensions::AddHeaderComment"); TextSelection selection = (TextSelection)instance.Document.Selection; selection.StartOfDocument(); selection.NewLine(); selection.LineUp(); selection.Text = headerComment; }
public bool ToggleAllRegions(EnvDTE.Document doc, bool closeAll) { bool open = false; TextSelection ts = (TextSelection)doc.Selection; string startpattern; string endpattern; if (!this.GetPatterns(doc, out startpattern, out endpattern)) { return(false); } ts.EndOfDocument(false); EditPoint ep = ts.ActivePoint.CreateEditPoint(); string line; while (!ep.AtStartOfDocument) { ts.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, false); ts.LineUp(true, 1); line = ts.Text.ToLower().Trim(); if (line.StartsWith(endpattern)) { open = true; } else if (line.StartsWith(startpattern)) { if (closeAll) { if (open) { doc.DTE.ExecuteCommand("Edit.ToggleOutliningExpansion", ""); } } else { if (!open) { doc.DTE.ExecuteCommand("Edit.ToggleOutliningExpansion", ""); } } open = false; } ep = ts.ActivePoint.CreateEditPoint(); } toogleRegionDocument = doc; ts.Cancel(); return(true); }
/// <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> /// Moves the down after comment. /// </summary> /// <param name="sel">The sel.</param> /// ------------------------------------------------------------------------------------ private void MoveDownAfterComment(TextSelection sel) { // Go to the beginning of the line and move down until we find a line that doesn't // start with ///. while (true) { sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); sel.EndOfLine(true); if (!sel.Text.StartsWith("///")) { break; } // GhostDoc messes up dashed lines from inherited comments from base class, // so delete those if (sel.Text.StartsWith("/// -----")) { sel.WordRight(true, 1); sel.Delete(1); sel.LineUp(false, 1); } sel.MoveToLineAndOffset(sel.ActivePoint.Line + 1, 1, false); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Moves the down after comment. /// </summary> /// <param name="sel">The sel.</param> /// ------------------------------------------------------------------------------------ private void MoveDownAfterComment(TextSelection sel) { // Go to the beginning of the line and move down until we find a line that doesn't // start with ///. while (true) { sel.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); sel.EndOfLine(true); if (!sel.Text.StartsWith("///")) break; // GhostDoc messes up dashed lines from inherited comments from base class, // so delete those if (sel.Text.StartsWith("/// -----")) { sel.WordRight(true, 1); sel.Delete(1); sel.LineUp(false, 1); } sel.MoveToLineAndOffset(sel.ActivePoint.Line + 1, 1, false); } }
/// ------------------------------------------------------------------------------------ /// <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("/"); }
protected int ShowEventHandler(string document, string codeBehind, string codeBehindFile, string className, string objectTypeName, string eventName, string eventHandlerName) { var projectItem = GetProjectItem(document, codeBehind, codeBehindFile); var binder = GetBinder(projectItem); if (binder == null) { return(NativeMethods.E_FAIL); } projectItem.Open(EnvDTE.Constants.vsViewKindCode); var function = binder.FindEventHandler(className, objectTypeName, eventName, eventHandlerName); if (function != null) { bool prevLineIsEmpty = true; EditPoint point = function.EndPoint.CreateEditPoint(); point.LineUp(1); string lines = point.GetLines(point.Line, (int)(point.Line + 1)); for (int i = 0; i < lines.Length; i++) { if (!char.IsWhiteSpace(lines[i])) { prevLineIsEmpty = false; break; } } Document document2 = projectItem.Document; if (document2 != null) { Window activeWindow = document2.ActiveWindow; if (activeWindow != null) { TextSelection selection = activeWindow.Selection as TextSelection; if (selection != null) { selection.MoveToPoint(function.EndPoint, false); if (prevLineIsEmpty) { selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText, false); int virtualCharOffset = selection.AnchorPoint.VirtualCharOffset; selection.LineUp(false, 1); if (selection.AnchorPoint.VirtualCharOffset <= virtualCharOffset) { int indentSize = 4; TextDocument document3 = document2 as TextDocument; if (document3 != null) { indentSize = document3.IndentSize; } selection.MoveToLineAndOffset(selection.AnchorPoint.Line, (int)(virtualCharOffset + indentSize), false); } } else { selection.LineUp(false, 1); //selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, false); selection.EndOfLine(false); } } } } } return(NativeMethods.S_OK); }
private void EnterTextToActiveDocument(string text) { if (Statics.DTE.ActiveDocument == null) { MessageBox.Show("No active document is visible to write the generated code in, copying to clipboard instead (press ctrl-v on the document you want to place the code into)", "No Active Document", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); Clipboard.Clear(); if (!string.IsNullOrEmpty(text)) { Clipboard.SetText(text); } return; } TextSelection sel = (TextSelection)Statics.DTE.ActiveDocument.Selection; TextRanges dummy = null; if (Statics.Language == ProjectLanguage.CSharp) { bool isRegionExists = false; sel.StartOfDocument(true); if (sel.FindPattern("#region Temporary Recording", (int)vsFindOptions.vsFindOptionsMatchInHiddenText, ref dummy)) { isRegionExists = true; } sel.EndOfDocument(true); sel.FindPattern("}", (int)(vsFindOptions.vsFindOptionsBackwards | vsFindOptions.vsFindOptionsMatchInHiddenText), ref dummy); sel.FindPattern("}", (int)(vsFindOptions.vsFindOptionsBackwards | vsFindOptions.vsFindOptionsMatchInHiddenText), ref dummy); if (isRegionExists) { sel.FindPattern("#endregion", (int)(vsFindOptions.vsFindOptionsBackwards | vsFindOptions.vsFindOptionsMatchInHiddenText), ref dummy); } sel.LineUp(true, 1); if (!isRegionExists) { sel.Insert("\t\t#region Temporary Recording Code\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); } sel.Insert("\t\tprivate void " + GetAvailableMethodName() + "()\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert("\t\t{\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert(text, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert("\r\n\t\t}\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); if (!isRegionExists) { sel.Insert("\t\t#endregion\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert("\t}\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); } } else if (Statics.Language == ProjectLanguage.VB) { sel.EndOfDocument(true); sel.FindPattern("End Class", (int)(vsFindOptions.vsFindOptionsBackwards | vsFindOptions.vsFindOptionsMatchInHiddenText), ref dummy); //sel.LineUp(true, 1); sel.Insert("\tPrivate Sub " + GetAvailableMethodName() + "()\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert(text, (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert("\tEnd Sub\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); sel.Insert("End Class\r\n", (int)vsInsertFlags.vsInsertFlagsCollapseToEnd); } //sel.SelectAll(); Statics.DTE.ActiveDocument.Activate(); System.Threading.Thread.Sleep(200); Statics.DTE.ExecuteCommand("Edit.FormatDocument", string.Empty); }
/// <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(); } }