diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java index e38b908983e..60ea298142f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/ICStatusConstants.java @@ -11,15 +11,15 @@ package org.eclipse.cdt.internal.ui; /** - * Defines status codes relevant to the Java UI plug-in. When a + * Defines status codes relevant to the CDT UI plug-in. When a * Core exception is thrown, it contain a status object describing * the cause of the exception. The status objects originating from the - * Java UI plug-in use the codes defined in this interface. + * CDT UI plug-in use the codes defined in this interface. */ public interface ICStatusConstants { // C UI status constants start at 10000 to make sure that we don't - // collide with resource and java model constants. + // collide with resource and c model constants. public static final int INTERNAL_ERROR= 10001; @@ -46,4 +46,12 @@ public interface ICStatusConstants { * parsing template file. */ public static final int TEMPLATE_PARSE_EXCEPTION = 10005; - } + + /** + * Status constant indication that a problem occurred while calculating + * the changed region during a save. + * + * @since 5.1 + */ + public static final int EDITOR_CHANGED_REGION_CALCULATION= 10006; +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java index bf52c685781..8b78e3dc68f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CDocumentProvider.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; @@ -26,7 +27,11 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.BadLocationException; @@ -46,6 +51,10 @@ import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.TextEdit; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.editors.text.ForwardingDocumentProvider; @@ -71,6 +80,7 @@ import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.ui.text.ICPartitions; +import org.eclipse.cdt.internal.core.model.CommitWorkingCopyOperation; import org.eclipse.cdt.internal.core.model.IBufferFactory; import org.eclipse.cdt.internal.core.model.TranslationUnit; @@ -313,7 +323,6 @@ public class CDocumentProvider extends TextFileDocumentProvider { } return true; } - } /** @@ -926,28 +935,69 @@ public class CDocumentProvider extends TextFileDocumentProvider { super.disposeFileInfo(element, info); } - protected void commitWorkingCopy(IProgressMonitor monitor, Object element, TranslationUnitInfo info, boolean overwrite) - throws CoreException { + /** + * Creates and returns a new sub-progress monitor for the + * given parent monitor. + * + * @param monitor the parent progress monitor + * @param ticks the number of work ticks allocated from the parent monitor + * @return the new sub-progress monitor + */ + private IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) { + if (monitor != null) + return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); - IDocument document= info.fTextFileBuffer.getDocument(); - IResource resource= info.fCopy.getResource(); - - if (resource instanceof IFile && !resource.exists()) { - // underlying resource has been deleted, just recreate file, ignore the rest - createFileFromDocument(monitor, (IFile) resource, document); - return; - } + return new NullProgressMonitor(); + } + + protected void commitWorkingCopy(IProgressMonitor monitor, Object element, TranslationUnitInfo info, + boolean overwrite) throws CoreException { + if (monitor == null) + monitor= new NullProgressMonitor(); + + monitor.beginTask("", 100); //$NON-NLS-1$ try { - commitFileBuffer(monitor, info, overwrite); - } catch (CoreException x) { - // inform about the failure - fireElementStateChangeFailed(element); - throw x; - } catch (RuntimeException x) { - // inform about the failure - fireElementStateChangeFailed(element); - throw x; + IDocument document= info.fTextFileBuffer.getDocument(); + IResource resource= info.fCopy.getResource(); + + boolean isSynchronized= resource.isSynchronized(IResource.DEPTH_ZERO); + + // Make sure file gets save in commit() if the underlying file has been deleted + if (!isSynchronized && isDeleted(element)) + info.fTextFileBuffer.setDirty(true); + + if (resource instanceof IFile && !resource.exists()) { + // Underlying resource has been deleted, just recreate file, ignore the rest + createFileFromDocument(monitor, (IFile) resource, document); + return; + } + + try { + CoreException saveActionException= null; + try { + performSaveActions(info.fTextFileBuffer, getSubProgressMonitor(monitor, 20)); + } catch (CoreException e) { + saveActionException = e; + } + + CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(info.fCopy, isSynchronized || overwrite); + op.runOperation(getSubProgressMonitor(monitor, 80)); + + if (saveActionException != null) { + throw saveActionException; + } + } catch (CoreException x) { + // inform about the failure + fireElementStateChangeFailed(element); + throw x; + } catch (RuntimeException x) { + // inform about the failure + fireElementStateChangeFailed(element); + throw x; + } + } finally { + monitor.done(); } } @@ -955,14 +1005,8 @@ public class CDocumentProvider extends TextFileDocumentProvider { * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createSaveOperation(java.lang.Object, org.eclipse.jface.text.IDocument, boolean) */ @Override - protected DocumentProviderOperation createSaveOperation(final Object element, final IDocument document, final boolean overwrite) throws CoreException { - try { - performSaveActions(document); - } catch (Exception exc) { - // log any exeption, but perform save anyway - CUIPlugin.log(exc); - } - + protected DocumentProviderOperation createSaveOperation(final Object element, final IDocument document, + final boolean overwrite) throws CoreException { final FileInfo info= getFileInfo(element); if (info instanceof TranslationUnitInfo) { return new DocumentProviderOperation() { @@ -993,66 +1037,117 @@ public class CDocumentProvider extends TextFileDocumentProvider { } /** - * Perform configured document manipulations before save. - * - * @param document + * Removes trailing whitespaces from changed lines and adds newline at the end of the file, + * if the last line of the file was changed. * @throws BadLocationException */ - private void performSaveActions(final IDocument document) throws BadLocationException { - //add a newline to the end of the document (if it is not already present) - //----------------------------------------------------------------------- - //for people who do not want auto-modification of their files, - //this flag will prevent addition of a newline unless the user - //explicitly sets the preference thru Window -> Preferences -> C/C++ -> Editor - // -> Appearance Tab -> Ensure newline end of file when saving - if (PreferenceConstants.getPreferenceStore().getBoolean( - PreferenceConstants.ENSURE_NEWLINE_AT_EOF)) { - // even if the document is empty, there will be at least one line in - // it (the 0th one) - int lastLineIndex = document.getNumberOfLines() - 1; - - // we have to ensure that the length of the last line is 0. - // this will also take care of empty files. empty files have - // only one line in them and the length of this one and only - // line is 0. - // Thus we do not need to append an extra line separator to - // empty files. - int lastLineLength = document.getLineLength(lastLineIndex); - if (lastLineLength != 0) { - document.replace(document.getLength(), 0, - TextUtilities.getDefaultLineDelimiter(document)); - } - } - - // Remove trailing whitespace when saving. Triggered by the flag - // in Preferences -> C/C++ -> Editor - if (PreferenceConstants.getPreferenceStore().getBoolean( - PreferenceConstants.REMOVE_TRAILING_WHITESPACE)) { - - int lineCount= document.getNumberOfLines(); - for (int i= 0; i < lineCount; i++) { - - IRegion region= document.getLineInformation(i); - if (region.getLength() == 0) - continue; - - int lineStart= region.getOffset(); - int lineExclusiveEnd= lineStart + region.getLength(); - - // Find the rightmost none-whitespace character - int charPos= lineExclusiveEnd - 1; - while (charPos >= lineStart && Character.isWhitespace(document.getChar(charPos))) - charPos--; - - charPos++; - if (charPos < lineExclusiveEnd) { - DeleteEdit edit= new DeleteEdit(charPos, lineExclusiveEnd - charPos); + private void performSaveActions(ITextFileBuffer buffer, IProgressMonitor monitor) throws CoreException { + if (shouldRemoveTrailingWhitespace() || shouldAddNewlineAtEof()) { + IRegion[] changedRegions= EditorUtility.calculateChangedLineRegions(buffer, getSubProgressMonitor(monitor, 20)); + IDocument document = buffer.getDocument(); + TextEdit edit = createSaveActionEdit(document, changedRegions); + if (edit != null) { + try { edit.apply(document); + } catch (MalformedTreeException e) { + String message= e.getMessage(); + if (message == null) + message= "MalformedTreeException"; //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, message, e)); + } catch (BadLocationException e) { + String message= e.getMessage(); + if (message == null) + message= "BadLocationException"; //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, message, e)); } } } } + private static boolean shouldAddNewlineAtEof() { + return PreferenceConstants.getPreferenceStore().getBoolean( + PreferenceConstants.ENSURE_NEWLINE_AT_EOF); + } + + private static boolean shouldRemoveTrailingWhitespace() { + return PreferenceConstants.getPreferenceStore().getBoolean( + PreferenceConstants.REMOVE_TRAILING_WHITESPACE); + } + + /** + * Creates a text edit for the save actions. + * @return a text edit, or null if the save actions leave the file intact. + */ + private TextEdit createSaveActionEdit(IDocument document, IRegion[] changedRegions) { + TextEdit rootEdit = null; + try { + if (shouldRemoveTrailingWhitespace()) { + // Remove trailing whitespace from changed lines. + for (IRegion region : changedRegions) { + int firstLine = document.getLineOfOffset(region.getOffset()); + int lastLine = document.getLineOfOffset(region.getOffset() + region.getLength()); + for (int line = firstLine; line <= lastLine; line++) { + IRegion lineRegion = document.getLineInformation(line); + if (lineRegion.getLength() == 0) { + continue; + } + int lineStart = lineRegion.getOffset(); + int lineEnd = lineStart + lineRegion.getLength(); + + // Find the rightmost none-whitespace character + int charPos = lineEnd - 1; + while (charPos >= lineStart && Character.isWhitespace(document.getChar(charPos))) + charPos--; + + charPos++; + if (charPos < lineEnd) { + TextEdit edit= new DeleteEdit(charPos, lineEnd - charPos); + if (rootEdit == null) { + rootEdit = new MultiTextEdit(); + } + rootEdit.addChild(edit); + } + } + } + } + if (shouldAddNewlineAtEof()) { + // Add newline at the end of the file. + int endOffset = document.getLength(); + IRegion lastLineRegion = document.getLineInformationOfOffset(endOffset); + if (lastLineRegion.getLength() != 0) { + for (IRegion region : changedRegions) { + if (region.getOffset() + region.getLength() >= lastLineRegion.getOffset()) { + // Last line has changed + if (!shouldRemoveTrailingWhitespace() || !isWhitespaceRegion(document, lastLineRegion)) { + TextEdit edit = new InsertEdit(endOffset, + TextUtilities.getDefaultLineDelimiter(document)); + if (rootEdit == null) { + rootEdit = edit; + } else { + rootEdit.addChild(edit); + } + } + break; + } + } + } + } + } catch (BadLocationException e) { + CUIPlugin.log(e); + } + return rootEdit; + } + + private static boolean isWhitespaceRegion(IDocument document, IRegion region) throws BadLocationException { + int end = region.getOffset() + region.getLength(); + for (int i = region.getOffset(); i < end; i++) { + if (!Character.isWhitespace(document.getChar(i))) { + return false; + } + } + return true; + } + /** * Returns the preference whether handling temporary problems is enabled. */ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties index c0204575571..5518298716f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties @@ -85,8 +85,8 @@ CEditorColoringConfigurationBlock_underline=&Underline CEditorColoringConfigurationBlock_strikethrough=&Strikethrough CEditorPreferencePage_colorPage_systemDefault=S&ystem Default -CEditorPreferencePage_behaviorPage_removeTrailingWhitespace=Remove trailing &whitespace -CEditorPreferencePage_behaviorPage_ensureNewline=Ensure &newline at end of file +CEditorPreferencePage_behaviorPage_removeTrailingWhitespace=Remove trailing &whitespace in edited lines +CEditorPreferencePage_behaviorPage_ensureNewline=Ensure &newline at the end of file CEditorPreferencePage_behaviorPage_matchingBrackets=Highlight &matching brackets CEditorPreferencePage_behaviorPage_subWordNavigation=Smart &caret positioning in identifiers CEditorPreferencePage_behaviorPage_inactiveCode=Highlight &inactive code diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/LineComparator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/LineComparator.java new file mode 100644 index 00000000000..eba6c92998d --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/LineComparator.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2009 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.text; + +import org.eclipse.compare.rangedifferencer.IRangeComparator; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; + +import org.eclipse.cdt.ui.CUIPlugin; + + +/** + * This implementation of IRangeComparator compares lines of a document. + * The lines are compared using a DJB hash function. + * + * @since 5.1 + */ +public class LineComparator implements IRangeComparator { + private static final long UNKNOWN_HASH = Long.MIN_VALUE; + private final IDocument fDocument; + private final long[] fHashes; + + /** + * Create a line comparator for the given document. + * + * @param document + */ + public LineComparator(IDocument document) { + fDocument= document; + + fHashes= new long[fDocument.getNumberOfLines()]; + for (int i = 0; i < fHashes.length; i++) { + fHashes[i] = UNKNOWN_HASH; + } + } + + /* + * @see org.eclipse.compare.rangedifferencer.IRangeComparator#getRangeCount() + */ + public int getRangeCount() { + return fDocument.getNumberOfLines(); + } + + /* + * @see org.eclipse.compare.rangedifferencer.IRangeComparator#rangesEqual(int, org.eclipse.compare.rangedifferencer.IRangeComparator, int) + */ + public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) { + try { + return getHash(thisIndex) == ((LineComparator) other).getHash(otherIndex); + } catch (BadLocationException e) { + CUIPlugin.log(e); + return false; + } + } + + /* + * @see org.eclipse.compare.rangedifferencer.IRangeComparator#skipRangeComparison(int, int, org.eclipse.compare.rangedifferencer.IRangeComparator) + */ + public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) { + return false; + } + + /** + * @param line the number of the line in the document to get the hash for + * @return the hash of the line + * @throws BadLocationException if the line number is invalid + */ + private int getHash(int line) throws BadLocationException { + long hash= fHashes[line]; + if (hash == UNKNOWN_HASH) { + IRegion lineRegion= fDocument.getLineInformation(line); + String lineContents= fDocument.get(lineRegion.getOffset(), lineRegion.getLength()); + hash= computeDJBHash(lineContents); + fHashes[line] = hash; + } + + return (int) hash; + } + + /** + * Compute a hash using the DJB hash algorithm + * + * @param string the string for which to compute a hash + * @return the DJB hash value of the string + */ + private int computeDJBHash(String string) { + int hash= 5381; + int len= string.length(); + for (int i= 0; i < len; i++) { + char ch= string.charAt(i); + hash= (hash << 5) + hash + ch; + } + + return hash; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java index e2d50a9a9cd..3ac5ff58128 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java @@ -18,8 +18,16 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.net.URI; +import java.util.ArrayList; +import java.util.List; import com.ibm.icu.text.MessageFormat; +import org.eclipse.compare.rangedifferencer.IRangeComparator; +import org.eclipse.compare.rangedifferencer.RangeDifference; +import org.eclipse.compare.rangedifferencer.RangeDifferencer; +import org.eclipse.core.filebuffers.FileBuffers; +import org.eclipse.core.filebuffers.ITextFileBuffer; +import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.URIUtil; @@ -33,10 +41,21 @@ import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.action.Action; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.MessageBox; @@ -71,9 +90,11 @@ import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.core.resources.ResourceLookup; +import org.eclipse.cdt.internal.ui.ICStatusConstants; import org.eclipse.cdt.internal.ui.editor.CEditor; import org.eclipse.cdt.internal.ui.editor.CEditorMessages; import org.eclipse.cdt.internal.ui.editor.ITranslationUnitEditorInput; +import org.eclipse.cdt.internal.ui.text.LineComparator; public class EditorUtility { @@ -726,4 +747,128 @@ public class EditorUtility { } return cProject; } + + /** + * Return the regions of all lines which have changed in the given buffer since the + * last save occurred. Each region in the result spans over the size of at least one line. + * If successive lines have changed a region spans over the size of all successive lines. + * The regions include line delimiters. + * + * @param buffer the buffer to compare contents from + * @param monitor to report progress to + * @return the regions of the changed lines + * @throws CoreException + * @since 5.1 + */ + public static IRegion[] calculateChangedLineRegions(final ITextFileBuffer buffer, final IProgressMonitor monitor) throws CoreException { + final IRegion[][] result= new IRegion[1][]; + final IStatus[] errorStatus= new IStatus[] { Status.OK_STATUS }; + + try { + SafeRunner.run(new ISafeRunnable() { + /* + * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) + */ + public void handleException(Throwable exception) { + CUIPlugin.log(new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, ICStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, exception.getLocalizedMessage(), exception)); + String msg= Messages.EditorUtility_error_calculatingChangedRegions; + errorStatus[0]= new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, ICStatusConstants.EDITOR_CHANGED_REGION_CALCULATION, msg, exception); + result[0]= null; + } + + /* + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + public void run() throws Exception { + monitor.beginTask(Messages.EditorUtility_calculatingChangedRegions_message, 20); + IFileStore fileStore= buffer.getFileStore(); + + ITextFileBufferManager fileBufferManager= FileBuffers.createTextFileBufferManager(); + fileBufferManager.connectFileStore(fileStore, getSubProgressMonitor(monitor, 15)); + try { + IDocument currentDocument= buffer.getDocument(); + IDocument oldDocument= ((ITextFileBuffer) fileBufferManager.getFileStoreFileBuffer(fileStore)).getDocument(); + + result[0]= getChangedLineRegions(oldDocument, currentDocument); + } finally { + fileBufferManager.disconnectFileStore(fileStore, getSubProgressMonitor(monitor, 5)); + monitor.done(); + } + } + + /** + * Return regions of all lines which differ comparing oldDocuments content + * with currentDocuments content. Successive lines are merged into one region. + * + * @param oldDocument a document containing the old content + * @param currentDocument a document containing the current content + * @return the changed regions + * @throws BadLocationException + */ + private IRegion[] getChangedLineRegions(IDocument oldDocument, IDocument currentDocument) throws BadLocationException { + /* + * Do not change the type of those local variables. We use Object + * here in order to prevent loading of the Compare plug-in at load + * time of this class. + */ + Object leftSide= new LineComparator(oldDocument); + Object rightSide= new LineComparator(currentDocument); + + RangeDifference[] differences= RangeDifferencer.findDifferences((IRangeComparator) leftSide, (IRangeComparator) rightSide); + + // It holds that: + // 1. Ranges are sorted: + // forAll r1,r2 element differences: indexOf(r1) < indexOf(r2) -> r1.rightStart() < r2.rightStart(); + // 2. Successive changed lines are merged into on RangeDifference + // forAll r1,r2 element differences: r1.rightStart() < r2.rightStart() -> r1.rightEnd() < r2.rightStart + + List regions= new ArrayList(); + for (int i= 0; i < differences.length; i++) { + RangeDifference curr= differences[i]; + if (curr.kind() == RangeDifference.CHANGE) { + int startLine= curr.rightStart(); + int endLine= curr.rightEnd() - 1; + + IRegion startLineRegion= currentDocument.getLineInformation(startLine); + if (startLine >= endLine) { + // startLine > endLine indicates a deletion of one or more lines. + // Deletions are ignored except at the end of the document. + if (startLine == endLine || + startLineRegion.getOffset() + startLineRegion.getLength() == currentDocument.getLength()) { + regions.add(startLineRegion); + } + } else { + IRegion endLineRegion= currentDocument.getLineInformation(endLine); + int startOffset= startLineRegion.getOffset(); + int endOffset= endLineRegion.getOffset() + endLineRegion.getLength(); + regions.add(new Region(startOffset, endOffset - startOffset)); + } + } + } + + return regions.toArray(new IRegion[regions.size()]); + } + }); + } finally { + if (!errorStatus[0].isOK()) + throw new CoreException(errorStatus[0]); + } + + return result[0]; + } + + /** + * Creates and returns a new sub-progress monitor for + * the given parent monitor. + * + * @param monitor the parent progress monitor + * @param ticks the number of work ticks allocated from the parent monitor + * @return the new sub-progress monitor + */ + private static IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) { + if (monitor != null) + return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); + + return new NullProgressMonitor(); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java index fd5d024cba2..0b90c85d7a6 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.java @@ -7,30 +7,29 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ - package org.eclipse.cdt.internal.ui.util; import com.ibm.icu.text.MessageFormat; -public class Messages { - public static String format(String pattern, Object[] args) { - return MessageFormat.format(pattern, args); +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME= Messages.class.getName(); + + public static String EditorUtility_calculatingChangedRegions_message; + public static String EditorUtility_error_calculatingChangedRegions; + + public static String format(String pattern, Object... arguments) { + return MessageFormat.format(pattern, arguments); } - public static String format(String pattern, Object arg0) { - return format(pattern, new Object[] {arg0}); - } + private Messages() { + // Do not instantiate + } - public static String format(String pattern, Object arg0, Object arg1) { - return format(pattern, new Object[] {arg0, arg1}); - } - - public static String format(String pattern, Object arg0, Object arg1, Object arg2) { - return format(pattern, new Object[] {arg0, arg1, arg2}); - } - - public static String format(String pattern, Object arg0, Object arg1, Object arg2, Object arg3) { - return format(pattern, new Object[] {arg0, arg1, arg2, arg3}); - } + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.properties new file mode 100644 index 00000000000..6805d5fb139 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/Messages.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2009 Google, Inc and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Sergey Prigogin (Google) - initial API and implementation +############################################################################### + +EditorUtility_calculatingChangedRegions_message=Calculating changed regions +EditorUtility_error_calculatingChangedRegions=An error occurred while calculating the changed regions. See error log for details.