### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: formatter/org/eclipse/jdt/internal/formatter/Scribe.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java,v retrieving revision 1.147 diff -u -r1.147 Scribe.java --- formatter/org/eclipse/jdt/internal/formatter/Scribe.java 1 Jul 2008 10:04:23 -0000 1.147 +++ formatter/org/eclipse/jdt/internal/formatter/Scribe.java 10 Jul 2008 17:19:04 -0000 @@ -165,26 +165,31 @@ if (index >= 0) { // the offset of the region is inside a comment => restart the region from the comment start adaptedOffset = this.commentPositions[index][0]; - if (adaptedOffset < 0) adaptedOffset = -adaptedOffset; - adaptedLength = length + offset - adaptedOffset; - commentIndex = index; - // include also the indentation edit just before the comment if any - for (int j=0; j 0 && this.edits[j].replacement.trim().length() == 0) { - adaptedLength += adaptedOffset - this.edits[j].offset; - adaptedOffset = editOffset; + if (adaptedOffset >= 0) { + // adapt only javadoc or block commments. Since fix for bug + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=238210 + // edits in line comments only concerns whitespaces hence can be + // treated as edits in code + adaptedLength = length + offset - adaptedOffset; + commentIndex = index; + // include also the indentation edit just before the comment if any + for (int j=0; j 0 && this.edits[j].replacement.trim().length() == 0) { + adaptedLength += adaptedOffset - this.edits[j].offset; + adaptedOffset = editOffset; + break; + } + } else if (editEnd > adaptedOffset) { break; } - } else if (editEnd > adaptedOffset) { - break; } } } index = getCommentIndex(commentIndex, offset+length-1); - if (index >= 0) { + if (index >= 0 && this.commentPositions[index][0] >= 0) { // only javadoc or block comment // the region end is inside a comment => set the region end at the comment end int commentEnd = this.commentPositions[index][1]; if (commentEnd < 0) commentEnd = -commentEnd; @@ -194,9 +199,12 @@ if (adaptedLength != length) { // adapt the region and jump to next one this.adaptedRegions[i] = new Region(adaptedOffset, adaptedLength); - continue; +// continue; + } else { + this.adaptedRegions[i] = aRegion; } + /* if (offset > 0) { if (isAdaptableRegion(offset, length)) { // if we have a selection, search for overlapping edits @@ -254,9 +262,58 @@ } else { this.adaptedRegions[i] = this.regions[i]; } + */ + } + } + + /* + * Adapt edits to regions. + * + * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=234583#c2" + * for more details + */ + private void adaptEdits() { + + // See if adapting edits is really necessary + int max = this.regions.length; + if (max == 1) { + if (this.regions[0].getOffset() == 0 && this.regions[0].getLength() == this.scannerEndPosition) { + // No need to adapt as the regions covers the whole source + return; + } + } + + // Sort edits + OptimizedReplaceEdit[] sortedEdits = new OptimizedReplaceEdit[this.editsIndex]; + System.arraycopy(this.edits, 0, sortedEdits, 0, this.editsIndex); +// long start = System.currentTimeMillis(); + Arrays.sort(sortedEdits, new Comparator() { + public int compare(Object o1, Object o2) { + OptimizedReplaceEdit edit1 = (OptimizedReplaceEdit) o1; + OptimizedReplaceEdit edit2 = (OptimizedReplaceEdit) o2; + return edit1.offset - edit2.offset; + } + }); +// System.out.println("Time to sort edits = "+(System.currentTimeMillis()-start)); + + // Adapt overlapping edits + int currentEdit = -1; + for (int i = 0; i < max; i++) { + IRegion region = this.regions[i]; + int offset = region.getOffset(); + int length = region.getLength(); + + // modify overlapping edits on the region (if any) + if (length > 1) { // nothing can be done for region which have only one character... + int index = modifyOverlappingEdit(sortedEdits, currentEdit, offset, offset+length); + if (index != -1) { + currentEdit = index; + } + } } } + private final void addDeleteEdit(int start, int end) { if (this.edits.length == this.editsIndex) { // resize @@ -607,6 +664,107 @@ return -1; } + /* + * + */ + private int modifyOverlappingEdit(OptimizedReplaceEdit[] sortedEdits, int start, int regionStart, int regionEnd) { + int bottom = start==-1?0:start, top = sortedEdits.length - 1; + int topEnd = top; + int i = 0; + OptimizedReplaceEdit edit = null; + int overlapIndex = -1; + int currentLine = 1; + + // Look for an edit overlapping the region start + while (bottom <= top) { + i = bottom + (top - bottom) /2; + edit = sortedEdits[i]; + int editStart = edit.offset; + int editEnd = editStart + edit.length; + if (regionStart < editStart) { + top = i-1; + if (regionEnd < editStart) { + topEnd = top; + } + } else { + if (regionStart >= editEnd) { + bottom = i+1; + } else { + + // restart the edit at the beginning of the line where the region start + currentLine = Util.getLineNumber(regionStart, this.lineEnds, currentLine<2?0:currentLine-2, this.maxLines); + int lineStart = currentLine == 1 ? 0 : getLineEnd(currentLine-1) + 1; + edit.offset = lineStart; + edit.length -= edit.offset - editStart; + + // keep the end of replacement after the last line break + int length = edit.replacement.length(); + if (length > 0) { + int idx = length - 1; + char ch = edit.replacement.charAt(idx); + while (ch != '\r' && ch != '\n') { + if (--idx < 0) break; + ch = edit.replacement.charAt(idx); + } + if (idx > 0) { + if ((idx+1)==length) { + edit.replacement = ""; //$NON-NLS-1$ + } else { + edit.replacement = edit.replacement.substring(idx+1); + } + } + } + overlapIndex = i; + break; + } + } + } + + // Look for an edit overlapping the region end + if (overlapIndex != -1) bottom = overlapIndex; + while (bottom <= topEnd) { + i = bottom + (topEnd - bottom) /2; + edit = sortedEdits[i]; + int editStart = edit.offset; + int editEnd = editStart + edit.length; + if (regionEnd < editStart) { + topEnd = i-1; + } else { + if (regionEnd >= editEnd) { + bottom = i+1; + } else { + // count lines between region and edits ends + int lineRegionEnd = Util.getLineNumber(regionEnd, this.lineEnds, currentLine<2?0:currentLine-2, this.maxLines); + currentLine = Util.getLineNumber(editEnd, this.lineEnds, lineRegionEnd<2?0:lineRegionEnd-2, this.maxLines); + int delta = currentLine - lineRegionEnd; + + // try to keep the same number of lines in the new replacement string + int length = edit.replacement.length(); + if (length > 0) { + int idx = 0; + int count = 0; + char ch = edit.replacement.charAt(idx); + while (ch == '\r' || ch == '\n') { + if (ch == '\n') count++; + if (count == delta || ++idx == length) break; + ch = edit.replacement.charAt(idx); + } + if (idx > 0) { + if (idx == length) { + edit.replacement = ""; //$NON-NLS-1$ + } else { + edit.replacement = edit.replacement.substring(idx); + } + } + } + edit.length -= editEnd - regionEnd; + return i; + } + } + } + return overlapIndex; + } + private IRegion getCoveringAdaptedRegion(int offset, int end) { int index = getIndexOfAdaptedRegionAt(offset); @@ -805,6 +963,8 @@ public TextEdit getRootEdit() { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=208541 adaptRegions(); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=234583 + adaptEdits(); MultiTextEdit edit = null; int regionsLength = this.adaptedRegions.length; @@ -951,7 +1111,7 @@ this.formatterCommentParser.scanner.linePtr = this.maxLines; } - /** + /* * Returns whether the given region should be adpated of not. * A region should be adapted only if: * - region does not exceed the page width @@ -959,7 +1119,7 @@ * @param offset the offset of the region to consider * @param length the length of the region to consider * @return boolean true if line should be adapted, false otherwhise - */ + * private boolean isAdaptableRegion(int offset, int length) { int regionEnd = offset + length; @@ -1000,6 +1160,7 @@ } return false; } + */ private boolean isOnFirstColumn(int start) { if (this.lineEnds == null) return start == 0;