javax.swing.text.AbstractDocument#readLock ( )源码实例Demo

下面列出了javax.swing.text.AbstractDocument#readLock ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

源代码1 项目: netbeans   文件: CodeFoldingTestCase.java
public static String foldHierarchyToString(JTextComponent target){
    String ret = "";
    AbstractDocument adoc = (AbstractDocument)target.getDocument();

    // Dump fold hierarchy
    FoldHierarchy hierarchy = FoldHierarchy.get(target);
    adoc.readLock();
    try {
        hierarchy.lock();
        try {
            Fold root = hierarchy.getRootFold();
            ret = (root == null) ? "root is null" : foldToStringChildren(root, 0); //NOI18N
        } finally {
            hierarchy.unlock();
        }
    } finally {
        adoc.readUnlock();
    }
    return ret;
}
 
源代码2 项目: netbeans   文件: PHPTokenList.java
private int[] findNextPHPDocComment() throws BadLocationException {
    TokenSequence<PHPTokenId> ts = null;
    if (doc instanceof AbstractDocument) {
        AbstractDocument ad = (AbstractDocument) doc;
        ad.readLock();
        try {
            ts = LexUtilities.getPHPTokenSequence(ad, nextBlockStart);
        } finally {
            ad.readUnlock();
        }
    }
    if (ts == null) {
        return new int[]{-1, -1};
    }

    ts.move(nextBlockStart);
    while (ts.moveNext()) {
        if (ts.token().id() == PHPTokenId.PHPDOC_COMMENT) {
            return new int[]{ts.offset(), ts.offset() + ts.token().length()};
        }
    }
    return new int[]{-1, -1};
}
 
源代码3 项目: netbeans   文件: GapDocumentView.java
public void run() {
    AbstractDocument doc = (AbstractDocument)getDocument();
    if (doc!=null){
        doc.readLock();
        try {
            LockView lockView = LockView.get(GapDocumentView.this);
            if (lockView != null) {
                lockView.lock();
                try {
                    layoutLock();
                    try {
                        updateView(lockView);
                    } finally {
                        updateLayout();
                        layoutUnlock();
                    }
                } finally {
                    lockView.unlock();
                }
            } // missing lock view => likely disconnected from hierarchy
        } finally {
            doc.readUnlock();
        }
    }
}
 
源代码4 项目: netbeans   文件: EditorCaret.java
/**
 * Schedule recomputation of visual bounds of all carets.
 */
private void requestUpdateAllCaretsBounds() {
    JTextComponent c = component;
    AbstractDocument doc;
    if (c != null && (doc = activeDoc) != null) {
        doc.readLock();
        try {
            List<CaretInfo> sortedCarets = getSortedCarets();
            for (CaretInfo caret : sortedCarets) {
                caret.getCaretItem().markUpdateCaretBounds();
            }
        } finally {
            doc.readUnlock();
        }
    }
}
 
源代码5 项目: netbeans   文件: ParserManagerImpl.java
static void refreshHack () {
        Iterator<Document> it = managers.keySet ().iterator ();
        while (it.hasNext ()) {
            AbstractDocument document = (AbstractDocument) it.next ();
            document.readLock ();
            try {
                MutableTextInput mti = (MutableTextInput) document.getProperty (MutableTextInput.class);
                mti.tokenHierarchyControl ().rebuild ();
            } finally {
                document.readUnlock ();
            }
//            final StyledDocument document = (StyledDocument) it.next ();
//            NbDocument.runAtomic (document, new Runnable () {
//                public void run() {
//                    MutableTextInput mti = (MutableTextInput) document.getProperty (MutableTextInput.class);
//                    mti.tokenHierarchyControl ().rebuild ();
//                }
//            });
        }
    }
 
源代码6 项目: netbeans   文件: NbGenerateCodeAction.java
private static MimePath getFullMimePath(Document document, int offset) {
    String langPath = null;

    if (document instanceof AbstractDocument) {
        AbstractDocument adoc = (AbstractDocument)document;
        adoc.readLock();
        try {
            List<TokenSequence<?>> list = TokenHierarchy.get(document).embeddedTokenSequences(offset, true);
            if (list.size() > 1) {
                langPath = list.get(list.size() - 1).languagePath().mimePath();
            }
        } finally {
            adoc.readUnlock();
        }
    }

    if (langPath == null) {
        langPath = NbEditorUtilities.getMimeType(document);
    }

    if (langPath != null) {
        return MimePath.parse(langPath);
    } else {
        return null;
    }
}
 
