Commit f302f3b8 authored by Lukas Holecek's avatar Lukas Holecek Committed by hjk
Browse files

fakevim: <C-O> to execute single command and return to insert mode



After Ctrl+O combination in insert or replace mode enter command mode
and after a single command (can consist of entering Ex command or can be
switch to other buffer) or escape key return to previous insert or
replace mode. One exception is that if entering insert mode is part of
the command after <C-O> pressing escape key will exit to command mode
(Vim behavior).

Change-Id: I37d684b691157001e2cab156687d6771afdec7b9
Reviewed-by: default avatarhjk <qthjk@ovi.com>
parent 9ab2d3d0
......@@ -217,6 +217,7 @@ struct FakeVimPlugin::TestData
void FakeVimPlugin::setup(TestData *data)
{
setupTest(&data->title, &data->handler, &data->edit);
data->handler->handleInput("<ESC><ESC>gg");
}
......@@ -426,6 +427,24 @@ void FakeVimPlugin::test_vim_insert()
data.setText("abc" N "def");
KEYS("3O 123<esc>", " 123" N " 123" N " 12" X "3" N "abc" N "def");
INTEGRITY(false);
// <C-O>
data.setText("abc" N "d" X "ef");
KEYS("i<c-o>xX", "abc" N "dX" X "f");
KEYS("i<c-o><end>", "abc" N "dXf" X);
data.setText("ab" X "c" N "def");
KEYS("i<c-o>rX", "ab" X "X" N "def");
data.setText("abc" N "def");
KEYS("A<c-o>x", "ab" X N "def");
data.setText("abc" N "de" X "f");
KEYS("i<c-o>0x", "abc" N "x" X "def");
data.setText("abc" N "de" X "f");
KEYS("i<c-o>ggx", "x" X "abc" N "def");
// <INSERT> to toggle between insert and replace mode
data.setText("abc" N "def");
KEYS("<insert>XYZ<insert>xyz<esc>", "XYZxy" X "z" N "def");
KEYS("<insert><insert>" "<c-o>0<c-o>j" "XY<insert>Z", "XYZxyz" N "XYZ" X "f");
}
void FakeVimPlugin::test_vim_fFtT()
......@@ -1821,8 +1840,6 @@ void FakeVimPlugin::test_map()
KEYS("Y", X "abc" N "def");
data.doCommand("unmap X|unmap Y");
NOT_IMPLEMENTED
// <C-o>
data.setText("abc def");
data.doCommand("imap X <c-o>:%s/def/xxx/<cr>");
......
......@@ -1341,6 +1341,8 @@ public:
friend class FakeVimHandler;
void init();
void focus();
EventResult handleKey(const Input &input);
EventResult handleDefaultKey(const Input &input);
void handleMappedKeys();
......@@ -1532,7 +1534,7 @@ public:
void enterInsertMode();
void enterReplaceMode();
void enterCommandMode();
void enterCommandMode(Mode returnToMode = CommandMode);
void enterExMode(const QString &contents = QString());
void showMessage(MessageLevel level, const QString &msg);
void clearMessage() { showMessage(MessageInfo, QString()); }
......@@ -1761,7 +1763,7 @@ public:
{
GlobalData()
: mappings(), currentMap(&mappings), inputTimer(-1), currentMessageLevel(MessageInfo),
lastSearchForward(false), findPending(false)
lastSearchForward(false), findPending(false), returnToMode(CommandMode)
{
// default mapping state - shouldn't be removed
mapStates << MappingState();
......@@ -1803,6 +1805,9 @@ public:
// Global marks.
Marks marks;
// Return to insert/replace mode after single command (<C-O>).
Mode returnToMode;
} g;
};
......@@ -1854,6 +1859,17 @@ void FakeVimHandler::Private::init()
setupCharClass();
}
void FakeVimHandler::Private::focus()
{
stopIncrementalFind();
if (g.returnToMode != CommandMode && g.currentCommand.isEmpty() && m_mode != ExMode) {
// Return to insert mode.
resetCommandMode();
updateMiniBuffer();
updateCursorShape();
}
}
bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
{
const int key = ev->key();
......@@ -1867,7 +1883,8 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
if (isNoVisualMode()
&& m_mode == CommandMode
&& m_submode == NoSubMode
&& g.currentCommand.isEmpty())
&& g.currentCommand.isEmpty()
&& g.returnToMode == CommandMode)
return false;
return true;
}
......@@ -2009,7 +2026,7 @@ void FakeVimHandler::Private::installEventFilter()
void FakeVimHandler::Private::setupWidget()
{
enterCommandMode();
resetCommandMode();
if (m_textedit) {
m_textedit->setLineWrapMode(QTextEdit::NoWrap);
} else if (m_plaintextedit) {
......@@ -2325,8 +2342,9 @@ void FakeVimHandler::Private::updateFind(bool isComplete)
g.currentMessage.clear();
const QString &needle = g.searchBuffer.contents();
SearchData sd;
sd.needle = g.searchBuffer.contents();
sd.needle = needle;
sd.forward = g.lastSearchForward;
sd.highlightMatches = isComplete;
if (isComplete) {
......@@ -2573,7 +2591,8 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
if (m_movetype == MoveLineWise)
insertAutomaticIndentation(true);
endEditBlock();
enterInsertMode();
setTargetColumn();
g.returnToMode = InsertMode;
} else if (m_submode == DeleteSubMode) {
setUndoPosition();
removeText(currentRange());
......@@ -2643,6 +2662,13 @@ void FakeVimHandler::Private::resetCommandMode()
if (isNoVisualMode())
setAnchor();
g.currentCommand.clear();
if (g.returnToMode != CommandMode) {
if (g.returnToMode == InsertMode)
enterInsertMode();
else
enterReplaceMode();
moveToTargetColumn();
}
}
void FakeVimHandler::Private::updateSelection()
......@@ -2718,7 +2744,12 @@ void FakeVimHandler::Private::updateMiniBuffer()
msg = "REPLACE";
} else {
QTC_CHECK(m_mode == CommandMode && m_subsubmode != SearchSubSubMode);
msg = "COMMAND";
if (g.returnToMode == CommandMode)
msg = "COMMAND";
else if (g.returnToMode == InsertMode)
msg = "(insert)";
else
msg = "(replace)";
}
emit q->commandBufferChanged(msg, cursorPos, messageLevel, q);
......@@ -3261,7 +3292,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
QString savedCommand = g.dotCommand;
g.dotCommand.clear();
replay(savedCommand);
enterCommandMode();
resetCommandMode();
g.dotCommand = savedCommand;
} else if (input.is('<') || input.is('>') || input.is('=')) {
if (isNoVisualMode()) {
......@@ -3876,10 +3907,7 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
if (input.isEscape()) {
moveLeft(qMin(1, leftDist()));
setTargetColumn();
m_submode = NoSubMode;
m_mode = CommandMode;
finishMovement();
updateMiniBuffer();
enterCommandMode();
} else if (input.isKey(Key_Left)) {
breakEditBlock();
moveLeft(1);
......@@ -3895,6 +3923,10 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
} else if (input.isKey(Key_Down)) {
breakEditBlock();
moveDown(1);
} else if (input.isKey(Key_Insert)) {
m_mode = InsertMode;
} else if (input.isControl('o')) {
enterCommandMode(ReplaceMode);
} else {
joinPreviousEditBlock();
if (!atEndOfLine()) {
......@@ -3910,6 +3942,8 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
endEditBlock();
setTargetColumn();
}
updateMiniBuffer();
return EventHandled;
}
......@@ -3960,12 +3994,13 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
g.dotCommand += m_lastInsertion;
g.dotCommand += QChar(27);
enterCommandMode();
m_submode = NoSubMode;
m_ctrlVActive = false;
m_opcount.clear();
m_mvcount.clear();
} else if (m_ctrlVActive) {
insertInInsertMode(input.raw());
} else if (input.isControl('o')) {
enterCommandMode(InsertMode);
} else if (input.isControl('v')) {
m_ctrlVActive = true;
} else if (input.isControl('w')) {
......@@ -3976,10 +4011,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
Range range(beginPos, endPos, RangeCharMode);
removeText(range);
} else if (input.isKey(Key_Insert)) {
if (m_mode == ReplaceMode)
m_mode = InsertMode;
else
m_mode = ReplaceMode;
m_mode = ReplaceMode;
} else if (input.isKey(Key_Left)) {
moveLeft(count());
setTargetColumn();
......@@ -4145,7 +4177,8 @@ EventResult FakeVimHandler::Private::handleExMode(const Input &input)
{
if (input.isEscape()) {
g.commandBuffer.clear();
enterCommandMode();
enterCommandMode(g.returnToMode);
resetCommandMode();
m_ctrlVActive = false;
} else if (m_ctrlVActive) {
g.commandBuffer.insertChar(input.raw());
......@@ -4154,10 +4187,12 @@ EventResult FakeVimHandler::Private::handleExMode(const Input &input)
m_ctrlVActive = true;
return EventHandled;
} else if (input.isBackspace()) {
if (g.commandBuffer.isEmpty())
enterCommandMode();
else
if (g.commandBuffer.isEmpty()) {
enterCommandMode(g.returnToMode);
resetCommandMode();
} else {
g.commandBuffer.deleteChar();
}
} else if (input.isKey(Key_Tab)) {
// FIXME: Complete actual commands.
g.commandBuffer.historyUp();
......@@ -4190,10 +4225,11 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input)
g.searchBuffer.clear();
setAnchorAndPosition(m_searchStartPosition, m_searchStartPosition);
scrollToLine(m_searchFromScreenLine);
enterCommandMode();
enterCommandMode(g.returnToMode);
resetCommandMode();
} else if (input.isBackspace()) {
if (g.searchBuffer.isEmpty()) {
enterCommandMode();
resetCommandMode();
} else {
g.searchBuffer.deleteChar();
}
......@@ -4217,7 +4253,8 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input)
showMessage(MessageCommand, g.searchBuffer.display());
else
handled = EventCancelled;
enterCommandMode();
enterCommandMode(g.returnToMode);
resetCommandMode();
g.searchBuffer.clear();
} else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
g.searchBuffer.historyUp();
......@@ -5122,7 +5159,7 @@ void FakeVimHandler::Private::handleExCommand(const QString &line0)
//qDebug() << "CMD: " << cmd;
enterCommandMode();
enterCommandMode(g.returnToMode);
beginLargeEditBlock();
ExCommand cmd;
......@@ -5135,6 +5172,8 @@ void FakeVimHandler::Private::handleExCommand(const QString &line0)
lastCommand = line;
}
endEditBlock();
resetCommandMode();
}
bool FakeVimHandler::Private::handleExCommandHelper(ExCommand &cmd)
......@@ -5420,17 +5459,14 @@ void FakeVimHandler::Private::moveToTargetColumn()
const QTextBlock &bl = block();
//Column column = cursorColumn();
//int logical = logical
const int maxcol = bl.length() - 2;
const int pos = lastPositionInLine(bl.blockNumber() + 1, false);
if (m_targetColumn == -1) {
setPosition(bl.position() + qMax(0, maxcol));
setPosition(pos);
return;
}
const int physical = logicalToPhysicalColumn(m_targetColumn, bl.text());
const int physical = bl.position() + logicalToPhysicalColumn(m_targetColumn, bl.text());
//qDebug() << "CORRECTING COLUMN FROM: " << logical << "TO" << m_targetColumn;
if (physical >= maxcol)
setPosition(bl.position() + qMax(0, maxcol));
else
setPosition(bl.position() + physical);
setPosition(qMin(pos, physical));
}
/* if simple is given:
......@@ -6463,6 +6499,7 @@ void FakeVimHandler::Private::enterReplaceMode()
m_subsubmode = NoSubSubMode;
m_lastInsertion.clear();
m_lastDeletion.clear();
g.returnToMode = ReplaceMode;
}
void FakeVimHandler::Private::enterInsertMode()
......@@ -6472,15 +6509,17 @@ void FakeVimHandler::Private::enterInsertMode()
m_subsubmode = NoSubSubMode;
m_lastInsertion.clear();
m_lastDeletion.clear();
g.returnToMode = InsertMode;
}
void FakeVimHandler::Private::enterCommandMode()
void FakeVimHandler::Private::enterCommandMode(Mode returnToMode)
{
if (atEndOfLine())
moveLeft();
m_mode = CommandMode;
m_submode = NoSubMode;
m_subsubmode = NoSubSubMode;
g.returnToMode = returnToMode;
}
void FakeVimHandler::Private::enterExMode(const QString &contents)
......@@ -7012,7 +7051,8 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
return res == EventHandled || res == EventCancelled;
}
if (active && ev->type() == QEvent::KeyPress) {
if (active && ev->type() == QEvent::KeyPress &&
(ob == d->editor() || (d->m_mode == ExMode || d->m_subsubmode == SearchSubSubMode))) {
QKeyEvent *kev = static_cast<QKeyEvent *>(ev);
KEY_DEBUG("KEYPRESS" << kev->key() << kev->text() << QChar(kev->key()));
EventResult res = d->handleEvent(kev);
......@@ -7037,7 +7077,7 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
}
if (active && ev->type() == QEvent::FocusIn && ob == d->editor()) {
d->stopIncrementalFind();
d->focus();
}
return QObject::eventFilter(ob, ev);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment