vim-mode: fix w/W/e/E/b/B/ge/gE movement with block cursor

This commit is contained in:
Le Tan 2017-12-13 19:55:00 +08:00
parent 559f5090bf
commit 70eb04ebd2
4 changed files with 301 additions and 68 deletions

View File

@ -43,7 +43,7 @@ background: c5cae9
# [VNote] Vim insert mode cursor line background
vim-insert-background: c5cae9
# [VNote] Vim normal mode cursor line background
vim-normal-background: bdbdbd
vim-normal-background: c6c6c6
# [VNote] Vim visual mode cursor line background
vim-visual-background: 90caf9
# [VNote] Vim replace mode cursor line background
@ -130,42 +130,39 @@ font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New
# [VNote] Codeblock sylte from HighlightJS (bold, italic, underlined, color)
# The last occurence of the same attribute takes effect
# Could specify multiple attribute in one line
hljs-comment: italic, 898989
hljs-quote: italic, 898989
hljs-doctag: a626a4
hljs-keyword: a626a4
hljs-formula: a626a4
hljs-section: e45649
hljs-name: e45649
hljs-selector-tag: e45649
hljs-deletion: e45649
hljs-subst: e45649
hljs-literal: 0184bb
hljs-string: 50a1f4
hljs-regexp: 50a1f4
hljs-addition: 50a1f4
hljs-attribute: 50a1f4
hljs-meta-string: 50a1f4
hljs-built_in: c18401
hljs-attr: 986801
hljs-variable: 986801
hljs-template-variable: 986801
hljs-type: 986801
hljs-selector-class: 986801
hljs-selector-attr: 986801
hljs-selector-pseudo: 986801
hljs-number: 986801
hljs-symbol: 4078f2
hljs-bullet: 4078f2
hljs-link: underlined, 4078f2
hljs-meta: 4078f2
hljs-selector-id: 4078f2
hljs-title: 4078f2
hljs-comment: 6c6c6c
hljs-keyword: 0000ee
hljs-attribute: 0000ee
hljs-selector-tag: 0000ee
hljs-meta-keyword: 0000ee
hljs-doctag: 0000ee
hljs-name: 0000ee
hljs-type: 880000
hljs-string: 880000
hljs-number: 880000
hljs-selector-id: 880000
hljs-selector-class: 880000
hljs-quote: 880000
hljs-template-tag: 880000
hljs-deletion: 880000
hljs-title: bold, 880000
hljs-section: bold, 880000
hljs-regexp: bc6060
hljs-symbol: bc6060
hljs-variable: bc6060
hljs-template-variable: bc6060
hljs-link: bc6060
hljs-selector-attr: bc6060
hljs-selector-pseudo: bc6060
hljs-literal: af00d7
hljs-built_in: 008700
hljs-bullet: 008700
hljs-code: 008700
hljs-addition: 008700
hljs-meta: 1f7199
hljs-meta-string: 4d99bf
hljs-emphasis: italic
hljs-strong: bold
hljs-meta-keyword: 0000ee
hljs-template-tag: 880000
hljs-code: 008700
BLOCKQUOTE
foreground: 00af00

View File

@ -176,7 +176,6 @@ public:
// Find the start and end of the WORD @p_cursor locates in (within a single block).
// @p_start and @p_end will be the global position of the start and end of the WORD.
// @p_start will equals to @p_end if @p_cursor is a space.
// Attention: www|sss will select www, which is different from findCurrentWord().
static void findCurrentWORD(const QTextCursor &p_cursor,
int &p_start,
int &p_end);

View File

