6/03/2019

How to setup Eclipse PyDev to run yapf and buildifier on save

Worked for my Eclipse version (May or may not work with other versions)
Eclipse IDE for C/C++ Developers
Version: Photon (4.8), Oxygen (4.7)

I. Save this file to: $HOME/eclipse-workspace/pydev_scripts (this is a folder, not a file). The file name should be pyedit_pydev_formatter.py

----------Begin of Script------------------------------------------------
"""
This script makes Eclipse PyDev smart to autoformat .py and BUILD files on save.
"""

# Ensure that yapf and buildifier are executable (chmod +x).
# Change the red text to your yapf and buildifier paths.
ABS_PATH_TO_YAPF = '/usr/local/bin/yapf'
ABS_PATH_TO_BUILDIFIER = '/home/liangzou/bin/buildifier'

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


def run_formatter():
    ENABLED = True
    try:
        doc = editor.getDocument()
        sel= editor.getSelectionProvider().getSelection()
        startLine = doc.getLineOfOffset(sel.getOffset())
        editor.performSave(True, None)

        file_path_full = str(editor.getEditorFile())
        formatter = ''
        flags = ''
        if 'BUILD' in file_path_full:
            bin_to_use = ABS_PATH_TO_BUILDIFIER
            formatter = 'buidifier'
        elif file_path_full.endswith('WORKSPACE'):
            ENABLED = False
        else:
            bin_to_use = ABS_PATH_TO_YAPF
            formatter = 'yapf'
            # flags = '-i --style="{based_on_style: google}"'
            flags = '-i'
        if ENABLED:
            os.system('%s %s "%s"' % (bin_to_use, flags, file_path_full))
            print('%s formatted by %s' % (file_path_full, formatter))

        with open(file_path_full) as f:
            # Got the functions from:
            # https://help.eclipse.org/neon/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/jface/text/ILineTracker.html
            lines = []
            for each_line in f.readlines():
                clean_line = each_line.rstrip()
                if clean_line:
                    lines.append(clean_line)
                lines.append('\n')
            doc.set(''.join(lines))

            # Got the functions from:
            # https://help.eclipse.org/kepler/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/ui/texteditor/AbstractTextEditor.html
            editor.performSave(True, None)

        sel = TextSelection(doc, doc.getLineOffset(startLine), 0)
        editor.getSelectionProvider().setSelection(sel)
    except Exception, e:
        print(e)
        self.beep(e)


if cmd == 'onCreateActions':
    import os

    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 TextSelection

    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):
            run_formatter()

    def bindInInterface():
        act = PythonTidyAction()

        act.setActionDefinitionId(FORMAT_ACTION_DEFINITION_ID)
        act.setId(FORMAT_ACTION_ID)
        try:
            editor.setAction(FORMAT_ACTION_ID, act)
        except Exception, e:
            print(e)

    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):
        """
        Args:
            callable: the callable that will be run in the UI
        """
        Display.getDefault().asyncExec(RunInUi(callable))

    runInUi(bindInInterface)


----------End of Script------------------------------------------------

II. Then open
Preferences | PyDev | Scripting PyDev | Location of additional Jpython scripts: /home/liangzou/eclipse/pydev_scripts  (NOTE: this is the parent folder of the script.) Check the "Show the output given from the scripting to some console?" for debugging purpose.

III. Preferences | Keys, search for Python Format Code and change the Binding to ctrl+s.

When you press ctrl+s to save the .py and BUILD files, they'll be automatically formatted.
If it doesn't work, you can modify the script, then reopen the python file so that the pydev_scripting file can be reloaded.

No comments: