/****************************************************************************** * Copyright (C) 2013 Fabio Zadrozny * * 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: * Fabio Zadrozny <fabiofz@gmail.com> - initial API and implementation ******************************************************************************/ package org.python.pydev.shared_core.auto_edit; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.source.DefaultCharacterPairMatcher; import org.python.pydev.shared_core.partitioner.PartitionCodeReader; import org.python.pydev.shared_core.string.ICharacterPairMatcher2; import org.python.pydev.shared_core.string.StringUtils; public class AutoEditPairMatcher extends DefaultCharacterPairMatcher implements ICharacterPairMatcher2 { private final char[] fChars; private final String contentType; public AutoEditPairMatcher(char[] chars, String contentType) { super(chars, contentType); this.fChars = chars; this.contentType = contentType; } @Override public int searchForClosingPeer(int offset, char openingPeer, char closingPeer, IDocument document) { try { PartitionCodeReader reader = new PartitionCodeReader(contentType); reader.configureForwardReader(document, offset, document.getLength()); int stack = 1; int c = reader.read(); while (c != PartitionCodeReader.EOF) { if (c == openingPeer && c != closingPeer) { stack++; } else if (c == closingPeer) { stack--; } if (stack <= 0) { //<= 0 because if we have a closing peer without an opening one, we'll return it. return reader.getOffset(); } c = reader.read(); } return -1; } catch (Exception e) { throw new RuntimeException(e); } } @Override public int searchForOpeningPeer(int offset, char openingPeer, char closingPeer, IDocument document) { try { PartitionCodeReader fReader = new PartitionCodeReader(contentType); fReader.configureBackwardReader(document, offset); int stack = 1; int c = fReader.read(); while (c != PartitionCodeReader.EOF) { if (c == closingPeer && c != openingPeer) { stack++; } else if (c == openingPeer) { stack--; } if (stack <= 0) {//<= 0 because if we have an opening peer without a closing one, we'll return it. return fReader.getOffset(); } c = fReader.read(); } return -1; } catch (Exception e) { throw new RuntimeException(e); } } @Override public int searchForAnyOpeningPeer(int offset, IDocument document) { try { PartitionCodeReader fReader = new PartitionCodeReader(contentType); fReader.configureBackwardReader(document, offset); Map<Character, Integer> stack = new HashMap<Character, Integer>(); HashSet<Character> closing = new HashSet<Character>(); HashSet<Character> opening = new HashSet<Character>(); for (int i = 0; i < fChars.length; i++) { stack.put(fChars[i], 1); if (i % 2 == 0) { opening.add(fChars[i]); } else { closing.add(fChars[i]); } } int c = fReader.read(); while (c != PartitionCodeReader.EOF) { if (closing.contains((char) c)) { // c == ')' || c == ']' || c == '}' char peer = StringUtils.getPeer((char) c); Integer iStack = stack.get(peer); iStack++; stack.put(peer, iStack); } else if (opening.contains((char) c)) { //c == '(' || c == '[' || c == '{' Integer iStack = stack.get((char) c); iStack--; stack.put((char) c, iStack); if (iStack == 0) { return fReader.getOffset(); } } c = fReader.read(); } return -1; } catch (Exception e) { throw new RuntimeException(e); } } }