jeetsukumaran / vim-indentwise

A Vim plugin for indent-level based motion.
220 stars 17 forks source link

Bug with ]= in livescript file type #8

Closed raine closed 9 years ago

raine commented 9 years ago

For example in this file and line, with cursor on the first column, pressing ]= will go to the absolute bottom, to module.exports = main, instead of line 58.

Meanwhile, if you press [=, it will correctly go to line 44. So it works as expected when going up, but not when going down.

emmalemma commented 9 years ago

I've been wrestling with this problem in CoffeeScript for a while too, and seeing this issue inspired me to hunt for a workaround. Long story short I've got a commit: https://github.com/cushman/vim-indentwise/commit/2619003dfd7dc0d1c02a64358d439813ee03396d and a PR: https://github.com/jeetsukumaran/vim-indentwise/pull/9

The actual bug has to do with handling of blank lines in the context of "same indent separated by lines of different indents". Here's an example for context:

block 0

block 1 ->

  indent 1

block 2 ->
  indent 2(1)

  indent 2(2)

block 3 
block 4 ->
  indent 4

block 5 ->
  indent 5

This issue comes up when you're on a line of indentation 0, such as block 2, and you want to move to another line with the same indentation, like block 3. So you push ]=, and you wind up on... block 5. What gives?

Well, what it's actually doing is looking for a line of indentation 0 immediately after a line of different indentation, or failing that, the last such line in the file.

You can reproduce the same behavior in the other direction: from block 3, [= takes you to block 2 as you'd expect. But press it again, and you'll end up at block 0, not block 1-- because block 1 isn't directly above a line of different indentation, it's above a blank line, and all blank lines have 0 indentation.

So what's really going on is, when indentwise looks for a 0-indented line, it finds that blank line. But since indentwise_skip_blanks is 1, it won't move to that line, and it keeps looking. But not before it unsets the indent_depth_changed flag, helpfully restarting the search.

The upshot is, you're headed for the last contiguous 0-indent block in the file, unless you happen to cross a block like this:

promise.then ->
  throw error # since this indented line is *directly* above,
.done() # <-- you will wind up here

And that's not usually the style in indent-sensitive languages, so it feels pretty random where you end up.

What to do? The easiest fix is to just comment out that line that unsets indent_depth_changed, but that breaks repetition: If you're at block 1 and press 3]=, you wind up at block 4 instead of block 5 as you intend. Instead, we just want to duplicate the blank_line test in the searching logic, so we won't end the search on a line that we won't accept. So that's what my PR does!

I've also noticed that, in practice, I'd like to be able to use it to move between lines of the same indentation separated by blanks: so from indent 2(1), I want ]= to take me to indent 2(2), not straight down to indent 4, and the same for block 0 and block 1. To do that we need to treat blank lines as having no indentation, not even 0. I added that under the indentwise_blanks_have_null_indentation flag. That might actually replace the skip_blanks flag, or interact with it oddly, but I didn't spend much time looking at it.

Finally, while I was in there I figured, why not treat whitespace-only lines as if they were blank, too. That's under indentwise_treat_whitespace_as_blank.

I haven't tested this out too much, so there might still be bugs in there.