vim: Improve tests for compatibilities with Vim's visual line mode
Currently, there are several issues in tests for compatibilities with Vim visual line mode. Due to these issues, it is hard to test paragraph objects. This PR fixes those issues (affecting only to tests).
Issues:
- The current test is done by comparing the range starting from the position of the selection operation (
'v'') and the cursor position after the selection operation ('.') (the same range as in visual mode) between vim and zed, and does not compare the line-based selection ranges. This test works correctly for selection by motion, but not for selection by paragraph objects. - In the current selection using visual line mode + motion in zed, the selection range extends to the right side of the right-most character. As a result, the cursor position in "zed state" generated from the selection moves to the right by one character.
Examples of issues:
# initial state:
The quiˇck brown fox jumps over the lazy dog.
# keystrokes:
shift-v
# currently expected:
«The quiˇck brown fox jumps over the lazy dog.»
# neovim state:
The qui«cˇ»k brown fox jumps over the lazy dog.
# zed state:
The qui«cˇ»k brown fox jumps over the lazy dog.
# initial state:
The quiˇck brown fox
jumps
over the lazy dog.
# keystrokes:
shift-v j
# currently expected:
«The quick brown fox
jumpsˇ»
over the lazy dog.
# neovim state:
The quic«k brown fox
jumpsˇ»
over the lazy dog.
# zed state:
The qui«ck brown fox
jumps
ˇ»over the lazy dog.
# initial state:
The quick brown fox
jumps
over the lazˇy dog.
# keystrokes:
shift-v 2 k
# currently expected:
«The quick brˇown fox
jumps
over the lazy dog.»
# neovim state:
The quick bro«ˇwn fox
jumps
over the laz»y dog.
# zed state:
The quick br«ˇown fox
jumps
over the lazy» dog.
# initial state:
The quick brown fox
jumpˇs
over the lazy dog.
# keystrokes:
v i p
# currently expected:
«The quick brown fox
jumps
ˇover the lazy dog.»
# neovim state:
«The quick brown fox
jumps
oˇ»ver the lazy dog.
# zed state:
(currently N/A)
# initial state:
The quiˇck brown fox
jumps
over the lazy dog.
# keystrokes:
v i p
# currently expected:
«The quick brown fox
jumps
ˇover the lazy dog.»
# neovim state:
The quic«k brown fox
jumps
ˇ»over the lazy dog.
# zed state:
(currently N/A)
This PR attempts to solve these issues with the following approach:
- For selections where
line_modeis true, extend the selections between line breaks in generating the marked text data. - Make motions in visual line mode to select ranges up to the left side of the rightmost character.
Release Notes:
- N/A
(Currently, I have made only the first change. As for the second change, I have not been able to change the selection range when keystroke is only shift-v.)
@noritada Thanks for taking a pass at this! I agree the current situation is confusing.
To summarize what you said, there are at least ~2 problems right now:
- It's not obvious looking at the test what the line selection is (we only show the HEAD/TAIL). This is I think your "Example 1"
- There are bugs when the cursor is on a line boundary. Looking into these, both "Example 2" and "Example 3" are caused by a bug in this if statement: https://github.com/zed-industries/zed/blob/4b8a96c1eb31c2e62fcb97729b31fea40b8c6065/crates/vim/src/test/neovim_connection.rs#L422 – we should check
if (selection_row, selection_col) > (cursor_row, cursor_col)instead.
If we fix 2. then the question is, what do we want to do about 1?
For visual line mode there are three things to care about:
- Which "LINES" are highlighted (this is what looks selected)
- Where the "HEAD" of the selection is (where the cursor is painted).
- Where the "TAIL" of the selection is (where the cursor moves if you hit
o).
Tests currently look confusing because we show only HEAD/TAIL even in visual line mode; but when using zed/nvim you mostly see the LINES. I think at the very least we should add a check that the mode matches, so you can see on failure that the mode is visual line.
We could also try and change the «» syntax to expand to lines; but it does currently accurately model the way that zed maintains the selection internally. A better approach might be to represent the selected lines separately:
# Example 2: initial state:
The quiˇck brown fox
jumps
over the lazy dog.
# keystrokes:
shift-v j
# expected
∑The qui«ck brown
∑jumps
ˇ»over the lazy dog.
But I'm not sure if that makes it clearer or more confusing. I think in practice we'd have to validate that the ∑ makes sense given the positioning of your «», and if it did, then we could just check "if mode == visual_line" if we saw some ∑'s.
In summary, I think we should not try and fix this, but:
- Fix the broken if statement
- Ensure that
assert_shared_statechecks the mode.
I've implemented this https://github.com/zed-industries/zed/pull/8461 and fixed the one bug that the stronger mode checks found.