/** Copy constructor does deep copy */ public CommentBlock(CommentBlock other) { this.mName = other.mName; this.mFileAssociations = (string[])other.mFileAssociations.Clone(); this.mBlockStartType = other.mBlockStartType; this.mBlockStart = other.mBlockStart; this.mIsBlockStartRegEx = other.mIsBlockStartRegEx; this.mBlockEndType = other.mBlockEndType; this.mBlockEnd = other.mBlockEnd; this.mIsBlockEndRegEx = other.mIsBlockEndRegEx; this.mLineStart = other.mLineStart; this.mOnlyEmptyLineBeforeStartOfBlock = other.mOnlyEmptyLineBeforeStartOfBlock; }
private void BlockNewButton_Click(object sender, EventArgs args) { if (!validateSelectedBlock(true)) return; var list = new List<string>(); list.Add("*.new"); CommentBlock cb = new CommentBlock( "New comment block", list.ToArray(), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "#", false); _params.mCommentBlocks.Add(cb); BlockList.Items.Add(new ListViewItem(cb.mName)); int index = BlockList.Items.Count-1; selectBlockListItem(index); BlockList.Items[index].EnsureVisible(); BlockList.Items[index].BeginEdit(); updateItemsForBlock(index); }
/** * Determines if a block contains the given point, and is fo returns the * CommentBlock and MatchedBlockData for the match. */ public static bool GetBlockContainingPoint( ParameterSet pset, string fileName, EnvDTE.TextPoint pt, out CommentBlock retblock, out MatchedBlockData bdata) { retblock = null; bdata = new MatchedBlockData(); bdata.mEndLine = 0; bdata.mStartLine = 0; bdata.mIndentation = 0; EnvDTE.EditPoint ep = pt.CreateEditPoint(); EnvDTE.EditPoint enddoc = pt.CreateEditPoint(); enddoc.EndOfDocument(); string line = GetUntabbedLine(enddoc,ep.Line); foreach (CommentBlock block in pset.getBlocksForFileName(fileName)) { if (block.lineHasBlockPattern(line,out bdata.mIndentation)) { int currentLineNumber = ep.Line; // scan up for block start bool foundStart = false; for ( ;currentLineNumber >= 1; currentLineNumber--) { string currentLine = GetUntabbedLine(enddoc, currentLineNumber); string previousLine = GetUntabbedLine(enddoc, currentLineNumber-1); string nextLine = GetUntabbedLine(enddoc, currentLineNumber+1); if (block.lineIsStartOfBlock(currentLine, previousLine, bdata.mIndentation, out bdata.mMatchedBlockStart, out bdata.mSpacesTrimmedOffBlockStart)) { bdata.mStartLine = currentLineNumber; foundStart = true; break; } else if (!block.lineIsBlockContinuation(currentLine,bdata.mIndentation) && !block.lineIsEndOfBlock(currentLine,nextLine,bdata.mIndentation,out bdata.mMatchedBlockEnd)) { break; } } if (foundStart) { bool foundEnd = false; for ( ; currentLineNumber <= enddoc.Line ; currentLineNumber++) { string currentLine = GetUntabbedLine(enddoc, currentLineNumber); string nextLine = GetUntabbedLine(enddoc, currentLineNumber+1); if (block.lineIsEndOfBlock(currentLine, nextLine,bdata.mIndentation,out bdata.mMatchedBlockEnd)) { bdata.mEndLine = currentLineNumber; foundEnd = true; break; } else if ((currentLineNumber != bdata.mStartLine) && (!block.lineIsBlockContinuation(currentLine,bdata.mIndentation))) { break; } } if (foundEnd) { retblock = block; return true; } // else try next block } // else try next block } } return false; }
private static void WrapBlock( ParameterSet pset, CommentBlock block, MatchedBlockData bdata, EnvDTE.TextPoint pt) { int blockTabSize = pt.Parent.TabSize; if (!pset.mUseTabsToIndent) { blockTabSize = 0; } bool isInPreformmatedBlock = false; bool isLastLine = false; bool isStartOnSeparateLine = false; EnvDTE.EditPoint curPoint = pt.CreateEditPoint(); curPoint.MoveToLineAndOffset(bdata.mStartLine,1); // seems we have to pick the reight line ending ourselves string eol = "\r\n"; if (curPoint.GetText(-1).Length == 1) { eol = "\n"; } EnvDTE.EditPoint endPoint = pt.CreateEditPoint(); endPoint.MoveToLineAndOffset(bdata.mEndLine,1); if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) || (block.mBlockEndType == StartEndBlockType.NeverOnOwnLine)) { // delete the end block string endPoint.StartOfLine(); SkipColumns(endPoint, bdata.mIndentation); if (GetTextOnLine(endPoint, bdata.mMatchedBlockEnd.Length) == bdata.mMatchedBlockEnd) { // delete the whole line endPoint.EndOfLine(); EnvDTE.EditPoint secondLastLinePoint = endPoint.CreateEditPoint(); secondLastLinePoint.LineUp(1); secondLastLinePoint.EndOfLine(); secondLastLinePoint.Delete(endPoint); } else { // delete just the string EnvDTE.EditPoint eolPoint = endPoint.CreateEditPoint(); eolPoint.EndOfLine(); int endOffset = endPoint.GetText(eolPoint).LastIndexOf(bdata.mMatchedBlockEnd); endPoint.CharRight(endOffset); endPoint.Delete(eolPoint); } } else if (block.mBlockEndType == StartEndBlockType.AlwaysOnOwnLine) { // just move up al line as there is nothing interesting on it endPoint.LineUp(1); } endPoint.EndOfLine(); // now loop down the lines while (!isLastLine) { if (curPoint.Line >= endPoint.Line) { isLastLine = true; } curPoint.StartOfLine(); if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.AlwaysOnOwnLine)) { curPoint.LineDown(1);// simply go to the next line continue; } else if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.NeverOnOwnLine)) { SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart); } else if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne)) { // we will automatically pull up the next line if we can. We // also haqndle the case where traling spaces from the block // start have been removed SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart); if ((!AtLineEndIgnoringWhiteSpace(curPoint)) || isLastLine) { isStartOnSeparateLine = false; } else if (LineJustContainsContinuation(curPoint.Line+1,bdata.mIndentation,block.mLineStart, pset, pt)) { isStartOnSeparateLine = true; } else { isStartOnSeparateLine = false; if (bdata.mSpacesTrimmedOffBlockStart > 0) { curPoint.Insert(new String(' ', bdata.mSpacesTrimmedOffBlockStart)); // change these as we reprocess line! bdata.mMatchedBlockStart += new String(' ', bdata.mSpacesTrimmedOffBlockStart); bdata.mSpacesTrimmedOffBlockStart = 0; } EnvDTE.EditPoint nextLineStartPoint = curPoint.CreateEditPoint(); nextLineStartPoint.LineDown(1); nextLineStartPoint.StartOfLine(); SkipColumns(nextLineStartPoint, bdata.mIndentation); SkipString(nextLineStartPoint, block.mLineStart); curPoint.Delete(nextLineStartPoint); continue;// reprocess the line as it now may be last } } else // just a regular line start { // pass over line start SkipColumns(curPoint, bdata.mIndentation); if (GetTextOnLine(curPoint, block.mLineStart.Length) != block.mLineStart) { if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && (GetTextOnLine(curPoint, bdata.mMatchedBlockEnd.Length) == bdata.mMatchedBlockEnd)) { break;// we are done! } else if (GetTextOnLine(curPoint, block.mLineStart.TrimEnd().Length) == block.mLineStart.TrimEnd()) { curPoint.LineDown(1); continue;// empty line with just trimmed block line // start } else { throw new System.ArgumentException("Error parsing block line start"); } } curPoint.CharRight(block.mLineStart.Length); } // ASSERT: past the comment block start or comment line start // for the line int lastStartPre = GetRestOfLine(curPoint).ToLower().LastIndexOf("<pre>"); int lastEndPre = GetRestOfLine(curPoint).ToLower().LastIndexOf("</pre>"); // work out if we are in a preformatted block if ((lastStartPre != -1) && (lastStartPre > lastEndPre)) { isInPreformmatedBlock = true; } // check all cases that stop wrapping of this line to the next if (isInPreformmatedBlock || AtLineEndIgnoringWhiteSpace(curPoint) || pset.matchesBreakFlowString(GetRestOfLine(curPoint),false)) { if ((lastEndPre != -1) && (lastEndPre > lastStartPre)) { isInPreformmatedBlock = false; } curPoint.LineDown(1); continue; } bool breakLine = pset.matchesBreakFlowString(GetRestOfLine(curPoint),true); // work out if we are in a preformatted block if ((lastEndPre != -1) && (lastEndPre > lastStartPre)) { isInPreformmatedBlock = false; } // work out indent for current line int currentIndent = -1; int thisIndent; if (pset.matchesBulletPoint(GetRestOfLine(curPoint),out thisIndent, out currentIndent)) { // We need to convert current indent to number of columns // as at the moment it is number of characters. EnvDTE.EditPoint tempPoint = curPoint.CreateEditPoint(); tempPoint.CharRight(currentIndent); currentIndent = tempPoint.DisplayColumn - curPoint.DisplayColumn; // Now advance on this line by the size of the bullet point. curPoint.CharRight(thisIndent); } else { currentIndent = SkipWhitespace(curPoint); } if ((block.mBlockStartType == StartEndBlockType.NeverOnOwnLine) && (curPoint.Line == bdata.mStartLine) ) { // Need to account that on the first line the block start // may have a different length to the line start. // // Note the reason we do not do the multi/ single option here // is that if we are pulling up text onto the first line we // actually break the reflowing indentation rule. This all // needs to be thought through a bit better. currentIndent += bdata.mMatchedBlockStart.Length - block.mLineStart.Length; } int blockWrapWidth = pset.mWrapWidth; if ((bdata.mIndentation + block.mLineStart.Length + currentIndent + pset.mMinimumBlockWidth) > blockWrapWidth) { blockWrapWidth = bdata.mIndentation + block.mLineStart.Length + currentIndent + pset.mMinimumBlockWidth; } // Now see if we can wrap into the next line, or if we wrap by // inserting a new line before it. EnvDTE.EditPoint nextLinePoint = null; bool wrapIntoNextLine = false; if (!isLastLine && !breakLine) { nextLinePoint = curPoint.CreateEditPoint(); nextLinePoint.LineDown(1); nextLinePoint.StartOfLine(); SkipColumns(nextLinePoint, bdata.mIndentation); if ((block.mLineStart.TrimEnd().Length != block.mLineStart.Length) && (GetRestOfLine(nextLinePoint).CompareTo(block.mLineStart.TrimEnd()) == 0)) { // handle the next line that is completely empty with // rimmed line end nextLinePoint = null; } else { SkipString(nextLinePoint, block.mLineStart); if (!pset.matchesBulletPoint(GetRestOfLine(nextLinePoint)) && !pset.matchesBreakFlowString(GetRestOfLine(nextLinePoint),false) && (SkipWhitespace(nextLinePoint) == currentIndent)) { wrapIntoNextLine = true; } else { nextLinePoint = null; } } } // if on the first line and we can'd wrap the text into the next // line, then push any text on the first line down to a separate // line if ((block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && (curPoint.Line == bdata.mStartLine) && !wrapIntoNextLine && !isLastLine && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + block.mLineStart); continue; } // ASSERT: if we have got here, there is at least one word on // this line, and if wrapIntoNextLine then there is at least one // word on the next line // now go to the start of the first word that passes the wrap // point, or the end of the line if it is sooner int wordCount = 0; while (((curPoint.DisplayColumn-1) <= blockWrapWidth) && !AtLineEndIgnoringWhiteSpace(curPoint)) { wordCount++; GoToEndOfNextWord(curPoint); } if ((curPoint.DisplayColumn-1) <= blockWrapWidth) { // the end of line occurs at or before the wrap point. Try // to fill in the gap from the next line if we can if (!wrapIntoNextLine) { curPoint.LineDown(1); } else { int charsToFill = blockWrapWidth - ((curPoint.DisplayColumn-1)+1);//+1 for extra space EnvDTE.EditPoint nextLineEndPoint = nextLinePoint.CreateEditPoint(); int numChars = 0; int numWords =0; while ((numChars < charsToFill) && !AtLineEndIgnoringWhiteSpace(nextLineEndPoint)) { numWords++; GoToEndOfNextWord(nextLineEndPoint); numChars = nextLineEndPoint.DisplayColumn - nextLinePoint.DisplayColumn; } if ((numChars > charsToFill) && (numWords > 1)) { GoToEndOfPreviousWord(nextLineEndPoint); numChars = nextLineEndPoint.DisplayColumn - nextLinePoint.DisplayColumn; } if ((numChars <= 0) || (numChars > charsToFill)) { // the first word on the next line is too long to // pull up // push comment block start onto separate line and // retry if we can if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + block.mLineStart); } else { // just skip onto the next line curPoint.LineDown(1); } } else { // delete trailing whitespace from this line EnvDTE.EditPoint lineEndPoint = curPoint.CreateEditPoint(); lineEndPoint.EndOfLine(); curPoint.Delete(lineEndPoint); // get new string from next line and insert it string st = nextLinePoint.GetText(nextLineEndPoint); if (AtLineEndIgnoringWhiteSpace(nextLineEndPoint)) { // no text left on next line, so delete the // whole thing nextLineEndPoint.EndOfLine(); curPoint.Delete(nextLineEndPoint); curPoint.Insert(" " + st); // don't move curPoint down as we want to // reprocess this line in case there is more // room left } else { // there is still text left on the next line // push comment block start onto separate line // if neccesary if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + block.mLineStart); // reprocess this moved down line! } else { // remove trailing string as well as // trailing spaces while ((nextLineEndPoint.GetText(1) == " ") || (nextLineEndPoint.GetText(1) == "\t")) { nextLineEndPoint.CharRight(1); } nextLinePoint.Delete(nextLineEndPoint); curPoint.Insert(" " + st); curPoint.LineDown(1);//move to next line } } } } } else // ((curPoint.DisplayColumn-1) > blockWrapWidth) { // push start onto separate line if neccesary if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + block.mLineStart); isLastLine = false;// forces reprocess even if isLatLine // was just true continue;// reprocess the just moved line } // this line overflows the word wrap. Move back to the end // of the last word that doesn't overflow if possible if (wordCount > 1) { GoToEndOfPreviousWord(curPoint); } if (AtLineEndIgnoringWhiteSpace(curPoint)) { curPoint.LineDown(1);// the single line is too long, so // forget about it // and go to the next line } else { // copy the remainder of the line after a space but // delete the space as well if (!wrapIntoNextLine) { EnvDTE.EditPoint dataStartPoint = curPoint.CreateEditPoint(); SkipWhitespace(dataStartPoint); curPoint.Delete(dataStartPoint); // insert a whole new line curPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + block.mLineStart); if (currentIndent > 0) { curPoint.Insert(GetIndentationString(curPoint.DisplayColumn,currentIndent,blockTabSize)); } } else { // insert at the start of the next line EnvDTE.EditPoint dataStartPoint = curPoint.CreateEditPoint(); SkipWhitespace(dataStartPoint); EnvDTE.EditPoint lineEndPoint = curPoint.CreateEditPoint(); lineEndPoint.EndOfLine(); string st = dataStartPoint.GetText(lineEndPoint).TrimEnd(); curPoint.Delete(lineEndPoint); nextLinePoint.Insert(st + " "); curPoint.LineDown(1); } // if there is enough there to create one or multiple // lines, then create them while (true) { curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, block.mLineStart); SkipColumns(curPoint, currentIndent); int myWordCount = 0; while ((curPoint.DisplayColumn-1) <= blockWrapWidth && !AtLineEndIgnoringWhiteSpace(curPoint)) { myWordCount++; GoToEndOfNextWord(curPoint); } if ((curPoint.DisplayColumn-1) <= blockWrapWidth) { break; // don't move down a line as we want to // reprocess this line } if (myWordCount > 1) { GoToEndOfPreviousWord(curPoint); } if (AtLineEndIgnoringWhiteSpace(curPoint)) { break; } EnvDTE.EditPoint dataStartPoint = curPoint.CreateEditPoint(); SkipWhitespace(dataStartPoint); curPoint.Delete(dataStartPoint); curPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + block.mLineStart); if (currentIndent > 0) { curPoint.Insert(GetIndentationString(curPoint.DisplayColumn,currentIndent,blockTabSize)); } // process the just created line in the next // iteration } } } } if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && (endPoint.Line != bdata.mStartLine)) { endPoint.EndOfLine(); endPoint.Insert(eol + GetIndentationString(1,bdata.mIndentation,blockTabSize) + bdata.mMatchedBlockEnd); } else if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) || (block.mBlockEndType == StartEndBlockType.NeverOnOwnLine)) { endPoint.EndOfLine(); endPoint.Insert(bdata.mMatchedBlockEnd); } }
private void BlockNewButton_Click(object sender, System.EventArgs e) { if (!validateSelectedBlock(true)) { return; } ArrayList cPlusPlusCba = new ArrayList(); cPlusPlusCba.Add("*.new"); CommentBlock newObj = new CommentBlock("New comment block", (ArrayList)cPlusPlusCba.Clone(), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "#", false); mpset.mCommentBlocks.Add(newObj); BlockList.Items.Add(new ListViewItem(newObj.mName)); int index = BlockList.Items.Count-1; selectBlockListItem(index); BlockList.Items[index].EnsureVisible(); BlockList.Items[index].BeginEdit(); updateItemsForBlock(index); }
static private void WrapBlock( ParameterSet pset, CommentBlock block, MatchedBlockData bdata, EnvDTE.TextPoint pt) { int blockTabSize = pt.Parent.TabSize; if (!pset.mUseTabsToIndent) { blockTabSize = 0; } bool isInPreformmatedBlock = false; bool isLastLine = false; bool isStartOnSeparateLine = false; EnvDTE.EditPoint curPoint = pt.CreateEditPoint(); curPoint.MoveToLineAndOffset(bdata.mStartLine, 1); // seems we have to pick the reight line ending ourselves string eol = "\r\n"; if (curPoint.GetText(-1).Length == 1) { eol = "\n"; } EnvDTE.EditPoint endPoint = pt.CreateEditPoint(); endPoint.MoveToLineAndOffset(bdata.mEndLine, 1); if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) || (block.mBlockEndType == StartEndBlockType.NeverOnOwnLine)) { // delete the end block string endPoint.StartOfLine(); SkipColumns(endPoint, bdata.mIndentation); if (GetTextOnLine(endPoint, bdata.mMatchedBlockEnd.Length) == bdata.mMatchedBlockEnd) { // delete the whole line endPoint.EndOfLine(); EnvDTE.EditPoint secondLastLinePoint = endPoint.CreateEditPoint(); secondLastLinePoint.LineUp(1); secondLastLinePoint.EndOfLine(); secondLastLinePoint.Delete(endPoint); } else { // delete just the string EnvDTE.EditPoint eolPoint = endPoint.CreateEditPoint(); eolPoint.EndOfLine(); int endOffset = endPoint.GetText(eolPoint).LastIndexOf(bdata.mMatchedBlockEnd); endPoint.CharRight(endOffset); endPoint.Delete(eolPoint); } } else if (block.mBlockEndType == StartEndBlockType.AlwaysOnOwnLine) { // just move up al line as there is nothing interesting on it endPoint.LineUp(1); } endPoint.EndOfLine(); // now loop down the lines while (!isLastLine) { if (curPoint.Line >= endPoint.Line) { isLastLine = true; } curPoint.StartOfLine(); if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.AlwaysOnOwnLine)) { curPoint.LineDown(1);// simply go to the next line continue; } else if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.NeverOnOwnLine)) { SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart); } else if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne)) { // we will automatically pull up the next line if we can. We // also haqndle the case where traling spaces from the block // start have been removed SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart); if ((!AtLineEndIgnoringWhiteSpace(curPoint)) || isLastLine) { isStartOnSeparateLine = false; } else if (LineJustContainsContinuation(curPoint.Line + 1, bdata.mIndentation, block.mLineStart, pset, pt)) { isStartOnSeparateLine = true; } else { isStartOnSeparateLine = false; if (bdata.mSpacesTrimmedOffBlockStart > 0) { curPoint.Insert(new String(' ', bdata.mSpacesTrimmedOffBlockStart)); // change these as we reprocess line! bdata.mMatchedBlockStart += new String(' ', bdata.mSpacesTrimmedOffBlockStart); bdata.mSpacesTrimmedOffBlockStart = 0; } EnvDTE.EditPoint nextLineStartPoint = curPoint.CreateEditPoint(); nextLineStartPoint.LineDown(1); nextLineStartPoint.StartOfLine(); SkipColumns(nextLineStartPoint, bdata.mIndentation); SkipString(nextLineStartPoint, block.mLineStart); curPoint.Delete(nextLineStartPoint); continue;// reprocess the line as it now may be last } } else // just a regular line start { // pass over line start SkipColumns(curPoint, bdata.mIndentation); if (GetTextOnLine(curPoint, block.mLineStart.Length) != block.mLineStart) { if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && (GetTextOnLine(curPoint, bdata.mMatchedBlockEnd.Length) == bdata.mMatchedBlockEnd)) { break;// we are done! } else if (GetTextOnLine(curPoint, block.mLineStart.TrimEnd().Length) == block.mLineStart.TrimEnd()) { curPoint.LineDown(1); continue; // empty line with just trimmed block line // start } else { throw new System.ArgumentException("Error parsing block line start"); } } curPoint.CharRight(block.mLineStart.Length); } // ASSERT: past the comment block start or comment line start // for the line int lastStartPre = GetRestOfLine(curPoint).ToLower().LastIndexOf("<pre>"); int lastEndPre = GetRestOfLine(curPoint).ToLower().LastIndexOf("</pre>"); // work out if we are in a preformatted block if ((lastStartPre != -1) && (lastStartPre > lastEndPre)) { isInPreformmatedBlock = true; } // check all cases that stop wrapping of this line to the next if (isInPreformmatedBlock || AtLineEndIgnoringWhiteSpace(curPoint) || pset.matchesBreakFlowString(GetRestOfLine(curPoint), false)) { if ((lastEndPre != -1) && (lastEndPre > lastStartPre)) { isInPreformmatedBlock = false; } curPoint.LineDown(1); continue; } bool breakLine = pset.matchesBreakFlowString(GetRestOfLine(curPoint), true); // work out if we are in a preformatted block if ((lastEndPre != -1) && (lastEndPre > lastStartPre)) { isInPreformmatedBlock = false; } // work out indent for current line int currentIndent = -1; int thisIndent; if (pset.matchesBulletPoint(GetRestOfLine(curPoint), out thisIndent, out currentIndent)) { // We need to convert current indent to number of columns // as at the moment it is number of characters. EnvDTE.EditPoint tempPoint = curPoint.CreateEditPoint(); tempPoint.CharRight(currentIndent); currentIndent = tempPoint.DisplayColumn - curPoint.DisplayColumn; // Now advance on this line by the size of the bullet point. curPoint.CharRight(thisIndent); } else { currentIndent = SkipWhitespace(curPoint); } if ((block.mBlockStartType == StartEndBlockType.NeverOnOwnLine) && (curPoint.Line == bdata.mStartLine)) { // Need to account that on the first line the block start // may have a different length to the line start. // // Note the reason we do not do the multi/ single option here // is that if we are pulling up text onto the first line we // actually break the reflowing indentation rule. This all // needs to be thought through a bit better. currentIndent += bdata.mMatchedBlockStart.Length - block.mLineStart.Length; } int blockWrapWidth = pset.mWrapWidth; if ((bdata.mIndentation + block.mLineStart.Length + currentIndent + pset.mMinimumBlockWidth) > blockWrapWidth) { blockWrapWidth = bdata.mIndentation + block.mLineStart.Length + currentIndent + pset.mMinimumBlockWidth; } // Now see if we can wrap into the next line, or if we wrap by // inserting a new line before it. EnvDTE.EditPoint nextLinePoint = null; bool wrapIntoNextLine = false; if (!isLastLine && !breakLine) { nextLinePoint = curPoint.CreateEditPoint(); nextLinePoint.LineDown(1); nextLinePoint.StartOfLine(); SkipColumns(nextLinePoint, bdata.mIndentation); if ((block.mLineStart.TrimEnd().Length != block.mLineStart.Length) && (GetRestOfLine(nextLinePoint).CompareTo(block.mLineStart.TrimEnd()) == 0)) { // handle the next line that is completely empty with // rimmed line end nextLinePoint = null; } else { SkipString(nextLinePoint, block.mLineStart); if (!pset.matchesBulletPoint(GetRestOfLine(nextLinePoint)) && !pset.matchesBreakFlowString(GetRestOfLine(nextLinePoint), false) && (SkipWhitespace(nextLinePoint) == currentIndent)) { wrapIntoNextLine = true; } else { nextLinePoint = null; } } } // if on the first line and we can'd wrap the text into the next // line, then push any text on the first line down to a separate // line if ((block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && (curPoint.Line == bdata.mStartLine) && !wrapIntoNextLine && !isLastLine && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + block.mLineStart); continue; } // ASSERT: if we have got here, there is at least one word on // this line, and if wrapIntoNextLine then there is at least one // word on the next line // now go to the start of the first word that passes the wrap // point, or the end of the line if it is sooner int wordCount = 0; while (((curPoint.DisplayColumn - 1) <= blockWrapWidth) && !AtLineEndIgnoringWhiteSpace(curPoint)) { wordCount++; GoToEndOfNextWord(curPoint); } if ((curPoint.DisplayColumn - 1) <= blockWrapWidth) { // the end of line occurs at or before the wrap point. Try // to fill in the gap from the next line if we can if (!wrapIntoNextLine) { curPoint.LineDown(1); } else { int charsToFill = blockWrapWidth - ((curPoint.DisplayColumn - 1) + 1);//+1 for extra space EnvDTE.EditPoint nextLineEndPoint = nextLinePoint.CreateEditPoint(); int numChars = 0; int numWords = 0; while ((numChars < charsToFill) && !AtLineEndIgnoringWhiteSpace(nextLineEndPoint)) { numWords++; GoToEndOfNextWord(nextLineEndPoint); numChars = nextLineEndPoint.DisplayColumn - nextLinePoint.DisplayColumn; } if ((numChars > charsToFill) && (numWords > 1)) { GoToEndOfPreviousWord(nextLineEndPoint); numChars = nextLineEndPoint.DisplayColumn - nextLinePoint.DisplayColumn; } if ((numChars <= 0) || (numChars > charsToFill)) { // the first word on the next line is too long to // pull up // push comment block start onto separate line and // retry if we can if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + block.mLineStart); } else { // just skip onto the next line curPoint.LineDown(1); } } else { // delete trailing whitespace from this line EnvDTE.EditPoint lineEndPoint = curPoint.CreateEditPoint(); lineEndPoint.EndOfLine(); curPoint.Delete(lineEndPoint); // get new string from next line and insert it string st = nextLinePoint.GetText(nextLineEndPoint); if (AtLineEndIgnoringWhiteSpace(nextLineEndPoint)) { // no text left on next line, so delete the // whole thing nextLineEndPoint.EndOfLine(); curPoint.Delete(nextLineEndPoint); curPoint.Insert(" " + st); // don't move curPoint down as we want to // reprocess this line in case there is more // room left } else { // there is still text left on the next line // push comment block start onto separate line // if neccesary if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + block.mLineStart); // reprocess this moved down line! } else { // remove trailing string as well as // trailing spaces while ((nextLineEndPoint.GetText(1) == " ") || (nextLineEndPoint.GetText(1) == "\t")) { nextLineEndPoint.CharRight(1); } nextLinePoint.Delete(nextLineEndPoint); curPoint.Insert(" " + st); curPoint.LineDown(1);//move to next line } } } } } else // ((curPoint.DisplayColumn-1) > blockWrapWidth) { // push start onto separate line if neccesary if ((curPoint.Line == bdata.mStartLine) && (block.mBlockStartType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && !isStartOnSeparateLine) { isStartOnSeparateLine = true; curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, bdata.mMatchedBlockStart.TrimEnd()); curPoint.Delete(bdata.mMatchedBlockStart.Length - bdata.mMatchedBlockStart.TrimEnd().Length); curPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + block.mLineStart); isLastLine = false; // forces reprocess even if isLatLine // was just true continue; // reprocess the just moved line } // this line overflows the word wrap. Move back to the end // of the last word that doesn't overflow if possible if (wordCount > 1) { GoToEndOfPreviousWord(curPoint); } if (AtLineEndIgnoringWhiteSpace(curPoint)) { curPoint.LineDown(1); // the single line is too long, so // forget about it // and go to the next line } else { // copy the remainder of the line after a space but // delete the space as well if (!wrapIntoNextLine) { EnvDTE.EditPoint dataStartPoint = curPoint.CreateEditPoint(); SkipWhitespace(dataStartPoint); curPoint.Delete(dataStartPoint); // insert a whole new line curPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + block.mLineStart); if (currentIndent > 0) { curPoint.Insert(GetIndentationString(curPoint.DisplayColumn, currentIndent, blockTabSize)); } } else { // insert at the start of the next line EnvDTE.EditPoint dataStartPoint = curPoint.CreateEditPoint(); SkipWhitespace(dataStartPoint); EnvDTE.EditPoint lineEndPoint = curPoint.CreateEditPoint(); lineEndPoint.EndOfLine(); string st = dataStartPoint.GetText(lineEndPoint).TrimEnd(); curPoint.Delete(lineEndPoint); nextLinePoint.Insert(st + " "); curPoint.LineDown(1); } // if there is enough there to create one or multiple // lines, then create them while (true) { curPoint.StartOfLine(); SkipColumns(curPoint, bdata.mIndentation); SkipString(curPoint, block.mLineStart); SkipColumns(curPoint, currentIndent); int myWordCount = 0; while ((curPoint.DisplayColumn - 1) <= blockWrapWidth && !AtLineEndIgnoringWhiteSpace(curPoint)) { myWordCount++; GoToEndOfNextWord(curPoint); } if ((curPoint.DisplayColumn - 1) <= blockWrapWidth) { break; // don't move down a line as we want to // reprocess this line } if (myWordCount > 1) { GoToEndOfPreviousWord(curPoint); } if (AtLineEndIgnoringWhiteSpace(curPoint)) { break; } EnvDTE.EditPoint dataStartPoint = curPoint.CreateEditPoint(); SkipWhitespace(dataStartPoint); curPoint.Delete(dataStartPoint); curPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + block.mLineStart); if (currentIndent > 0) { curPoint.Insert(GetIndentationString(curPoint.DisplayColumn, currentIndent, blockTabSize)); } // process the just created line in the next // iteration } } } } if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) && (endPoint.Line != bdata.mStartLine)) { endPoint.EndOfLine(); endPoint.Insert(eol + GetIndentationString(1, bdata.mIndentation, blockTabSize) + bdata.mMatchedBlockEnd); } else if ((block.mBlockEndType == StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne) || (block.mBlockEndType == StartEndBlockType.NeverOnOwnLine)) { endPoint.EndOfLine(); endPoint.Insert(bdata.mMatchedBlockEnd); } }
/** * Determines if a block contains the given point, and is fo returns the * CommentBlock and MatchedBlockData for the match. */ static public bool GetBlockContainingPoint( ParameterSet pset, string fileName, EnvDTE.TextPoint pt, out CommentBlock retblock, out MatchedBlockData bdata) { retblock = null; bdata = new MatchedBlockData(); bdata.mEndLine = 0; bdata.mStartLine = 0; bdata.mIndentation = 0; EnvDTE.EditPoint ep = pt.CreateEditPoint(); EnvDTE.EditPoint enddoc = pt.CreateEditPoint(); enddoc.EndOfDocument(); string line = GetUntabbedLine(enddoc, ep.Line); foreach (CommentBlock block in pset.getBlocksForFileName(fileName)) { if (block.lineHasBlockPattern(line, out bdata.mIndentation)) { int currentLineNumber = ep.Line; // scan up for block start bool foundStart = false; for ( ; currentLineNumber >= 1; currentLineNumber--) { string currentLine = GetUntabbedLine(enddoc, currentLineNumber); string previousLine = GetUntabbedLine(enddoc, currentLineNumber - 1); string nextLine = GetUntabbedLine(enddoc, currentLineNumber + 1); if (block.lineIsStartOfBlock(currentLine, previousLine, bdata.mIndentation, out bdata.mMatchedBlockStart, out bdata.mSpacesTrimmedOffBlockStart)) { bdata.mStartLine = currentLineNumber; foundStart = true; break; } else if (!block.lineIsBlockContinuation(currentLine, bdata.mIndentation) && !block.lineIsEndOfBlock(currentLine, nextLine, bdata.mIndentation, out bdata.mMatchedBlockEnd)) { break; } } if (foundStart) { bool foundEnd = false; for ( ; currentLineNumber <= enddoc.Line; currentLineNumber++) { string currentLine = GetUntabbedLine(enddoc, currentLineNumber); string nextLine = GetUntabbedLine(enddoc, currentLineNumber + 1); if (block.lineIsEndOfBlock(currentLine, nextLine, bdata.mIndentation, out bdata.mMatchedBlockEnd)) { bdata.mEndLine = currentLineNumber; foundEnd = true; break; } else if ((currentLineNumber != bdata.mStartLine) && (!block.lineIsBlockContinuation(currentLine, bdata.mIndentation))) { break; } } if (foundEnd) { retblock = block; return(true); } // else try next block } // else try next block } } return(false); }
/** * Validates the comment block at the given index, throws an exception * if it is invalis */ public void validateCommentBlock(int index) { CommentBlock cb = (CommentBlock)mCommentBlocks[index]; if (cb.mName.Trim().Length == 0) { throw new System.ArgumentException("Comment block name must not be empty"); } int i = 0; foreach (CommentBlock bpother in mCommentBlocks) { if ((i != index) && (bpother.mName.CompareTo(cb.mName) == 0)) { throw new System.ArgumentException("Comment Block must be unique"); } i++; } if (cb.mBlockStartType == StartEndBlockType.Empty) { cb.mBlockStart = ""; } else { if (cb.mBlockStart.Trim().Length == 0) { throw new System.ArgumentException("Block start type is not empty but actual string only contains whitespace"); } if (cb.mIsBlockStartRegEx) { try { Regex regex = new Regex(cb.mBlockStart); } catch (Exception) { throw new System.ArgumentException("Block start regular expression is invalid"); } } } if (cb.mBlockEndType == StartEndBlockType.Empty) { cb.mBlockEnd = ""; } else { if (cb.mBlockEnd.Trim().Length == 0) { throw new System.ArgumentException("Block End type is not empty but actual string only contains whitespace"); } if (cb.mIsBlockEndRegEx) { try { Regex regex = new Regex(cb.mBlockEnd); } catch (Exception) { throw new System.ArgumentException("Block End regular expression is invalid"); } } } }
/** Default constuctor creates a default ParameterSet */ public ParameterSet() { var cPlusPlusCba = new List <string>(); cPlusPlusCba.Add("*.c"); cPlusPlusCba.Add("*.cpp"); cPlusPlusCba.Add("*.cs"); cPlusPlusCba.Add("*.cc"); cPlusPlusCba.Add("*.h"); mCommentBlocks.Add(new CommentBlock( "C style function block", cPlusPlusCba.ToArray(), StartEndBlockType.AlwaysOnOwnLine, @"/\*\*\*+", true, StartEndBlockType.AlwaysOnOwnLine, @" \*\*\*+/", true, " * ", true)); mCommentBlocks.Add(new CommentBlock( "Doxygen C style (/**)", cPlusPlusCba.ToArray(), StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne, "/** ", false, StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne, " */", false, " * ", false)); mCommentBlocks.Add(new CommentBlock( "Doxygen C style 2 (/*!), which may have text on first line", cPlusPlusCba.ToArray(), StartEndBlockType.NeverOnOwnLine, "/*! ", false, StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne, " */", false, " * ", false)); mCommentBlocks.Add(new CommentBlock( "C style", cPlusPlusCba.ToArray(), StartEndBlockType.NeverOnOwnLine, "/* ", false, StartEndBlockType.OnOwnLineIfBlockIsMoreThanOne, " */", false, " * ", false)); cPlusPlusCba.Add("*.js"); // ADD JAVASCRIPT AFTER C BLOCK COMMENTS // DONE! mCommentBlocks.Add(new CommentBlock( "C++ style function block", cPlusPlusCba.ToArray(), StartEndBlockType.AlwaysOnOwnLine, @"////+", true, StartEndBlockType.AlwaysOnOwnLine, @"////+", true, "// ", true)); mCommentBlocks.Add(new CommentBlock( "Doxygen C++ style (///)", cPlusPlusCba.ToArray(), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "/// ", false)); mCommentBlocks.Add(new CommentBlock( "Doxygen C++ style (///) with trailing tab", cPlusPlusCba.ToArray(), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "///\t", false)); mCommentBlocks.Add(new CommentBlock( "C++ style", cPlusPlusCba.ToArray(), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "// ", false)); mCommentBlocks.Add(new CommentBlock( "Doxygen C++ style 2 (//!)", cPlusPlusCba.ToArray(), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "//! ", false)); mCommentBlocks.Add(new CommentBlock( "Visual Basic Single Quote (') Function Block", CommentBlock.createFileAssocFromString("*.vb;*.vbs"), StartEndBlockType.AlwaysOnOwnLine, @"'''''+", true, StartEndBlockType.AlwaysOnOwnLine, @"'''''+", true, "' ", true)); mCommentBlocks.Add(new CommentBlock( "Visual Basic Triple Quote (''')", CommentBlock.createFileAssocFromString("*.vb;*.vbs"), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "''' ", false)); mCommentBlocks.Add(new CommentBlock( "Visual Basic Double Quote ('')", CommentBlock.createFileAssocFromString("*.vb;*.vbs"), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "'' ", false)); mCommentBlocks.Add(new CommentBlock( "Visual Basic Single Quote (')", CommentBlock.createFileAssocFromString("*.vb;*.vbs"), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "' ", false)); mCommentBlocks.Add(new CommentBlock( "# Block", CommentBlock.createFileAssocFromString("Jamfile;Jamrules;*.jam"), StartEndBlockType.AlwaysOnOwnLine, @"\#\#\#+", true, StartEndBlockType.AlwaysOnOwnLine, @"\#\#\#+", true, "# ", true)); mCommentBlocks.Add(new CommentBlock( "# Comment", CommentBlock.createFileAssocFromString("Jamfile;Jamrules;*.jam"), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "# ", false)); mCommentBlocks.Add(new CommentBlock( "Empty Block for Text Files", CommentBlock.createFileAssocFromString("*.txt"), StartEndBlockType.Empty, "", false, StartEndBlockType.Empty, "", false, "", false)); mBulletPoints.Add(new BulletPoint( "Numbered comment followed by a tag and a hyphen like '1) tag - '", @"[0-9]+\) \w+ - ", true, true)); mBulletPoints.Add(new BulletPoint( "Numbered comment like '1) '", @"[0-9]+\) ", true, true)); mBulletPoints.Add(new BulletPoint( "Hyphen at the start of a line '- '", @"- ", true, true)); mBulletPoints.Add(new BulletPoint( "Doxygen style tag followed by hyphen, like '@tag - '", @"@\w+ - ", true, true)); mBulletPoints.Add(new BulletPoint( "Doxygen style tag followed by space, like '@tag '", @"@\w+ ", true, true)); mBulletPoints.Add(new BulletPoint( "Doxygen style tag followed by space, like '\\tag '", @"\\\w+ ", true, true)); mBulletPoints.Add(new BulletPoint( "Single character followed by hyphen, like '0 - '", @". - ", true, true)); mBreakFlowStrings.Add(new BreakFlowString( "HTML Line break tag", @"<BR>", false, false, true)); mBreakFlowStrings.Add(new BreakFlowString( "XML comment on a line by itself", @"^\s*<.+?>\s*$", true, true, true)); mBreakFlowStrings.Add(new BreakFlowString( "Consecutive spaces anywhere on the line between non-space elements", @"[^\s]+?\s\s[^\s]+?", true, true, true)); mBreakFlowStrings.Add(new BreakFlowString( "(Underline) consecutive -'s on a line by themselves", @"^\s*--+\s*$", true, true, true)); mBreakFlowStrings.Add(new BreakFlowString( "(Double Underline) consecutive ='s on a line by themselves", @"^\s*==+\s*$", true, true, true)); mBreakFlowStrings.Add(new BreakFlowString( "$Source rcs tag", @"$Source", false, true, true)); mBreakFlowStrings.Add(new BreakFlowString( "$Id rcs tag", @"$Id", false, true, true)); mUseTabsToIndent = false; mWrapWidth = 80; mMinimumBlockWidth = 30; }