源代码7 项目: netbeans   文件: CodeFoldingTestCase.java
protected void waitForFolding(JTextComponent target, int maxMiliSeconds){
    //wait for parser and folding hierarchy creation
    int time = (int) maxMiliSeconds / 100;
    
    AbstractDocument adoc = (AbstractDocument)target.getDocument();
    
    // Dump fold hierarchy
    FoldHierarchy hierarchy = FoldHierarchy.get(target);
    int foldCount = 0;
    while (foldCount==0 && time > 0) {
        
        adoc.readLock();
        try {
            hierarchy.lock();
            try {
                foldCount = hierarchy.getRootFold().getFoldCount();
            } finally {
                hierarchy.unlock();
            }
        } finally {
            adoc.readUnlock();
        }
        
        try {
            Thread.currentThread().sleep(100);
        } catch (InterruptedException ex) {
            time=0;
        }
        time--;
        
    }
        
}
 
源代码8 项目: netbeans   文件: DrawEngineDocView.java
public void propertyChange(java.beans.PropertyChangeEvent evt) {
    JTextComponent component = (JTextComponent)getContainer();
    if (component==null || evt==null || 
        (!EditorUI.LINE_HEIGHT_CHANGED_PROP.equals(evt.getPropertyName()) &&
         !EditorUI.TAB_SIZE_CHANGED_PROP.equals(evt.getPropertyName())
        )
    ) {
        return;
    }
    
    AbstractDocument doc = (AbstractDocument)getDocument();
    if (doc!=null) {
        doc.readLock();
        try{
            LockView lockView = LockView.get(this);
            lockView.lock();
            try {
                rebuild(0, getViewCount());
            } finally {
                lockView.unlock();
            }
        } finally {
            doc.readUnlock();
        }
    component.revalidate();
    }
}
 
源代码9 项目: netbeans   文件: AnnotationView.java
int[] getLinesSpan(int currentLine) {
    AbstractDocument adoc = doc;
    if (adoc != null)
        adoc.readLock();
    try {
        double componentHeight = getComponentHeight();
        double usableHeight = getUsableHeight();

        double position  = _modelToView(currentLine, componentHeight, usableHeight);

        if (position == (-1))
            return new int[] {currentLine, currentLine};

        int    startLine = currentLine;
        int    endLine   = currentLine;

        while (position == _modelToView(startLine - 1, componentHeight, usableHeight) && startLine > 0)
            startLine--;

        while ((endLine + 1) < Utilities.getRowCount(doc) && position == _modelToView(endLine + 1, componentHeight, usableHeight))
            endLine++;

        return new int[] {startLine, endLine};
    } finally {
        if (adoc != null)
            adoc.readUnlock();
    }
}
 
源代码10 项目: netbeans   文件: EditorCaret.java
/** Update visual position of caret(s) */
private void dispatchUpdate(boolean forceInvokeLater) {
    boolean alreadyPending;
    synchronized (listenerList) {
        alreadyPending = caretUpdatePending;
        caretUpdatePending = true;
    }
    if (!alreadyPending) {
        Runnable updateRunnable = new Runnable() {
            public @Override void run() {
                AbstractDocument doc = activeDoc;
                if (doc != null) {
                    doc.readLock();
                    try {
                        update(false);
                    } finally {
                        doc.readUnlock();
                    }
                } else {
                    // #269262 avoid that update() is not invoked
                    synchronized (listenerList) {
                        caretUpdatePending = false;
                    }
                }
            }
        };

        if (!forceInvokeLater && SwingUtilities.isEventDispatchThread()) {
            updateRunnable.run();
        } else {
            SwingUtilities.invokeLater(updateRunnable);
        }
    }
}
 
源代码11 项目: netbeans   文件: XMLBraceMatcher.java
/**
 * Checks to see if an end tag exists for a start tag at a given offset.
 * @param document
 * @param offset
 * @return true if an end tag is found for the start, false otherwise.
 */
