forked from qt-creator/qt-creator
fakevim: Improved undo/redo
Change-Id: I9326820cf0b8c551932ffae4cc4ae0af8415fd4e Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -100,7 +100,7 @@
|
|||||||
|
|
||||||
//#define DEBUG_UNDO 1
|
//#define DEBUG_UNDO 1
|
||||||
#if DEBUG_UNDO
|
#if DEBUG_UNDO
|
||||||
# define UNDO_DEBUG(s) qDebug() << << document()->availableUndoSteps() << s
|
# define UNDO_DEBUG(s) qDebug() << << revision() << s
|
||||||
#else
|
#else
|
||||||
# define UNDO_DEBUG(s)
|
# define UNDO_DEBUG(s)
|
||||||
#endif
|
#endif
|
||||||
@@ -245,6 +245,18 @@ enum EventResult
|
|||||||
EventPassedToCore
|
EventPassedToCore
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QHash<int, QTextCursor> Marks;
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
State() : revision(-1), position(-1), line(-1), marks() {}
|
||||||
|
State(int revision, int position, int line, const Marks &marks)
|
||||||
|
: revision(revision), position(position), line(line), marks(marks) {}
|
||||||
|
int revision;
|
||||||
|
int position;
|
||||||
|
int line;
|
||||||
|
Marks marks;
|
||||||
|
};
|
||||||
|
|
||||||
struct Column
|
struct Column
|
||||||
{
|
{
|
||||||
Column(int p, int l) : physical(p), logical(l) {}
|
Column(int p, int l) : physical(p), logical(l) {}
|
||||||
@@ -938,6 +950,7 @@ public:
|
|||||||
void shiftRegionRight(int repeat = 1);
|
void shiftRegionRight(int repeat = 1);
|
||||||
|
|
||||||
void moveToFirstNonBlankOnLine();
|
void moveToFirstNonBlankOnLine();
|
||||||
|
void moveToFirstNonBlankOnLine(QTextCursor *tc);
|
||||||
void moveToTargetColumn();
|
void moveToTargetColumn();
|
||||||
void setTargetColumn() {
|
void setTargetColumn() {
|
||||||
m_targetColumn = logicalCursorColumn();
|
m_targetColumn = logicalCursorColumn();
|
||||||
@@ -1025,21 +1038,22 @@ public:
|
|||||||
QTextDocument *document() const { return EDITOR(document()); }
|
QTextDocument *document() const { return EDITOR(document()); }
|
||||||
QChar characterAtCursor() const
|
QChar characterAtCursor() const
|
||||||
{ return document()->characterAt(position()); }
|
{ return document()->characterAt(position()); }
|
||||||
void beginEditBlock()
|
void joinPreviousEditBlock() {
|
||||||
{ UNDO_DEBUG("BEGIN EDIT BLOCK"); cursor().beginEditBlock(); }
|
UNDO_DEBUG("JOIN");
|
||||||
|
if (m_breakEditBlock)
|
||||||
|
beginEditBlock();
|
||||||
|
else
|
||||||
|
cursor().joinPreviousEditBlock();
|
||||||
|
}
|
||||||
|
void beginEditBlock() {
|
||||||
|
UNDO_DEBUG("BEGIN EDIT BLOCK");
|
||||||
|
cursor().beginEditBlock();
|
||||||
|
setUndoPosition(false);
|
||||||
|
m_breakEditBlock = false;
|
||||||
|
}
|
||||||
void endEditBlock()
|
void endEditBlock()
|
||||||
{ UNDO_DEBUG("END EDIT BLOCK"); cursor().endEditBlock(); }
|
{ UNDO_DEBUG("END EDIT BLOCK"); cursor().endEditBlock(); }
|
||||||
void joinPreviousEditBlock()
|
void breakEditBlock() { m_breakEditBlock = true; }
|
||||||
{ UNDO_DEBUG("JOIN"); cursor().joinPreviousEditBlock(); }
|
|
||||||
void breakEditBlock() {
|
|
||||||
QTextCursor tc = cursor();
|
|
||||||
tc.clearSelection();
|
|
||||||
tc.beginEditBlock();
|
|
||||||
tc.insertText("x");
|
|
||||||
tc.deletePreviousChar();
|
|
||||||
tc.endEditBlock();
|
|
||||||
setCursor(tc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isVisualMode() const { return m_visualMode != NoVisualMode; }
|
bool isVisualMode() const { return m_visualMode != NoVisualMode; }
|
||||||
bool isNoVisualMode() const { return m_visualMode == NoVisualMode; }
|
bool isNoVisualMode() const { return m_visualMode == NoVisualMode; }
|
||||||
@@ -1102,6 +1116,8 @@ public:
|
|||||||
QString m_lastInsertion;
|
QString m_lastInsertion;
|
||||||
QString m_lastDeletion;
|
QString m_lastDeletion;
|
||||||
|
|
||||||
|
bool m_breakEditBlock;
|
||||||
|
|
||||||
int anchor() const { return cursor().anchor(); }
|
int anchor() const { return cursor().anchor(); }
|
||||||
int position() const { return cursor().position(); }
|
int position() const { return cursor().position(); }
|
||||||
|
|
||||||
@@ -1144,10 +1160,13 @@ public:
|
|||||||
void pasteText(bool afterCursor);
|
void pasteText(bool afterCursor);
|
||||||
|
|
||||||
// undo handling
|
// undo handling
|
||||||
|
int revision() const { return document()->availableUndoSteps(); }
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
void setUndoPosition();
|
void setUndoPosition(bool overwrite = true);
|
||||||
QMap<int, int> m_undoCursorPosition; // revision -> position
|
// revision -> state
|
||||||
|
QStack<State> m_undo;
|
||||||
|
QStack<State> m_redo;
|
||||||
|
|
||||||
// extra data for '.'
|
// extra data for '.'
|
||||||
void replay(const QString &text, int count);
|
void replay(const QString &text, int count);
|
||||||
@@ -1168,7 +1187,6 @@ public:
|
|||||||
// marks as lines
|
// marks as lines
|
||||||
int mark(int code) const;
|
int mark(int code) const;
|
||||||
void setMark(int code, int position);
|
void setMark(int code, int position);
|
||||||
typedef QHash<int, QTextCursor> Marks;
|
|
||||||
typedef QHashIterator<int, QTextCursor> MarksIterator;
|
typedef QHashIterator<int, QTextCursor> MarksIterator;
|
||||||
Marks m_marks;
|
Marks m_marks;
|
||||||
|
|
||||||
@@ -1223,6 +1241,7 @@ public:
|
|||||||
bool handleExNormalCommand(const ExCommand &cmd);
|
bool handleExNormalCommand(const ExCommand &cmd);
|
||||||
bool handleExReadCommand(const ExCommand &cmd);
|
bool handleExReadCommand(const ExCommand &cmd);
|
||||||
bool handleExRedoCommand(const ExCommand &cmd);
|
bool handleExRedoCommand(const ExCommand &cmd);
|
||||||
|
bool handleExUndoCommand(const ExCommand &cmd);
|
||||||
bool handleExSetCommand(const ExCommand &cmd);
|
bool handleExSetCommand(const ExCommand &cmd);
|
||||||
bool handleExShiftCommand(const ExCommand &cmd);
|
bool handleExShiftCommand(const ExCommand &cmd);
|
||||||
bool handleExSourceCommand(const ExCommand &cmd);
|
bool handleExSourceCommand(const ExCommand &cmd);
|
||||||
@@ -1306,6 +1325,7 @@ void FakeVimHandler::Private::init()
|
|||||||
m_oldExternalPosition = -1;
|
m_oldExternalPosition = -1;
|
||||||
m_oldPosition = -1;
|
m_oldPosition = -1;
|
||||||
m_lastChangePosition = -1;
|
m_lastChangePosition = -1;
|
||||||
|
m_breakEditBlock = false;
|
||||||
|
|
||||||
setupCharClass();
|
setupCharClass();
|
||||||
}
|
}
|
||||||
@@ -1694,13 +1714,30 @@ bool FakeVimHandler::Private::isFirstNonBlankOnLine(int pos)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::setUndoPosition()
|
void FakeVimHandler::Private::setUndoPosition(bool overwrite)
|
||||||
{
|
{
|
||||||
int pos = qMin(position(), anchor());
|
const int rev = revision();
|
||||||
if (m_visualMode == VisualLineMode)
|
if (!overwrite && !m_undo.empty() && m_undo.top().revision >= rev)
|
||||||
pos = firstPositionInLine(lineForPosition(pos));
|
return;
|
||||||
const int rev = document()->availableUndoSteps();
|
|
||||||
m_undoCursorPosition[rev] = pos;
|
int pos = position();
|
||||||
|
if (m_mode != InsertMode && m_mode != ReplaceMode) {
|
||||||
|
if (isVisualMode() || m_submode == DeleteSubMode) {
|
||||||
|
pos = qMin(pos, anchor());
|
||||||
|
if (isVisualLineMode())
|
||||||
|
pos = firstPositionInLine(lineForPosition(pos));
|
||||||
|
} else if (m_movetype == MoveLineWise && hasConfig(ConfigStartOfLine)) {
|
||||||
|
QTextCursor tc = cursor();
|
||||||
|
moveToFirstNonBlankOnLine(&tc);
|
||||||
|
pos = qMin(pos, tc.position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_redo.clear();
|
||||||
|
while (!m_undo.empty() && m_undo.top().revision >= rev)
|
||||||
|
m_undo.pop();
|
||||||
|
m_undo.push(State(rev, pos, lineForPosition(pos), m_marks));
|
||||||
|
m_lastChangePosition = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::moveDown(int n)
|
void FakeVimHandler::Private::moveDown(int n)
|
||||||
@@ -1850,6 +1887,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
|
|||||||
enterInsertMode();
|
enterInsertMode();
|
||||||
m_submode = NoSubMode;
|
m_submode = NoSubMode;
|
||||||
} else if (m_submode == DeleteSubMode) {
|
} else if (m_submode == DeleteSubMode) {
|
||||||
|
setUndoPosition();
|
||||||
Range range = currentRange();
|
Range range = currentRange();
|
||||||
removeText(range);
|
removeText(range);
|
||||||
if (!dotCommand.isEmpty())
|
if (!dotCommand.isEmpty())
|
||||||
@@ -2175,7 +2213,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
} else if (m_submode == ReplaceSubMode) {
|
} else if (m_submode == ReplaceSubMode) {
|
||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
m_lastChangePosition = position();
|
|
||||||
if (isVisualLineMode())
|
if (isVisualLineMode())
|
||||||
m_rangemode = RangeLineMode;
|
m_rangemode = RangeLineMode;
|
||||||
else if (isVisualBlockMode())
|
else if (isVisualBlockMode())
|
||||||
@@ -2190,7 +2227,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
setPosition(range.beginPos);
|
setPosition(range.beginPos);
|
||||||
} else if (count() <= rightDist()) {
|
} else if (count() <= rightDist()) {
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
m_lastChangePosition = position();
|
|
||||||
setAnchor();
|
setAnchor();
|
||||||
moveRight(count());
|
moveRight(count());
|
||||||
Range range = currentRange();
|
Range range = currentRange();
|
||||||
@@ -2209,20 +2245,18 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
m_submode = NoSubMode;
|
m_submode = NoSubMode;
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (m_submode == ChangeSubMode && input.is('c')) { // tested
|
} else if (m_submode == ChangeSubMode && input.is('c')) { // tested
|
||||||
|
m_movetype = MoveLineWise;
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
m_lastChangePosition = position();
|
|
||||||
moveToStartOfLine();
|
moveToStartOfLine();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
moveDown(count() - 1);
|
moveDown(count() - 1);
|
||||||
moveToEndOfLine();
|
moveToEndOfLine();
|
||||||
m_movetype = MoveLineWise;
|
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
setDotCommand("%1cc", count());
|
setDotCommand("%1cc", count());
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (m_submode == DeleteSubMode && input.is('d')) { // tested
|
} else if (m_submode == DeleteSubMode && input.is('d')) { // tested
|
||||||
setUndoPosition();
|
|
||||||
m_lastChangePosition = position();
|
|
||||||
m_movetype = MoveLineWise;
|
m_movetype = MoveLineWise;
|
||||||
|
setUndoPosition();
|
||||||
int endPos = firstPositionInLine(lineForPosition(position()) + count() - 1);
|
int endPos = firstPositionInLine(lineForPosition(position()) + count() - 1);
|
||||||
Range range(position(), endPos, RangeLineMode);
|
Range range(position(), endPos, RangeLineMode);
|
||||||
yankText(range);
|
yankText(range);
|
||||||
@@ -2237,24 +2271,24 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
m_subsubmode = TextObjectSubSubMode;
|
m_subsubmode = TextObjectSubSubMode;
|
||||||
m_subsubdata = input;
|
m_subsubdata = input;
|
||||||
} else if (m_submode == ShiftLeftSubMode && input.is('<')) {
|
} else if (m_submode == ShiftLeftSubMode && input.is('<')) {
|
||||||
m_lastChangePosition = position();
|
m_movetype = MoveLineWise;
|
||||||
|
setUndoPosition();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
moveDown(count() - 1);
|
moveDown(count() - 1);
|
||||||
m_movetype = MoveLineWise;
|
|
||||||
setDotCommand("%1<<", count());
|
setDotCommand("%1<<", count());
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (m_submode == ShiftRightSubMode && input.is('>')) {
|
} else if (m_submode == ShiftRightSubMode && input.is('>')) {
|
||||||
m_lastChangePosition = position();
|
m_movetype = MoveLineWise;
|
||||||
|
setUndoPosition();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
moveDown(count() - 1);
|
moveDown(count() - 1);
|
||||||
m_movetype = MoveLineWise;
|
|
||||||
setDotCommand("%1>>", count());
|
setDotCommand("%1>>", count());
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (m_submode == IndentSubMode && input.is('=')) {
|
} else if (m_submode == IndentSubMode && input.is('=')) {
|
||||||
m_lastChangePosition = position();
|
m_movetype = MoveLineWise;
|
||||||
|
setUndoPosition();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
moveDown(count() - 1);
|
moveDown(count() - 1);
|
||||||
m_movetype = MoveLineWise;
|
|
||||||
setDotCommand("%1==", count());
|
setDotCommand("%1==", count());
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (m_submode == ZSubMode) {
|
} else if (m_submode == ZSubMode) {
|
||||||
@@ -2451,7 +2485,6 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
enterCommandMode();
|
enterCommandMode();
|
||||||
g.dotCommand = savedCommand;
|
g.dotCommand = savedCommand;
|
||||||
} else if (input.is('<')) {
|
} else if (input.is('<')) {
|
||||||
setUndoPosition();
|
|
||||||
if (isNoVisualMode()) {
|
if (isNoVisualMode()) {
|
||||||
m_submode = ShiftLeftSubMode;
|
m_submode = ShiftLeftSubMode;
|
||||||
} else {
|
} else {
|
||||||
@@ -2459,7 +2492,6 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
}
|
}
|
||||||
} else if (input.is('>')) {
|
} else if (input.is('>')) {
|
||||||
setUndoPosition();
|
|
||||||
if (isNoVisualMode()) {
|
if (isNoVisualMode()) {
|
||||||
m_submode = ShiftRightSubMode;
|
m_submode = ShiftRightSubMode;
|
||||||
} else {
|
} else {
|
||||||
@@ -2467,7 +2499,6 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
}
|
}
|
||||||
} else if (input.is('=')) {
|
} else if (input.is('=')) {
|
||||||
setUndoPosition();
|
|
||||||
if (isNoVisualMode()) {
|
if (isNoVisualMode()) {
|
||||||
m_submode = IndentSubMode;
|
m_submode = IndentSubMode;
|
||||||
} else {
|
} else {
|
||||||
@@ -2487,9 +2518,9 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
moveRight();
|
moveRight();
|
||||||
updateMiniBuffer();
|
updateMiniBuffer();
|
||||||
} else if (input.is('A')) {
|
} else if (input.is('A')) {
|
||||||
setUndoPosition();
|
|
||||||
breakEditBlock();
|
breakEditBlock();
|
||||||
moveBehindEndOfLine();
|
moveBehindEndOfLine();
|
||||||
|
setUndoPosition();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
enterInsertMode();
|
enterInsertMode();
|
||||||
setDotCommand(QString(QLatin1Char('A')));
|
setDotCommand(QString(QLatin1Char('A')));
|
||||||
@@ -2551,6 +2582,7 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
m_submode = DeleteSubMode;
|
m_submode = DeleteSubMode;
|
||||||
} else if ((input.is('d') || input.is('x') || input.isKey(Key_Delete))
|
} else if ((input.is('d') || input.is('x') || input.isKey(Key_Delete))
|
||||||
&& isVisualMode()) {
|
&& isVisualMode()) {
|
||||||
|
setUndoPosition();
|
||||||
if (isVisualCharMode()) {
|
if (isVisualCharMode()) {
|
||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
m_submode = DeleteSubMode;
|
m_submode = DeleteSubMode;
|
||||||
@@ -2569,6 +2601,7 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
setPosition(qMin(position(), anchor()));
|
setPosition(qMin(position(), anchor()));
|
||||||
}
|
}
|
||||||
} else if (input.is('D') && isNoVisualMode()) {
|
} else if (input.is('D') && isNoVisualMode()) {
|
||||||
|
setUndoPosition();
|
||||||
if (atEndOfLine())
|
if (atEndOfLine())
|
||||||
moveLeft();
|
moveLeft();
|
||||||
m_submode = DeleteSubMode;
|
m_submode = DeleteSubMode;
|
||||||
@@ -2669,7 +2702,6 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
|||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (!isVisualMode() && (input.is('i') || input.isKey(Key_Insert))) {
|
} else if (!isVisualMode() && (input.is('i') || input.isKey(Key_Insert))) {
|
||||||
setDotCommand(QString(QLatin1Char('i'))); // setDotCommand("%1i", count());
|
setDotCommand(QString(QLatin1Char('i'))); // setDotCommand("%1i", count());
|
||||||
setUndoPosition();
|
|
||||||
breakEditBlock();
|
breakEditBlock();
|
||||||
enterInsertMode();
|
enterInsertMode();
|
||||||
updateMiniBuffer();
|
updateMiniBuffer();
|
||||||
@@ -2796,14 +2828,13 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|||||||
} else if (input.is('o')) {
|
} else if (input.is('o')) {
|
||||||
setDotCommand("%1o", count());
|
setDotCommand("%1o", count());
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
breakEditBlock();
|
|
||||||
enterInsertMode();
|
|
||||||
beginEditBlock();
|
beginEditBlock();
|
||||||
moveToFirstNonBlankOnLine();
|
moveToFirstNonBlankOnLine();
|
||||||
moveBehindEndOfLine();
|
moveBehindEndOfLine();
|
||||||
insertText(QString("\n"));
|
insertText(QString("\n"));
|
||||||
insertAutomaticIndentation(true);
|
insertAutomaticIndentation(true);
|
||||||
endEditBlock();
|
endEditBlock();
|
||||||
|
enterInsertMode();
|
||||||
} else if (input.is('O')) {
|
} else if (input.is('O')) {
|
||||||
setDotCommand("%1O", count());
|
setDotCommand("%1O", count());
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
@@ -2824,7 +2855,6 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|||||||
setDotCommand("%1p", count());
|
setDotCommand("%1p", count());
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (input.is('r')) {
|
} else if (input.is('r')) {
|
||||||
setUndoPosition();
|
|
||||||
m_submode = ReplaceSubMode;
|
m_submode = ReplaceSubMode;
|
||||||
} else if (!isVisualMode() && input.is('R')) {
|
} else if (!isVisualMode() && input.is('R')) {
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
@@ -2832,7 +2862,10 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|||||||
enterReplaceMode();
|
enterReplaceMode();
|
||||||
updateMiniBuffer();
|
updateMiniBuffer();
|
||||||
} else if (input.isControl('r')) {
|
} else if (input.isControl('r')) {
|
||||||
redo();
|
int repeat = count();
|
||||||
|
while (--repeat >= 0)
|
||||||
|
redo();
|
||||||
|
finishMovement();
|
||||||
} else if (input.is('s') && isVisualBlockMode()) {
|
} else if (input.is('s') && isVisualBlockMode()) {
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
Range range(position(), anchor(), RangeBlockMode);
|
Range range(position(), anchor(), RangeBlockMode);
|
||||||
@@ -2860,6 +2893,7 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|||||||
breakEditBlock();
|
breakEditBlock();
|
||||||
enterInsertMode();
|
enterInsertMode();
|
||||||
} else if (input.is('S')) {
|
} else if (input.is('S')) {
|
||||||
|
m_movetype = MoveLineWise;
|
||||||
setUndoPosition();
|
setUndoPosition();
|
||||||
beginEditBlock();
|
beginEditBlock();
|
||||||
if (!isVisualMode()) {
|
if (!isVisualMode()) {
|
||||||
@@ -2872,7 +2906,6 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|||||||
breakEditBlock();
|
breakEditBlock();
|
||||||
enterInsertMode();
|
enterInsertMode();
|
||||||
m_submode = ChangeSubMode;
|
m_submode = ChangeSubMode;
|
||||||
m_movetype = MoveLineWise;
|
|
||||||
endEditBlock();
|
endEditBlock();
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (m_gflag && input.is('t')) {
|
} else if (m_gflag && input.is('t')) {
|
||||||
@@ -2892,7 +2925,10 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|||||||
} else if (input.isControl('t')) {
|
} else if (input.isControl('t')) {
|
||||||
handleExCommand("pop");
|
handleExCommand("pop");
|
||||||
} else if (!m_gflag && input.is('u')) {
|
} else if (!m_gflag && input.is('u')) {
|
||||||
undo();
|
int repeat = count();
|
||||||
|
while (--repeat >= 0)
|
||||||
|
undo();
|
||||||
|
finishMovement();
|
||||||
} else if (input.isControl('u')) {
|
} else if (input.isControl('u')) {
|
||||||
int sline = cursorLineOnScreen();
|
int sline = cursorLineOnScreen();
|
||||||
// FIXME: this should use the "scroll" option, and "count"
|
// FIXME: this should use the "scroll" option, and "count"
|
||||||
@@ -3191,39 +3227,47 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
|
|||||||
} else if (input.isKey(Key_Left)) {
|
} else if (input.isKey(Key_Left)) {
|
||||||
moveLeft(count());
|
moveLeft(count());
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isControl(Key_Left)) {
|
} else if (input.isControl(Key_Left)) {
|
||||||
moveToNextWordStart(count(), false, false);
|
moveToNextWordStart(count(), false, false);
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isKey(Key_Down)) {
|
} else if (input.isKey(Key_Down)) {
|
||||||
//removeAutomaticIndentation();
|
//removeAutomaticIndentation();
|
||||||
m_submode = NoSubMode;
|
m_submode = NoSubMode;
|
||||||
moveDown(count());
|
moveDown(count());
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isKey(Key_Up)) {
|
} else if (input.isKey(Key_Up)) {
|
||||||
//removeAutomaticIndentation();
|
//removeAutomaticIndentation();
|
||||||
m_submode = NoSubMode;
|
m_submode = NoSubMode;
|
||||||
moveUp(count());
|
moveUp(count());
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isKey(Key_Right)) {
|
} else if (input.isKey(Key_Right)) {
|
||||||
moveRight(count());
|
moveRight(count());
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isControl(Key_Right)) {
|
} else if (input.isControl(Key_Right)) {
|
||||||
moveToNextWordStart(count(), false, true);
|
moveToNextWordStart(count(), false, true);
|
||||||
moveRight(); // we need one more move since we are in insert mode
|
moveRight(); // we need one more move since we are in insert mode
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isKey(Key_Home)) {
|
} else if (input.isKey(Key_Home)) {
|
||||||
moveToStartOfLine();
|
moveToStartOfLine();
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isKey(Key_End)) {
|
} else if (input.isKey(Key_End)) {
|
||||||
if (count() > 1)
|
if (count() > 1)
|
||||||
moveDown(count() - 1);
|
moveDown(count() - 1);
|
||||||
moveBehindEndOfLine();
|
moveBehindEndOfLine();
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
breakEditBlock();
|
||||||
m_lastInsertion.clear();
|
m_lastInsertion.clear();
|
||||||
} else if (input.isReturn()) {
|
} else if (input.isReturn()) {
|
||||||
joinPreviousEditBlock();
|
joinPreviousEditBlock();
|
||||||
@@ -3817,7 +3861,7 @@ bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd)
|
|||||||
showBlackMessage(QString());
|
showBlackMessage(QString());
|
||||||
SavedAction *act = theFakeVimSettings()->item(cmd.args);
|
SavedAction *act = theFakeVimSettings()->item(cmd.args);
|
||||||
QTC_CHECK(!cmd.args.isEmpty()); // Handled by plugin.
|
QTC_CHECK(!cmd.args.isEmpty()); // Handled by plugin.
|
||||||
if (act && act->value().type() == QVariant::Bool) {
|
if (act && act->value().canConvert(QVariant::Bool)) {
|
||||||
// Boolean config to be switched on.
|
// Boolean config to be switched on.
|
||||||
bool oldValue = act->value().toBool();
|
bool oldValue = act->value().toBool();
|
||||||
if (oldValue == false)
|
if (oldValue == false)
|
||||||
@@ -4038,6 +4082,17 @@ bool FakeVimHandler::Private::handleExRedoCommand(const ExCommand &cmd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FakeVimHandler::Private::handleExUndoCommand(const ExCommand &cmd)
|
||||||
|
{
|
||||||
|
// :undo
|
||||||
|
if (cmd.cmd != "u" && cmd.cmd != "un" && cmd.cmd != "undo")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
undo();
|
||||||
|
updateMiniBuffer();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool FakeVimHandler::Private::handleExGotoCommand(const ExCommand &cmd)
|
bool FakeVimHandler::Private::handleExGotoCommand(const ExCommand &cmd)
|
||||||
{
|
{
|
||||||
// :<nr>
|
// :<nr>
|
||||||
@@ -4150,6 +4205,7 @@ bool FakeVimHandler::Private::handleExCommandHelper(const ExCommand &cmd)
|
|||||||
|| handleExNormalCommand(cmd)
|
|| handleExNormalCommand(cmd)
|
||||||
|| handleExReadCommand(cmd)
|
|| handleExReadCommand(cmd)
|
||||||
|| handleExRedoCommand(cmd)
|
|| handleExRedoCommand(cmd)
|
||||||
|
|| handleExUndoCommand(cmd)
|
||||||
|| handleExSetCommand(cmd)
|
|| handleExSetCommand(cmd)
|
||||||
|| handleExShiftCommand(cmd)
|
|| handleExShiftCommand(cmd)
|
||||||
|| handleExSourceCommand(cmd)
|
|| handleExSourceCommand(cmd)
|
||||||
@@ -4297,15 +4353,22 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle)
|
|||||||
|
|
||||||
void FakeVimHandler::Private::moveToFirstNonBlankOnLine()
|
void FakeVimHandler::Private::moveToFirstNonBlankOnLine()
|
||||||
{
|
{
|
||||||
QTextDocument *doc = document();
|
QTextCursor tc2 = cursor();
|
||||||
int firstPos = block().position();
|
moveToFirstNonBlankOnLine(&tc2);
|
||||||
|
setPosition(tc2.position());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeVimHandler::Private::moveToFirstNonBlankOnLine(QTextCursor *tc)
|
||||||
|
{
|
||||||
|
QTextDocument *doc = tc->document();
|
||||||
|
int firstPos = tc->block().position();
|
||||||
for (int i = firstPos, n = firstPos + block().length(); i < n; ++i) {
|
for (int i = firstPos, n = firstPos + block().length(); i < n; ++i) {
|
||||||
if (!doc->characterAt(i).isSpace() || i == n - 1) {
|
if (!doc->characterAt(i).isSpace() || i == n - 1) {
|
||||||
setPosition(i);
|
tc->setPosition(i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setPosition(block().position());
|
tc->setPosition(block().position());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::indentSelectedText(QChar typedChar)
|
void FakeVimHandler::Private::indentSelectedText(QChar typedChar)
|
||||||
@@ -4358,6 +4421,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat)
|
|||||||
targetPos = firstPositionInLine(beginLine);
|
targetPos = firstPositionInLine(beginLine);
|
||||||
|
|
||||||
const int sw = config(ConfigShiftWidth).toInt();
|
const int sw = config(ConfigShiftWidth).toInt();
|
||||||
|
m_movetype = MoveLineWise;
|
||||||
beginEditBlock();
|
beginEditBlock();
|
||||||
for (int line = beginLine; line <= endLine; ++line) {
|
for (int line = beginLine; line <= endLine; ++line) {
|
||||||
QString data = lineContents(line);
|
QString data = lineContents(line);
|
||||||
@@ -4387,6 +4451,7 @@ void FakeVimHandler::Private::shiftRegionLeft(int repeat)
|
|||||||
if (hasConfig(ConfigStartOfLine))
|
if (hasConfig(ConfigStartOfLine))
|
||||||
targetPos = firstPositionInLine(beginLine);
|
targetPos = firstPositionInLine(beginLine);
|
||||||
|
|
||||||
|
m_movetype = MoveLineWise;
|
||||||
beginEditBlock();
|
beginEditBlock();
|
||||||
for (int line = endLine; line >= beginLine; --line) {
|
for (int line = endLine; line >= beginLine; --line) {
|
||||||
int pos = firstPositionInLine(line);
|
int pos = firstPositionInLine(line);
|
||||||
@@ -4889,7 +4954,6 @@ void FakeVimHandler::Private::insertText(const Register ®)
|
|||||||
qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return);
|
qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return);
|
||||||
setAnchor();
|
setAnchor();
|
||||||
cursor().insertText(reg.contents);
|
cursor().insertText(reg.contents);
|
||||||
m_lastChangePosition = cursor().position();
|
|
||||||
//dump("AFTER INSERT");
|
//dump("AFTER INSERT");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5216,16 +5280,31 @@ void FakeVimHandler::Private::undo()
|
|||||||
// FIXME: That's only an approximaxtion. The real solution might
|
// FIXME: That's only an approximaxtion. The real solution might
|
||||||
// be to store marks and old userData with QTextBlock setUserData
|
// be to store marks and old userData with QTextBlock setUserData
|
||||||
// and retrieve them afterward.
|
// and retrieve them afterward.
|
||||||
const int current = document()->availableUndoSteps();
|
const int current = revision();
|
||||||
EDITOR(undo());
|
EDITOR(undo());
|
||||||
const int rev = document()->availableUndoSteps();
|
const int rev = revision();
|
||||||
if (current == rev)
|
|
||||||
showBlackMessage(FakeVimHandler::tr("Already at oldest change"));
|
// rewind to last saved revision
|
||||||
else
|
while (!m_undo.empty() && m_undo.top().revision > rev)
|
||||||
showBlackMessage(QString());
|
m_undo.pop();
|
||||||
|
|
||||||
|
if (current == rev) {
|
||||||
|
showBlackMessage(FakeVimHandler::tr("Already at oldest change"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showBlackMessage(QString());
|
||||||
|
|
||||||
|
if (!m_undo.empty()) {
|
||||||
|
State &state = m_undo.top();
|
||||||
|
if (state.revision == rev) {
|
||||||
|
m_lastChangePosition = state.position;
|
||||||
|
m_marks = state.marks;
|
||||||
|
setPosition(m_lastChangePosition);
|
||||||
|
state.revision = current;
|
||||||
|
m_redo.push(m_undo.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_undoCursorPosition.contains(rev))
|
|
||||||
setPosition(m_undoCursorPosition[rev]);
|
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
if (atEndOfLine())
|
if (atEndOfLine())
|
||||||
moveLeft();
|
moveLeft();
|
||||||
@@ -5233,17 +5312,36 @@ void FakeVimHandler::Private::undo()
|
|||||||
|
|
||||||
void FakeVimHandler::Private::redo()
|
void FakeVimHandler::Private::redo()
|
||||||
{
|
{
|
||||||
const int current = document()->availableUndoSteps();
|
const int current = revision();
|
||||||
EDITOR(redo());
|
EDITOR(redo());
|
||||||
const int rev = document()->availableUndoSteps();
|
const int rev = revision();
|
||||||
if (rev == current)
|
|
||||||
showBlackMessage(FakeVimHandler::tr("Already at newest change"));
|
|
||||||
else
|
|
||||||
showBlackMessage(QString());
|
|
||||||
|
|
||||||
if (m_undoCursorPosition.contains(rev))
|
// forward to last saved revision
|
||||||
setPosition(m_undoCursorPosition[rev]);
|
while (!m_redo.empty() && m_redo.top().revision < rev)
|
||||||
|
m_redo.pop();
|
||||||
|
|
||||||
|
if (rev == current) {
|
||||||
|
showBlackMessage(FakeVimHandler::tr("Already at newest change"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
showBlackMessage(QString());
|
||||||
|
|
||||||
|
if (!m_redo.empty()) {
|
||||||
|
State &state = m_redo.top();
|
||||||
|
if (state.revision == rev) {
|
||||||
|
int pos = qMin(document()->characterCount() - 1, state.position);
|
||||||
|
if (lineForPosition(pos) != state.line)
|
||||||
|
pos = lastPositionInLine(state.line);
|
||||||
|
m_lastChangePosition = pos;
|
||||||
|
m_marks = state.marks;
|
||||||
|
setPosition(m_lastChangePosition);
|
||||||
|
state.revision = current;
|
||||||
|
m_undo.push(m_redo.pop());
|
||||||
|
}
|
||||||
|
}
|
||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
|
if (atEndOfLine())
|
||||||
|
moveLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimHandler::Private::updateCursorShape()
|
void FakeVimHandler::Private::updateCursorShape()
|
||||||
|
Reference in New Issue
Block a user