@ -2273,7 +2273,7 @@ void VVim::setMode(VimMode p_mode, bool p_clearSelection, int p_position)
VMdEditor *mdEditor = dynamic_cast<VMdEditor *>(m_editor);
switch (m_mode) {
case VimMode::Insert:
m_editor->setCursorBlockModeW(CursorBlock::None);
setCursorBlockMode(m_editor, CursorBlock::None);
if (mdEditor) {
mdEditor->setHighlightCursorLineBlockEnabled(false);
}
@ -2285,7 +2285,7 @@ void VVim::setMode(VimMode p_mode, bool p_clearSelection, int p_position)
V_FALLTHROUGH;
default:
m_editor->setCursorBlockModeW(CursorBlock::RightSide);
setCursorBlockMode(m_editor, CursorBlock::RightSide);
if (mdEditor) {
QString color;
if (m_mode == VimMode::Normal) {
@ -2777,7 +2777,24 @@ bool VVim::processMovement(QTextCursor &p_cursor,
p_repeat = 1;
}
p_cursor.movePosition(QTextCursor::NextWord, p_moveMode, p_repeat);
while (p_repeat) {
if (p_cursor.atEnd()) {
break;
}
p_cursor.movePosition(QTextCursor::NextWord, p_moveMode);
if (p_cursor.atBlockEnd() || VEditUtils::isSpaceBlock(p_cursor.block())) {
continue;
}
--p_repeat;
}
if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) {
// Move one character forward.
p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode);
}
hasMoved = true;
break;
}
@ -2789,16 +2806,28 @@ bool VVim::processMovement(QTextCursor &p_cursor,
p_repeat = 1;
}
for (int i = 0; i < p_repeat; ++i) {
while (p_repeat) {
if (p_cursor.atEnd()) {
break;
}
int start, end;
// [start, end] is current WORD.
VEditUtils::findCurrentWORD(p_cursor, start, end);
// Move cursor to end of current WORD.
p_cursor.setPosition(end, p_moveMode);
// Skip spaces.
moveCursorAcrossSpaces(p_cursor, p_moveMode, true);
if (p_cursor.atBlockEnd()) {
continue;
}
--p_repeat;
}
if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) {
// Move one character forward.
p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode);
}
hasMoved = true;
@ -2813,16 +2842,45 @@ bool VVim::processMovement(QTextCursor &p_cursor,
}
int pos = p_cursor.position();
bool leftSideBefore = useLeftSideOfCursor(p_cursor);
// First move to the end of current word.
p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode, 1);
if (pos != p_cursor.position()) {
// We did move.
p_repeat -= 1;
if (p_cursor.position() > pos) {
if (p_cursor.position() > pos + 1 || (leftSideBefore && useLeftSideOfCursor(p_cursor))) {
// We did move.
p_repeat -= 1;
}
}
if (p_repeat) {
p_cursor.movePosition(QTextCursor::NextWord, p_moveMode, p_repeat);
while (p_repeat) {
if (p_cursor.atEnd()) {
break;
}
pos = p_cursor.position();
p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode);
if (p_cursor.position() == pos) {
// Need to move to the start of next word.
p_cursor.movePosition(QTextCursor::NextWord, p_moveMode);
if (p_cursor.atBlockEnd()) {
continue;
}
p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode);
if (p_cursor.atBlockStart()) {
continue;
}
}
--p_repeat;
}
// Move one character back.
if (!p_cursor.atBlockStart()) {
if (p_moveMode == QTextCursor::MoveAnchor
|| (checkMode(VimMode::Visual) && !useLeftSideOfCursor(p_cursor))) {
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
}
}
hasMoved = true;
@ -2836,9 +2894,18 @@ bool VVim::processMovement(QTextCursor &p_cursor,
p_repeat = 1;
}
for (int i = 0; i < p_repeat; ++i) {
int pos = p_cursor.position();
bool leftSideBefore = useLeftSideOfCursor(p_cursor);
while (p_repeat) {
if (p_cursor.atEnd()) {
break;
}
// Skip spaces.
moveCursorAcrossSpaces(p_cursor, p_moveMode, true);
if (p_cursor.atBlockEnd()) {
continue;
}
int start, end;
// [start, end] is current WORD.
@ -2846,6 +2913,19 @@ bool VVim::processMovement(QTextCursor &p_cursor,
// Move cursor to the end of current WORD.
p_cursor.setPosition(end, p_moveMode);
if (p_cursor.position() > pos + 1
|| (leftSideBefore && useLeftSideOfCursor(p_cursor))) {
--p_repeat;
}
}
// Move one character back.
if (!p_cursor.atBlockStart()) {
if (p_moveMode == QTextCursor::MoveAnchor
|| (checkMode(VimMode::Visual) && !useLeftSideOfCursor(p_cursor))) {
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
}
}
hasMoved = true;
@ -2861,14 +2941,46 @@ bool VVim::processMovement(QTextCursor &p_cursor,
int pos = p_cursor.position();
// first move to the start of current word.
p_cursor.movePosition(QTextCursor::StartOfWord, p_moveMode, 1);
if (pos != p_cursor.position()) {
// We did move.
p_repeat -= 1;
p_cursor.movePosition(QTextCursor::StartOfWord, p_moveMode);
if (p_cursor.position() == pos && useLeftSideOfCursor(p_cursor)) {
// Cursor did not move and now is at the start of a word.
// Actually we are using the left side character so we need to move
// to previous word.
p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode);
}
if (p_repeat) {
p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode, p_repeat);
if (p_cursor.position() < pos) {
if (p_cursor.position() < pos - 1 || !useLeftSideOfCursor(p_cursor)) {
// We did move.
p_repeat -= 1;
}
}
while (p_repeat) {
if (p_cursor.atStart()) {
break;
}
pos = p_cursor.position();
p_cursor.movePosition(QTextCursor::StartOfWord, p_moveMode);
if (p_cursor.position() == pos) {
// Need to move to the start of previous word.
p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode);
if (p_cursor.atBlockEnd()) {
continue;
}
if (p_cursor.atBlockStart() && doc->characterAt(p_cursor.position()).isSpace()) {
continue;
}
}
--p_repeat;
}
if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) {
// Move one character forward.
p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode);
}
hasMoved = true;
@ -2882,9 +2994,19 @@ bool VVim::processMovement(QTextCursor &p_cursor,
p_repeat = 1;
}
for (int i = 0; i < p_repeat; ++i) {
int pos = p_cursor.position();
while (p_repeat) {
if (p_cursor.atStart()) {
break;
}
// Skip Spaces.
moveCursorAcrossSpaces(p_cursor, p_moveMode, false);
if (p_cursor.atBlockStart()) {
continue;
}
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
int start, end;
// [start, end] is current WORD.
@ -2892,6 +3014,15 @@ bool VVim::processMovement(QTextCursor &p_cursor,
// Move cursor to the start of current WORD.
p_cursor.setPosition(start, p_moveMode);
if (p_cursor.position() < pos - 1 || !useLeftSideOfCursor(p_cursor)) {
--p_repeat;
}
}
if (!p_cursor.atEnd() && useLeftSideOfCursor(p_cursor)) {
// Move one character forward.
p_cursor.movePosition(QTextCursor::NextCharacter, p_moveMode);
}
hasMoved = true;
@ -2905,13 +3036,55 @@ bool VVim::processMovement(QTextCursor &p_cursor,
p_repeat = 1;
}
int pib = p_cursor.positionInBlock();
if (!(pib > 0 && p_cursor.block().text()[pib -1].isSpace())) {
++p_repeat;
if (useLeftSideOfCursor(p_cursor)) {
// Move one previous char.
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
}
int pos = p_cursor.position();
// Move across spaces backward.
moveCursorAcrossSpaces(p_cursor, p_moveMode, false);
int start, end;
VEditUtils::findCurrentWord(p_cursor, start, end);
if (pos != p_cursor.position() || start == end || start == pos) {
// We are alreay at the end of previous word.
--p_repeat;
// Move it to the start of current word.
p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode);
} else {
p_cursor.movePosition(QTextCursor::StartOfWord, p_moveMode);
}
while (p_repeat) {
if (p_cursor.atStart()) {
break;
}
p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode);
if (p_cursor.atBlockEnd()) {
continue;
}
if (p_cursor.atBlockStart() && doc->characterAt(p_cursor.position()).isSpace()) {
continue;
}
--p_repeat;
}
// Move it to the end.
p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode);
// Move one character back.
if (!p_cursor.atBlockStart()) {
if (p_moveMode == QTextCursor::MoveAnchor
|| (checkMode(VimMode::Visual) && !useLeftSideOfCursor(p_cursor))
|| p_cursor.position() <= p_cursor.anchor()) {
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
}
}
p_cursor.movePosition(QTextCursor::PreviousWord, p_moveMode, p_repeat);
p_cursor.movePosition(QTextCursor::EndOfWord, p_moveMode, 1);
hasMoved = true;
break;
}
@ -2923,13 +3096,58 @@ bool VVim::processMovement(QTextCursor &p_cursor,
p_repeat = 1;
}
for (int i = 0; i < p_repeat; ++i) {
int start, end;
VEditUtils::findCurrentWORD(p_cursor, start, end);
if (useLeftSideOfCursor(p_cursor)) {
// Move one previous char.
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
}
int pos = p_cursor.position();
// Move across spaces backward.
moveCursorAcrossSpaces(p_cursor, p_moveMode, false);
int start, end;
VEditUtils::findCurrentWORD(p_cursor, start, end);
if (pos != p_cursor.position() || start == end) {
// We are alreay at the end of previous WORD.
--p_repeat;
// Move it to the start of current WORD.
p_cursor.setPosition(start, p_moveMode);
} else {
// Move it to the start of current WORD.
p_cursor.setPosition(start, p_moveMode);
}
while (p_repeat) {
if (p_cursor.atStart()) {
break;
}
moveCursorAcrossSpaces(p_cursor, p_moveMode, false);
if (p_cursor.atBlockStart()) {
continue;
}
if (p_cursor.atBlockStart() && doc->characterAt(p_cursor.position()).isSpace()) {
continue;
}
VEditUtils::findCurrentWORD(p_cursor, start, end);
p_cursor.setPosition(start, p_moveMode);
--p_repeat;
}
// Move it to the end.
VEditUtils::findCurrentWORD(p_cursor, start, end);
p_cursor.setPosition(end, p_moveMode);
// Move one character back.
if (!p_cursor.atBlockStart()) {
if (p_moveMode == QTextCursor::MoveAnchor
|| (checkMode(VimMode::Visual) && !useLeftSideOfCursor(p_cursor))
|| p_cursor.position() <= p_cursor.anchor()) {
p_cursor.movePosition(QTextCursor::PreviousCharacter, p_moveMode);
}
}
hasMoved = true;
@ -4940,7 +5158,7 @@ void VVim::maintainSelectionInVisualMode(QTextCursor *p_cursor)
hasChanged = true;
}
m_editor->setCursorBlockModeW(CursorBlock::LeftSide);
setCursorBlockMode(m_editor, CursorBlock::LeftSide);
} else if (pos == anchor) {
Q_ASSERT(anchor >= m_positionBeforeVisualMode);
// Re-select.
@ -4949,13 +5167,13 @@ void VVim::maintainSelectionInVisualMode(QTextCursor *p_cursor)
cursor->setPosition(pos, QTextCursor::KeepAnchor);
hasChanged = true;
m_editor->setCursorBlockModeW(CursorBlock::RightSide);
setCursorBlockMode(m_editor, CursorBlock::RightSide);
} else {
cursor->setPosition(m_positionBeforeVisualMode);
cursor->setPosition(pos, QTextCursor::KeepAnchor);
hasChanged = true;
m_editor->setCursorBlockModeW(CursorBlock::LeftSide);
setCursorBlockMode(m_editor, CursorBlock::LeftSide);
}
} else {
// Re-select.
@ -4965,7 +5183,7 @@ void VVim::maintainSelectionInVisualMode(QTextCursor *p_cursor)
hasChanged = true;
}
m_editor->setCursorBlockModeW(CursorBlock::RightSide);
setCursorBlockMode(m_editor, CursorBlock::RightSide);
}
if (hasChanged && !p_cursor) {
@ -6000,3 +6218,18 @@ void VVim::handleMouseMoved(QMouseEvent *p_event)
maintainSelectionInVisualMode();
}
}
void VVim::setCursorBlockMode(VEditor *p_cursor, CursorBlock p_mode)
{
p_cursor->setCursorBlockModeW(p_mode);
}
bool VVim::useLeftSideOfCursor(const QTextCursor &p_cursor)
{
if (!checkMode(VimMode::Visual)) {
return false;
}
Q_ASSERT(m_positionBeforeVisualMode >= 0);
return p_cursor.position() > m_positionBeforeVisualMode;
}

View File

@ -816,6 +816,11 @@ private:
// is always selected.
void maintainSelectionInVisualMode(QTextCursor *p_cursor = NULL);
void setCursorBlockMode(VEditor *p_cursor, CursorBlock p_mode);
// Whether we should consider the left or right side of the cursor.
bool useLeftSideOfCursor(const QTextCursor &p_cursor);
VEditor *m_editor;
const VEditConfig *m_editConfig;
VimMode m_mode;
@ -881,5 +886,4 @@ inline void VVim::setRegister(QChar p_regName, const QString &p_val)
{
s_registers[p_regName].update(p_val);
}
#endif // VVIM_H