public static boolean hasEndTag(Document document, int offset, String startTag) {
    AbstractDocument doc = (AbstractDocument)document;
    doc.readLock();
    try {
        TokenHierarchy th = TokenHierarchy.get(doc);
        TokenSequence ts = th.tokenSequence();
        Token token = findTokenAtContext(ts, offset);
        Stack<String> stack = new Stack<String>();
        while(ts.moveNext()) {
            Token t = ts.token();
            if(XMLTokenId.TAG != t.id())
                continue;
            String tag = t.text().toString();
            if(">".equals(tag))
                continue;
            if(stack.empty()) {
                if(("</"+startTag).equals(tag)) {
                    stack.empty();
                    stack = null;
                    return true;
                }
            } else {                
                if(tag.equals("/>") || ("</"+stack.peek()).equals(tag)) {
                    stack.pop();
                    continue;
                }
            }
            stack.push(tag.substring(1));
        }            
    } finally {
        doc.readUnlock();
    }
    
    return false;
}
 
源代码12 项目: netbeans   文件: SimpleFoldManagerTest.java
/**
 * Test the creation of several folds.
 */
public void test() throws Exception {
    FoldHierarchyTestEnv env = new FoldHierarchyTestEnv(new SimpleFoldManagerFactory());
    AbstractDocument doc = env.getDocument();
    doc.insertString(0, "1234567890", null);
    FoldHierarchy hierarchy = env.getHierarchy();
    doc.readLock();
    try {
        hierarchy.lock();
        try {
            
            Fold rootFold = hierarchy.getRootFold();
            int foldCount = rootFold.getFoldCount();
            int expectedFoldCount = 1;
            assertTrue("Incorrect fold count " + foldCount, // NOI18N
                (foldCount == expectedFoldCount)
            );
            
            Fold fold = rootFold.getFold(0);
            FoldType foldType = fold.getType();
            int foldStartOffset = fold.getStartOffset();
            int foldEndOffset = fold.getEndOffset();
            assertTrue("Incorrect fold type " + foldType, // NOI18N
                (foldType == AbstractFoldManager.REGULAR_FOLD_TYPE));
            assertTrue("Incorrect fold start offset " + foldStartOffset, // NOI18N
                (foldStartOffset == FOLD_START_OFFSET_1));
            assertTrue("Incorrect fold end offset " + foldEndOffset, // NOI18N
                (foldEndOffset == FOLD_END_OFFSET_1));
            
            // Check fold size
            assertSize("Size of the fold " , Collections.singleton(fold), // NOI18N
                MAX_FOLD_MEMORY_SIZE, new FoldMemoryFilter(fold));
            
        } finally {
            hierarchy.unlock();
        }
    } finally {
        doc.readUnlock();
    }
}
 
源代码13 项目: netbeans   文件: FoldUtilitiesImpl.java
public static void collapseOrExpand(FoldHierarchy hierarchy, Collection foldTypes,
boolean collapse) {

    Document d = hierarchy.getComponent().getDocument();
    if (!(d instanceof AbstractDocument)) {
        // no op, the folding hierarchy does not work for != AbstractDocument
        return;
    }
    AbstractDocument adoc = (AbstractDocument)d;
    adoc.readLock();
    try {
        hierarchy.lock();
        try {
            List foldList = findRecursive(null,
                hierarchy.getRootFold(), foldTypes);
            if (collapse) {
                hierarchy.collapse(foldList);
            } else {
                hierarchy.expand(foldList);
            }
        } finally {
            hierarchy.unlock();
        }
    } finally {
        adoc.readUnlock();
    }
}
 
源代码14 项目: netbeans   文件: GlyphGutter.java
public @Override void mouseDragged(MouseEvent e) {
    EditorUI eui = editorUI;
    if (eui == null) {
        return;
    }
    JTextComponent component = eui.getComponent();
    BaseTextUI textUI = (BaseTextUI)component.getUI();
    AbstractDocument aDoc = (AbstractDocument)component.getDocument();
    aDoc.readLock();
    try {
        // The drag must be extended to a next line in order to perform any selection
        int lineStartOffset = textUI.getPosFromY(e.getY());
        boolean updateDragEndOffset = false;
        if (dragStartOffset == -1) { // Drag starts now
            dragStartOffset = lineStartOffset;
            dragEndOffset = lineStartOffset;
        } else if (dragStartOffset == dragEndOffset) {
            if (lineStartOffset != dragStartOffset) {
                updateDragEndOffset = true;
            }
        } else {
            updateDragEndOffset = true;
        }
        if (updateDragEndOffset) {
            // Extend selection to active line's end or begining depending on dragStartOffset
            Caret caret = component.getCaret();
            if (lineStartOffset >= dragStartOffset) {
                if (caret.getMark() != dragStartOffset) {
                    caret.setDot(dragStartOffset);
                }
                // Check if the sele
                // Extend to next line's begining
                dragEndOffset = Math.min(Utilities.getRowEnd((BaseDocument) aDoc, lineStartOffset) + 1, aDoc.getLength());
            } else { // Backward selection
                // Check if the selection is already reverted i.e. it starts at dragStartOffset's line end
                if (caret.getMark() == dragStartOffset) {
                    caret.setDot(Utilities.getRowEnd((BaseDocument)aDoc, dragStartOffset) + 1);
                }
                dragEndOffset = lineStartOffset;
            }
            component.moveCaretPosition(dragEndOffset);
        }
    } catch (BadLocationException ble) {
        // Ignore rather than notify
    } finally {
        aDoc.readUnlock();
    }
}
 
