Apply automatic pep8 fixes from QuickFix window
Asked Answered
M

2

17

Background:

I'm using the (fantastic) Vim plugin python-mode, which includes the pep8 linter. The :PyLint command runs all linters and opens errors in a QuickFix window.

Problem:

Now, let's assume I'm only using the pep8 linter, and I have a QuickFix window full of errors. I'd like to step through each of these errors and apply an automatic fix (with something like autopep8). The autopep8 tool is fantastic, but it makes mistakes. Ideally, I'd like to be able to supervise each fix in Vim (apply fix, check, move to next fix).

My current approach is to run autopep8 on my Python file, diff the results, then repair any bad changes:

$ autopep8 --in-place spam.py
$ git difftool spam.py  # check edits in gVim, write to file
$ git commit spam.py -m "Fix bad PEP8 formatting"

However, this approach ruins my undo history, and seems needlessly complex. Is there a better way?

Question:

Is there any way to automatically apply pep8 fixes (when available) to pep8 errors within the QuickFix window?

Mcgaha answered 8/6, 2012 at 6:26 Comment(3)
thanks for the tip on python-mode -- looks great--especially support for virtualenv and syntax errors on the fly. (as opposed to syntastic/a few other newer vim plugins)Kylix
It's worth noting that as of version 0.6.6, Python-mode now has support for automatically making autopep8 changes within the buffer using :PyLintAuto. (However, there's no option to approve/deny changes one-by-one).Mcgaha
@DavidCain or :PymodeLintAutoBluecollar
K
7

Options

There are two simple answers that won't wipe out your undo history.

1. Diff with the saved file in Vim

I found this DiffWithSaved function online quite a while ago and it has been very useful. In this case, you can just run autopep8 in the terminal, and when Gvim asks to reload the file, choose no and then run this function, which will pop up a scratch buffer with your new file and allow you to change things around.

" copy this to your vimrc or source it

" tells vim not to automatically reload changed files
set noautoread 

function! DiffWithSaved()
  let filetype=&ft
  diffthis
  vnew | r # | normal! 1Gdd
  diffthis
  exe "setlocal bt=nofile bh=wipe nobl noswf ro ft=" . filetype
endfunction

" sets up mappings to function

com! DiffSaved call DiffWithSaved()
map <Leader>ds :DiffSaved<CR>

Once you run that, you can use the vim copy-diff and other diff commands to quickly go through and accept/not accept changes. Plus, all will be stored in undo history.

" run these commands after sourcing the above function

" % expands to filename (also %:h to head, %:t to tail)
" if it throws an error, just do :cd %:h first

:!autopep8 --in-place %
:DiffSaved

2. Diff with the git difftool and reload the file

If you want to diff with the file in the git index (and using git's difftool), you could do the following:

  1. leave gvim open,
  2. run your commands in the terminal and let the program open up a new instance of gvim (or vim) to handle the diffing.
  3. Save it all.
  4. Go back to your original gvim, let vim reload the file and (at least to my knowledge) your undo history should remain.

Advantages/Disadvantages

Option 1

Advantages:

  • each change will be saved in your undo history
  • graphical diffs in vim are easy to read

Disadvantages:

  • Won't be using git's difftool
  • relies upon vim's diff functions.

Option 2

Advantages:

  • uses git's difftool
  • cleaner undo history (single undo from pre and post autopep8--very dependent on what you want)

Disadvantages:

  • seems more awkward
  • less granular undo history
Kylix answered 11/6, 2012 at 23:50 Comment(5)
Thank you for such an incredibly detailed response. Option 1 does seem preferable- I was only using Git's difftool as a readable demonstration of my intended goal. I won't always be editing a recently committed file anyway.Mcgaha
Sadly, this is still a bit of a workaround, but it's much preferable to my previous approach.Mcgaha
do you want to just accept all the changes and only undo the ones you don't want?Kylix
Please don't take my comments as an insult to your solution - it's wonderful. However, I'd much prefer if the capability to auto-apply a solution from the QuickFix window, accept/reject, then move on were available. Seems like an extension of the pep8 linter that I should try writing.Mcgaha
no, no I wasn't offended. (and I appreciate your kind words!) I was really just wondering. honestly, the easiest thing might be to extend the autopep8 script to prompt you on each change and have you say y/n, instead of duplicating all the work.Kylix
D
0

You can also use the excellent vim-autopep8

Delora answered 14/11, 2016 at 16:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.