/** * Copyright (c) 2016 by Brainwy Software LTDA. 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. * * A re-factor of <code>PyTextHover</code> to use the extension point <code>org.python.pydev.pyTextHover</code> */ package org.python.pydev.editor.hover; import java.util.ArrayList; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.python.pydev.core.IDefinition; import org.python.pydev.core.IIndentPrefs; import org.python.pydev.core.IPythonNature; import org.python.pydev.core.IPythonPartitions; import org.python.pydev.core.MisconfigurationException; import org.python.pydev.core.docutils.PySelection; import org.python.pydev.core.docutils.PyStringUtils; import org.python.pydev.core.docutils.StringEscapeUtils; import org.python.pydev.core.log.Log; import org.python.pydev.core.structure.CompletionRecursionException; import org.python.pydev.editor.PyEdit; import org.python.pydev.editor.PyInformationPresenter; import org.python.pydev.editor.codecompletion.revisited.CompletionCache; import org.python.pydev.editor.codecompletion.revisited.visitors.Definition; import org.python.pydev.editor.codefolding.PySourceViewer; import org.python.pydev.editor.model.ItemPointer; import org.python.pydev.editor.refactoring.PyRefactoringFindDefinition; import org.python.pydev.editor.refactoring.RefactoringRequest; import org.python.pydev.parser.jython.SimpleNode; import org.python.pydev.parser.jython.ast.ClassDef; import org.python.pydev.parser.jython.ast.FunctionDef; import org.python.pydev.parser.jython.ast.Name; import org.python.pydev.parser.jython.ast.NameTok; import org.python.pydev.parser.jython.ast.stmtType; import org.python.pydev.parser.prettyprinterv2.MakeAstValidForPrettyPrintingVisitor; import org.python.pydev.parser.visitors.NodeUtils; import org.python.pydev.shared_core.string.FastStringBuffer; import org.python.pydev.shared_core.string.StringUtils; import org.python.pydev.shared_core.structure.FastStack; public class PyDocstringTextHover extends AbstractPyEditorTextHover { public static String ID = "org.python.pydev.editor.hover.pyDocstringTextHover"; @Override public String getHoverInfo(final ITextViewer textViewer, IRegion hoverRegion) { FastStringBuffer buf = new FastStringBuffer(); if (textViewer instanceof PySourceViewer) { PySourceViewer s = (PySourceViewer) textViewer; PySelection ps = new PySelection(s.getDocument(), hoverRegion.getOffset() + hoverRegion.getLength()); getDocstringHover(hoverRegion, s, ps, buf); } return buf.toString(); } public PyDocstringTextHover() { super(); } /* */ @Override public boolean isContentTypeSupported(String contentType) { boolean pythonCommentOrMultiline = IPythonPartitions.NON_DEFAULT_TYPES_AS_SET.contains(contentType); if (!pythonCommentOrMultiline) { return true; } return false; } /** * Fills the buffer with the text for docstrings of the selected element. */ @SuppressWarnings("unchecked") private void getDocstringHover(IRegion hoverRegion, PySourceViewer s, PySelection ps, FastStringBuffer buf) { //Now, aside from the marker, let's check if there's some definition we should show the user about. CompletionCache completionCache = new CompletionCache(); ArrayList<IDefinition> selected = new ArrayList<IDefinition>(); PyEdit edit = s.getEdit(); RefactoringRequest request; IPythonNature nature = null; try { nature = edit.getPythonNature(); request = new RefactoringRequest(edit.getEditorFile(), ps, new NullProgressMonitor(), nature, edit); } catch (MisconfigurationException e) { return; } String[] tokenAndQual = null; try { tokenAndQual = PyRefactoringFindDefinition.findActualDefinition(request, completionCache, selected); } catch (CompletionRecursionException | BadLocationException e1) { Log.log(e1); buf.append("Unable to compute hover. Details: " + e1.getMessage()); return; } FastStringBuffer temp = new FastStringBuffer(); if (tokenAndQual != null && selected.size() > 0) { for (IDefinition d : selected) { Definition def = (Definition) d; SimpleNode astToPrint = null; if (def.ast != null) { astToPrint = def.ast; if ((astToPrint instanceof Name || astToPrint instanceof NameTok) && def.scope != null) { //There's no real point in just printing the name, let's see if we're able to actually find //the scope where it's in and print that scope. FastStack<SimpleNode> scopeStack = def.scope.getScopeStack(); if (scopeStack != null && scopeStack.size() > 0) { SimpleNode peek = scopeStack.peek(); if (peek != null) { stmtType stmt = NodeUtils.findStmtForNode(peek, astToPrint); if (stmt != null) { astToPrint = stmt; } } } } try { astToPrint = astToPrint.createCopy(); MakeAstValidForPrettyPrintingVisitor.makeValid(astToPrint); } catch (Exception e) { Log.log(e); } } temp = temp.clear(); if (def.value != null) { if (astToPrint instanceof FunctionDef) { temp.append("def "); } else if (astToPrint instanceof ClassDef) { temp.append("class "); } temp.append("<pydev_hint_bold>"); temp.append(def.value); temp.append("</pydev_hint_bold>"); temp.append(' '); } if (def.module != null) { temp.append("Found at: "); temp.append("<pydev_hint_bold>"); temp.append(def.module.getName()); temp.append("</pydev_hint_bold>"); temp.append(PyInformationPresenter.LINE_DELIM); } if (def.module != null && def.value != null) { ItemPointer pointer = PyRefactoringFindDefinition.createItemPointer(def); String asPortableString = pointer.asPortableString(); if (asPortableString != null) { //may happen if file is not in the pythonpath temp.replaceAll( "<pydev_hint_bold>", StringUtils.format("<pydev_link pointer=\"%s\">", StringEscapeUtils.escapeXml(asPortableString))); temp.replaceAll("</pydev_hint_bold>", "</pydev_link>"); } } String str = printAst(edit, astToPrint); if (str != null && str.trim().length() > 0) { temp.append(PyInformationPresenter.LINE_DELIM); temp.append(str); } else { String docstring = d.getDocstring(nature, completionCache); if (docstring != null && docstring.trim().length() > 0) { IIndentPrefs indentPrefs = edit.getIndentPrefs(); temp.append(PyStringUtils.fixWhitespaceColumnsToLeftFromDocstring(docstring, indentPrefs.getIndentationString())); } } if (temp.length() > 0) { if (buf.length() > 0) { buf.append(PyInformationPresenter.LINE_DELIM); } buf.append(temp); } } } } }