使用PythonTidy作为PyDev的Code Formatter

Posted on Fri 25 November 2011 in 我用(IT)

PyDev自身的Code Formatter能力较弱,不支持Maximum Line Length(完整的编码格式标准)。但它支持插入其它beautifier,比如PythonTidy。

操作过程如下,我在Mac OS下,Eclipse Helios,PyDev 2.24下:

  1. 下载PythonTidy.py wget http://lacusveris.com/PythonTidy/PythonTidy-1.20.python -O PythonTidy.py

  2. 编写Jython脚本 参考:http://pydev.org/manual_articles_scripting.html 注意:pyedit_pythontidy.py的第64行各位要修改一些,让PythonTidy.py能被脚本找到,linux下注意PythonTidy.py需要有执行权限。

    """
    This code is public domain.
    The original author is Bear Huang (http://bear330.wordpress.com/).
    """
    if False:
        from org.python.pydev.editor import PyEdit #@UnresolvedImport
        cmd = 'command string'
        editor = PyEdit

assert cmd is not None assert editor is not None

if cmd == 'onCreateActions': # from org.eclipse.jface.action import Action from org.python.pydev.editor.actions import PyAction from org.python.pydev.core.docutils import PySelection from java.lang import Runnable from org.eclipse.swt.widgets import Display from org.eclipse.jface.text import IDocument from org.eclipse.jface.text import TextSelection

from java.io import FileWriter
import java.lang.Exception

FORMAT_ACTION_DEFINITION_ID = "org.python.pydev.editor.actions.pyFormatStd"
FORMAT_ACTION_ID = "org.python.pydev.editor.actions.navigation.pyFormatStd"

class PythonTidyAction(PyAction):

    def __init__(self, *args, **kws):
        PyAction.__init__(self, *args, **kws)

    def run(self):
        import tempfile
        import os

        try:
            ps = PySelection(editor)
            doc = ps.getDoc()
            startLine = ps.getStartLineIndex()

            p1 = tempfile.mktemp()
            p2 = tempfile.mktemp()
            f1 = FileWriter(p1)

            formatAll = False
            if ps.getTextSelection().getLength() == 0:
                # format all.
                c = doc.get()
                f1.write(c)
                formatAll = True
            else:
                # format selection.
                #c = ps.getSelectedText()
                #f1.write(ps.getSelectedText())
                print "Format selected text is not supported yet."
                f1.write("")
                # A kind of solution is to insert a special comment in
                # front and end of selection text, pythontidy it, and
                # extract text according that comment.

            f1.close()
            os.system('PythonTidy.py "%s" "%s"' % (p1, p2))
            f2 = open(p2, "r")
            result = f2.read()
            f2.close()

            os.remove(p1)
            os.remove(p2)

            if startLine >= doc.getNumberOfLines():
                startLine = doc.getNumberOfLines() - 1

            if formatAll:
                doc.set(result)
            else:
                #doc.replace(doc.getLineOffset(startLine), 0, result)
                pass

            sel = TextSelection(doc, doc.getLineOffset(startLine), 0)
            self.getTextEditor().getSelectionProvider().setSelection(sel)
        except java.lang.Exception, e:
            self.beep(e)

def bindInInterface():
    act = PythonTidyAction()

    act.setActionDefinitionId(FORMAT_ACTION_DEFINITION_ID)
    act.setId(FORMAT_ACTION_ID)
    try:
        editor.setAction(FORMAT_ACTION_ID, act)
    except:
        pass

class RunInUi(Runnable):
    '''Helper class that implements a Runnable (just so that we
    can pass it to the Java side). It simply calls some callable.
    '''

    def __init__(self, c):
        self.callable = c
    def run(self):
        self.callable ()

def runInUi(callable):
    '''
    @param callable: the callable that will be run in the UI
    '''
    Display.getDefault().asyncExec(RunInUi(callable))

runInUi(bindInInterface)
  1. 配置 PyDev下头找Scripting PyDev 第一个Checkbox的"Show the output ... to some console?"打上勾,有助于调试; Location of addintional jython scripts指向pyedit_pythontidy.py所在的路径

  2. 测试 打开一个行距超长的python文件,ctrl(cmd)+shift+F,看看效果,得嘞!

Reference

http://bear330.wordpress.com/2007/10/30/using-pythontidy-in-pydev-as-code-formatter/