源代码15 项目: netbeans   文件: ActionFactory.java
public void actionPerformed(ActionEvent evt, JTextComponent target) {
    AbstractDocument adoc = (AbstractDocument)target.getDocument();

    // Dump fold hierarchy
    FoldHierarchy hierarchy = FoldHierarchy.get(target);
    adoc.readLock();
    try {
        hierarchy.lock();
        try {
            /*DEBUG*/System.err.println("FOLD HIERARCHY DUMP:\n" + hierarchy); // NOI18N
            TokenHierarchy<?> th = TokenHierarchy.get(adoc);
            /*DEBUG*/System.err.println("TOKEN HIERARCHY DUMP:\n" + (th != null ? th : "<NULL-TH>")); // NOI18N

        } finally {
            hierarchy.unlock();
        }
    } finally {
        adoc.readUnlock();
    }

    View rootView = null;
    TextUI textUI = target.getUI();
    if (textUI != null) {
        rootView = textUI.getRootView(target); // Root view impl in BasicTextUI
        if (rootView != null && rootView.getViewCount() == 1) {
            rootView = rootView.getView(0); // Get DocumentView
        }
    }
    if (rootView != null) {
        String rootViewDump = (rootView instanceof DocumentView)
                ? ((DocumentView)rootView).toStringDetail()
                : rootView.toString();
        /*DEBUG*/System.err.println("DOCUMENT VIEW: " + System.identityHashCode(rootView) + // NOI18N
                "\n" + rootViewDump); // NOI18N
        int caretOffset = target.getCaretPosition();
        int caretViewIndex = rootView.getViewIndex(caretOffset, Position.Bias.Forward);
        /*DEBUG*/System.err.println("caretOffset=" + caretOffset + ", caretViewIndex=" + caretViewIndex); // NOI18N
        if (caretViewIndex >= 0 && caretViewIndex < rootView.getViewCount()) {
            View caretView = rootView.getView(caretViewIndex);
            /*DEBUG*/System.err.println("caretView: " + caretView); // NOI18N
        }
        /*DEBUG*/System.err.println(FixLineSyntaxState.lineInfosToString(adoc));
        // Check the hierarchy correctness
        //org.netbeans.editor.view.spi.ViewUtilities.checkViewHierarchy(rootView);
    }
    
    if (adoc instanceof BaseDocument) {
        /*DEBUG*/System.err.println("DOCUMENT:\n" + ((BaseDocument)adoc).toStringDetail()); // NOI18N
    }
}
 
