diff options
Diffstat (limited to 'bundles/org.eclipse.wst.jsdt.ui/src/org/eclipse/wst/jsdt/internal/ui/javaeditor/SemanticHighlightingPresenter.java')
-rw-r--r-- | bundles/org.eclipse.wst.jsdt.ui/src/org/eclipse/wst/jsdt/internal/ui/javaeditor/SemanticHighlightingPresenter.java | 772 |
1 files changed, 0 insertions, 772 deletions
diff --git a/bundles/org.eclipse.wst.jsdt.ui/src/org/eclipse/wst/jsdt/internal/ui/javaeditor/SemanticHighlightingPresenter.java b/bundles/org.eclipse.wst.jsdt.ui/src/org/eclipse/wst/jsdt/internal/ui/javaeditor/SemanticHighlightingPresenter.java deleted file mode 100644 index b0054bc5..00000000 --- a/bundles/org.eclipse.wst.jsdt.ui/src/org/eclipse/wst/jsdt/internal/ui/javaeditor/SemanticHighlightingPresenter.java +++ /dev/null @@ -1,772 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 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 - *******************************************************************************/ - -package org.eclipse.wst.jsdt.internal.ui.javaeditor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.BadPositionCategoryException; -import org.eclipse.jface.text.DocumentEvent; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.IDocumentListener; -import org.eclipse.jface.text.IPositionUpdater; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ISynchronizable; -import org.eclipse.jface.text.ITextInputListener; -import org.eclipse.jface.text.ITextPresentationListener; -import org.eclipse.jface.text.Position; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.TextPresentation; -import org.eclipse.swt.custom.StyleRange; -import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin; -import org.eclipse.wst.jsdt.internal.ui.javaeditor.SemanticHighlightingManager.HighlightedPosition; -import org.eclipse.wst.jsdt.internal.ui.javaeditor.SemanticHighlightingManager.Highlighting; -import org.eclipse.wst.jsdt.internal.ui.text.JavaPresentationReconciler; - - -/** - * Semantic highlighting presenter - UI thread implementation. - * - * - */ -public class SemanticHighlightingPresenter implements ITextPresentationListener, ITextInputListener, IDocumentListener { - - /** - * Semantic highlighting position updater. - */ - private class HighlightingPositionUpdater implements IPositionUpdater { - - /** The position category. */ - private final String fCategory; - - /** - * Creates a new updater for the given <code>category</code>. - * - * @param category the new category. - */ - public HighlightingPositionUpdater(String category) { - fCategory= category; - } - - /* - * @see org.eclipse.jface.text.IPositionUpdater#update(org.eclipse.jface.text.DocumentEvent) - */ - public void update(DocumentEvent event) { - - int eventOffset= event.getOffset(); - int eventOldLength= event.getLength(); - int eventEnd= eventOffset + eventOldLength; - - try { - Position[] positions= event.getDocument().getPositions(fCategory); - - for (int i= 0; i != positions.length; i++) { - - HighlightedPosition position= (HighlightedPosition) positions[i]; - - // Also update deleted positions because they get deleted by the background thread and removed/invalidated only in the UI runnable -// if (position.isDeleted()) -// continue; - - int offset= position.getOffset(); - int length= position.getLength(); - int end= offset + length; - - if (offset > eventEnd) - updateWithPrecedingEvent(position, event); - else if (end < eventOffset) - updateWithSucceedingEvent(position, event); - else if (offset <= eventOffset && end >= eventEnd) - updateWithIncludedEvent(position, event); - else if (offset <= eventOffset) - updateWithOverEndEvent(position, event); - else if (end >= eventEnd) - updateWithOverStartEvent(position, event); - else - updateWithIncludingEvent(position, event); - } - } catch (BadPositionCategoryException e) { - // ignore and return - } - } - - /** - * Update the given position with the given event. The event precedes the position. - * - * @param position The position - * @param event The event - */ - private void updateWithPrecedingEvent(HighlightedPosition position, DocumentEvent event) { - String newText= event.getText(); - int eventNewLength= newText != null ? newText.length() : 0; - int deltaLength= eventNewLength - event.getLength(); - - position.setOffset(position.getOffset() + deltaLength); - } - - /** - * Update the given position with the given event. The event succeeds the position. - * - * @param position The position - * @param event The event - */ - private void updateWithSucceedingEvent(HighlightedPosition position, DocumentEvent event) { - } - - /** - * Update the given position with the given event. The event is included by the position. - * - * @param position The position - * @param event The event - */ - private void updateWithIncludedEvent(HighlightedPosition position, DocumentEvent event) { - int eventOffset= event.getOffset(); - String newText= event.getText(); - if (newText == null) - newText= ""; //$NON-NLS-1$ - int eventNewLength= newText.length(); - - int deltaLength= eventNewLength - event.getLength(); - - int offset= position.getOffset(); - int length= position.getLength(); - int end= offset + length; - - int includedLength= 0; - while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength))) - includedLength++; - if (includedLength == eventNewLength) - position.setLength(length + deltaLength); - else { - int newLeftLength= eventOffset - offset + includedLength; - - int excludedLength= eventNewLength; - while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1))) - excludedLength--; - int newRightOffset= eventOffset + excludedLength; - int newRightLength= end + deltaLength - newRightOffset; - - if (newRightLength == 0) { - position.setLength(newLeftLength); - } else { - if (newLeftLength == 0) { - position.update(newRightOffset, newRightLength); - } else { - position.setLength(newLeftLength); - addPositionFromUI(newRightOffset, newRightLength, position.getHighlighting()); - } - } - } - } - - /** - * Update the given position with the given event. The event overlaps with the end of the position. - * - * @param position The position - * @param event The event - */ - private void updateWithOverEndEvent(HighlightedPosition position, DocumentEvent event) { - String newText= event.getText(); - if (newText == null) - newText= ""; //$NON-NLS-1$ - int eventNewLength= newText.length(); - - int includedLength= 0; - while (includedLength < eventNewLength && Character.isJavaIdentifierPart(newText.charAt(includedLength))) - includedLength++; - position.setLength(event.getOffset() - position.getOffset() + includedLength); - } - - /** - * Update the given position with the given event. The event overlaps with the start of the position. - * - * @param position The position - * @param event The event - */ - private void updateWithOverStartEvent(HighlightedPosition position, DocumentEvent event) { - int eventOffset= event.getOffset(); - int eventEnd= eventOffset + event.getLength(); - - String newText= event.getText(); - if (newText == null) - newText= ""; //$NON-NLS-1$ - int eventNewLength= newText.length(); - - int excludedLength= eventNewLength; - while (excludedLength > 0 && Character.isJavaIdentifierPart(newText.charAt(excludedLength - 1))) - excludedLength--; - int deleted= eventEnd - position.getOffset(); - int inserted= eventNewLength - excludedLength; - position.update(eventOffset + excludedLength, position.getLength() - deleted + inserted); - } - - /** - * Update the given position with the given event. The event includes the position. - * - * @param position The position - * @param event The event - */ - private void updateWithIncludingEvent(HighlightedPosition position, DocumentEvent event) { - position.delete(); - position.update(event.getOffset(), 0); - } - } - - /** Position updater */ - private IPositionUpdater fPositionUpdater= new HighlightingPositionUpdater(getPositionCategory()); - - /** The source viewer this semantic highlighting reconciler is installed on */ - private JavaSourceViewer fSourceViewer; - /** The background presentation reconciler */ - private JavaPresentationReconciler fPresentationReconciler; - - /** UI's current highlighted positions - can contain <code>null</code> elements */ - private List fPositions= new ArrayList(); - /** UI position lock */ - private Object fPositionLock= new Object(); - - /** <code>true</code> iff the current reconcile is canceled. */ - private boolean fIsCanceled= false; - - /** - * Creates and returns a new highlighted position with the given offset, length and highlighting. - * <p> - * NOTE: Also called from background thread. - * </p> - * - * @param offset The offset - * @param length The length - * @param highlighting The highlighting - * @return The new highlighted position - */ - public HighlightedPosition createHighlightedPosition(int offset, int length, Highlighting highlighting) { - // TODO: reuse deleted positions - return new HighlightedPosition(offset, length, highlighting, fPositionUpdater); - } - - /** - * Adds all current positions to the given list. - * <p> - * NOTE: Called from background thread. - * </p> - * - * @param list The list - */ - public void addAllPositions(List list) { - synchronized (fPositionLock) { - list.addAll(fPositions); - } - } - - /** - * Create a text presentation in the background. - * <p> - * NOTE: Called from background thread. - * </p> - * - * @param addedPositions the added positions - * @param removedPositions the removed positions - * @return the text presentation or <code>null</code>, if reconciliation should be canceled - */ - public TextPresentation createPresentation(List addedPositions, List removedPositions) { - JavaSourceViewer sourceViewer= fSourceViewer; - JavaPresentationReconciler presentationReconciler= fPresentationReconciler; - if (sourceViewer == null || presentationReconciler == null) - return null; - - if (isCanceled()) - return null; - - IDocument document= sourceViewer.getDocument(); - if (document == null) - return null; - - int minStart= Integer.MAX_VALUE; - int maxEnd= Integer.MIN_VALUE; - for (int i= 0, n= removedPositions.size(); i < n; i++) { - Position position= (Position) removedPositions.get(i); - int offset= position.getOffset(); - minStart= Math.min(minStart, offset); - maxEnd= Math.max(maxEnd, offset + position.getLength()); - } - for (int i= 0, n= addedPositions.size(); i < n; i++) { - Position position= (Position) addedPositions.get(i); - int offset= position.getOffset(); - minStart= Math.min(minStart, offset); - maxEnd= Math.max(maxEnd, offset + position.getLength()); - } - - if (minStart < maxEnd) - try { - return presentationReconciler.createRepairDescription(new Region(minStart, maxEnd - minStart), document); - } catch (RuntimeException e) { - // Assume concurrent modification from UI thread - } - - return null; - } - - /** - * Create a runnable for updating the presentation. - * <p> - * NOTE: Called from background thread. - * </p> - * @param textPresentation the text presentation - * @param addedPositions the added positions - * @param removedPositions the removed positions - * @return the runnable or <code>null</code>, if reconciliation should be canceled - */ - public Runnable createUpdateRunnable(final TextPresentation textPresentation, List addedPositions, List removedPositions) { - if (fSourceViewer == null || textPresentation == null) - return null; - - // TODO: do clustering of positions and post multiple fast runnables - final HighlightedPosition[] added= new SemanticHighlightingManager.HighlightedPosition[addedPositions.size()]; - addedPositions.toArray(added); - final SemanticHighlightingManager.HighlightedPosition[] removed= new SemanticHighlightingManager.HighlightedPosition[removedPositions.size()]; - removedPositions.toArray(removed); - - if (isCanceled()) - return null; - - Runnable runnable= new Runnable() { - public void run() { - updatePresentation(textPresentation, added, removed); - } - }; - return runnable; - } - - /** - * Invalidate the presentation of the positions based on the given added positions and the existing deleted positions. - * Also unregisters the deleted positions from the document and patches the positions of this presenter. - * <p> - * NOTE: Indirectly called from background thread by UI runnable. - * </p> - * @param textPresentation the text presentation or <code>null</code>, if the presentation should computed in the UI thread - * @param addedPositions the added positions - * @param removedPositions the removed positions - */ - public void updatePresentation(TextPresentation textPresentation, HighlightedPosition[] addedPositions, HighlightedPosition[] removedPositions) { - if (fSourceViewer == null) - return; - -// checkOrdering("added positions: ", Arrays.asList(addedPositions)); //$NON-NLS-1$ -// checkOrdering("removed positions: ", Arrays.asList(removedPositions)); //$NON-NLS-1$ -// checkOrdering("old positions: ", fPositions); //$NON-NLS-1$ - - // TODO: double-check consistency with document.getPositions(...) - // TODO: reuse removed positions - if (isCanceled()) - return; - - IDocument document= fSourceViewer.getDocument(); - if (document == null) - return; - - String positionCategory= getPositionCategory(); - - List removedPositionsList= Arrays.asList(removedPositions); - - try { - synchronized (fPositionLock) { - List oldPositions= fPositions; - int newSize= Math.max(fPositions.size() + addedPositions.length - removedPositions.length, 10); - - /* - * The following loop is a kind of merge sort: it merges two List<Position>, each - * sorted by position.offset, into one new list. The first of the two is the - * previous list of positions (oldPositions), from which any deleted positions get - * removed on the fly. The second of two is the list of added positions. The result - * is stored in newPositions. - */ - List newPositions= new ArrayList(newSize); - Position position= null; - Position addedPosition= null; - for (int i= 0, j= 0, n= oldPositions.size(), m= addedPositions.length; i < n || position != null || j < m || addedPosition != null;) { - // loop variant: i + j < old(i + j) - - // a) find the next non-deleted Position from the old list - while (position == null && i < n) { - position= (Position) oldPositions.get(i++); - if (position.isDeleted() || contain(removedPositionsList, position)) { - document.removePosition(positionCategory, position); - position= null; - } - } - - // b) find the next Position from the added list - if (addedPosition == null && j < m) { - addedPosition= addedPositions[j++]; - document.addPosition(positionCategory, addedPosition); - } - - // c) merge: add the next of position/addedPosition with the lower offset - if (position != null) { - if (addedPosition != null) - if (position.getOffset() <= addedPosition.getOffset()) { - newPositions.add(position); - position= null; - } else { - newPositions.add(addedPosition); - addedPosition= null; - } - else { - newPositions.add(position); - position= null; - } - } else if (addedPosition != null) { - newPositions.add(addedPosition); - addedPosition= null; - } - } - fPositions= newPositions; - } - } catch (BadPositionCategoryException e) { - // Should not happen - JavaScriptPlugin.log(e); - } catch (BadLocationException e) { - // Should not happen - JavaScriptPlugin.log(e); - } -// checkOrdering("new positions: ", fPositions); //$NON-NLS-1$ - - if (textPresentation != null) - fSourceViewer.changeTextPresentation(textPresentation, false); - else - fSourceViewer.invalidateTextPresentation(); - } - -// private void checkOrdering(String s, List positions) { -// Position previous= null; -// for (int i= 0, n= positions.size(); i < n; i++) { -// Position current= (Position) positions.get(i); -// if (previous != null && previous.getOffset() + previous.getLength() > current.getOffset()) -// return; -// } -// } - - /** - * Returns <code>true</code> iff the positions contain the position. - * @param positions the positions, must be ordered by offset but may overlap - * @param position the position - * @return <code>true</code> iff the positions contain the position - */ - private boolean contain(List positions, Position position) { - return indexOf(positions, position) != -1; - } - - /** - * Returns index of the position in the positions, <code>-1</code> if not found. - * @param positions the positions, must be ordered by offset but may overlap - * @param position the position - * @return the index - */ - private int indexOf(List positions, Position position) { - int index= computeIndexAtOffset(positions, position.getOffset()); - int size= positions.size(); - while (index < size) { - if (positions.get(index) == position) - return index; - index++; - } - return -1; - } - - /** - * Insert the given position in <code>fPositions</code>, s.t. the offsets remain in linear order. - * - * @param position The position for insertion - */ - private void insertPosition(Position position) { - int i= computeIndexAfterOffset(fPositions, position.getOffset()); - fPositions.add(i, position); - } - - /** - * Returns the index of the first position with an offset greater than the given offset. - * - * @param positions the positions, must be ordered by offset and must not overlap - * @param offset the offset - * @return the index of the last position with an offset greater than the given offset - */ - private int computeIndexAfterOffset(List positions, int offset) { - int i= -1; - int j= positions.size(); - while (j - i > 1) { - int k= (i + j) >> 1; - Position position= (Position) positions.get(k); - if (position.getOffset() > offset) - j= k; - else - i= k; - } - return j; - } - - /** - * Returns the index of the first position with an offset equal or greater than the given offset. - * - * @param positions the positions, must be ordered by offset and must not overlap - * @param offset the offset - * @return the index of the last position with an offset equal or greater than the given offset - */ - private int computeIndexAtOffset(List positions, int offset) { - int i= -1; - int j= positions.size(); - while (j - i > 1) { - int k= (i + j) >> 1; - Position position= (Position) positions.get(k); - if (position.getOffset() >= offset) - j= k; - else - i= k; - } - return j; - } - - /* - * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) - */ - public void applyTextPresentation(TextPresentation textPresentation) { - IRegion region= textPresentation.getExtent(); - int i= computeIndexAtOffset(fPositions, region.getOffset()), n= computeIndexAtOffset(fPositions, region.getOffset() + region.getLength()); - if (n - i > 2) { - List ranges= new ArrayList(n - i); - for (; i < n; i++) { - HighlightedPosition position= (HighlightedPosition) fPositions.get(i); - if (!position.isDeleted()) - ranges.add(position.createStyleRange()); - } - StyleRange[] array= new StyleRange[ranges.size()]; - array= (StyleRange[]) ranges.toArray(array); - textPresentation.replaceStyleRanges(array); - } else { - for (; i < n; i++) { - HighlightedPosition position= (HighlightedPosition) fPositions.get(i); - if (!position.isDeleted()) - textPresentation.replaceStyleRange(position.createStyleRange()); - } - } - } - - /* - * @see org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) - */ - public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { - setCanceled(true); - releaseDocument(oldInput); - resetState(); - } - - /* - * @see org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument) - */ - public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { - manageDocument(newInput); - } - - /* - * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) - */ - public void documentAboutToBeChanged(DocumentEvent event) { - setCanceled(true); - } - - /* - * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) - */ - public void documentChanged(DocumentEvent event) { - } - - /** - * @return Returns <code>true</code> iff the current reconcile is canceled. - * <p> - * NOTE: Also called from background thread. - * </p> - */ - public boolean isCanceled() { - IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null; - if (document == null) - return fIsCanceled; - - synchronized (getLockObject(document)) { - return fIsCanceled; - } - } - - /** - * Set whether or not the current reconcile is canceled. - * - * @param isCanceled <code>true</code> iff the current reconcile is canceled - */ - public void setCanceled(boolean isCanceled) { - IDocument document= fSourceViewer != null ? fSourceViewer.getDocument() : null; - if (document == null) { - fIsCanceled= isCanceled; - return; - } - - synchronized (getLockObject(document)) { - fIsCanceled= isCanceled; - } - } - - /** - * @param document the document - * @return the document's lock object - */ - private Object getLockObject(IDocument document) { - if (document instanceof ISynchronizable) { - Object lock= ((ISynchronizable)document).getLockObject(); - if (lock != null) - return lock; - } - return document; - } - - /** - * Install this presenter on the given source viewer and background presentation - * reconciler. - * - * @param sourceViewer the source viewer - * @param backgroundPresentationReconciler the background presentation reconciler, - * can be <code>null</code>, in that case {@link SemanticHighlightingPresenter#createPresentation(List, List)} - * should not be called - */ - public void install(JavaSourceViewer sourceViewer, JavaPresentationReconciler backgroundPresentationReconciler) { - fSourceViewer= sourceViewer; - fPresentationReconciler= backgroundPresentationReconciler; - - fSourceViewer.prependTextPresentationListener(this); - fSourceViewer.addTextInputListener(this); - manageDocument(fSourceViewer.getDocument()); - } - - /** - * Uninstall this presenter. - */ - public void uninstall() { - setCanceled(true); - - if (fSourceViewer != null) { - fSourceViewer.removeTextPresentationListener(this); - releaseDocument(fSourceViewer.getDocument()); - invalidateTextPresentation(); - resetState(); - - fSourceViewer.removeTextInputListener(this); - fSourceViewer= null; - } - } - - /** - * Invalidate text presentation of positions with the given highlighting. - * - * @param highlighting The highlighting - */ - public void highlightingStyleChanged(Highlighting highlighting) { - for (int i= 0, n= fPositions.size(); i < n; i++) { - HighlightedPosition position= (HighlightedPosition) fPositions.get(i); - if (position.getHighlighting() == highlighting) - fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength()); - } - } - - /** - * Invalidate text presentation of all positions. - */ - private void invalidateTextPresentation() { - for (int i= 0, n= fPositions.size(); i < n; i++) { - Position position= (Position) fPositions.get(i); - fSourceViewer.invalidateTextPresentation(position.getOffset(), position.getLength()); - } - } - - /** - * Add a position with the given range and highlighting unconditionally, only from UI thread. - * The position will also be registered on the document. The text presentation is not invalidated. - * - * @param offset The range offset - * @param length The range length - * @param highlighting - */ - private void addPositionFromUI(int offset, int length, Highlighting highlighting) { - Position position= createHighlightedPosition(offset, length, highlighting); - synchronized (fPositionLock) { - insertPosition(position); - } - - IDocument document= fSourceViewer.getDocument(); - if (document == null) - return; - String positionCategory= getPositionCategory(); - try { - document.addPosition(positionCategory, position); - } catch (BadLocationException e) { - // Should not happen - JavaScriptPlugin.log(e); - } catch (BadPositionCategoryException e) { - // Should not happen - JavaScriptPlugin.log(e); - } - } - - /** - * Reset to initial state. - */ - private void resetState() { - synchronized (fPositionLock) { - fPositions.clear(); - } - } - - /** - * Start managing the given document. - * - * @param document The document - */ - private void manageDocument(IDocument document) { - if (document != null) { - document.addPositionCategory(getPositionCategory()); - document.addPositionUpdater(fPositionUpdater); - document.addDocumentListener(this); - } - } - - /** - * Stop managing the given document. - * - * @param document The document - */ - private void releaseDocument(IDocument document) { - if (document != null) { - document.removeDocumentListener(this); - document.removePositionUpdater(fPositionUpdater); - try { - document.removePositionCategory(getPositionCategory()); - } catch (BadPositionCategoryException e) { - // Should not happen - JavaScriptPlugin.log(e); - } - } - } - - /** - * @return The semantic reconciler position's category. - */ - private String getPositionCategory() { - return toString(); - } -} |