public void emit(IToken tok) { //This (the token having no text) might occur with an empty semicolon token (semic). I think nothing needs to be done here and //no state needs to be saved. if (tok.Text==null) return; //look at hidden tokens to see if the tag to turn off formatting is seen. If so, then just emit all the hidden tokens and //the main token. Want to let operations happen that don't insert text and maintain state that we need to keep. int currentBufferOffset=mOutputBuffer.Length; mLastToken=tok; //handle whitespace CommonTokenStream tokens=mRawTokens;//(CommonTokenStream)getTokenStream(); int currentTokenIndex=((CommonToken)tok).TokenIndex-1; List<IToken> hiddenTokens = new List<IToken>(); //collect all of the hidden tokens since the last non-whitespace token while (currentTokenIndex>=0) { IToken t = tokens.Get(currentTokenIndex); if (t.Channel==Token.DEFAULT_CHANNEL) break; hiddenTokens.Add(t); currentTokenIndex--; } IToken[] rev = hiddenTokens.ToArray(); Array.Reverse(rev); hiddenTokens.Clear(); hiddenTokens.AddRange(rev); if (!mProcessingBindableTag && mBindableMode && mBindablePos>=0 && getFormatMode()==FORMAT_ALL) { //TODO: figure out how a partial range will figure into this. I may have to shift the position if it's already //been set while (mBindablePos<mOutputBuffer.Length) { char c=mOutputBuffer[mBindablePos]; if (!AntlrUtilities.isASWhitespace(c)) break; mBindablePos++; } while (mBindablePos>0) { char c=mOutputBuffer[mBindablePos-1]; if (c=='\n') break; mBindablePos--; } String bindableText = mOutputBuffer.ToString().Substring(mBindablePos); mOutputBuffer.Remove(mBindablePos, mOutputBuffer.Length - mBindablePos); //this should spit out the blank lines before function and similar whitespace printNecessaryWS(mOutputBuffer); mOutputBuffer.Append(bindableText); mBindableMode=false; mBindablePos=(-1); //check for one of the next hidden tokens being a comment. If so, we //have to add a newline. bool commentFollows=false; foreach (IToken token in hiddenTokens) { if (AntlrUtilities.asTrim(token.Text).Length>0) { commentFollows=true; break; } } //now, spit out either newline or space to separate bindable tag from bound item if (!commentFollows && ((!isNewlineBeforeBindableFunction() && mBindingContext==BindingContext_Function && getMetaTagsToKeepOnSameLineAsFunction().Contains(mLastBindableTagName)) || (!isNewlineBeforeBindableProperty() && mBindingContext==BindingContext_Property && getMetaTagsToKeepOnSameLineAsProperty().Contains(mLastBindableTagName)))) { insertWS(1); } else { insertCR(false); } //if (/*isNewlineAfterBindable() || /*mMultipleBindableItems ||*/ commentFollows /*|| mLastBindableWasConditionalTag */ || (mBindingContext==BindingContext_Function && !getMetaTagsToKeepOnSameLineAsFunction().contains(mLastBindableTagName)) || (mBindingContext==BindingContext_Property && !getMetaTagsToKeepOnSameLineAsProperty().contains(mLastBindableTagName)) || mBindingContext==BindingContext_Class) //{ //insertCR(false); //} //else //{ //insertWS(1); //} } //handle user selection range if (mSelectedRange!=null && !mBindableMode) { if (mOutputRange==null) { if (tok.Line>=mSelectedRange.X) { mOutputRange=new Point(mOutputBuffer.Length, -1); mReplaceRange=new Point(0, -1); IToken firstToken=tok; if (hiddenTokens.Count>0) { firstToken=hiddenTokens[0]; } mReplaceRange.X=((CommonToken)firstToken).StartIndex; } } else { if (mOutputRange.Y<0 && tok.Line>mSelectedRange.Y) { mOutputRange.Y = mOutputBuffer.Length; IToken firstToken=tok; if (hiddenTokens.Count>0) { firstToken=hiddenTokens[0]; } mReplaceRange.Y=((CommonToken)firstToken).StartIndex; } } } bool onBlankLine=ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer); //I think I can only be on a blank line at the start of the document int blankLines=0; bool needToEnsureNewLine=false; foreach (Int32 ws in mAddedCRs) { if (ws==AddCR || ws==AddCR_BlankLine) { needToEnsureNewLine=true; break; } } //process hidden tokens (whitespace and comments) before this token bool seenCR=(mOutputBuffer.Length==0); //if 0, then we're on a new line. Otherwise, we're at the end of the previous code token. bool seenCommentText=false; for (int ti=0;ti<hiddenTokens.Count;ti++) { if (seenCR) captureBraceStartPos(); IToken t=hiddenTokens[ti]; switch (t.Channel) { case AS3_exParser.CHANNEL_EOL: //if we're not formatting at all, then just add the cr. if (isFormatterOff()) { insertCRIntoBuffer(mOutputBuffer); break; } seenCR=true; //we only want to preserve blank lines (or possibly not preserve blank lines) if we're in format mode where //we're taking control of the whitespace. if (getFormatMode()==FORMAT_ALL) { if (isKeepBlankLines() || getBlankLinesToKeep()>blankLines) { if (onBlankLine) { //we got a carriage return but we were already on a new line. Don't add the initial carriage //return. This happens at the start of the file or after a line comment if (blankLines==0 && !ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer)) { insertCRIntoBuffer(mOutputBuffer); } blankLines++; insertCRIntoBuffer(mOutputBuffer); } onBlankLine=true; } //if seen comment and !current line empty? else if (seenCommentText && !ASFormatter.isOnlyWhitespaceOnLastLine(getOutputBuffer())) { insertCRIntoBuffer(mOutputBuffer); onBlankLine=true; blankLines=0; } } else { //we're indenting (or formatting but without removing newlines), so just don't lose the CR insertCRIntoBuffer(mOutputBuffer); onBlankLine=true; } break; case AS3_exParser.CHANNEL_SLCOMMENT: //NOTE: the single line comment contains a carriage return, so we are guaranteed to //be on a new line afterward /////////////////////// Handling of "exclude from formatting" tags ////////////////////// if (t.Text.IndexOfOrdinal(mStartExcludeProcessing)>=0) { pushFormatterOff(); } else if (t.Text.IndexOfOrdinal(mStopExcludeProcessing)>=0) { popFormatterOff(); } //if not in format mode at all, then just append the comment text, clear any accumulated whitespace and exit case if (isFormatterOff()) { if (isDoFormat() && !ASFormatter.isLineEmpty(mOutputBuffer)) insertCRIntoBuffer(mOutputBuffer); mOutputBuffer.Append(t.Text.Replace("\r\n", "\n")); mAddedCRs.Clear(); break; } /////////////////////////////////////////////////////////////////////////////////////// //if we've seen a carriage return in the whitespace, but we haven't added one yet (because the SLComment was the next line), //then we need to add a CR. if (onBlankLine) insertCR(false); //here, we check the mDoFormat flag, NOT the format stack, because we want to know if it's legal to add spaces, not //whether we are currently in a "don't format" block. We might care if we were in code, but since this //is for comments I think it makes sense. if (isDoFormat() && !seenCR) //if no carriage return before this comment, then it's on the same line with other text { addLineCommentPreSpacing(hiddenTokens, ti); mOutputBuffer.Append(t.Text.Replace("\r\n", "\n")); } else { //add a lazy space so that there will be one space before the '//' if there are preceding //chars on the line. I don't know if this can ever have an effect, but it seems safest to leave it. insertWS(1); //otherwise, we add the accumulated whitespace, which may include multiple blank lines, as we push //the comment down to be with the following statement printNecessaryWS(mOutputBuffer); int commentIndent=0; if (isKeepSingleLineCommentsAtColumn1() && t.CharPositionInLine==0) { //do nothing; hopefully we've not added any whitespace to a blank line } else { bool addSpecialIndent=false; if (tok.Type==AS3_exParser.RCURLY) addSpecialIndent=true; if (addSpecialIndent) pushIndent(STATEMENT_INDENT); commentIndent=addIndentIfAtStartOfLine(mOutputBuffer); if (addSpecialIndent) popIndent(); } if (isDoFormat() && isUseLineCommentWrapping()) { //wrap comment based on max line length and current indent spaces List<CommentLineWrapData> commentLines=wrapLineComment(t.Text, commentIndent, mMaxLineLength); bool firstLine=true; foreach (CommentLineWrapData line in commentLines) { if (!firstLine) { mOutputBuffer.Append(generateIndent(commentIndent)); int replaceOffset=((CommonToken)t).StartIndex+line.mOriginalStartOffset; ReplacementRange range=new ReplacementRange(new Point(mOutputBuffer.Length, mOutputBuffer.Length+2), new Point(replaceOffset, replaceOffset)); if (mReplaceMap==null) mReplaceMap=new Dictionary<Int32, ReplacementRange>(); range.setChangedText("//", ""); mReplaceMap[mOutputBuffer.Length] = range; mAdditionalTextAdded+="//"; mAdditionalTextAddedAllPasses+="//"; } mOutputBuffer.Append(line.mText); firstLine=false; } } else { //add the actual text mOutputBuffer.Append(t.Text.Replace("\r\n", "\n")); } } onBlankLine=true; blankLines=0; //make sure we note that we have just seen a carriage return seenCR=true; break; case AS3_exParser.CHANNEL_MLCOMMENT: //if not in format mode at all, then just append the comment text, clear any accumulated whitespace and exit switch if (isFormatterOff()) { mOutputBuffer.Append(t.Text.Replace("\r\n", "\n")); mAddedCRs.Clear(); break; } //if we've seen a carriage return in the whitespace, but we haven't added one yet (because the MLComment was the next line), //then we need to add a CR. if (onBlankLine) insertCR(false); //here, we check the mDoFormat flag, NOT the format stack, because we want to know if it's legal to add spaces, not //whether we are currently in a "don't format" block. We might care if we were in code, but since this //is for comments I think it makes sense. //if the comment is at the end of a line of text, and the comment doesn't span multiple lines (and we're in a mode that allows space insertion) if (isDoFormat() && !seenCR && t.Text.IndexOf('\n')<0) { addLineCommentPreSpacing(hiddenTokens, ti); mOutputBuffer.Append(t.Text); } else { seenCR=true; //add a lazy space so that there will be one space before the '/*' if there are preceding //chars on the line. I don't even know if this can ever have an effect, but it seems safest to leave it. insertWS(1); printNecessaryWS(mOutputBuffer); //TODO: something else completely, which might involve adding newlines, wrapping lines, etc. // -when I wrote this for Java, I did some fancy code to determine the relative offset of // the original lines to maintain the indenting within the comment. String[] commentLines=t.Text.Split('\n'); int indentAmount=getIndentForNextLine(mOutputBuffer); int originalIndent=0; bool useReplaceRange=false; if (t.Text.StartsWithOrdinal("/**")) { if (isUseDocCommentWrapping() && !isKeepRelativeCommentIndent()) { commentLines=wrapMultilineComment(indentAmount, commentLines, mDocCommentCollapseLines, isDocCommentKeepBlankLines(), true, MLAsteriskStyle_All, "/**", getDocCommentHangingIndentTabs()); useReplaceRange=true; } } else if (t.Text.StartsWithOrdinal("/*")) { if (isUseMLCommentWrapping() && !isKeepRelativeCommentIndent()) { commentLines=wrapMultilineComment(indentAmount, commentLines, mMLCommentCollapseLines, isMLCommentKeepBlankLines(), mMLTextOnNewLines, mMLAsteriskMode, "/*", 0); useReplaceRange=true; } } if (isKeepRelativeCommentIndent()) { //find original indent String lineData=t.Text; int prevLineEnd=mSourceData.LastIndexOf('\n', ((CommonToken)t).StartIndex); if (prevLineEnd<0) prevLineEnd=0; else prevLineEnd++; //move to start of next line lineData.Insert(0, mSourceData.Substring(prevLineEnd, ((CommonToken)t).StartIndex - prevLineEnd)); originalIndent=findIndent(lineData, getTabSize()); } Point replaceArea=new Point(mOutputBuffer.Length, -1); for (int j=0;j<commentLines.Length;j++) { bool onLastLine=(j==commentLines.Length-1); indentAmount=getIndentForNextLine(mOutputBuffer); String data=AntlrUtilities.asTrim(commentLines[j]); //this removes the \r, if it exists if (j>0) { if (isKeepRelativeCommentIndent() && originalIndent>=0) { int existingIndent=findIndent(commentLines[j], getTabSize()); indentAmount=Math.Max(0, indentAmount+(existingIndent-originalIndent)); } else //using rules assuming '*' lines { if (onLastLine && data.StartsWithOrdinal("*/")) //if we're on the last line and there's more than one line { if (mIndentMultilineComments) indentAmount += 1; else indentAmount += 0; } else { //on a middle line, we have 2 cases. If the line starts with an asterisk, then attempt to line the //asterisk up with the asterisk on the first line. Otherwise, indent the text to the right of the open asterisk. //String nextLine=data; //if (nextLine.Length>0 && nextLine[0]=='*') //indentAmount+=1; //else //indentAmount+=3; // FIXED: Multiline comment indent support added String nextLine = data; if (nextLine.Length > 0 && nextLine[0] == '*') { if (mIndentMultilineComments) indentAmount += 1; else indentAmount += 0; } else indentAmount += 3; } } } //only add indent if not on an empty line if (data.Length>0) { if (ASFormatter.isLineEmpty(mOutputBuffer)) { mOutputBuffer.Append(generateIndent(indentAmount)); } mOutputBuffer.Append(data); } if (!onLastLine) { insertCRIntoBuffer(mOutputBuffer); } } if (useReplaceRange) { replaceArea.Y=mOutputBuffer.Length; CommonToken commonTok=(CommonToken)t; for (;replaceArea.X<mOutputBuffer.Length;replaceArea.X++) { if (!Char.IsWhiteSpace(mOutputBuffer[replaceArea.X])) break; } ReplacementRange replaceRange=new ReplacementRange(replaceArea, new Point(commonTok.StartIndex, commonTok.StartIndex+t.Text.Length)); replaceRange.setChangedText(mOutputBuffer.ToString().Substring(replaceArea.X), t.Text); if (!ASFormatter.validateNonWhitespaceIdentical(replaceRange.getAddedText(), replaceRange.getDeletedText())) { if (mReplaceMap==null) mReplaceMap=new Dictionary<Int32, ReplacementRange>(); mReplaceMap[replaceArea.X] = replaceRange; } } } onBlankLine=false; blankLines=0; seenCommentText=true; break; case AS3_exParser.CHANNEL_WHITESPACE: if (isFormatterOff()) { //just spit the text out mOutputBuffer.Append(t.Text); } else if (getFormatMode()==FORMAT_INDENT) // || isFirstTokenBeforeChangeFromFormatToIndent() || isFirstTokenBeforeChangeFromIndentToFormat()) { //we don't care about whitespace if we are on the first token in an format-indent element; we only //care about whitespace within the element if (!ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer))// && (getFormatMode()==FORMAT_INDENT || !AntlrUtilities.isASWhitespace(mOutputBuffer.charAt(mOutputBuffer.Length-1)))) mOutputBuffer.Append(t.Text); } else { //do nothing; we'll add our own whitespace } break; default: break; } } // mFirstTokenBeforeChangeFromFormatToIndent=false; // mFirstTokenBeforeChangeFromIndentToFormat=false; // mFirstTokenBeforeIndentBoundary=false; //if still in non-formatting mode, then clear any whitespace that has been added to our list if (isFormatterOff()) mAddedCRs.Clear(); printNecessaryWS(mOutputBuffer); if (!isFormatterOff()) { if ((getFormatMode()==FORMAT_ALL || getFormatMode()==FORMAT_OnlyAddCRs /*|| (getFormatMode()==FORMAT_INDENT && isFirstTokenBeforeChangeFromIndentToFormat())*/) && needToEnsureNewLine) { if (!ASFormatter.isOnlyWhitespaceOnLastLine(mOutputBuffer)) { insertCRIntoBuffer(mOutputBuffer); } } { int indentAmount=getCurrentIndent(); if (getIndentType(0)!=EXPRESSION_INDENT && (tok.Type==AS3_exParser.LCURLY || tok.Type==AS3_exParser.RCURLY)) { if (!isHardIndent()) { if (!mUseGNUBraceIndent) indentAmount-=getBlockIndent(); else { IndentType indentInfo=mIndentStack[mIndentStack.Count-1]; if (tok.Type==AS3_exParser.LCURLY) { indentInfo.mOriginalIndent=indentInfo.mAmount; indentInfo.mAmount+=getTabSize(); } else //rcurly { if (indentInfo.mOriginalIndent>=0) indentInfo.mAmount=indentInfo.mOriginalIndent; indentAmount=indentInfo.mAmount; } } } } if (ASFormatter.isLineEmpty(mOutputBuffer)) { String indentString=generateIndent(indentAmount); mOutputBuffer.Append(indentString); } } if( getFormatMode() != FORMAT_INDENT ) { if (mOutputBuffer.Length > 0 && InfoCollector.Utilities.isJavaIdentifierPart(mOutputBuffer[mOutputBuffer.Length - 1])) { //if the start of the token is a java identifier char (any letter or number or '_') //or if the token doesn't start with whitespace, but isn't an operator either ('+=' is an operator, so we wouldn't add space, but we would add space for a string literal) if ((tok.Text.Length > 0 && InfoCollector.Utilities.isJavaIdentifierPart(tok.Text[0])) || isSymbolTokenThatShouldHaveSpaceBeforeIt(tok.Type)) { mOutputBuffer.Append(' '); } } //remove extra spaces before token for paren/brace/bracket case (if we're in a format mode) if (tok.Text.Length==1) { char c = tok.Text[0]; if (isGroupingChar(c)) { int i=mOutputBuffer.Length-1; int spaceCount=0; while (i>=0) { if (mOutputBuffer[i] == ' ') { spaceCount++; i--; } else break; } if (i>=0 && spaceCount>0) //only care if there are some spaces { char prevChar=mOutputBuffer[i]; int nestingType=determineMatchingGroupingCharType(c, prevChar); if (nestingType!=Nesting_Unrelated) { int amtToKeep=0; //TODO: not sure how this will work with advanced spacing settings if (!isCollapseSpaceForAdjacentParens() && nestingType!=Nesting_Opposite) { //TODO: Determine if the current context is a function call or a general //expression so that the proper 'getAdvancedSpaces' call can be made if (prevChar=='(' || c==')') amtToKeep = getAdvancedSpacesInsideParensInOtherPlaces(); else if (prevChar=='{' || c=='}') amtToKeep=getAdvancedSpacesInsideObjectBraces(); else if (prevChar=='[' || c==']') { amtToKeep=getAdvancedSpacesInsideArrayDeclBrackets(); } } if (amtToKeep<spaceCount) { mOutputBuffer.Remove(mOutputBuffer.Length-(spaceCount-amtToKeep), mOutputBuffer.Length); } } } } } } } //if we have a lazy indent, push it after we've processed the token if (mLazyIndentType>0) { if (mLazyIndentType==EXPRESSION_INDENT_NEXTITEM) { pushExpressionIndent(determineLastLineLength(mOutputBuffer, getTabSize())); } else { //we know it's an expression indent because that's the other possibility. We take the current indent and add //the number of tab stops based on the hanging indent setting. pushIndent(mLazyIndentType); } mLazyIndentType=0; } if (mLazyFormatType>0) { pushFormatMode(mLazyFormatType); mLazyFormatType=0; } //special case for handling the need to lose 1 indent to support 'else-if' on the same line. The grammar has code to //pop an indent and re-add later, but it can't know whether it needs to until we get to this point and determine whether //the 'if' is actually on the same line with the else or not (based on else-if setting, blank lines settings, indent vs. format, etc.) if (mNextTokenInElseIfState) { mNextTokenInElseIfState=false; String newText = mOutputBuffer.ToString().Substring(currentBufferOffset); if (!newText.Contains("\n")) { mElseIfNeedToLoseIndent=true; } } if (mLastCapturePosition<0) mLastCapturePosition=mOutputBuffer.Length; captureBraceStartPos(); mOutputBuffer.Append(tok.Text); }
public String print(int startIndent) { if (mSourceData.IndexOfOrdinal(mIgnoreFileProcessing)>=0) { mParseErrors=new List<Exception>(); mParseErrors.Add(new Exception("File ignored: Ignore tag exists in file==> "+mIgnoreFileProcessing)); return null; } //mOutputRange = null; //mReplaceRange = null; mAdditionalTextAddedAllPasses=""; mRemovedTextAllPasses=""; int maxPasses=2; //right now, there's only two passes if we are aligning equals signs or adding braces int currentPasses=0; while (currentPasses<maxPasses) { currentPasses++; mAlreadyHaveDeclPositions=(mDeclEqualPosMap!=null); //initialize the parser state variables mBindablePos=(-1); mBindableMode=false; mInSingleLineFunctionMode=false; mAdditionalTextAdded=""; mRemovedText=""; mReplaceMap=null; mNextTokenInElseIfState=false; mElseIfNeedToLoseIndent=false; mLazyIndentType=(-1); mLazyFormatType=(-1); mFormatTypeStack=new List<Int32>(); if (mDoFormat) pushFormatMode(FORMAT_ALL); else pushFormatMode(FORMAT_INDENT); mLastBindableTagName=""; mExpressionWrapData=new List<WrapInfo>(); mSourceData=InfoCollector.Utilities.convertCarriageReturnsToLineFeeds(mSourceData); bool addedEndCRs=false; if (getEndEOLs(mSourceData)<2) { mSourceData+="\n\n"; addedEndCRs=true; } mAddBraceStack=new List<StatementBraceInfo>(); mCompletedBraceInfos=new List<StatementBraceInfo>(); mAddedCRs=new List<Int32>(); mParseErrors=null; mIndentStack=new List<IndentType>(); mIndentStack.Add(new IndentType(INITIAL_INDENT, startIndent)); mExcludeStackCount=0; mLastCapturePosition=0; mOutputBuffer = new StringBuilder(); // mAlignDeclEquals=true; if (mAlignDeclEquals && !mIsKeepingExcessDeclWhitespace)// && currentPasses==0) { mCurrentDeclEqualContext=new EqualContext(null, 0); mRootDeclEqualContext=mCurrentDeclEqualContext; } // else // mCurrentDeclEqualContext=null; try { // if (mIsCompleteFile) mWorkingSource=mSourceData; // else // mWorkingSource="class DummyClassWrapper {"+mSourceData+ "}"; ANTLRStringStream stream=new ANTLRStringStream(mWorkingSource); AS3_exLexer l2=new AS3_exLexer(stream); mRawTokens=new CommonTokenStream(l2); AS3_exParser p2=new AS3_exParser(this, mRawTokens); AS3_exParser.fileContents_return retVal=p2.fileContents(); //handle any remaining hidden tokens IToken t = new CommonToken(AS3_exParser.EOF, ""); t.TokenIndex = mRawTokens.Count; emit(t); //process braces that may need to be added or deleted List<EditItem> editItems=new List<EditItem>(); foreach (StatementBraceInfo info in mCompletedBraceInfos) { if (info.isBracesCurrentlyExist()) { if (isRemoveBraces(info)) { int startBracePos = mOutputBuffer.ToString().IndexOf('{', info.getStartBracePos()); int endBracePos = mOutputBuffer.ToString().LastIndexOf('}', info.getEndBracePos()); int endBracePosInSource=mSourceData.LastIndexOf('}', info.getOriginalDocEndPosition()); editItems.Add(new DeleteItem(startBracePos, 1, info.getOriginalDocStartPosition())); editItems.Add(new DeleteItem(endBracePos, 1, endBracePosInSource)); //if brace is followed by nothing but a carriage return, return the next //cr as well. int nextCR = mOutputBuffer.ToString().IndexOf('\n', startBracePos + 1); if (nextCR>=0) { String nextChars = mOutputBuffer.ToString().Substring(startBracePos + 1, nextCR - (startBracePos + 1)).Trim(); if (nextChars.Length==0) { editItems.Add(new DeleteItem(nextCR, 1, -1)); } } nextCR = mOutputBuffer.ToString().IndexOf('\n', endBracePos + 1); if (nextCR>=0) { String nextChars = mOutputBuffer.ToString().Substring(endBracePos + 1, nextCR - (endBracePos + 1)).Trim(); if (nextChars.Length==0) { editItems.Add(new DeleteItem(nextCR, 1, -1)); } } } } else { if (isAddBraces(info)) { editItems.Add(new InsertItem(info.getStartBracePos(), "{", info.getOriginalDocStartPosition())); editItems.Add(new InsertItem(info.getEndBracePos(), "}", info.getOriginalDocEndPosition())); } } } editItems.Sort((o1, o2) => o1.getLocation() - o2.getLocation()); /* Collections.sort(editItems, new IComparer<EditItem>() { public int compare(EditItem o1, EditItem o2) { return o1.mLocation-o2.mLocation; } }); */ if (mReplaceMap==null) mReplaceMap=new Dictionary<Int32, ReplacementRange>(); int addedChars=0; for (int j=0;j<editItems.Count;j++) { EditItem item=editItems[j]; if (item is InsertItem) { InsertItem iItem=(InsertItem)item; mOutputBuffer.Insert(item.getLocation()+addedChars, iItem.getData()); ReplacementRange existingRange=mReplaceMap[iItem.getOriginalInsertLocation()]; if (existingRange!=null) { //this can happen if two close braces are added at the same point in the file. As such, //I'm handling this special case. existingRange.setChangedText(existingRange.getAddedText()+iItem.getData(), existingRange.getDeletedText()); existingRange.mRangeInFormattedDoc.Y += iItem.getData().Length; } else { ReplacementRange range=new ReplacementRange(new Point(item.getLocation()+addedChars, item.getLocation()+addedChars+iItem.getData().Length), new Point(iItem.getOriginalInsertLocation(),iItem.getOriginalInsertLocation())); mReplaceMap[iItem.getOriginalInsertLocation()] = range; range.setChangedText(iItem.getData(), ""); } addedChars+=iItem.getData().Length; mAdditionalTextAdded+=iItem.getData(); mAdditionalTextAddedAllPasses+=iItem.getData(); } else { //add replacemap item, but only if non-whitespace is being deleted //TODO: what if a brace is added and deleted at same location? Will that break the merging code? DeleteItem dItem=(DeleteItem)item; Int32 start = dItem.getLocation() + addedChars; Int32 end = dItem.getLocation() + dItem.getLength() + addedChars; String removedData = mOutputBuffer.ToString().Substring(start, end - start); if (dItem.getOriginalDeleteLocation()>=0) { ReplacementRange range=new ReplacementRange(new Point(item.getLocation()+addedChars, item.getLocation()+addedChars), new Point(dItem.getOriginalDeleteLocation(),dItem.getOriginalDeleteLocation()+dItem.getLength())); mReplaceMap[dItem.getOriginalDeleteLocation()] = range; range.setChangedText("", removedData); } mOutputBuffer.Remove(dItem.getLocation()+addedChars, dItem.getLocation()+dItem.getLength()+addedChars); addedChars-=removedData.Length; mRemovedText+=removedData; mRemovedTextAllPasses+=removedData; } } String resultText=mOutputBuffer.ToString(); mParseErrors=p2.getParseErrors(); if (mParseErrors!=null || resultText==null) return null; String oldString=mWorkingSource+mAdditionalTextAdded; if (mAdditionalTextAdded.Length==0 && mRemovedText.Length==0 && ASFormatter.validateNonWhitespaceIdentical(resultText, mWorkingSource) || ((mAdditionalTextAdded.Length>0 || (mRemovedText.Length>0)) && ASFormatter.validateNonWhitespaceCharCounts(resultText+mRemovedText, oldString))) { //trim extra newlines at the end of result text if (mDoFormat) { int oldEndLines=getEndEOLs(mWorkingSource)-(addedEndCRs ? 2 : 0); //I may have added two above int newEndLines=getEndEOLs(resultText); if (newEndLines>oldEndLines) { resultText=resultText.Substring(0, resultText.Length-(newEndLines-oldEndLines)); if (mOutputRange!=null && mOutputRange.Y>resultText.Length) { mOutputRange.Y = resultText.Length; } } } //if we are trying to capture the output range but haven't captured it yet if (mOutputRange != null && mOutputRange.Y < 0) { mOutputRange.Y = resultText.Length; mReplaceRange.Y = mWorkingSource.Length; if (mDoFormat && addedEndCRs) mReplaceRange.Y -= "\n\n".Length; } if (mRootDeclEqualContext!=null) { mDeclEqualPosMap=new Dictionary<String, Int32>(); mRootDeclEqualContext.fillMap(mDeclEqualPosMap); } //if multiple passes are allowed and we would benefit from one and this is not a partial format if (mAllowMultiplePasses && needAnotherPass() && mOutputRange==null) { mSourceData=resultText; continue; } return resultText; } else { mParseErrors=new List<Exception>(); mParseErrors.Add(new Exception("Internal error: Formatted text doesn't match source. "+resultText+"!="+mWorkingSource)); } } finally { } return null; } //return what I have in case the multiple //passes algorithm gets confused return mSourceData; }