@Override
public void exportToClipboard(JComponent c, Clipboard clip, int action) throws IllegalStateException {
    List<Position> regions;
    if (c instanceof JTextComponent &&
            (Boolean.TRUE.equals(c.getClientProperty(RECTANGULAR_SELECTION_PROPERTY))) &&
            (regions = RectangularSelectionUtils.regionsCopy(c)) != null)
    {
        final JTextComponent tc = (JTextComponent) c;
        String[] data;
        StringBuilder stringSelectionBuffer;
        AbstractDocument doc = (AbstractDocument) tc.getDocument();
        doc.readLock();
        try {
            // Cannot delegate to overriden transfer handler - at least not the JTextComponent.DefaultTransferHandler
            // because it would:
            // for COPY action whole selection would be copied which is wrong
            // for MOVE selection it would in addition remove <dot,mark> portion of the document.
            // Therefore handle string selection here explicitly.
            CharSequence docText = DocumentUtilities.getText(doc);
            stringSelectionBuffer = new StringBuilder(100);
            int size = regions.size();
            data = new String[size >>> 1];
            for (int i = 0; i < size; i++) {
                Position startPos = regions.get(i++);
                Position endPos = regions.get(i);
                CharSequence lineSel = docText.subSequence(startPos.getOffset(), endPos.getOffset());
                int halfI = (i >>> 1);
                if (halfI != 0) {
                    stringSelectionBuffer.append('\n');
                }
                stringSelectionBuffer.append(lineSel);
                data[halfI] = lineSel.toString();
            }
        } finally {
            doc.readUnlock();
        }

        clip.setContents(
                new WrappedTransferable(
                    new StringSelection(stringSelectionBuffer.toString()),
                    new RectangularSelectionData(data)),
                null);

        if (action == TransferHandler.MOVE) {
            try {
                RectangularSelectionUtils.removeSelection(doc, regions);
            } catch (BadLocationException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
        return;

    } else { // No rectangular selection
        delegate.exportToClipboard(c, clip, action);
    }
}
 
源代码17 项目: netbeans   文件: EditorCaret.java
private void updateRectangularSelectionPositionBlocks() {
    JTextComponent c = component;
    if (rectangularSelection) {
        AbstractDocument doc = activeDoc;
        if (doc != null) {
            doc.readLock();
            try {
                if (rsRegions == null) {
                    rsRegions = new ArrayList<Position>();
                    component.putClientProperty(RECTANGULAR_SELECTION_REGIONS_PROPERTY, rsRegions);
                }
                synchronized (rsRegions) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.fine("EditorCaret.updateRectangularSelectionPositionBlocks: position regions:\n");
                    }
                    rsRegions.clear();
                    if (rsPaintRect != null) {
                        LockedViewHierarchy lvh = ViewHierarchy.get(c).lock();
                        try {
                            float rowHeight = lvh.getDefaultRowHeight();
                            double y = rsPaintRect.y;
                            double maxY = y + rsPaintRect.height;
                            double minX = rsPaintRect.getMinX();
                            double maxX = rsPaintRect.getMaxX();
                            do {
                                int startOffset = lvh.viewToModel(minX, y, null);
                                int endOffset = lvh.viewToModel(maxX, y, null);
                                // They could be swapped due to RTL text
                                if (startOffset > endOffset) {
                                    int tmp = startOffset;
                                    startOffset = endOffset;
                                    endOffset = tmp;
                                }
                                Position startPos = activeDoc.createPosition(startOffset);
                                Position endPos = activeDoc.createPosition(endOffset);
                                rsRegions.add(startPos);
                                rsRegions.add(endPos);
                                if (LOG.isLoggable(Level.FINE)) {
                                    LOG.fine("    <" + startOffset + "," + endOffset + ">\n");
                                }
                                y += rowHeight;
                            } while (y < maxY);
                            c.putClientProperty(RECTANGULAR_SELECTION_REGIONS_PROPERTY, rsRegions);
                        } finally {
                            lvh.unlock();
                        }
                    }
                }
            } catch (BadLocationException ex) {
                Exceptions.printStackTrace(ex);
            } finally {
                doc.readUnlock();
            }
        }
    }
}
 
源代码18 项目: netbeans   文件: FoldOperationTest.java
/**
 * Checks that folds are created beween two folds, encapsulating existing folds.
 * 
 * @throws Exception 
 */
public void testUpdateCreateFold() throws Exception {
    final TestFoldManager[] mgr = new TestFoldManager[1];
    FoldHierarchyTestEnv env = new FoldHierarchyTestEnv(new FoldManagerFactory() {
        @Override
        public FoldManager createFoldManager() {
            return mgr[0] = new TestFoldManager();
        }
    });
    AbstractDocument doc = env.getDocument();
    doc.insertString(0, "12345678901234567890", null);

    FoldHierarchy hierarchy = env.getHierarchy();
    
    List<FoldInfo> infos = createDefaultInfos();
    
    // add a new fold between #1 and #2
    infos.add(FoldInfo.range(2, 3, FoldType.MEMBER));
    
    // add a new fold at the end:
    infos.add(FoldInfo.range(19,20, FoldType.MEMBER));
    
    // add a fold, which encapsulates #2 - #5
    infos.add(FoldInfo.range(3, 18, FoldType.MEMBER));
    
    // add a fold, which encapsulates ##5
    infos.add(FoldInfo.range(13, 16, FoldType.MEMBER));
    
    doc.readLock();
    try {
        hierarchy.lock();
        TestFoldManager m = mgr[0];
        try {
            Collection<Fold> remove = new ArrayList<Fold>();
            Collection<FoldInfo> create = new ArrayList<FoldInfo>();
            
            final boolean[] changed = new boolean[1];
            
            hierarchy.addFoldHierarchyListener(new FoldHierarchyListener() {
                @Override
                public void foldHierarchyChanged(FoldHierarchyEvent evt) {
                    changed[0] = true;
                }
            });
            Map<FoldInfo, Fold> mapping = m.operation.update(infos, remove, create);
            
            // 3 folds added, no deleted:
            assertEquals(4, create.size());
            assertEquals(0, remove.size());
            
        } finally {
            hierarchy.unlock();
        }
    } finally {
        doc.readUnlock();
    }
}
 
