/* * Copyright (C) 2006, 2007 Dennis Hunziker, Ueli Kistler * Copyright (C) 2007 Reto Schuettel, Robin Stocker * * IFS Institute for Software, HSR Rapperswil, Switzerland * */ package org.python.pydev.refactoring.coderefactoring.extractlocal.edit; import java.util.List; import org.eclipse.jface.text.ITextSelection; import org.python.pydev.core.ILocalScope; import org.python.pydev.core.docutils.PySelection; import org.python.pydev.core.log.Log; import org.python.pydev.core.structure.FastStack; import org.python.pydev.editor.codecompletion.revisited.visitors.FindScopeVisitor; import org.python.pydev.parser.jython.SimpleNode; import org.python.pydev.parser.jython.Visitor; import org.python.pydev.parser.jython.ast.Assign; import org.python.pydev.parser.jython.ast.Module; import org.python.pydev.parser.jython.ast.Name; import org.python.pydev.parser.jython.ast.exprType; import org.python.pydev.parser.jython.ast.expr_contextType; import org.python.pydev.parser.visitors.scope.GetNodeForExtractLocalVisitor; import org.python.pydev.refactoring.coderefactoring.extractlocal.request.ExtractLocalRequest; import org.python.pydev.refactoring.core.base.RefactoringInfo; import org.python.pydev.refactoring.core.edit.AbstractInsertEdit; import com.aptana.shared_core.structure.Tuple; public class CreateLocalVariableEdit extends AbstractInsertEdit { private RefactoringInfo info; private String variableName; private exprType expression; private int lineForLocal = -1; private boolean replaceDuplicates; private List<Tuple<ITextSelection, SimpleNode>> duplicates; public CreateLocalVariableEdit(ExtractLocalRequest req) { super(req); this.info = req.info; this.variableName = req.variableName; this.expression = (exprType) req.expression.createCopy(); replaceDuplicates = req.replaceDuplicates; duplicates = req.duplicates; } @Override protected SimpleNode getEditNode() { exprType variable = new Name(variableName, expr_contextType.Store, false); exprType[] target = { variable }; return new Assign(target, expression); } private int calculateLineForLocal() { if (lineForLocal == -1) { ITextSelection userSelection = info.getUserSelection(); if (replaceDuplicates) { //When replacing duplicates, we have to consider the selection the first //replace (so that the local created works for all the replaces). for (Tuple<ITextSelection, SimpleNode> dup : duplicates) { if (dup.o1.getStartLine() < userSelection.getStartLine()) { userSelection = dup.o1; } } } PySelection selection = new PySelection(info.getDocument(), userSelection); int startLineIndexIndocCoords = selection.getStartLineIndex(); int startLineIndexInASTCoords = startLineIndexIndocCoords + 1; //from doc to ast Module module = info.getModuleAdapter().getASTNode(); SimpleNode currentScope = module; try { FindScopeVisitor scopeVisitor = new FindScopeVisitor(startLineIndexInASTCoords, selection.getCursorColumn() + 1); module.accept(scopeVisitor); ILocalScope scope = scopeVisitor.scope; FastStack scopeStack = scope.getScopeStack(); currentScope = (SimpleNode) scopeStack.peek(); //at least the module should be there if we don't have anything. } catch (Exception e1) { Log.log(e1); } GetNodeForExtractLocalVisitor visitor = new GetNodeForExtractLocalVisitor(startLineIndexInASTCoords); try { currentScope.accept(visitor); } catch (Exception e) { throw new RuntimeException(e); } SimpleNode lastNodeBeforePassedLine = visitor.getLastInContextBeforePassedLine(); if (lastNodeBeforePassedLine != null) { final int[] line = new int[] { Integer.MAX_VALUE }; try { Visitor v = new Visitor() { protected Object unhandled_node(SimpleNode node) throws Exception { if (node.beginLine > 0) { line[0] = Math.min(line[0], node.beginLine - 1); } else { Log.log("Found node with beginLine <= 0:" + node + " line: " + node.beginLine); } return this; } }; lastNodeBeforePassedLine.accept(v); } catch (Exception e) { Log.log(e); } if (line[0] != Integer.MAX_VALUE) { lineForLocal = line[0]; } else { lineForLocal = lastNodeBeforePassedLine.beginLine - 1; } } else { lineForLocal = startLineIndexIndocCoords; } //The above should give us the proper location, but let's make sure it's NEVER after the current //location! if (lineForLocal > startLineIndexIndocCoords) { lineForLocal = startLineIndexIndocCoords; } } return lineForLocal; } @Override public int getOffset() { PySelection selection = new PySelection(info.getDocument(), calculateLineForLocal(), 0); return selection.getStartLineOffset(); } @Override public int getOffsetStrategy() { return 0; } @Override public String getIndent() { PySelection selection = new PySelection(info.getDocument(), calculateLineForLocal(), 0); return selection.getIndentationFromLine(); } }