forked from qt-creator/qt-creator
FakeVim: Fixes for insert/change in visual mode
Always limit position of marks to current document (mainly position of '<' and '>' marks for last selection). Command '$' selects end of selected lines in visual block mode. This will require editor support since visual representation of such selection isn't always rectangle. Command 'c' works the same as 's' in visual block mode. Corrected positions for 'I', 'A', 's' and 'c' commands in visual block mode after '<ESC>'. Task-number: QTCREATORBUG-11378 Change-Id: I86582b634eb782829db48fd1b914713f87ac409f Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -644,19 +644,6 @@ void FakeVimPlugin::test_vim_insert()
|
|||||||
KEYS("i<bs>XY", "aXY" X "c" N "def");
|
KEYS("i<bs>XY", "aXY" X "c" N "def");
|
||||||
KEYS("j.", "aXYc" N "dX" X "Yf");
|
KEYS("j.", "aXYc" N "dX" X "Yf");
|
||||||
|
|
||||||
// insert in visual block mode
|
|
||||||
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
|
|
||||||
KEYS("<c-v>2j" "2I" "XYZ<esc>", "abc" N "d" X "XYZXYZef" N "jXYZXYZkl" N "mXYZXYZno" N "pqr");
|
|
||||||
INTEGRITY(false);
|
|
||||||
|
|
||||||
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
|
|
||||||
KEYS("<c-v>2j" "2A" "XYZ<esc>", "abc" N "d" X "eXYZXYZf" N "jkXYZXYZl" N "mnXYZXYZo" N "pqr");
|
|
||||||
INTEGRITY(false);
|
|
||||||
|
|
||||||
data.setText("abc" N "de" X "f" N "" N "jkl" N "mno");
|
|
||||||
KEYS("<c-v>2jh" "2I" "XYZ<esc>", "abc" N "d" X "XYZXYZef" N "" N "jXYZXYZkl" N "mno");
|
|
||||||
INTEGRITY(false);
|
|
||||||
|
|
||||||
// insert in visual mode
|
// insert in visual mode
|
||||||
data.setText(" a" X "bcde" N " fghij" N " klmno");
|
data.setText(" a" X "bcde" N " fghij" N " klmno");
|
||||||
KEYS("v2l" "2Ixyz<esc>", "xyzxy" X "z abcde" N " fghij" N " klmno");
|
KEYS("v2l" "2Ixyz<esc>", "xyzxy" X "z abcde" N " fghij" N " klmno");
|
||||||
@@ -1199,12 +1186,36 @@ void FakeVimPlugin::test_vim_change_replace()
|
|||||||
INTEGRITY(false);
|
INTEGRITY(false);
|
||||||
|
|
||||||
// insert in visual block mode
|
// insert in visual block mode
|
||||||
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
|
data.setText(
|
||||||
KEYS("<c-v>2j" "2s" "XYZ<esc>", "abc" N "d" X "XYZf" N "jXYZl" N "mXYZo" N "pqr");
|
"abc" N
|
||||||
|
"d" X "ef" N
|
||||||
|
"" N
|
||||||
|
"jkl" N
|
||||||
|
"mno" N
|
||||||
|
);
|
||||||
|
KEYS("<c-v>2j2sXYZ<esc>",
|
||||||
|
"abc" N
|
||||||
|
"dXY" X "Zf" N
|
||||||
|
"" N
|
||||||
|
"jXYZl" N
|
||||||
|
"mno" N
|
||||||
|
);
|
||||||
INTEGRITY(false);
|
INTEGRITY(false);
|
||||||
|
|
||||||
data.setText("abc" N "de" X "f" N "" N "jkl" N "mno");
|
data.setText(
|
||||||
KEYS("<c-v>2jh" "2s" "XYZ<esc>", "abc" N "d" X "XYZ" N "" N "jXYZ" N "mno");
|
"abc" N
|
||||||
|
"de" X "f" N
|
||||||
|
"" N
|
||||||
|
"jkl" N
|
||||||
|
"mno" N
|
||||||
|
);
|
||||||
|
KEYS("<c-v>2jh2sXYZ<esc>",
|
||||||
|
"abc" N
|
||||||
|
"dXY" X "Z" N
|
||||||
|
"" N
|
||||||
|
"jXYZ" N
|
||||||
|
"mno" N
|
||||||
|
);
|
||||||
INTEGRITY(false);
|
INTEGRITY(false);
|
||||||
|
|
||||||
// change with copy to a register
|
// change with copy to a register
|
||||||
@@ -1322,6 +1333,76 @@ void FakeVimPlugin::test_vim_block_selection()
|
|||||||
KEYS("u", "\"abc\"\"" X "def\"");
|
KEYS("u", "\"abc\"\"" X "def\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FakeVimPlugin::test_vim_block_selection_insert()
|
||||||
|
{
|
||||||
|
TestData data;
|
||||||
|
setup(&data);
|
||||||
|
|
||||||
|
// insert in visual block mode
|
||||||
|
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
|
||||||
|
KEYS("<c-v>2j" "2I" "XYZ<esc>", "abc" N "d" X "XYZXYZef" N "jXYZXYZkl" N "mXYZXYZno" N "pqr");
|
||||||
|
INTEGRITY(false);
|
||||||
|
|
||||||
|
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
|
||||||
|
KEYS("<c-v>2j" "2A" "XYZ<esc>", "abc" N "d" X "eXYZXYZf" N "jkXYZXYZl" N "mnXYZXYZo" N "pqr");
|
||||||
|
INTEGRITY(false);
|
||||||
|
|
||||||
|
data.setText("abc" N "de" X "f" N "" N "jkl" N "mno");
|
||||||
|
KEYS("<c-v>2jh" "2I" "XYZ<esc>", "abc" N "d" X "XYZXYZef" N "" N "jXYZXYZkl" N "mno");
|
||||||
|
INTEGRITY(false);
|
||||||
|
|
||||||
|
/* QTCREATORBUG-11378 */
|
||||||
|
data.setText(
|
||||||
|
" abcd" N
|
||||||
|
" efgh" N
|
||||||
|
" ijkl" N
|
||||||
|
" mnop" N
|
||||||
|
"");
|
||||||
|
KEYS("<C-V>3j$AXYZ<ESC>",
|
||||||
|
X " abcdXYZ" N
|
||||||
|
" efghXYZ" N
|
||||||
|
" ijklXYZ" N
|
||||||
|
" mnopXYZ" N
|
||||||
|
"");
|
||||||
|
|
||||||
|
data.setText(
|
||||||
|
" abcd" N
|
||||||
|
" ef" N
|
||||||
|
" ghijk" N
|
||||||
|
" lm" N
|
||||||
|
"");
|
||||||
|
KEYS("<C-V>3j$AXYZ<ESC>",
|
||||||
|
X " abcdXYZ" N
|
||||||
|
" efXYZ" N
|
||||||
|
" ghijkXYZ" N
|
||||||
|
" lmXYZ" N
|
||||||
|
"");
|
||||||
|
|
||||||
|
data.setText(
|
||||||
|
"a" N
|
||||||
|
"" N
|
||||||
|
"b" N
|
||||||
|
"" N
|
||||||
|
);
|
||||||
|
KEYS("j<C-V>$jAXYZ<ESC>",
|
||||||
|
"a" N
|
||||||
|
"|XYZ" N
|
||||||
|
"bXYZ" N
|
||||||
|
"" N
|
||||||
|
);
|
||||||
|
|
||||||
|
data.setText(
|
||||||
|
"abc" N
|
||||||
|
"" N
|
||||||
|
"def" N
|
||||||
|
);
|
||||||
|
KEYS("l<c-v>2jAXYZ<ESC>",
|
||||||
|
"a" X "bXYZc" N
|
||||||
|
" XYZ" N
|
||||||
|
"deXYZf" N
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void FakeVimPlugin::test_vim_repeat()
|
void FakeVimPlugin::test_vim_repeat()
|
||||||
{
|
{
|
||||||
TestData data;
|
TestData data;
|
||||||
|
|||||||
@@ -158,6 +158,15 @@ enum Mode
|
|||||||
ExMode
|
ExMode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BlockInsertMode
|
||||||
|
{
|
||||||
|
NoneBlockInsertMode,
|
||||||
|
AppendBlockInsertMode,
|
||||||
|
AppendToEndOfLineBlockInsertMode,
|
||||||
|
InsertBlockInsertMode,
|
||||||
|
ChangeBlockInsertMode
|
||||||
|
};
|
||||||
|
|
||||||
/*! A \e SubMode is used for things that require one more data item
|
/*! A \e SubMode is used for things that require one more data item
|
||||||
and are 'nested' behind a \l Mode.
|
and are 'nested' behind a \l Mode.
|
||||||
*/
|
*/
|
||||||
@@ -268,20 +277,45 @@ struct CursorPosition
|
|||||||
int column; // Position on line.
|
int column; // Position on line.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mark
|
class Mark
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
Mark(const CursorPosition &pos = CursorPosition(), const QString &fileName = QString())
|
Mark(const CursorPosition &pos = CursorPosition(), const QString &fileName = QString())
|
||||||
: position(pos), fileName(fileName) {}
|
: m_position(pos), m_fileName(fileName) {}
|
||||||
|
|
||||||
bool isValid() const { return position.isValid(); }
|
bool isValid() const { return m_position.isValid(); }
|
||||||
|
|
||||||
bool isLocal(const QString &localFileName) const
|
bool isLocal(const QString &localFileName) const
|
||||||
{
|
{
|
||||||
return fileName.isEmpty() || fileName == localFileName;
|
return m_fileName.isEmpty() || m_fileName == localFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
CursorPosition position;
|
/* Return position of mark within given document.
|
||||||
QString fileName;
|
* If saved line number is too big, mark position is at the end of document.
|
||||||
|
* If line number is in document but column is too big, mark position is at the end of line.
|
||||||
|
*/
|
||||||
|
CursorPosition position(const QTextDocument *document) const
|
||||||
|
{
|
||||||
|
QTextBlock block = document->findBlockByNumber(m_position.line);
|
||||||
|
CursorPosition pos;
|
||||||
|
if (block.isValid()) {
|
||||||
|
pos.line = m_position.line;
|
||||||
|
pos.column = qMax(0, qMin(m_position.column, block.length() - 2));
|
||||||
|
} else if (document->isEmpty()) {
|
||||||
|
pos.line = 0;
|
||||||
|
pos.column = 0;
|
||||||
|
} else {
|
||||||
|
pos.line = document->blockCount() - 1;
|
||||||
|
pos.column = qMax(0, document->lastBlock().length() - 2);
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &fileName() const { return m_fileName; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CursorPosition m_position;
|
||||||
|
QString m_fileName;
|
||||||
};
|
};
|
||||||
typedef QHash<QChar, Mark> Marks;
|
typedef QHash<QChar, Mark> Marks;
|
||||||
typedef QHashIterator<QChar, Mark> MarksIterator;
|
typedef QHashIterator<QChar, Mark> MarksIterator;
|
||||||
@@ -1561,6 +1595,7 @@ public:
|
|||||||
EventResult handleInsertOrReplaceMode(const Input &);
|
EventResult handleInsertOrReplaceMode(const Input &);
|
||||||
void handleInsertMode(const Input &);
|
void handleInsertMode(const Input &);
|
||||||
void handleReplaceMode(const Input &);
|
void handleReplaceMode(const Input &);
|
||||||
|
void finishInsertMode();
|
||||||
|
|
||||||
EventResult handleCommandMode(const Input &);
|
EventResult handleCommandMode(const Input &);
|
||||||
|
|
||||||
@@ -1755,7 +1790,7 @@ public:
|
|||||||
|
|
||||||
bool handleFfTt(QString key);
|
bool handleFfTt(QString key);
|
||||||
|
|
||||||
void initVisualInsertMode(QChar command);
|
void enterVisualInsertMode(QChar command);
|
||||||
void enterReplaceMode();
|
void enterReplaceMode();
|
||||||
void enterInsertMode();
|
void enterInsertMode();
|
||||||
void enterInsertOrReplaceMode(Mode mode);
|
void enterInsertOrReplaceMode(Mode mode);
|
||||||
@@ -1843,7 +1878,7 @@ public:
|
|||||||
int m_oldInternalPosition; // copy from last event to check for external changes
|
int m_oldInternalPosition; // copy from last event to check for external changes
|
||||||
int m_oldInternalAnchor;
|
int m_oldInternalAnchor;
|
||||||
int m_register;
|
int m_register;
|
||||||
bool m_visualBlockInsert;
|
BlockInsertMode m_visualBlockInsert;
|
||||||
|
|
||||||
// Insert state to get last inserted text.
|
// Insert state to get last inserted text.
|
||||||
struct InsertState {
|
struct InsertState {
|
||||||
@@ -1949,6 +1984,8 @@ public:
|
|||||||
// update marks on undo/redo
|
// update marks on undo/redo
|
||||||
void updateMarks(const Marks &newMarks);
|
void updateMarks(const Marks &newMarks);
|
||||||
Marks m_marks; // local marks
|
Marks m_marks; // local marks
|
||||||
|
CursorPosition markLessPosition() const { return mark(QLatin1Char('<')).position(document()); }
|
||||||
|
CursorPosition markGreaterPosition() const { return mark(QLatin1Char('>')).position(document()); }
|
||||||
|
|
||||||
// vi style configuration
|
// vi style configuration
|
||||||
QVariant config(int code) const { return theFakeVimSetting(code)->value(); }
|
QVariant config(int code) const { return theFakeVimSetting(code)->value(); }
|
||||||
@@ -2136,7 +2173,7 @@ void FakeVimHandler::Private::init()
|
|||||||
{
|
{
|
||||||
m_inFakeVim = false;
|
m_inFakeVim = false;
|
||||||
m_findStartPosition = -1;
|
m_findStartPosition = -1;
|
||||||
m_visualBlockInsert = false;
|
m_visualBlockInsert = NoneBlockInsertMode;
|
||||||
m_fakeEnd = false;
|
m_fakeEnd = false;
|
||||||
m_positionPastEnd = false;
|
m_positionPastEnd = false;
|
||||||
m_anchorPastEnd = false;
|
m_anchorPastEnd = false;
|
||||||
@@ -2406,8 +2443,10 @@ void FakeVimHandler::Private::exportSelection()
|
|||||||
const int col2 = pos - document()->findBlock(pos).position();
|
const int col2 = pos - document()->findBlock(pos).position();
|
||||||
if (col1 > col2)
|
if (col1 > col2)
|
||||||
++anc;
|
++anc;
|
||||||
else
|
else if (!atEndOfLine())
|
||||||
++pos;
|
++pos;
|
||||||
|
// FIXME: After '$' command (i.e. m_visualTargetColumn == -1), end of selected lines
|
||||||
|
// should be selected.
|
||||||
setAnchorAndPosition(anc, pos);
|
setAnchorAndPosition(anc, pos);
|
||||||
commitCursor();
|
commitCursor();
|
||||||
emit q->requestSetBlockSelection(false);
|
emit q->requestSetBlockSelection(false);
|
||||||
@@ -2435,8 +2474,8 @@ void FakeVimHandler::Private::exportSelection()
|
|||||||
|
|
||||||
setAnchorAndPosition(anc, pos);
|
setAnchorAndPosition(anc, pos);
|
||||||
|
|
||||||
setMark(QLatin1Char('<'), mark(QLatin1Char('<')).position);
|
setMark(QLatin1Char('<'), markLessPosition());
|
||||||
setMark(QLatin1Char('>'), mark(QLatin1Char('>')).position);
|
setMark(QLatin1Char('>'), markGreaterPosition());
|
||||||
} else {
|
} else {
|
||||||
if (g.subsubmode == SearchSubSubMode && !m_searchCursor.isNull())
|
if (g.subsubmode == SearchSubSubMode && !m_searchCursor.isNull())
|
||||||
m_cursor = m_searchCursor;
|
m_cursor = m_searchCursor;
|
||||||
@@ -2914,8 +2953,8 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite)
|
|||||||
m_redo.clear();
|
m_redo.clear();
|
||||||
m_lastChangePosition = CursorPosition(document(), pos);
|
m_lastChangePosition = CursorPosition(document(), pos);
|
||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
setMark(QLatin1Char('<'), mark(QLatin1Char('<')).position);
|
setMark(QLatin1Char('<'), markLessPosition());
|
||||||
setMark(QLatin1Char('>'), mark(QLatin1Char('>')).position);
|
setMark(QLatin1Char('>'), markGreaterPosition());
|
||||||
}
|
}
|
||||||
m_undoState = State(revision(), m_lastChangePosition, m_marks, m_lastVisualMode,
|
m_undoState = State(revision(), m_lastChangePosition, m_marks, m_lastVisualMode,
|
||||||
m_lastVisualModeInverted);
|
m_lastVisualModeInverted);
|
||||||
@@ -3333,7 +3372,7 @@ void FakeVimHandler::Private::updateSelection()
|
|||||||
it.next();
|
it.next();
|
||||||
QTextEdit::ExtraSelection sel;
|
QTextEdit::ExtraSelection sel;
|
||||||
sel.cursor = m_cursor;
|
sel.cursor = m_cursor;
|
||||||
setCursorPosition(&sel.cursor, it.value().position);
|
setCursorPosition(&sel.cursor, it.value().position(document()));
|
||||||
sel.cursor.setPosition(sel.cursor.position(), MoveAnchor);
|
sel.cursor.setPosition(sel.cursor.position(), MoveAnchor);
|
||||||
sel.cursor.movePosition(Right, KeepAnchor);
|
sel.cursor.movePosition(Right, KeepAnchor);
|
||||||
sel.format = m_cursor.blockCharFormat();
|
sel.format = m_cursor.blockCharFormat();
|
||||||
@@ -4046,13 +4085,13 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
}
|
}
|
||||||
} else if ((!isVisualMode() && input.is('a')) || (isVisualMode() && input.is('A'))) {
|
} else if ((!isVisualMode() && input.is('a')) || (isVisualMode() && input.is('A'))) {
|
||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
initVisualInsertMode(QLatin1Char('A'));
|
enterVisualInsertMode(QLatin1Char('A'));
|
||||||
} else {
|
} else {
|
||||||
setDotCommand(_("%1a"), count());
|
setDotCommand(_("%1a"), count());
|
||||||
moveRight(qMin(rightDist(), 1));
|
moveRight(qMin(rightDist(), 1));
|
||||||
|
breakEditBlock();
|
||||||
|
enterInsertMode();
|
||||||
}
|
}
|
||||||
breakEditBlock();
|
|
||||||
enterInsertMode();
|
|
||||||
} else if (input.is('A')) {
|
} else if (input.is('A')) {
|
||||||
breakEditBlock();
|
breakEditBlock();
|
||||||
moveBehindEndOfLine();
|
moveBehindEndOfLine();
|
||||||
@@ -4076,6 +4115,9 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
g.submode = ChangeSubMode;
|
g.submode = ChangeSubMode;
|
||||||
finishMovement();
|
finishMovement();
|
||||||
|
} else if ((input.is('c') || input.is('s')) && isVisualBlockMode()) {
|
||||||
|
resetCount();
|
||||||
|
enterVisualInsertMode(input.asChar());
|
||||||
} else if (input.is('C')) {
|
} else if (input.is('C')) {
|
||||||
setAnchor();
|
setAnchor();
|
||||||
moveToEndOfLine();
|
moveToEndOfLine();
|
||||||
@@ -4150,7 +4192,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
moveLeft();
|
moveLeft();
|
||||||
} else if (input.is('I')) {
|
} else if (input.is('I')) {
|
||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
initVisualInsertMode(QLatin1Char('I'));
|
enterVisualInsertMode(QLatin1Char('I'));
|
||||||
} else {
|
} else {
|
||||||
if (g.gflag) {
|
if (g.gflag) {
|
||||||
setDotCommand(_("%1gI"), count());
|
setDotCommand(_("%1gI"), count());
|
||||||
@@ -4159,11 +4201,9 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
setDotCommand(_("%1I"), count());
|
setDotCommand(_("%1I"), count());
|
||||||
moveToFirstNonBlankOnLine();
|
moveToFirstNonBlankOnLine();
|
||||||
}
|
}
|
||||||
|
breakEditBlock();
|
||||||
|
enterInsertMode();
|
||||||
}
|
}
|
||||||
pushUndoState();
|
|
||||||
breakEditBlock();
|
|
||||||
enterInsertMode();
|
|
||||||
setTargetColumn();
|
|
||||||
} else if (input.isControl('i')) {
|
} else if (input.isControl('i')) {
|
||||||
jump(count());
|
jump(count());
|
||||||
} else if (input.is('J')) {
|
} else if (input.is('J')) {
|
||||||
@@ -4251,13 +4291,6 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
int repeat = count();
|
int repeat = count();
|
||||||
while (--repeat >= 0)
|
while (--repeat >= 0)
|
||||||
redo();
|
redo();
|
||||||
} else if (input.is('s') && isVisualBlockMode()) {
|
|
||||||
resetCount();
|
|
||||||
pushUndoState();
|
|
||||||
beginEditBlock();
|
|
||||||
initVisualInsertMode(QLatin1Char('s'));
|
|
||||||
endEditBlock();
|
|
||||||
enterInsertMode();
|
|
||||||
} else if (input.is('s')) {
|
} else if (input.is('s')) {
|
||||||
pushUndoState();
|
pushUndoState();
|
||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
@@ -4299,8 +4332,8 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
scrollToLine(cursorLine() - sline);
|
scrollToLine(cursorLine() - sline);
|
||||||
} else if (g.gflag && input.is('v')) {
|
} else if (g.gflag && input.is('v')) {
|
||||||
if (m_lastVisualMode != NoVisualMode) {
|
if (m_lastVisualMode != NoVisualMode) {
|
||||||
CursorPosition from = mark(QLatin1Char('<')).position;
|
CursorPosition from = markLessPosition();
|
||||||
CursorPosition to = mark(QLatin1Char('>')).position;
|
CursorPosition to = markGreaterPosition();
|
||||||
toggleVisualMode(m_lastVisualMode);
|
toggleVisualMode(m_lastVisualMode);
|
||||||
setCursorPosition(m_lastVisualModeInverted ? to : from);
|
setCursorPosition(m_lastVisualModeInverted ? to : from);
|
||||||
setAnchor();
|
setAnchor();
|
||||||
@@ -4679,6 +4712,7 @@ EventResult FakeVimHandler::Private::handleInsertOrReplaceMode(const Input &inpu
|
|||||||
commitInsertState();
|
commitInsertState();
|
||||||
invalidateInsertState();
|
invalidateInsertState();
|
||||||
breakEditBlock();
|
breakEditBlock();
|
||||||
|
m_visualBlockInsert = NoneBlockInsertMode;
|
||||||
} else if (m_oldInternalPosition == position()) {
|
} else if (m_oldInternalPosition == position()) {
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
}
|
}
|
||||||
@@ -4724,73 +4758,94 @@ void FakeVimHandler::Private::handleReplaceMode(const Input &input)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::handleInsertMode(const Input &input)
|
void FakeVimHandler::Private::finishInsertMode()
|
||||||
{
|
{
|
||||||
if (input.isEscape()) {
|
bool newLineAfter = m_insertState.newLineAfter;
|
||||||
bool newLineAfter = m_insertState.newLineAfter;
|
bool newLineBefore = m_insertState.newLineBefore;
|
||||||
bool newLineBefore = m_insertState.newLineBefore;
|
|
||||||
|
|
||||||
// Repeat insertion [count] times.
|
// Repeat insertion [count] times.
|
||||||
// One instance was already physically inserted while typing.
|
// One instance was already physically inserted while typing.
|
||||||
if (!m_breakEditBlock && isInsertStateValid()) {
|
if (!m_breakEditBlock && isInsertStateValid()) {
|
||||||
commitInsertState();
|
commitInsertState();
|
||||||
|
|
||||||
QString text = m_lastInsertion;
|
QString text = m_lastInsertion;
|
||||||
const QString dotCommand = g.dotCommand;
|
const QString dotCommand = g.dotCommand;
|
||||||
const int repeat = count() - 1;
|
const int repeat = count() - 1;
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
joinPreviousEditBlock();
|
joinPreviousEditBlock();
|
||||||
|
|
||||||
if (newLineAfter) {
|
if (newLineAfter) {
|
||||||
text.chop(1);
|
text.chop(1);
|
||||||
text.prepend(_("<END>\n"));
|
text.prepend(_("<END>\n"));
|
||||||
} else if (newLineBefore) {
|
} else if (newLineBefore) {
|
||||||
text.prepend(_("<END>"));
|
text.prepend(_("<END>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
replay(text, repeat);
|
replay(text, repeat);
|
||||||
|
|
||||||
if (m_visualBlockInsert && !text.contains(QLatin1Char('\n'))) {
|
if (m_visualBlockInsert != NoneBlockInsertMode && !text.contains(QLatin1Char('\n'))) {
|
||||||
const CursorPosition lastAnchor = mark(QLatin1Char('<')).position;
|
const CursorPosition lastAnchor = markLessPosition();
|
||||||
const CursorPosition lastPosition = mark(QLatin1Char('>')).position;
|
const CursorPosition lastPosition = markGreaterPosition();
|
||||||
CursorPosition startPos(lastAnchor.line,
|
bool change = m_visualBlockInsert == ChangeBlockInsertMode;
|
||||||
qMin(lastPosition.column, lastAnchor.column));
|
const int insertColumn = (m_visualBlockInsert == InsertBlockInsertMode || change)
|
||||||
CursorPosition pos = startPos;
|
? qMin(lastPosition.column, lastAnchor.column)
|
||||||
if (dotCommand.endsWith(QLatin1Char('A')))
|
: qMax(lastPosition.column, lastAnchor.column) + 1;
|
||||||
pos.column = qMax(lastPosition.column, lastAnchor.column) + 1;
|
|
||||||
while (pos.line < lastPosition.line) {
|
CursorPosition pos(lastAnchor.line, insertColumn);
|
||||||
++pos.line;
|
|
||||||
QTextCursor tc = m_cursor;
|
if (change)
|
||||||
setCursorPosition(&tc, pos);
|
pos.column = m_insertState.pos1 - document()->findBlock(m_insertState.pos1).position();
|
||||||
if (pos.line != tc.blockNumber())
|
|
||||||
break;
|
// Cursor position after block insert is on the first selected line,
|
||||||
m_cursor = tc;
|
// last selected column for 's' command, otherwise first selected column.
|
||||||
if (tc.positionInBlock() == pos.column)
|
const int endColumn = change ? qMax(0, m_cursor.positionInBlock() - 1)
|
||||||
replay(text, repeat + 1);
|
: qMin(lastPosition.column, lastAnchor.column);
|
||||||
|
|
||||||
|
while (pos.line < lastPosition.line) {
|
||||||
|
++pos.line;
|
||||||
|
setCursorPosition(&m_cursor, pos);
|
||||||
|
if (m_visualBlockInsert == AppendToEndOfLineBlockInsertMode) {
|
||||||
|
moveToEndOfLine();
|
||||||
|
} else if (m_visualBlockInsert == AppendBlockInsertMode) {
|
||||||
|
// Prepend spaces if necessary.
|
||||||
|
int spaces = pos.column - m_cursor.positionInBlock();
|
||||||
|
if (spaces > 0) {
|
||||||
|
setAnchor();
|
||||||
|
m_cursor.insertText(QString(_(" ")).repeated(spaces));
|
||||||
|
}
|
||||||
|
} else if (m_cursor.positionInBlock() != pos.column) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
replay(text, repeat + 1);
|
||||||
setCursorPosition(startPos);
|
|
||||||
} else {
|
|
||||||
moveLeft(qMin(1, leftDist()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
endEditBlock();
|
setCursorPosition(CursorPosition(lastAnchor.line, endColumn));
|
||||||
breakEditBlock();
|
|
||||||
|
|
||||||
m_lastInsertion = text;
|
|
||||||
g.dotCommand = dotCommand;
|
|
||||||
} else {
|
} else {
|
||||||
moveLeft(qMin(1, leftDist()));
|
moveLeft(qMin(1, leftDist()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newLineBefore || newLineAfter)
|
endEditBlock();
|
||||||
m_lastInsertion.remove(0, m_lastInsertion.indexOf(QLatin1Char('\n')) + 1);
|
breakEditBlock();
|
||||||
g.dotCommand.append(m_lastInsertion + _("<ESC>"));
|
|
||||||
|
|
||||||
enterCommandMode();
|
m_lastInsertion = text;
|
||||||
setTargetColumn();
|
g.dotCommand = dotCommand;
|
||||||
m_ctrlVActive = false;
|
} else {
|
||||||
m_visualBlockInsert = false;
|
moveLeft(qMin(1, leftDist()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newLineBefore || newLineAfter)
|
||||||
|
m_lastInsertion.remove(0, m_lastInsertion.indexOf(QLatin1Char('\n')) + 1);
|
||||||
|
g.dotCommand.append(m_lastInsertion + _("<ESC>"));
|
||||||
|
|
||||||
|
enterCommandMode();
|
||||||
|
setTargetColumn();
|
||||||
|
m_ctrlVActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeVimHandler::Private::handleInsertMode(const Input &input)
|
||||||
|
{
|
||||||
|
if (input.isEscape()) {
|
||||||
|
finishInsertMode();
|
||||||
} else if (m_ctrlVActive) {
|
} else if (m_ctrlVActive) {
|
||||||
insertInInsertMode(input.raw());
|
insertInInsertMode(input.raw());
|
||||||
} else if (input.isControl('o')) {
|
} else if (input.isControl('o')) {
|
||||||
@@ -5109,7 +5164,7 @@ int FakeVimHandler::Private::parseLineAddress(QString *cmd)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
cmd->remove(0, 1);
|
cmd->remove(0, 1);
|
||||||
result = m.position.line;
|
result = m.position(document()).line;
|
||||||
} else if (c.isDigit()) { // line with given number
|
} else if (c.isDigit()) { // line with given number
|
||||||
result = 0;
|
result = 0;
|
||||||
} else if (c == QLatin1Char('-') || c == QLatin1Char('+')) { // add or subtract from current line number
|
} else if (c == QLatin1Char('-') || c == QLatin1Char('+')) { // add or subtract from current line number
|
||||||
@@ -5644,8 +5699,8 @@ bool FakeVimHandler::Private::handleExMoveCommand(const ExCommand &cmd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CursorPosition lastAnchor = mark(QLatin1Char('<')).position;
|
CursorPosition lastAnchor = markLessPosition();
|
||||||
CursorPosition lastPosition = mark(QLatin1Char('>')).position;
|
CursorPosition lastPosition = markGreaterPosition();
|
||||||
|
|
||||||
recordJump();
|
recordJump();
|
||||||
setPosition(cmd.range.beginPos);
|
setPosition(cmd.range.beginPos);
|
||||||
@@ -7397,8 +7452,8 @@ void FakeVimHandler::Private::leaveVisualMode()
|
|||||||
if (!isVisualMode())
|
if (!isVisualMode())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setMark(QLatin1Char('<'), mark(QLatin1Char('<')).position);
|
setMark(QLatin1Char('<'), markLessPosition());
|
||||||
setMark(QLatin1Char('>'), mark(QLatin1Char('>')).position);
|
setMark(QLatin1Char('>'), markGreaterPosition());
|
||||||
m_lastVisualModeInverted = anchor() > position();
|
m_lastVisualModeInverted = anchor() > position();
|
||||||
if (isVisualLineMode()) {
|
if (isVisualLineMode()) {
|
||||||
g.rangemode = RangeLineMode;
|
g.rangemode = RangeLineMode;
|
||||||
@@ -7655,28 +7710,41 @@ void FakeVimHandler::Private::enterInsertOrReplaceMode(Mode mode)
|
|||||||
clearLastInsertion();
|
clearLastInsertion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::initVisualInsertMode(QChar command)
|
void FakeVimHandler::Private::enterVisualInsertMode(QChar command)
|
||||||
{
|
{
|
||||||
m_visualBlockInsert = isVisualBlockMode();
|
if (isVisualBlockMode()) {
|
||||||
|
bool append = command == QLatin1Char('A');
|
||||||
|
bool change = command == QLatin1Char('s') || command == QLatin1Char('c');
|
||||||
|
|
||||||
if (m_visualBlockInsert) {
|
|
||||||
setDotCommand(visualDotCommand() + QString::number(count()) + command);
|
setDotCommand(visualDotCommand() + QString::number(count()) + command);
|
||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
|
|
||||||
const CursorPosition lastAnchor = mark(QLatin1Char('<')).position;
|
const CursorPosition lastAnchor = markLessPosition();
|
||||||
const CursorPosition lastPosition = mark(QLatin1Char('>')).position;
|
const CursorPosition lastPosition = markGreaterPosition();
|
||||||
CursorPosition pos(lastAnchor.line,
|
CursorPosition pos(lastAnchor.line,
|
||||||
command == QLatin1Char('A') ? qMax(lastPosition.column, lastAnchor.column) + 1
|
append ? qMax(lastPosition.column, lastAnchor.column) + 1
|
||||||
: qMin(lastPosition.column, lastAnchor.column));
|
: qMin(lastPosition.column, lastAnchor.column));
|
||||||
|
|
||||||
if (command == QLatin1Char('s')) {
|
if (append) {
|
||||||
|
m_visualBlockInsert = m_visualTargetColumn == -1 ? AppendToEndOfLineBlockInsertMode
|
||||||
|
: AppendBlockInsertMode;
|
||||||
|
} else if (change) {
|
||||||
|
m_visualBlockInsert = ChangeBlockInsertMode;
|
||||||
|
pushUndoState();
|
||||||
|
beginEditBlock();
|
||||||
Range range(position(), anchor(), RangeBlockMode);
|
Range range(position(), anchor(), RangeBlockMode);
|
||||||
yankText(range, m_register);
|
yankText(range, m_register);
|
||||||
removeText(range);
|
removeText(range);
|
||||||
|
endEditBlock();
|
||||||
|
} else {
|
||||||
|
m_visualBlockInsert = InsertBlockInsertMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCursorPosition(pos);
|
setCursorPosition(pos);
|
||||||
|
if (m_visualBlockInsert == AppendToEndOfLineBlockInsertMode)
|
||||||
|
moveBehindEndOfLine();
|
||||||
} else {
|
} else {
|
||||||
|
m_visualBlockInsert = NoneBlockInsertMode;
|
||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
if (command == QLatin1Char('I')) {
|
if (command == QLatin1Char('I')) {
|
||||||
setDotCommand(_("%1i"), count());
|
setDotCommand(_("%1i"), count());
|
||||||
@@ -7697,6 +7765,9 @@ void FakeVimHandler::Private::initVisualInsertMode(QChar command)
|
|||||||
}
|
}
|
||||||
|
|
||||||
setAnchor();
|
setAnchor();
|
||||||
|
if (m_visualBlockInsert != ChangeBlockInsertMode)
|
||||||
|
breakEditBlock();
|
||||||
|
enterInsertMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::enterCommandMode(Mode returnToMode)
|
void FakeVimHandler::Private::enterCommandMode(Mode returnToMode)
|
||||||
@@ -8129,14 +8200,14 @@ bool FakeVimHandler::Private::jumpToMark(QChar mark, bool backTickMode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!m.isLocal(m_currentFileName)) {
|
if (!m.isLocal(m_currentFileName)) {
|
||||||
emit q->jumpToGlobalMark(mark, backTickMode, m.fileName);
|
emit q->jumpToGlobalMark(mark, backTickMode, m.fileName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mark == QLatin1Char('\'') || mark == QLatin1Char('`')) && !m_jumpListUndo.isEmpty())
|
if ((mark == QLatin1Char('\'') || mark == QLatin1Char('`')) && !m_jumpListUndo.isEmpty())
|
||||||
m_jumpListUndo.pop();
|
m_jumpListUndo.pop();
|
||||||
recordJump();
|
recordJump();
|
||||||
setCursorPosition(m.position);
|
setCursorPosition(m.position(document()));
|
||||||
if (!backTickMode)
|
if (!backTickMode)
|
||||||
moveToFirstNonBlankOnLine();
|
moveToFirstNonBlankOnLine();
|
||||||
if (g.submode == NoSubMode)
|
if (g.submode == NoSubMode)
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ private slots:
|
|||||||
void test_vim_change_a_word();
|
void test_vim_change_a_word();
|
||||||
void test_vim_change_replace();
|
void test_vim_change_replace();
|
||||||
void test_vim_block_selection();
|
void test_vim_block_selection();
|
||||||
|
void test_vim_block_selection_insert();
|
||||||
void test_vim_repeat();
|
void test_vim_repeat();
|
||||||
void test_vim_search();
|
void test_vim_search();
|
||||||
void test_vim_indent();
|
void test_vim_indent();
|
||||||
|
|||||||
Reference in New Issue
Block a user