源代码19 项目: netbeans   文件: XMLBraceMatcher.java
public int[] doFindOrigin() throws InterruptedException, BadLocationException {
    AbstractDocument doc = (AbstractDocument)document;
    doc.readLock();
    try {
        TokenHierarchy th = TokenHierarchy.get(doc);
        TokenSequence ts = th.tokenSequence();
        Token token = atOffset(ts, searchOffset);
        token = ts.token();
        int start = ts.offset();
        if(token == null)
            return null;
        XMLTokenId id = (XMLTokenId)token.id();
        String tokenText = token.text().toString();

        switch(id) {
            case PI_START:
            case PI_END: {
                return new int[] {start, start+token.length()};
            }
            case TAG: {
                //for ">" move back till the start tag
                if(">".equals(tokenText)) {
                    while(move(ts)) {
                        if(ts.token().id() == XMLTokenId.TAG)
                            break;
                    }
                }                    
                return findTagPosition(ts, false);
            }
            case BLOCK_COMMENT: {
                if(!tokenText.startsWith(COMMENT_START) &&
                   !tokenText.endsWith(COMMENT_END))
                   return null;
                return findGenericOrigin(ts, COMMENT_START, COMMENT_END);
            }
            case CDATA_SECTION: {
                if(!tokenText.startsWith(CDATA_START) &&
                   !tokenText.endsWith(CDATA_END))
                    return null;
                return findGenericOrigin(ts, CDATA_START, CDATA_END);
            }
            case DECLARATION: {
                if(!tokenText.startsWith(DECLARATION_START) &&
                   !tokenText.endsWith(DECLARATION_END))
                    return null;
                return findGenericOrigin(ts, DECLARATION_START, DECLARATION_END);
            }

            default:
                break;
        }
    } finally {
        doc.readUnlock();
    }
    return null;
}
 
源代码20 项目: netbeans   文件: XMLBraceMatcher.java
public int[] doFindMatches() throws InterruptedException, BadLocationException {
    AbstractDocument doc = (AbstractDocument)document;
    doc.readLock();
    try {
        TokenHierarchy th = TokenHierarchy.get(doc);
        TokenSequence ts = th.tokenSequence();
        Token token = atOffset(ts, searchOffset);
        if(token == null) return null;
        XMLTokenId id = (XMLTokenId)token.id();
        switch(id) {
            case PI_START: {
                return findMatchingPair(ts, XMLTokenId.PI_END, true);
            }
            case PI_END: {
                return findMatchingPair(ts, XMLTokenId.PI_START, false);
            }
            case TAG: {
                //for ">" move back till the start tag
                if(">".equals(ts.token().text().toString())) {
                    while(ts.movePrevious()) {
                        if(ts.token().id() == XMLTokenId.TAG)
                            break;
                    }
                }                    
                String tagName = ts.token().text().toString();
                if(tagName.startsWith("</")) {
                    return findMatchingTagBackward(ts, tagName.substring(2));
                }
                if(tagName.startsWith("<")) {
                    return findMatchingTagForward(ts, tagName.substring(1));
                }
            }
            case BLOCK_COMMENT: {
                return findGenericMatch(ts, COMMENT_START, COMMENT_END);
            }
            case CDATA_SECTION: {
                return findGenericMatch(ts, CDATA_START, CDATA_END);
            }
            case DECLARATION: {
                return findGenericMatch(ts, DECLARATION_START, DECLARATION_END);
            }
        }
    } finally {
        doc.readUnlock();
    }
    return null;
}