/** * Copyright (c) 2005-2013 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.core.docutils; import java.util.Iterator; import org.eclipse.jface.text.IDocument; import org.python.pydev.shared_core.string.StringUtils; /** * Iterator through imports that yields tuples with the import itself, the initial line of the import * and the final line of the import. * * @author Fabio */ public class PyImportsIterator implements Iterator<ImportHandle> { /** * Helper to iterate in the document */ private final PyDocIterator docIterator; /** * Variable holding whether hasNext should return true or not */ private boolean hasNext = true; /** * Variable holding the next return value */ private ImportHandle nextImport; /** * Delimiter to be used to add new lines in the imports found. */ private final String delimiter; /** * Document used in the iteration */ private final IDocument doc; private final boolean addOnlyGlobalImports; private final boolean allowBadInput; public PyImportsIterator(IDocument doc) { this(doc, true); } /** * Constructor * * @param doc the document from where the import should be gathered. * @param allowBadInput */ public PyImportsIterator(IDocument doc, boolean addOnlyGlobalImports, boolean allowBadInput) { this.doc = doc; this.addOnlyGlobalImports = addOnlyGlobalImports; this.allowBadInput = allowBadInput; delimiter = PySelection.getDelimiter(doc); this.docIterator = new PyDocIterator(doc, false, false, false, true); //gather the 1st import calcNext(); } public PyImportsIterator(IDocument doc, boolean addOnlyGlobalImports) { this(doc, addOnlyGlobalImports, false); } public void setStartingOffset(int offset) { this.docIterator.setStartingOffset(offset); } /** * Pre-calculates the next return value and whether there is a next value to be returned. */ private void calcNext() { if (!hasNext) { //only pre-calculate if there's something to pre-calculate. return; } int startFoundLine = -1; hasNext = false; nextImport = null; while (docIterator.hasNext()) { String str = docIterator.next(); boolean match; if (addOnlyGlobalImports) { match = str.startsWith("import ") || str.startsWith("from ") || str.trim().equals("import"); } else { str = StringUtils.leftTrim(str); match = str.startsWith("import ") || str.startsWith("from ") || str.trim().equals("import"); } if (match) { startFoundLine = docIterator.getLastReturnedLine(); if (str.indexOf('(') != -1) { //we have something like from os import (pipe,\nfoo) while (docIterator.hasNext() && str.indexOf(')') == -1) { str += delimiter + docIterator.next(); } } if (StringUtils.endsWith(str, '\\')) { while (docIterator.hasNext() && StringUtils.endsWith(str, '\\')) { str += delimiter + docIterator.next(); } } try { nextImport = new ImportHandle(doc, str, startFoundLine, -1, allowBadInput); //-1 == endFoundLine (which will be properly set later on). } catch (ImportNotRecognizedException e) { continue; } hasNext = true; nextImport.endFoundLine = docIterator.getLastReturnedLine(); break; //ok, import found } } } /** * From the iterator interface */ @Override public boolean hasNext() { return this.hasNext; } /** * From the iterator interface */ @Override public ImportHandle next() { ImportHandle ret = this.nextImport; calcNext(); //pre-compute the next step return ret; } /** * From the iterator interface (not implemented) */ @Override public void remove() { throw new RuntimeException("Not implemented"); } }