Mercurial > projects > dwt-addons
view dwtx/jface/text/source/DefaultCharacterPairMatcher.d @ 153:f70d9508c95c
Fix java Collection imports
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 25 Aug 2008 00:27:31 +0200 |
parents | 75302ef3f92f |
children |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2006, 2007 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: * Christian Plesner Hansen (plesner@quenta.org) - initial API and implementation * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwtx.jface.text.source.DefaultCharacterPairMatcher; import dwtx.jface.text.source.ISharedTextColors; // packageimport import dwtx.jface.text.source.ILineRange; // packageimport import dwtx.jface.text.source.IAnnotationPresentation; // packageimport import dwtx.jface.text.source.IVerticalRulerInfoExtension; // packageimport import dwtx.jface.text.source.ICharacterPairMatcher; // packageimport import dwtx.jface.text.source.TextInvocationContext; // packageimport import dwtx.jface.text.source.LineChangeHover; // packageimport import dwtx.jface.text.source.IChangeRulerColumn; // packageimport import dwtx.jface.text.source.IAnnotationMap; // packageimport import dwtx.jface.text.source.IAnnotationModelListenerExtension; // packageimport import dwtx.jface.text.source.ISourceViewerExtension2; // packageimport import dwtx.jface.text.source.IAnnotationHover; // packageimport import dwtx.jface.text.source.ContentAssistantFacade; // packageimport import dwtx.jface.text.source.IAnnotationAccess; // packageimport import dwtx.jface.text.source.IVerticalRulerExtension; // packageimport import dwtx.jface.text.source.IVerticalRulerColumn; // packageimport import dwtx.jface.text.source.LineNumberRulerColumn; // packageimport import dwtx.jface.text.source.MatchingCharacterPainter; // packageimport import dwtx.jface.text.source.IAnnotationModelExtension; // packageimport import dwtx.jface.text.source.ILineDifferExtension; // packageimport import dwtx.jface.text.source.LineNumberChangeRulerColumn; // packageimport import dwtx.jface.text.source.IAnnotationAccessExtension; // packageimport import dwtx.jface.text.source.ISourceViewer; // packageimport import dwtx.jface.text.source.AnnotationModel; // packageimport import dwtx.jface.text.source.ILineDifferExtension2; // packageimport import dwtx.jface.text.source.IAnnotationModelListener; // packageimport import dwtx.jface.text.source.IVerticalRuler; // packageimport import dwtx.jface.text.source.DefaultAnnotationHover; // packageimport import dwtx.jface.text.source.SourceViewer; // packageimport import dwtx.jface.text.source.SourceViewerConfiguration; // packageimport import dwtx.jface.text.source.AnnotationBarHoverManager; // packageimport import dwtx.jface.text.source.CompositeRuler; // packageimport import dwtx.jface.text.source.ImageUtilities; // packageimport import dwtx.jface.text.source.VisualAnnotationModel; // packageimport import dwtx.jface.text.source.IAnnotationModel; // packageimport import dwtx.jface.text.source.ISourceViewerExtension3; // packageimport import dwtx.jface.text.source.ILineDiffInfo; // packageimport import dwtx.jface.text.source.VerticalRulerEvent; // packageimport import dwtx.jface.text.source.ChangeRulerColumn; // packageimport import dwtx.jface.text.source.ILineDiffer; // packageimport import dwtx.jface.text.source.AnnotationModelEvent; // packageimport import dwtx.jface.text.source.AnnotationColumn; // packageimport import dwtx.jface.text.source.AnnotationRulerColumn; // packageimport import dwtx.jface.text.source.IAnnotationHoverExtension; // packageimport import dwtx.jface.text.source.AbstractRulerColumn; // packageimport import dwtx.jface.text.source.ISourceViewerExtension; // packageimport import dwtx.jface.text.source.AnnotationMap; // packageimport import dwtx.jface.text.source.IVerticalRulerInfo; // packageimport import dwtx.jface.text.source.IAnnotationModelExtension2; // packageimport import dwtx.jface.text.source.LineRange; // packageimport import dwtx.jface.text.source.IAnnotationAccessExtension2; // packageimport import dwtx.jface.text.source.VerticalRuler; // packageimport import dwtx.jface.text.source.JFaceTextMessages; // packageimport import dwtx.jface.text.source.IOverviewRuler; // packageimport import dwtx.jface.text.source.Annotation; // packageimport import dwtx.jface.text.source.IVerticalRulerListener; // packageimport import dwtx.jface.text.source.ISourceViewerExtension4; // packageimport import dwtx.jface.text.source.AnnotationPainter; // packageimport import dwtx.jface.text.source.IAnnotationHoverExtension2; // packageimport import dwtx.jface.text.source.OverviewRuler; // packageimport import dwtx.jface.text.source.OverviewRulerHoverManager; // packageimport import dwt.dwthelper.utils; import dwtx.dwtxhelper.Collection; import dwtx.core.runtime.Assert; import dwtx.jface.text.BadLocationException; import dwtx.jface.text.IDocument; import dwtx.jface.text.IDocumentExtension3; import dwtx.jface.text.IRegion; import dwtx.jface.text.ITypedRegion; import dwtx.jface.text.Region; import dwtx.jface.text.TextUtilities; /** * A character pair matcher that matches a specified set of character * pairs against each other. Only characters that occur in the same * partitioning are matched. * * @since 3.3 */ public class DefaultCharacterPairMatcher : ICharacterPairMatcher { private int fAnchor= -1; private const CharPairs fPairs; private const String fPartitioning; /** * Creates a new character pair matcher that matches the specified * characters within the specified partitioning. The specified * list of characters must have the form * <blockquote>{ <i>start</i>, <i>end</i>, <i>start</i>, <i>end</i>, ..., <i>start</i>, <i>end</i> }</blockquote> * For instance: * <pre> * char[] chars = new char[] {'(', ')', '{', '}', '[', ']'}; * new SimpleCharacterPairMatcher(chars, ...); * </pre> * * @param chars a list of characters * @param partitioning the partitioning to match within */ public this(char[] chars, String partitioning) { Assert.isLegal(chars.length % 2 is 0); Assert.isNotNull(partitioning); fPairs= new CharPairs(chars); fPartitioning= partitioning; } /** * Creates a new character pair matcher that matches characters * within the default partitioning. The specified list of * characters must have the form * <blockquote>{ <i>start</i>, <i>end</i>, <i>start</i>, <i>end</i>, ..., <i>start</i>, <i>end</i> }</blockquote> * For instance: * <pre> * char[] chars = new char[] {'(', ')', '{', '}', '[', ']'}; * new SimpleCharacterPairMatcher(chars); * </pre> * * @param chars a list of characters */ public this(char[] chars) { this(chars, IDocumentExtension3.DEFAULT_PARTITIONING); } /* @see ICharacterPairMatcher#match(IDocument, int) */ public IRegion match(IDocument doc, int offset) { if (doc is null || offset < 0 || offset > doc.getLength()) return null; try { return performMatch(doc, offset); } catch (BadLocationException ble) { return null; } } /* * Performs the actual work of matching for #match(IDocument, int). */ private IRegion performMatch(IDocument doc, int caretOffset) { final int charOffset= caretOffset - 1; final char prevChar= doc.getChar(Math.max(charOffset, 0)); if (!fPairs.contains(prevChar)) return null; final bool isForward= fPairs.isStartCharacter(prevChar); fAnchor= isForward ? ICharacterPairMatcher.LEFT : ICharacterPairMatcher.RIGHT; final int searchStartPosition= isForward ? caretOffset : caretOffset - 2; final int adjustedOffset= isForward ? charOffset : caretOffset; final String partition= TextUtilities.getContentType(doc, fPartitioning, charOffset, false); final DocumentPartitionAccessor partDoc= new DocumentPartitionAccessor(doc, fPartitioning, partition); int endOffset= findMatchingPeer(partDoc, prevChar, fPairs.getMatching(prevChar), isForward, isForward ? doc.getLength() : -1, searchStartPosition); if (endOffset is -1) return null; final int adjustedEndOffset= isForward ? endOffset + 1: endOffset; if (adjustedEndOffset is adjustedOffset) return null; return new Region(Math.min(adjustedOffset, adjustedEndOffset), Math.abs(adjustedEndOffset - adjustedOffset)); } /** * Searches <code>doc</code> for the specified end character, <code>end</code>. * * @param doc the document to search * @param start the opening matching character * @param end the end character to search for * @param searchForward search forwards or backwards? * @param boundary a boundary at which the search should stop * @param startPos the start offset * @return the index of the end character if it was found, otherwise -1 * @throws BadLocationException */ private int findMatchingPeer(DocumentPartitionAccessor doc, char start, char end, bool searchForward, int boundary, int startPos) { int pos= startPos; while (pos !is boundary) { final char c= doc.getChar(pos); if (doc.isMatch(pos, end)) { return pos; } else if (c is start && doc.inPartition(pos)) { pos= findMatchingPeer(doc, start, end, searchForward, boundary, doc.getNextPosition(pos, searchForward)); if (pos is -1) return -1; } pos= doc.getNextPosition(pos, searchForward); } return -1; } /* @see ICharacterPairMatcher#getAnchor() */ public int getAnchor() { return fAnchor; } /* @see ICharacterPairMatcher#dispose() */ public void dispose() { } /* @see ICharacterPairMatcher#clear() */ public void clear() { fAnchor= -1; } /** * Utility class that wraps a document and gives access to * partitioning information. A document is tied to a particular * partition and, when considering whether or not a position is a * valid match, only considers position within its partition. */ private static class DocumentPartitionAccessor { private const IDocument fDocument; private const String fPartitioning, fPartition; private ITypedRegion fCachedPartition; /** * Creates a new partitioned document for the specified document. * * @param doc the document to wrap * @param partitioning the partitioning used * @param partition the partition managed by this document */ public this(IDocument doc, String partitioning, String partition) { fDocument= doc; fPartitioning= partitioning; fPartition= partition; } /** * Returns the character at the specified position in this document. * * @param pos an offset within this document * @return the character at the offset * @throws BadLocationException */ public char getChar(int pos) { return fDocument.getChar(pos); } /** * Returns true if the character at the specified position is a * valid match for the specified end character. To be a valid * match, it must be in the appropriate partition and equal to the * end character. * * @param pos an offset within this document * @param end the end character to match against * @return true exactly if the position represents a valid match * @throws BadLocationException */ public bool isMatch(int pos, char end) { return getChar(pos) is end && inPartition(pos); } /** * Returns true if the specified offset is within the partition * managed by this document. * * @param pos an offset within this document * @return true if the offset is within this document's partition */ public bool inPartition(int pos) { final ITypedRegion partition= getPartition(pos); return partition !is null && partition.getType().equals(fPartition); } /** * Returns the next position to query in the search. The position * is not guaranteed to be in this document's partition. * * @param pos an offset within the document * @param searchForward the direction of the search * @return the next position to query */ public int getNextPosition(int pos, bool searchForward) { final ITypedRegion partition= getPartition(pos); if (partition is null) return simpleIncrement(pos, searchForward); if (fPartition.equals(partition.getType())) return simpleIncrement(pos, searchForward); if (searchForward) { int end= partition.getOffset() + partition.getLength(); if (pos < end) return end; } else { int offset= partition.getOffset(); if (pos > offset) return offset - 1; } return simpleIncrement(pos, searchForward); } private int simpleIncrement(int pos, bool searchForward) { return pos + (searchForward ? 1 : -1); } /** * Returns partition information about the region containing the * specified position. * * @param pos a position within this document. * @return positioning information about the region containing the * position */ private ITypedRegion getPartition(int pos) { if (fCachedPartition is null || !contains(fCachedPartition, pos)) { Assert.isTrue(pos >= 0 && pos <= fDocument.getLength()); try { fCachedPartition= TextUtilities.getPartition(fDocument, fPartitioning, pos, false); } catch (BadLocationException e) { fCachedPartition= null; } } return fCachedPartition; } private static bool contains(IRegion region, int pos) { int offset= region.getOffset(); return offset <= pos && pos < offset + region.getLength(); } } /** * Utility class that encapsulates access to matching character pairs. */ private static class CharPairs { private const char[] fPairs; public this(char[] pairs) { fPairs= pairs; } /** * Returns true if the specified character pair occurs in one * of the character pairs. * * @param c a character * @return true exactly if the character occurs in one of the pairs */ public bool contains(char c) { return getAllCharacters().contains(new Character(c)); } private Set/*<Character>*/ fCharsCache= null; /** * @return A set containing all characters occurring in character pairs. */ private Set/*<Character>*/ getAllCharacters() { if (fCharsCache is null) { Set/*<Character>*/ set= new HashSet/*<Character>*/(); for (int i= 0; i < fPairs.length; i++) set.add(new Character(fPairs[i])); fCharsCache= set; } return fCharsCache; } /** * Returns true if the specified character opens a character pair * when scanning in the specified direction. * * @param c a character * @param searchForward the direction of the search * @return whether or not the character opens a character pair */ public bool isOpeningCharacter(char c, bool searchForward) { for (int i= 0; i < fPairs.length; i += 2) { if (searchForward && getStartChar(i) is c) return true; else if (!searchForward && getEndChar(i) is c) return true; } return false; } /** * Returns true of the specified character is a start character. * * @param c a character * @return true exactly if the character is a start character */ public bool isStartCharacter(char c) { return this.isOpeningCharacter(c, true); } /** * Returns the matching character for the specified character. * * @param c a character occurring in a character pair * @return the matching character */ public char getMatching(char c) { for (int i= 0; i < fPairs.length; i += 2) { if (getStartChar(i) is c) return getEndChar(i); else if (getEndChar(i) is c) return getStartChar(i); } Assert.isTrue(false); return '\0'; } private char getStartChar(int i) { return fPairs[i]; } private char getEndChar(int i) { return fPairs[i + 1]; } } }