2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-19 12:20:04 +01:00
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2012-01-26 18:33:46 +01:00
|
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-19 12:20:04 +01:00
|
|
|
**
|
2012-07-19 12:26:56 +02:00
|
|
|
** Contact: http://www.qt-project.org/
|
2008-12-19 12:20:04 +01:00
|
|
|
**
|
|
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-19 12:20:04 +01:00
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
|
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
|
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
|
|
|
|
** Please review the following information to ensure the GNU Lesser General
|
|
|
|
|
** Public License version 2.1 requirements will be met:
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2008-12-19 12:20:04 +01:00
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-04-13 08:42:33 +02:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Other Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
|
**
|
2008-12-19 12:20:04 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2009-03-06 11:22:16 +01:00
|
|
|
//
|
2009-04-16 09:18:09 +02:00
|
|
|
// ATTENTION:
|
|
|
|
|
//
|
|
|
|
|
// 1 Please do not add any direct dependencies to other Qt Creator code here.
|
|
|
|
|
// Instead emit signals and let the FakeVimPlugin channel the information to
|
|
|
|
|
// Qt Creator. The idea is to keep this file here in a "clean" state that
|
|
|
|
|
// allows easy reuse with any QTextEdit or QPlainTextEdit derived class.
|
|
|
|
|
//
|
|
|
|
|
// 2 There are a few auto tests located in ../../../tests/auto/fakevim.
|
|
|
|
|
// Commands that are covered there are marked as "// tested" below.
|
|
|
|
|
//
|
|
|
|
|
// 3 Some conventions:
|
2009-03-06 11:22:16 +01:00
|
|
|
//
|
2009-04-16 09:18:09 +02:00
|
|
|
// Use 1 based line numbers and 0 based column numbers. Even though
|
|
|
|
|
// the 1 based line are not nice it matches vim's and QTextEdit's 'line'
|
|
|
|
|
// concepts.
|
2009-03-06 11:22:16 +01:00
|
|
|
//
|
2009-04-16 09:18:09 +02:00
|
|
|
// Do not pass QTextCursor etc around unless really needed. Convert
|
|
|
|
|
// early to line/column.
|
|
|
|
|
//
|
2010-01-21 17:38:28 +01:00
|
|
|
// A QTextCursor is always between characters, whereas vi's cursor is always
|
|
|
|
|
// over a character. FakeVim interprets the QTextCursor to be over the character
|
|
|
|
|
// to the right of the QTextCursor's position().
|
|
|
|
|
//
|
2010-09-13 14:16:18 +02:00
|
|
|
// A current "region of interest"
|
2010-09-14 14:04:13 +02:00
|
|
|
// spans between anchor(), (i.e. the character below anchor()), and
|
|
|
|
|
// position(). The character below position() is not included
|
2010-01-21 17:38:28 +01:00
|
|
|
// if the last movement command was exclusive (MoveExclusive).
|
2010-05-06 14:08:09 +02:00
|
|
|
//
|
2009-03-06 11:22:16 +01:00
|
|
|
|
2010-04-27 18:02:19 +02:00
|
|
|
#include "fakevimhandler.h"
|
|
|
|
|
|
2012-08-23 15:53:58 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
2009-03-30 12:40:08 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2009-01-15 13:32:36 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include <QObject>
|
|
|
|
|
#include <QPointer>
|
|
|
|
|
#include <QProcess>
|
|
|
|
|
#include <QRegExp>
|
|
|
|
|
#include <QTextStream>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QtAlgorithms>
|
|
|
|
|
#include <QStack>
|
2008-12-19 16:20:39 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QApplication>
|
2012-07-26 21:46:38 +02:00
|
|
|
#include <QClipboard>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QInputMethodEvent>
|
|
|
|
|
#include <QKeyEvent>
|
|
|
|
|
#include <QLineEdit>
|
|
|
|
|
#include <QPlainTextEdit>
|
|
|
|
|
#include <QScrollBar>
|
|
|
|
|
#include <QTextBlock>
|
|
|
|
|
#include <QTextCursor>
|
|
|
|
|
#include <QTextDocumentFragment>
|
|
|
|
|
#include <QTextEdit>
|
2012-08-21 11:39:35 +02:00
|
|
|
#include <QMimeData>
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-01-25 10:45:30 +01:00
|
|
|
#include <algorithm>
|
2009-08-11 16:45:29 +02:00
|
|
|
#include <climits>
|
2009-12-11 13:24:53 +01:00
|
|
|
#include <ctype.h>
|
2009-08-11 16:45:29 +02:00
|
|
|
|
2009-03-05 11:06:25 +01:00
|
|
|
//#define DEBUG_KEY 1
|
|
|
|
|
#if DEBUG_KEY
|
|
|
|
|
# define KEY_DEBUG(s) qDebug() << s
|
|
|
|
|
#else
|
|
|
|
|
# define KEY_DEBUG(s)
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-03-06 11:22:16 +01:00
|
|
|
//#define DEBUG_UNDO 1
|
|
|
|
|
#if DEBUG_UNDO
|
2012-08-26 18:39:48 +02:00
|
|
|
# define UNDO_DEBUG(s) qDebug() << << revision() << s
|
2009-03-06 11:22:16 +01:00
|
|
|
#else
|
|
|
|
|
# define UNDO_DEBUG(s)
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-10-05 11:06:05 +02:00
|
|
|
using namespace Utils;
|
2009-03-30 12:40:08 +02:00
|
|
|
|
|
|
|
|
namespace FakeVim {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2009-03-06 13:22:39 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// FakeVimHandler
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-04-14 15:47:25 +02:00
|
|
|
#define StartOfLine QTextCursor::StartOfLine
|
|
|
|
|
#define EndOfLine QTextCursor::EndOfLine
|
|
|
|
|
#define MoveAnchor QTextCursor::MoveAnchor
|
|
|
|
|
#define KeepAnchor QTextCursor::KeepAnchor
|
|
|
|
|
#define Up QTextCursor::Up
|
|
|
|
|
#define Down QTextCursor::Down
|
|
|
|
|
#define Right QTextCursor::Right
|
|
|
|
|
#define Left QTextCursor::Left
|
|
|
|
|
#define EndOfDocument QTextCursor::End
|
|
|
|
|
#define StartOfDocument QTextCursor::Start
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
#define ParagraphSeparator QChar::ParagraphSeparator
|
|
|
|
|
|
2008-12-26 18:29:38 +01:00
|
|
|
#define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
|
|
|
|
|
|
2012-09-07 13:31:29 +02:00
|
|
|
#define MetaModifier // Use HostOsInfo::controlModifier() instead
|
|
|
|
|
#define ControlModifier // Use HostOsInfo::controlModifier() instead
|
2011-04-07 17:59:12 +02:00
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
typedef QLatin1String _;
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2012-08-09 17:32:39 +02:00
|
|
|
/* Clipboard MIME types used by Vim. */
|
|
|
|
|
static const QString vimMimeText = "_VIM_TEXT";
|
|
|
|
|
static const QString vimMimeTextEncoded = "_VIMENC_TEXT";
|
|
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
using namespace Qt;
|
|
|
|
|
|
2010-05-06 14:08:09 +02:00
|
|
|
/*! A \e Mode represents one of the basic modes of operation of FakeVim.
|
|
|
|
|
*/
|
2009-04-01 15:11:26 +02:00
|
|
|
|
2008-12-19 16:20:39 +01:00
|
|
|
enum Mode
|
|
|
|
|
{
|
|
|
|
|
InsertMode,
|
2010-05-06 12:10:57 +02:00
|
|
|
ReplaceMode,
|
2008-12-19 16:20:39 +01:00
|
|
|
CommandMode,
|
2010-12-16 12:05:48 +01:00
|
|
|
ExMode
|
2008-12-19 16:20:39 +01:00
|
|
|
};
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-05-06 14:08:09 +02:00
|
|
|
/*! A \e SubMode is used for things that require one more data item
|
|
|
|
|
and are 'nested' behind a \l Mode.
|
|
|
|
|
*/
|
2008-12-19 16:20:39 +01:00
|
|
|
enum SubMode
|
|
|
|
|
{
|
|
|
|
|
NoSubMode,
|
2010-07-14 13:02:17 +02:00
|
|
|
ChangeSubMode, // Used for c
|
|
|
|
|
DeleteSubMode, // Used for d
|
|
|
|
|
FilterSubMode, // Used for !
|
|
|
|
|
IndentSubMode, // Used for =
|
|
|
|
|
RegisterSubMode, // Used for "
|
|
|
|
|
ShiftLeftSubMode, // Used for <
|
|
|
|
|
ShiftRightSubMode, // Used for >
|
|
|
|
|
TransformSubMode, // Used for ~/gu/gU
|
|
|
|
|
WindowSubMode, // Used for Ctrl-w
|
|
|
|
|
YankSubMode, // Used for y
|
|
|
|
|
ZSubMode, // Used for z
|
|
|
|
|
CapitalZSubMode, // Used for Z
|
|
|
|
|
ReplaceSubMode, // Used for r
|
|
|
|
|
OpenSquareSubMode, // Used for [
|
2011-12-27 14:54:49 +01:00
|
|
|
CloseSquareSubMode // Used for ]
|
2008-12-19 16:20:39 +01:00
|
|
|
};
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-05-06 14:08:09 +02:00
|
|
|
/*! A \e SubSubMode is used for things that require one more data item
|
|
|
|
|
and are 'nested' behind a \l SubMode.
|
|
|
|
|
*/
|
2008-12-26 00:18:03 +01:00
|
|
|
enum SubSubMode
|
|
|
|
|
{
|
|
|
|
|
NoSubSubMode,
|
2010-05-06 14:08:09 +02:00
|
|
|
FtSubSubMode, // Used for f, F, t, T.
|
|
|
|
|
MarkSubSubMode, // Used for m.
|
|
|
|
|
BackTickSubSubMode, // Used for `.
|
|
|
|
|
TickSubSubMode, // Used for '.
|
|
|
|
|
InvertCaseSubSubMode, // Used for ~.
|
|
|
|
|
DownCaseSubSubMode, // Used for gu.
|
|
|
|
|
UpCaseSubSubMode, // Used for gU.
|
|
|
|
|
TextObjectSubSubMode, // Used for thing like iw, aW, as etc.
|
2010-12-16 12:05:48 +01:00
|
|
|
SearchSubSubMode
|
2008-12-26 00:18:03 +01:00
|
|
|
};
|
|
|
|
|
|
2009-01-06 11:52:05 +01:00
|
|
|
enum VisualMode
|
|
|
|
|
{
|
|
|
|
|
NoVisualMode,
|
|
|
|
|
VisualCharMode,
|
|
|
|
|
VisualLineMode,
|
2010-12-16 12:05:48 +01:00
|
|
|
VisualBlockMode
|
2009-01-06 11:52:05 +01:00
|
|
|
};
|
|
|
|
|
|
2009-01-16 16:57:00 +01:00
|
|
|
enum MoveType
|
|
|
|
|
{
|
|
|
|
|
MoveExclusive,
|
|
|
|
|
MoveInclusive,
|
2010-12-16 12:05:48 +01:00
|
|
|
MoveLineWise
|
2009-01-16 16:57:00 +01:00
|
|
|
};
|
|
|
|
|
|
2010-05-06 14:08:09 +02:00
|
|
|
/*!
|
|
|
|
|
\enum RangeMode
|
|
|
|
|
|
|
|
|
|
The \e RangeMode serves as a means to define how the "Range" between
|
|
|
|
|
the \l cursor and the \l anchor position is to be interpreted.
|
|
|
|
|
|
|
|
|
|
\value RangeCharMode Entered by pressing \key v. The range includes
|
|
|
|
|
all characters between cursor and anchor.
|
|
|
|
|
\value RangeLineMode Entered by pressing \key V. The range includes
|
|
|
|
|
all lines between the line of the cursor and
|
|
|
|
|
the line of the anchor.
|
|
|
|
|
\value RangeLineModeExclusice Like \l RangeLineMode, but keeps one
|
|
|
|
|
newline when deleting.
|
|
|
|
|
\value RangeBlockMode Entered by pressing \key Ctrl-v. The range includes
|
|
|
|
|
all characters with line and column coordinates
|
|
|
|
|
between line and columns coordinates of cursor and
|
|
|
|
|
anchor.
|
|
|
|
|
\value RangeBlockAndTailMode Like \l RangeBlockMode, but also includes
|
|
|
|
|
all characters in the affected lines up to the end
|
|
|
|
|
of these lines.
|
|
|
|
|
*/
|
2009-08-11 14:39:44 +02:00
|
|
|
|
|
|
|
|
enum EventResult
|
|
|
|
|
{
|
|
|
|
|
EventHandled,
|
|
|
|
|
EventUnhandled,
|
|
|
|
|
EventPassedToCore
|
|
|
|
|
};
|
|
|
|
|
|
2012-08-26 18:39:48 +02:00
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
2010-03-09 16:44:36 +01:00
|
|
|
struct Column
|
2009-12-11 13:24:53 +01:00
|
|
|
{
|
2010-03-09 16:44:36 +01:00
|
|
|
Column(int p, int l) : physical(p), logical(l) {}
|
2010-05-06 14:08:09 +02:00
|
|
|
int physical; // Number of characters in the data.
|
|
|
|
|
int logical; // Column on screen.
|
2009-12-11 13:24:53 +01:00
|
|
|
};
|
|
|
|
|
|
2010-07-06 16:17:27 +02:00
|
|
|
QDebug operator<<(QDebug ts, const Column &col)
|
|
|
|
|
{
|
|
|
|
|
return ts << "(p: " << col.physical << ", l: " << col.logical << ")";
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-11 14:39:44 +02:00
|
|
|
struct CursorPosition
|
|
|
|
|
{
|
|
|
|
|
// for jump history
|
|
|
|
|
CursorPosition() : position(-1), scrollLine(-1) {}
|
|
|
|
|
CursorPosition(int pos, int line) : position(pos), scrollLine(line) {}
|
|
|
|
|
int position; // Position in document
|
|
|
|
|
int scrollLine; // First visible line
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Register
|
|
|
|
|
{
|
|
|
|
|
Register() : rangemode(RangeCharMode) {}
|
2010-05-11 14:26:37 +02:00
|
|
|
Register(const QString &c) : contents(c), rangemode(RangeCharMode) {}
|
2009-08-11 14:39:44 +02:00
|
|
|
Register(const QString &c, RangeMode m) : contents(c), rangemode(m) {}
|
|
|
|
|
QString contents;
|
|
|
|
|
RangeMode rangemode;
|
|
|
|
|
};
|
|
|
|
|
|
2010-05-20 14:08:11 +02:00
|
|
|
QDebug operator<<(QDebug ts, const Register ®)
|
|
|
|
|
{
|
|
|
|
|
return ts << reg.contents;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 18:24:00 +02:00
|
|
|
struct SearchData
|
|
|
|
|
{
|
2011-02-18 15:31:31 +01:00
|
|
|
SearchData()
|
|
|
|
|
{
|
|
|
|
|
forward = true;
|
|
|
|
|
highlightMatches = true;
|
|
|
|
|
}
|
2010-05-18 18:24:00 +02:00
|
|
|
|
|
|
|
|
QString needle;
|
|
|
|
|
bool forward;
|
|
|
|
|
bool highlightMatches;
|
|
|
|
|
};
|
2009-08-11 14:39:44 +02:00
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// If string begins with given prefix remove it with trailing spaces and return true.
|
|
|
|
|
static bool eatString(const QString &prefix, QString *str)
|
|
|
|
|
{
|
|
|
|
|
if (!str->startsWith(prefix))
|
|
|
|
|
return false;
|
|
|
|
|
*str = str->mid(prefix.size()).trimmed();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-22 14:30:56 +02:00
|
|
|
static QRegExp vimPatternToQtPattern(QString needle, bool smartcase)
|
|
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
/* Transformations (Vim regexp -> QRegExp):
|
2012-07-22 14:30:56 +02:00
|
|
|
* \a -> [A-Za-z]
|
|
|
|
|
* \A -> [^A-Za-z]
|
|
|
|
|
* \h -> [A-Za-z_]
|
|
|
|
|
* \H -> [^A-Za-z_]
|
|
|
|
|
* \l -> [a-z]
|
|
|
|
|
* \L -> [^a-z]
|
|
|
|
|
* \o -> [0-7]
|
|
|
|
|
* \O -> [^0-7]
|
|
|
|
|
* \u -> [A-Z]
|
|
|
|
|
* \U -> [^A-Z]
|
|
|
|
|
* \x -> [0-9A-Fa-f]
|
|
|
|
|
* \X -> [^0-9A-Fa-f]
|
|
|
|
|
*
|
|
|
|
|
* \< -> \b
|
|
|
|
|
* \> -> \b
|
|
|
|
|
* [] -> \[\]
|
|
|
|
|
* \= -> ?
|
|
|
|
|
*
|
|
|
|
|
* (...) <-> \(...\)
|
|
|
|
|
* {...} <-> \{...\}
|
|
|
|
|
* | <-> \|
|
|
|
|
|
* ? <-> \?
|
|
|
|
|
* + <-> \+
|
|
|
|
|
* \{...} -> {...}
|
|
|
|
|
*
|
|
|
|
|
* \c - set ignorecase for rest
|
|
|
|
|
* \C - set noignorecase for rest
|
|
|
|
|
*/
|
|
|
|
|
bool ignorecase = smartcase && !needle.contains(QRegExp("[A-Z]"));
|
|
|
|
|
QString pattern;
|
|
|
|
|
pattern.reserve(2 * needle.size());
|
|
|
|
|
|
|
|
|
|
bool escape = false;
|
|
|
|
|
bool brace = false;
|
|
|
|
|
bool curly = false;
|
|
|
|
|
foreach (const QChar &c, needle) {
|
|
|
|
|
if (brace) {
|
|
|
|
|
brace = false;
|
|
|
|
|
if (c == ']') {
|
|
|
|
|
pattern.append(_("\\[\\]"));
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
pattern.append('[');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (QString("(){}+|?").indexOf(c) != -1) {
|
|
|
|
|
if (c == '{') {
|
|
|
|
|
curly = escape;
|
|
|
|
|
} else if (c == '}' && curly) {
|
|
|
|
|
curly = false;
|
|
|
|
|
escape = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (escape)
|
|
|
|
|
escape = false;
|
|
|
|
|
else
|
|
|
|
|
pattern.append('\\');
|
|
|
|
|
pattern.append(c);
|
|
|
|
|
} else if (escape) {
|
|
|
|
|
// escape expression
|
|
|
|
|
escape = false;
|
|
|
|
|
if (c == '<' || c == '>')
|
|
|
|
|
pattern.append(_("\\b"));
|
|
|
|
|
else if (c == 'a')
|
|
|
|
|
pattern.append(_("[a-zA-Z]"));
|
|
|
|
|
else if (c == 'A')
|
|
|
|
|
pattern.append(_("[^a-zA-Z]"));
|
|
|
|
|
else if (c == 'h')
|
|
|
|
|
pattern.append(_("[A-Za-z_]"));
|
|
|
|
|
else if (c == 'H')
|
|
|
|
|
pattern.append(_("[^A-Za-z_]"));
|
|
|
|
|
else if (c == 'c' || c == 'C')
|
|
|
|
|
ignorecase = (c == 'c');
|
|
|
|
|
else if (c == 'l')
|
|
|
|
|
pattern.append(_("[a-z]"));
|
|
|
|
|
else if (c == 'L')
|
|
|
|
|
pattern.append(_("[^a-z]"));
|
|
|
|
|
else if (c == 'o')
|
|
|
|
|
pattern.append(_("[0-7]"));
|
|
|
|
|
else if (c == 'O')
|
|
|
|
|
pattern.append(_("[^0-7]"));
|
|
|
|
|
else if (c == 'u')
|
|
|
|
|
pattern.append(_("[A-Z]"));
|
|
|
|
|
else if (c == 'U')
|
|
|
|
|
pattern.append(_("[^A-Z]"));
|
|
|
|
|
else if (c == 'x')
|
|
|
|
|
pattern.append(_("[0-9A-Fa-f]"));
|
|
|
|
|
else if (c == 'X')
|
|
|
|
|
pattern.append(_("[^0-9A-Fa-f]"));
|
|
|
|
|
else if (c == '=')
|
|
|
|
|
pattern.append(_("?"));
|
|
|
|
|
else
|
|
|
|
|
pattern.append('\\' + c);
|
|
|
|
|
} else {
|
|
|
|
|
// unescaped expression
|
|
|
|
|
if (c == '\\')
|
|
|
|
|
escape = true;
|
|
|
|
|
else if (c == '[')
|
|
|
|
|
brace = true;
|
|
|
|
|
else if (c.isLetter() && ignorecase)
|
|
|
|
|
pattern.append('[' + c.toLower() + c.toUpper() + ']');
|
|
|
|
|
else
|
|
|
|
|
pattern.append(c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (escape)
|
|
|
|
|
pattern.append('\\');
|
|
|
|
|
else if (brace)
|
|
|
|
|
pattern.append('[');
|
|
|
|
|
|
|
|
|
|
return QRegExp(pattern);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-09 17:32:39 +02:00
|
|
|
static void setClipboardData(const QString &content, RangeMode mode,
|
|
|
|
|
QClipboard::Mode clipboardMode)
|
|
|
|
|
{
|
|
|
|
|
QClipboard *clipboard = QApplication::clipboard();
|
|
|
|
|
char vimRangeMode = mode;
|
|
|
|
|
|
|
|
|
|
QByteArray bytes1;
|
|
|
|
|
bytes1.append(vimRangeMode);
|
|
|
|
|
bytes1.append(content.toUtf8());
|
|
|
|
|
|
|
|
|
|
QByteArray bytes2;
|
|
|
|
|
bytes2.append(vimRangeMode);
|
|
|
|
|
bytes2.append("utf-8");
|
|
|
|
|
bytes2.append('\0');
|
|
|
|
|
bytes2.append(content.toUtf8());
|
|
|
|
|
|
|
|
|
|
QMimeData *data = new QMimeData;
|
|
|
|
|
data->setText(content);
|
|
|
|
|
data->setData(vimMimeText, bytes1);
|
|
|
|
|
data->setData(vimMimeTextEncoded, bytes2);
|
|
|
|
|
clipboard->setMimeData(data, clipboardMode);
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-11 14:39:44 +02:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
Range::Range()
|
|
|
|
|
: beginPos(-1), endPos(-1), rangemode(RangeCharMode)
|
|
|
|
|
{}
|
2009-11-10 09:25:22 +01:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
Range::Range(int b, int e, RangeMode m)
|
|
|
|
|
: beginPos(qMin(b, e)), endPos(qMax(b, e)), rangemode(m)
|
|
|
|
|
{}
|
2009-08-11 14:39:44 +02:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
QString Range::toString() const
|
2010-05-12 11:18:18 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
return QString("%1-%2 (mode: %3)").arg(beginPos).arg(endPos)
|
|
|
|
|
.arg(rangemode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDebug operator<<(QDebug ts, const Range &range)
|
|
|
|
|
{
|
|
|
|
|
return ts << '[' << range.beginPos << ',' << range.endPos << ']';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExCommand::ExCommand(const QString &c, const QString &a, const Range &r)
|
2010-07-14 14:33:26 +02:00
|
|
|
: cmd(c), hasBang(false), args(a), range(r), count(1)
|
2010-05-18 14:48:12 +02:00
|
|
|
{}
|
2010-05-12 11:18:18 +02:00
|
|
|
|
2010-07-14 18:15:17 +02:00
|
|
|
bool ExCommand::matches(const QString &min, const QString &full) const
|
|
|
|
|
{
|
|
|
|
|
return cmd.startsWith(min) && full.startsWith(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-10 15:47:17 +01:00
|
|
|
void ExCommand::setContentsFromLine(const QString &line)
|
|
|
|
|
{
|
2012-09-29 19:09:08 +02:00
|
|
|
// split command to subcommands
|
|
|
|
|
subCommands = line.split('|');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExCommand::nextSubcommand()
|
|
|
|
|
{
|
|
|
|
|
cmd.clear();
|
|
|
|
|
while (cmd.isEmpty() && !subCommands.isEmpty()) {
|
|
|
|
|
cmd = subCommands.takeFirst().trimmed();
|
|
|
|
|
cmd.remove(QRegExp("^:+\\s*")); // remove leading colons
|
|
|
|
|
hasBang = cmd.endsWith('!');
|
|
|
|
|
if (hasBang)
|
|
|
|
|
cmd.chop(1);
|
|
|
|
|
|
|
|
|
|
// command arguments
|
|
|
|
|
args = cmd.section(QRegExp("\\s+"), 1);
|
|
|
|
|
if (!args.isEmpty())
|
|
|
|
|
cmd = cmd.left(cmd.size() - args.size()).trimmed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !cmd.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString ExCommand::printCommand() const
|
|
|
|
|
{
|
|
|
|
|
return subCommands.isEmpty() ? cmd : cmd + "|" + subCommands.join("|");
|
2011-11-10 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
QDebug operator<<(QDebug ts, const ExCommand &cmd)
|
|
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
return ts << cmd.cmd << ' ' << cmd.args << ' ' << cmd.range;
|
2010-05-12 11:18:18 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 19:46:16 +02:00
|
|
|
QDebug operator<<(QDebug ts, const QList<QTextEdit::ExtraSelection> &sels)
|
2009-01-23 16:37:32 +01:00
|
|
|
{
|
2010-02-01 14:00:07 +01:00
|
|
|
foreach (const QTextEdit::ExtraSelection &sel, sels)
|
2009-04-01 15:14:10 +02:00
|
|
|
ts << "SEL: " << sel.cursor.anchor() << sel.cursor.position();
|
2009-01-23 16:37:32 +01:00
|
|
|
return ts;
|
|
|
|
|
}
|
2009-04-01 15:14:10 +02:00
|
|
|
|
2009-06-11 17:09:05 +02:00
|
|
|
QString quoteUnprintable(const QString &ba)
|
2009-01-16 16:15:01 +01:00
|
|
|
{
|
2009-06-11 17:09:05 +02:00
|
|
|
QString res;
|
|
|
|
|
for (int i = 0, n = ba.size(); i != n; ++i) {
|
2010-05-04 17:58:53 +02:00
|
|
|
const QChar c = ba.at(i);
|
|
|
|
|
const int cc = c.unicode();
|
2009-06-11 17:09:05 +02:00
|
|
|
if (c.isPrint())
|
|
|
|
|
res += c;
|
2010-05-04 17:58:53 +02:00
|
|
|
else if (cc == '\n')
|
2010-05-11 14:26:37 +02:00
|
|
|
res += _("<CR>");
|
2009-06-11 17:09:05 +02:00
|
|
|
else
|
2010-05-04 17:58:53 +02:00
|
|
|
res += QString("\\x%1").arg(c.unicode(), 2, 16, QLatin1Char('0'));
|
2009-06-11 17:09:05 +02:00
|
|
|
}
|
|
|
|
|
return res;
|
2009-01-16 16:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
2010-02-15 17:55:26 +01:00
|
|
|
static bool startsWithWhitespace(const QString &str, int col)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(str.size() >= col, return false);
|
|
|
|
|
for (int i = 0; i < col; ++i) {
|
|
|
|
|
uint u = str.at(i).unicode();
|
|
|
|
|
if (u != ' ' && u != '\t')
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 19:46:16 +02:00
|
|
|
inline QString msgMarkNotSet(const QString &text)
|
2009-10-07 09:25:19 +02:00
|
|
|
{
|
2010-05-11 14:26:37 +02:00
|
|
|
return FakeVimHandler::tr("Mark '%1' not set").arg(text);
|
2009-10-07 09:25:19 +02:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
class Input
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-03-26 13:22:06 +01:00
|
|
|
public:
|
2010-11-02 12:37:36 +01:00
|
|
|
// Remove some extra "information" on Mac.
|
|
|
|
|
static int cleanModifier(int m) { return m & ~Qt::KeypadModifier; }
|
|
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
Input()
|
|
|
|
|
: m_key(0), m_xkey(0), m_modifiers(0) {}
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
explicit Input(QChar x)
|
2012-09-01 07:47:25 +02:00
|
|
|
: m_key(x.unicode()), m_xkey(x.unicode()), m_modifiers(0), m_text(x)
|
|
|
|
|
{
|
|
|
|
|
if (x.isUpper())
|
|
|
|
|
m_modifiers = Qt::ShiftModifier;
|
2012-09-13 18:44:36 +02:00
|
|
|
else if (x.isLower())
|
|
|
|
|
m_key = x.toUpper().unicode();
|
2012-09-01 07:47:25 +02:00
|
|
|
}
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2010-05-07 17:32:46 +02:00
|
|
|
Input(int k, int m, const QString &t)
|
2010-11-02 12:37:36 +01:00
|
|
|
: m_key(k), m_modifiers(cleanModifier(m)), m_text(t)
|
2010-04-28 14:00:44 +02:00
|
|
|
{
|
2010-06-04 12:53:38 +02:00
|
|
|
// On Mac, QKeyEvent::text() returns non-empty strings for
|
|
|
|
|
// cursor keys. This breaks some of the logic later on
|
|
|
|
|
// relying on text() being empty for "special" keys.
|
|
|
|
|
// FIXME: Check the real conditions.
|
|
|
|
|
if (m_text.size() == 1 && m_text.at(0).unicode() < ' ')
|
|
|
|
|
m_text.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
// m_xkey is only a cache.
|
|
|
|
|
m_xkey = (m_text.size() == 1 ? m_text.at(0).unicode() : m_key);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
bool isValid() const
|
|
|
|
|
{
|
|
|
|
|
return m_key != 0 || !m_text.isNull();
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
bool isDigit() const
|
|
|
|
|
{
|
|
|
|
|
return m_xkey >= '0' && m_xkey <= '9';
|
|
|
|
|
}
|
2010-05-10 16:41:35 +02:00
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
bool isKey(int c) const
|
|
|
|
|
{
|
|
|
|
|
return !m_modifiers && m_key == c;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-10 16:41:35 +02:00
|
|
|
bool isBackspace() const
|
|
|
|
|
{
|
|
|
|
|
return m_key == Key_Backspace || isControl('h');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isReturn() const
|
|
|
|
|
{
|
2012-03-09 09:44:54 +01:00
|
|
|
return m_key == Key_Return || m_key == Key_Enter;
|
2010-05-10 16:41:35 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-18 18:24:00 +02:00
|
|
|
bool isEscape() const
|
|
|
|
|
{
|
|
|
|
|
return isKey(Key_Escape) || isKey(27) || isControl('c')
|
|
|
|
|
|| isControl(Key_BracketLeft);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
bool is(int c) const
|
|
|
|
|
{
|
2012-09-07 13:31:29 +02:00
|
|
|
return m_xkey == c && m_modifiers != int(HostOsInfo::controlModifier());
|
2010-04-28 14:00:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isControl(int c) const
|
|
|
|
|
{
|
2012-09-07 13:31:29 +02:00
|
|
|
return m_modifiers == int(HostOsInfo::controlModifier())
|
2010-10-26 10:56:32 +02:00
|
|
|
&& (m_xkey == c || m_xkey + 32 == c || m_xkey + 64 == c || m_xkey + 96 == c);
|
2010-04-28 14:00:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isShift(int c) const
|
|
|
|
|
{
|
|
|
|
|
return m_modifiers == Qt::ShiftModifier && m_xkey == c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator==(const Input &a) const
|
|
|
|
|
{
|
2012-09-13 18:44:36 +02:00
|
|
|
return m_key == a.m_key && m_modifiers == a.m_modifiers && m_text == a.m_text;
|
2010-04-28 14:00:44 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
bool operator!=(const Input &a) const { return !operator==(a); }
|
|
|
|
|
|
|
|
|
|
bool operator<(const Input &a) const
|
2011-11-10 16:13:10 +01:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
return m_key < a.m_key || m_modifiers < a.m_modifiers || m_text < a.m_text;
|
2011-11-10 16:13:10 +01:00
|
|
|
}
|
|
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
QString text() const { return m_text; }
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
QChar asChar() const
|
|
|
|
|
{
|
|
|
|
|
return (m_text.size() == 1 ? m_text.at(0) : QChar());
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
int key() const { return m_key; }
|
|
|
|
|
|
2010-07-06 09:20:40 +02:00
|
|
|
QChar raw() const
|
|
|
|
|
{
|
|
|
|
|
if (m_key == Key_Tab)
|
|
|
|
|
return '\t';
|
|
|
|
|
if (m_key == Key_Return)
|
|
|
|
|
return '\n';
|
|
|
|
|
return m_key;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 17:32:46 +02:00
|
|
|
QDebug dump(QDebug ts) const
|
|
|
|
|
{
|
|
|
|
|
return ts << m_key << '-' << m_modifiers << '-'
|
|
|
|
|
<< quoteUnprintable(m_text);
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
private:
|
|
|
|
|
int m_key;
|
|
|
|
|
int m_xkey;
|
|
|
|
|
int m_modifiers;
|
|
|
|
|
QString m_text;
|
|
|
|
|
};
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// mapping to <Nop> (do nothing)
|
|
|
|
|
static const Input Nop(-1, -1, QString());
|
|
|
|
|
|
2010-05-07 17:32:46 +02:00
|
|
|
QDebug operator<<(QDebug ts, const Input &input) { return input.dump(ts); }
|
|
|
|
|
|
|
|
|
|
class Inputs : public QVector<Input>
|
2010-05-04 11:00:40 +02:00
|
|
|
{
|
2010-05-07 17:32:46 +02:00
|
|
|
public:
|
2012-09-01 07:47:25 +02:00
|
|
|
Inputs() : m_noremap(true), m_silent(false) {}
|
|
|
|
|
|
|
|
|
|
explicit Inputs(const QString &str, bool noremap = true, bool silent = false)
|
|
|
|
|
: m_noremap(noremap), m_silent(silent)
|
|
|
|
|
{
|
|
|
|
|
parseFrom(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool noremap() const { return m_noremap; }
|
|
|
|
|
|
|
|
|
|
bool silent() const { return m_silent; }
|
|
|
|
|
|
|
|
|
|
private:
|
2010-05-07 17:32:46 +02:00
|
|
|
void parseFrom(const QString &str);
|
2012-09-01 07:47:25 +02:00
|
|
|
|
|
|
|
|
bool m_noremap;
|
|
|
|
|
bool m_silent;
|
2010-05-07 17:32:46 +02:00
|
|
|
};
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
static QMap<QString, int> vimKeyNames()
|
|
|
|
|
{
|
|
|
|
|
QMap<QString, int> k;
|
|
|
|
|
|
|
|
|
|
// FIXME: Should be value of mapleader.
|
|
|
|
|
k.insert("LEADER", Key_Backslash);
|
|
|
|
|
|
|
|
|
|
k.insert("SPACE", Key_Space);
|
|
|
|
|
k.insert("TAB", Key_Tab);
|
|
|
|
|
k.insert("NL", Key_Return);
|
|
|
|
|
k.insert("NEWLINE", Key_Return);
|
|
|
|
|
k.insert("LINEFEED", Key_Return);
|
|
|
|
|
k.insert("LF", Key_Return);
|
|
|
|
|
k.insert("CR", Key_Return);
|
|
|
|
|
k.insert("RETURN", Key_Return);
|
|
|
|
|
k.insert("ENTER", Key_Return);
|
|
|
|
|
k.insert("BS", Key_Backspace);
|
|
|
|
|
k.insert("BACKSPACE", Key_Backspace);
|
|
|
|
|
k.insert("ESC", Key_Escape);
|
|
|
|
|
k.insert("BAR", Key_Bar);
|
|
|
|
|
k.insert("BSLASH", Key_Backslash);
|
|
|
|
|
k.insert("DEL", Key_Delete);
|
|
|
|
|
k.insert("DELETE", Key_Delete);
|
|
|
|
|
k.insert("KDEL", Key_Delete);
|
|
|
|
|
k.insert("UP", Key_Up);
|
|
|
|
|
k.insert("DOWN", Key_Down);
|
|
|
|
|
k.insert("LEFT", Key_Left);
|
|
|
|
|
k.insert("RIGHT", Key_Right);
|
|
|
|
|
|
|
|
|
|
k.insert("F1", Key_F1);
|
|
|
|
|
k.insert("F2", Key_F2);
|
|
|
|
|
k.insert("F3", Key_F3);
|
|
|
|
|
k.insert("F4", Key_F4);
|
|
|
|
|
k.insert("F5", Key_F5);
|
|
|
|
|
k.insert("F6", Key_F6);
|
|
|
|
|
k.insert("F7", Key_F7);
|
|
|
|
|
k.insert("F8", Key_F8);
|
|
|
|
|
k.insert("F9", Key_F9);
|
|
|
|
|
k.insert("F10", Key_F10);
|
|
|
|
|
|
|
|
|
|
k.insert("F11", Key_F11);
|
|
|
|
|
k.insert("F12", Key_F12);
|
|
|
|
|
k.insert("F13", Key_F13);
|
|
|
|
|
k.insert("F14", Key_F14);
|
|
|
|
|
k.insert("F15", Key_F15);
|
|
|
|
|
k.insert("F16", Key_F16);
|
|
|
|
|
k.insert("F17", Key_F17);
|
|
|
|
|
k.insert("F18", Key_F18);
|
|
|
|
|
k.insert("F19", Key_F19);
|
|
|
|
|
k.insert("F20", Key_F20);
|
|
|
|
|
|
|
|
|
|
k.insert("F21", Key_F21);
|
|
|
|
|
k.insert("F22", Key_F22);
|
|
|
|
|
k.insert("F23", Key_F23);
|
|
|
|
|
k.insert("F24", Key_F24);
|
|
|
|
|
k.insert("F25", Key_F25);
|
|
|
|
|
k.insert("F26", Key_F26);
|
|
|
|
|
k.insert("F27", Key_F27);
|
|
|
|
|
k.insert("F28", Key_F28);
|
|
|
|
|
k.insert("F29", Key_F29);
|
|
|
|
|
k.insert("F30", Key_F30);
|
|
|
|
|
|
|
|
|
|
k.insert("F31", Key_F31);
|
|
|
|
|
k.insert("F32", Key_F32);
|
|
|
|
|
k.insert("F33", Key_F33);
|
|
|
|
|
k.insert("F34", Key_F34);
|
|
|
|
|
k.insert("F35", Key_F35);
|
|
|
|
|
|
|
|
|
|
k.insert("INSERT", Key_Insert);
|
|
|
|
|
k.insert("INS", Key_Insert);
|
|
|
|
|
k.insert("KINSERT", Key_Insert);
|
|
|
|
|
k.insert("HOME", Key_Home);
|
|
|
|
|
k.insert("END", Key_End);
|
|
|
|
|
k.insert("PAGEUP", Key_PageUp);
|
|
|
|
|
k.insert("PAGEDOWN", Key_PageDown);
|
|
|
|
|
|
|
|
|
|
k.insert("KPLUS", Key_Plus);
|
|
|
|
|
k.insert("KMINUS", Key_Minus);
|
|
|
|
|
k.insert("KDIVIDE", Key_Slash);
|
|
|
|
|
k.insert("KMULTIPLY", Key_Asterisk);
|
|
|
|
|
k.insert("KENTER", Key_Enter);
|
|
|
|
|
k.insert("KPOINT", Key_Period);
|
|
|
|
|
|
|
|
|
|
return k;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Input parseVimKeyName(const QString &keyName)
|
|
|
|
|
{
|
|
|
|
|
if (keyName.length() == 1)
|
|
|
|
|
return Input(keyName.at(0));
|
|
|
|
|
|
|
|
|
|
const QStringList keys = keyName.split('-');
|
|
|
|
|
const int len = keys.length();
|
|
|
|
|
|
|
|
|
|
if (len == 1 && keys.at(0) == _("nop"))
|
|
|
|
|
return Nop;
|
|
|
|
|
|
|
|
|
|
int mods = NoModifier;
|
|
|
|
|
for (int i = 0; i < len - 1; ++i) {
|
|
|
|
|
const QString &key = keys[i].toUpper();
|
|
|
|
|
if (key == "S")
|
|
|
|
|
mods |= Qt::ShiftModifier;
|
|
|
|
|
else if (key == "C")
|
2012-09-07 13:31:29 +02:00
|
|
|
mods |= HostOsInfo::controlModifier();
|
2012-09-01 07:47:25 +02:00
|
|
|
else
|
|
|
|
|
return Input();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!keys.isEmpty()) {
|
|
|
|
|
const QString key = keys.last();
|
|
|
|
|
if (key.length() == 1) {
|
|
|
|
|
// simple character
|
|
|
|
|
QChar c = key.at(0).toUpper();
|
|
|
|
|
return Input(c.unicode(), mods, QString(c));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find key name
|
|
|
|
|
static const QMap<QString, int> k = vimKeyNames();
|
|
|
|
|
QMap<QString, int>::ConstIterator it = k.constFind(key.toUpper());
|
|
|
|
|
if (it != k.end())
|
2012-09-21 13:54:38 +02:00
|
|
|
return Input(*it, mods, *it <= 0x7f ? QString(QChar::fromLatin1(*it)) : QString(""));
|
2012-09-01 07:47:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Input();
|
2011-12-08 22:47:29 +01:00
|
|
|
}
|
2010-05-04 11:00:40 +02:00
|
|
|
|
2010-05-07 17:32:46 +02:00
|
|
|
void Inputs::parseFrom(const QString &str)
|
|
|
|
|
{
|
|
|
|
|
const int n = str.size();
|
|
|
|
|
for (int i = 0; i < n; ++i) {
|
2012-09-01 07:47:25 +02:00
|
|
|
uint c = str.at(i).unicode();
|
|
|
|
|
if (c == '<') {
|
|
|
|
|
int j = str.indexOf('>', i);
|
|
|
|
|
Input input;
|
|
|
|
|
if (j != -1)
|
|
|
|
|
input = parseVimKeyName(str.mid(i+1, j - i - 1));
|
|
|
|
|
if (input.isValid()) {
|
|
|
|
|
append(input);
|
|
|
|
|
i = j;
|
2010-05-07 17:32:46 +02:00
|
|
|
} else {
|
2012-09-01 07:47:25 +02:00
|
|
|
append(Input(QLatin1Char(c)));
|
2010-05-07 17:32:46 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2012-09-01 07:47:25 +02:00
|
|
|
append(Input(QLatin1Char(c)));
|
2010-05-07 17:32:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2012-09-09 10:32:45 +02:00
|
|
|
class History
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
History() : m_items(QString()), m_index(0) {}
|
|
|
|
|
void append(const QString &item);
|
|
|
|
|
const QString &move(const QStringRef &prefix, int skip);
|
|
|
|
|
const QString ¤t() const { return m_items[m_index]; }
|
|
|
|
|
const QStringList &items() const { return m_items; }
|
|
|
|
|
void restart() { m_index = m_items.size() - 1; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Last item is always empty or current search prefix.
|
|
|
|
|
QStringList m_items;
|
|
|
|
|
int m_index;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void History::append(const QString &item)
|
|
|
|
|
{
|
|
|
|
|
if (item.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
m_items.pop_back();
|
|
|
|
|
m_items.removeAll(item);
|
|
|
|
|
m_items << item << QString();
|
|
|
|
|
restart();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QString &History::move(const QStringRef &prefix, int skip)
|
|
|
|
|
{
|
|
|
|
|
if (!current().startsWith(prefix))
|
|
|
|
|
restart();
|
|
|
|
|
|
|
|
|
|
if (m_items.last() != prefix)
|
|
|
|
|
m_items[m_items.size() - 1] = prefix.toString();
|
|
|
|
|
|
|
|
|
|
int i = m_index + skip;
|
|
|
|
|
if (!prefix.isEmpty())
|
|
|
|
|
for (; i >= 0 && i < m_items.size() && !m_items[i].startsWith(prefix); i += skip);
|
|
|
|
|
if (i >= 0 && i < m_items.size())
|
|
|
|
|
m_index = i;
|
|
|
|
|
|
|
|
|
|
return current();
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-17 17:44:05 +02:00
|
|
|
// Command line buffer with prompt (i.e. :, / or ? characters), text contents and cursor position.
|
2011-07-15 13:22:38 +02:00
|
|
|
class CommandBuffer
|
|
|
|
|
{
|
|
|
|
|
public:
|
2012-09-01 07:47:25 +02:00
|
|
|
CommandBuffer() : m_pos(0), m_userPos(0), m_historyAutoSave(true) {}
|
2011-07-15 13:22:38 +02:00
|
|
|
|
2012-09-09 10:32:45 +02:00
|
|
|
void setPrompt(const QChar &prompt) { m_prompt = prompt; }
|
2011-07-15 13:22:38 +02:00
|
|
|
void setContents(const QString &s) { m_buffer = s; m_pos = s.size(); }
|
2012-09-09 10:32:45 +02:00
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void setContents(const QString &s, int pos) { m_buffer = s; m_pos = m_userPos = pos; }
|
|
|
|
|
|
2012-09-09 10:32:45 +02:00
|
|
|
QStringRef userContents() const { return m_buffer.leftRef(m_userPos); }
|
|
|
|
|
const QChar &prompt() const { return m_prompt; }
|
|
|
|
|
const QString &contents() const { return m_buffer; }
|
2011-07-15 13:22:38 +02:00
|
|
|
bool isEmpty() const { return m_buffer.isEmpty(); }
|
|
|
|
|
int cursorPos() const { return m_pos; }
|
|
|
|
|
|
2012-09-09 10:32:45 +02:00
|
|
|
void insertChar(QChar c) { m_buffer.insert(m_pos++, c); m_userPos = m_pos; }
|
|
|
|
|
void insertText(const QString &s)
|
|
|
|
|
{
|
|
|
|
|
m_buffer.insert(m_pos, s); m_userPos = m_pos = m_pos + s.size();
|
|
|
|
|
}
|
|
|
|
|
void deleteChar() { if (m_pos) m_buffer.remove(--m_pos, 1); m_userPos = m_pos; }
|
|
|
|
|
|
|
|
|
|
void moveLeft() { if (m_pos) m_userPos = --m_pos; }
|
|
|
|
|
void moveRight() { if (m_pos < m_buffer.size()) m_userPos = ++m_pos; }
|
|
|
|
|
void moveStart() { m_userPos = m_pos = 0; }
|
|
|
|
|
void moveEnd() { m_userPos = m_pos = m_buffer.size(); }
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
void setHistoryAutoSave(bool autoSave) { m_historyAutoSave = autoSave; }
|
2012-09-09 10:32:45 +02:00
|
|
|
void historyDown() { setContents(m_history.move(userContents(), 1)); }
|
|
|
|
|
void historyUp() { setContents(m_history.move(userContents(), -1)); }
|
|
|
|
|
const QStringList &historyItems() const { return m_history.items(); }
|
|
|
|
|
void historyPush(const QString &item = QString())
|
|
|
|
|
{
|
|
|
|
|
m_history.append(item.isNull() ? contents() : item);
|
|
|
|
|
}
|
2011-07-15 13:22:38 +02:00
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
if (m_historyAutoSave)
|
|
|
|
|
historyPush();
|
|
|
|
|
m_buffer.clear();
|
|
|
|
|
m_userPos = m_pos = 0;
|
|
|
|
|
}
|
2011-07-15 13:22:38 +02:00
|
|
|
|
|
|
|
|
QString display() const
|
|
|
|
|
{
|
2012-09-09 10:32:45 +02:00
|
|
|
QString msg(m_prompt);
|
2011-07-15 13:22:38 +02:00
|
|
|
for (int i = 0; i != m_buffer.size(); ++i) {
|
|
|
|
|
const QChar c = m_buffer.at(i);
|
|
|
|
|
if (c.unicode() < 32) {
|
|
|
|
|
msg += '^';
|
2012-09-09 10:32:45 +02:00
|
|
|
msg += QLatin1Char(c.unicode() + 64);
|
2011-07-15 13:22:38 +02:00
|
|
|
} else {
|
|
|
|
|
msg += c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return msg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool handleInput(const Input &input)
|
|
|
|
|
{
|
|
|
|
|
if (input.isKey(Key_Left)) {
|
|
|
|
|
moveLeft();
|
|
|
|
|
} else if (input.isKey(Key_Right)) {
|
|
|
|
|
moveRight();
|
|
|
|
|
} else if (input.isKey(Key_Home)) {
|
|
|
|
|
moveStart();
|
|
|
|
|
} else if (input.isKey(Key_End)) {
|
|
|
|
|
moveEnd();
|
|
|
|
|
} else if (input.isKey(Key_Delete)) {
|
|
|
|
|
if (m_pos < m_buffer.size())
|
|
|
|
|
m_buffer.remove(m_pos, 1);
|
2012-09-09 10:32:45 +02:00
|
|
|
else
|
|
|
|
|
deleteChar();
|
2011-07-15 13:22:38 +02:00
|
|
|
} else if (!input.text().isEmpty()) {
|
|
|
|
|
insertText(input.text());
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QString m_buffer;
|
2012-09-09 10:32:45 +02:00
|
|
|
QChar m_prompt;
|
|
|
|
|
History m_history;
|
2011-07-15 13:22:38 +02:00
|
|
|
int m_pos;
|
2012-09-09 10:32:45 +02:00
|
|
|
int m_userPos; // last position of inserted text (for retrieving history items)
|
2012-09-01 07:47:25 +02:00
|
|
|
bool m_historyAutoSave; // store items to history on clear()?
|
2011-07-15 13:22:38 +02:00
|
|
|
};
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// Mappings for a specific mode (trie structure)
|
|
|
|
|
class ModeMapping : public QMap<Input, ModeMapping>
|
2010-03-26 13:22:06 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2012-09-01 07:47:25 +02:00
|
|
|
const Inputs &value() const { return m_value; }
|
|
|
|
|
void setValue(const Inputs &value) { m_value = value; }
|
|
|
|
|
private:
|
|
|
|
|
Inputs m_value;
|
|
|
|
|
};
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// Mappings for all modes
|
|
|
|
|
typedef QHash<char, ModeMapping> Mappings;
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// Iterator for mappings
|
|
|
|
|
class MappingsIterator : public QVector<ModeMapping::Iterator>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
MappingsIterator(Mappings *mappings, char mode = -1, const Inputs &inputs = Inputs())
|
|
|
|
|
: m_parent(mappings)
|
2010-03-26 13:22:06 +01:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
reset(mode);
|
|
|
|
|
walk(inputs);
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// Reset iterator state. Keep previous mode if 0.
|
|
|
|
|
void reset(char mode = 0)
|
2010-03-26 13:22:06 +01:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
clear();
|
|
|
|
|
m_lastValid = -1;
|
|
|
|
|
m_invalidInputCount = 0;
|
|
|
|
|
if (mode != 0) {
|
|
|
|
|
m_mode = mode;
|
|
|
|
|
if (mode != -1)
|
|
|
|
|
m_modeMapping = m_parent->find(mode);
|
|
|
|
|
}
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
bool isValid() const { return !empty(); }
|
|
|
|
|
|
|
|
|
|
// Return true if mapping can be extended.
|
|
|
|
|
bool canExtend() const { return isValid() && !last()->empty(); }
|
|
|
|
|
|
|
|
|
|
// Return true if this mapping can be used.
|
|
|
|
|
bool isComplete() const { return m_lastValid != -1; }
|
|
|
|
|
|
|
|
|
|
// Return size of current map.
|
|
|
|
|
int mapLength() const { return m_lastValid + 1; }
|
|
|
|
|
|
|
|
|
|
int invalidInputCount() const { return m_invalidInputCount; }
|
|
|
|
|
|
|
|
|
|
bool walk(const Input &input)
|
2010-03-26 13:22:06 +01:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
if (m_modeMapping == m_parent->end())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!input.isValid()) {
|
|
|
|
|
m_invalidInputCount += 1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ModeMapping::Iterator it;
|
|
|
|
|
if (isValid()) {
|
|
|
|
|
it = last()->find(input);
|
|
|
|
|
if (it == last()->end())
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
it = m_modeMapping->find(input);
|
|
|
|
|
if (it == m_modeMapping->end())
|
|
|
|
|
return false;
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
2012-09-01 07:47:25 +02:00
|
|
|
|
|
|
|
|
if (!it->value().isEmpty())
|
|
|
|
|
m_lastValid = size();
|
|
|
|
|
append(it);
|
|
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
bool walk(const Inputs &inputs)
|
2010-03-26 13:22:06 +01:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
foreach (const Input &input, inputs) {
|
|
|
|
|
if (!walk(input))
|
2010-03-26 13:22:06 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2012-09-01 07:47:25 +02:00
|
|
|
|
|
|
|
|
// Return current mapped value. Iterator must be valid.
|
|
|
|
|
const Inputs &inputs() const
|
|
|
|
|
{
|
|
|
|
|
return at(m_lastValid)->value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void remove()
|
|
|
|
|
{
|
|
|
|
|
if (isValid()) {
|
|
|
|
|
if (canExtend()) {
|
|
|
|
|
last()->setValue(Inputs());
|
|
|
|
|
} else {
|
|
|
|
|
if (size() > 1) {
|
|
|
|
|
while (last()->empty()) {
|
|
|
|
|
at(size() - 2)->erase(last());
|
|
|
|
|
pop_back();
|
|
|
|
|
if (size() == 1 || !last()->value().isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (last()->empty() && last()->value().isEmpty())
|
|
|
|
|
m_modeMapping->erase(last());
|
|
|
|
|
} else if (last()->empty() && !last()->value().isEmpty()) {
|
|
|
|
|
m_modeMapping->erase(last());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setInputs(const Inputs &key, const Inputs &inputs, bool unique = false)
|
|
|
|
|
{
|
|
|
|
|
ModeMapping *current = &(*m_parent)[m_mode];
|
|
|
|
|
foreach (const Input &input, key)
|
|
|
|
|
current = &(*current)[input];
|
|
|
|
|
if (!unique || current->value().isEmpty())
|
|
|
|
|
current->setValue(inputs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Mappings *m_parent;
|
|
|
|
|
Mappings::Iterator m_modeMapping;
|
|
|
|
|
int m_lastValid;
|
|
|
|
|
int m_invalidInputCount;
|
|
|
|
|
char m_mode;
|
2010-03-26 13:22:06 +01:00
|
|
|
};
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
// state of current mapping
|
|
|
|
|
struct MappingState {
|
|
|
|
|
MappingState()
|
|
|
|
|
: maxMapDepth(1000), noremap(false), silent(false) {}
|
|
|
|
|
MappingState(int depth, bool noremap, bool silent)
|
|
|
|
|
: maxMapDepth(depth), noremap(noremap), silent(silent) {}
|
|
|
|
|
int maxMapDepth;
|
|
|
|
|
bool noremap;
|
|
|
|
|
bool silent;
|
|
|
|
|
};
|
2010-05-05 15:50:05 +02:00
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
class FakeVimHandler::Private : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
public:
|
2009-01-23 15:12:04 +01:00
|
|
|
Private(FakeVimHandler *parent, QWidget *widget);
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2009-03-05 11:06:25 +01:00
|
|
|
EventResult handleEvent(QKeyEvent *ev);
|
|
|
|
|
bool wantsOverride(QKeyEvent *ev);
|
2010-03-18 17:45:15 +01:00
|
|
|
void handleCommand(const QString &cmd); // Sets m_tc + handleExCommand
|
2009-01-06 11:52:05 +01:00
|
|
|
void handleExCommand(const QString &cmd);
|
2010-03-18 17:45:15 +01:00
|
|
|
|
2009-03-30 16:54:25 +02:00
|
|
|
void installEventFilter();
|
2010-01-05 15:30:22 +01:00
|
|
|
void passShortcuts(bool enable);
|
2009-01-23 15:12:04 +01:00
|
|
|
void setupWidget();
|
2010-03-26 17:55:43 +01:00
|
|
|
void restoreWidget(int tabSize);
|
2009-01-23 15:12:04 +01:00
|
|
|
|
2009-01-09 17:31:20 +01:00
|
|
|
friend class FakeVimHandler;
|
2008-12-19 12:20:04 +01:00
|
|
|
|
|
|
|
|
void init();
|
2012-09-01 07:47:25 +02:00
|
|
|
EventResult handleKey(const Input &input);
|
|
|
|
|
EventResult handleDefaultKey(const Input &input);
|
|
|
|
|
Q_SLOT void handleMappedKeys();
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult handleInsertMode(const Input &);
|
2010-05-06 12:10:57 +02:00
|
|
|
EventResult handleReplaceMode(const Input &);
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult handleCommandMode(const Input &);
|
2011-05-16 17:21:43 +02:00
|
|
|
EventResult handleCommandMode1(const Input &);
|
2011-05-16 10:31:29 +02:00
|
|
|
EventResult handleCommandMode2(const Input &);
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult handleRegisterMode(const Input &);
|
2010-05-05 16:23:39 +02:00
|
|
|
EventResult handleExMode(const Input &);
|
2010-07-14 13:02:17 +02:00
|
|
|
EventResult handleOpenSquareSubMode(const Input &);
|
|
|
|
|
EventResult handleCloseSquareSubMode(const Input &);
|
2010-05-05 16:23:39 +02:00
|
|
|
EventResult handleSearchSubSubMode(const Input &);
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult handleCommandSubSubMode(const Input &);
|
2012-09-28 17:01:24 +02:00
|
|
|
void finishMovement(const QString &dotCommandMovement = QString());
|
|
|
|
|
void finishMovement(const QString &dotCommandMovement, int count);
|
2010-01-21 17:38:24 +01:00
|
|
|
void resetCommandMode();
|
2012-09-10 22:10:23 +02:00
|
|
|
void search(const SearchData &sd, bool showMessages = true);
|
2012-09-01 10:44:02 +02:00
|
|
|
void searchNext(bool forward = true);
|
2010-07-14 13:02:17 +02:00
|
|
|
void searchBalanced(bool forward, QChar needle, QChar other);
|
2009-03-12 18:05:36 +01:00
|
|
|
void highlightMatches(const QString &needle);
|
2010-01-21 17:23:30 +01:00
|
|
|
void stopIncrementalFind();
|
2012-09-10 22:10:23 +02:00
|
|
|
void updateFind(bool isComplete);
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2008-12-25 22:41:09 +01:00
|
|
|
int mvCount() const { return m_mvcount.isEmpty() ? 1 : m_mvcount.toInt(); }
|
|
|
|
|
int opCount() const { return m_opcount.isEmpty() ? 1 : m_opcount.toInt(); }
|
|
|
|
|
int count() const { return mvCount() * opCount(); }
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextBlock block() const { return cursor().block(); }
|
|
|
|
|
int leftDist() const { return position() - block().position(); }
|
|
|
|
|
int rightDist() const { return block().length() - leftDist() - 1; }
|
2012-08-19 19:08:04 +02:00
|
|
|
bool atBlockStart() const { return cursor().atBlockStart(); }
|
2010-09-14 14:04:13 +02:00
|
|
|
bool atBlockEnd() const { return cursor().atBlockEnd(); }
|
|
|
|
|
bool atEndOfLine() const { return atBlockEnd() && block().length() > 1; }
|
2012-08-19 19:08:04 +02:00
|
|
|
bool atDocumentEnd() const { return cursor().atEnd(); }
|
|
|
|
|
bool atDocumentStart() const { return cursor().atStart(); }
|
|
|
|
|
|
|
|
|
|
bool atEmptyLine(const QTextCursor &tc = QTextCursor()) const;
|
|
|
|
|
bool atBoundary(bool end, bool simple, bool onlyWords = false,
|
|
|
|
|
const QTextCursor &tc = QTextCursor()) const;
|
|
|
|
|
bool atWordBoundary(bool end, bool simple, const QTextCursor &tc = QTextCursor()) const;
|
|
|
|
|
bool atWordStart(bool simple, const QTextCursor &tc = QTextCursor()) const;
|
|
|
|
|
bool atWordEnd(bool simple, const QTextCursor &tc = QTextCursor()) const;
|
|
|
|
|
bool isFirstNonBlankOnLine(int pos);
|
2008-12-19 16:20:39 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
int lastPositionInDocument() const; // Returns last valid position in doc.
|
2009-02-05 17:06:45 +01:00
|
|
|
int firstPositionInLine(int line) const; // 1 based line, 0 based pos
|
|
|
|
|
int lastPositionInLine(int line) const; // 1 based line, 0 based pos
|
2009-01-06 11:42:44 +01:00
|
|
|
int lineForPosition(int pos) const; // 1 based line, 0 based pos
|
2009-12-09 17:40:00 +01:00
|
|
|
QString lineContents(int line) const; // 1 based line
|
2010-05-11 14:26:37 +02:00
|
|
|
void setLineContents(int line, const QString &contents); // 1 based line
|
2012-07-14 16:56:37 +02:00
|
|
|
int blockBoundary(const QString &left, const QString &right,
|
2012-08-14 18:53:33 +02:00
|
|
|
bool end, int count) const; // end or start position of current code block
|
2008-12-25 19:11:21 +01:00
|
|
|
|
2009-01-06 11:11:31 +01:00
|
|
|
int linesOnScreen() const;
|
|
|
|
|
int columnsOnScreen() const;
|
2009-12-11 13:24:53 +01:00
|
|
|
int linesInDocument() const;
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
// The following use all zero-based counting.
|
2009-12-11 13:24:53 +01:00
|
|
|
int cursorLineOnScreen() const;
|
2010-07-06 10:12:21 +02:00
|
|
|
int cursorLine() const;
|
|
|
|
|
int physicalCursorColumn() const; // as stored in the data
|
|
|
|
|
int logicalCursorColumn() const; // as visible on screen
|
|
|
|
|
int physicalToLogicalColumn(int physical, const QString &text) const;
|
|
|
|
|
int logicalToPhysicalColumn(int logical, const QString &text) const;
|
|
|
|
|
Column cursorColumn() const; // as visible on screen
|
|
|
|
|
int firstVisibleLine() const;
|
|
|
|
|
void scrollToLine(int line);
|
2009-03-20 08:44:52 +01:00
|
|
|
void scrollUp(int count);
|
|
|
|
|
void scrollDown(int count) { scrollUp(-count); }
|
2008-12-25 16:27:47 +01:00
|
|
|
|
2009-07-13 14:04:47 +02:00
|
|
|
CursorPosition cursorPosition() const
|
2010-07-06 10:12:21 +02:00
|
|
|
{ return CursorPosition(position(), firstVisibleLine()); }
|
2009-07-13 14:04:47 +02:00
|
|
|
void setCursorPosition(const CursorPosition &p)
|
2010-07-06 10:12:21 +02:00
|
|
|
{ setPosition(p.position); scrollToLine(p.scrollLine); }
|
2009-07-13 14:04:47 +02:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
// Helper functions for indenting/
|
2010-01-06 14:57:46 +01:00
|
|
|
bool isElectricCharacter(QChar c) const;
|
2010-01-06 14:57:46 +01:00
|
|
|
void indentSelectedText(QChar lastTyped = QChar());
|
2010-06-02 15:27:10 +02:00
|
|
|
void indentText(const Range &range, QChar lastTyped = QChar());
|
2009-03-06 13:03:33 +01:00
|
|
|
void shiftRegionLeft(int repeat = 1);
|
|
|
|
|
void shiftRegionRight(int repeat = 1);
|
2008-12-26 10:36:40 +01:00
|
|
|
|
2008-12-19 14:35:57 +01:00
|
|
|
void moveToFirstNonBlankOnLine();
|
2012-08-26 18:39:48 +02:00
|
|
|
void moveToFirstNonBlankOnLine(QTextCursor *tc);
|
2009-04-03 14:58:41 +02:00
|
|
|
void moveToTargetColumn();
|
2009-06-11 15:41:20 +02:00
|
|
|
void setTargetColumn() {
|
2010-07-06 10:12:21 +02:00
|
|
|
m_targetColumn = logicalCursorColumn();
|
2010-01-21 17:38:31 +01:00
|
|
|
m_visualTargetColumn = m_targetColumn;
|
2009-06-11 15:41:20 +02:00
|
|
|
//qDebug() << "TARGET: " << m_targetColumn;
|
|
|
|
|
}
|
2009-01-13 12:35:43 +01:00
|
|
|
void moveToMatchingParanthesis();
|
2012-08-19 19:08:04 +02:00
|
|
|
void moveToBoundary(bool simple, bool forward = true);
|
|
|
|
|
void moveToNextBoundary(bool end, int count, bool simple, bool forward);
|
|
|
|
|
void moveToNextBoundaryStart(int count, bool simple, bool forward = true);
|
|
|
|
|
void moveToNextBoundaryEnd(int count, bool simple, bool forward = true);
|
|
|
|
|
void moveToBoundaryStart(int count, bool simple, bool forward = true);
|
|
|
|
|
void moveToBoundaryEnd(int count, bool simple, bool forward = true);
|
|
|
|
|
void moveToNextWord(bool end, int count, bool simple, bool forward, bool emptyLines);
|
|
|
|
|
void moveToNextWordStart(int count, bool simple, bool forward = true, bool emptyLines = true);
|
|
|
|
|
void moveToNextWordEnd(int count, bool simple, bool forward = true, bool emptyLines = true);
|
|
|
|
|
void moveToWordStart(int count, bool simple, bool forward = true, bool emptyLines = true);
|
|
|
|
|
void moveToWordEnd(int count, bool simple, bool forward = true, bool emptyLines = true);
|
2009-01-16 14:11:44 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
// Convenience wrappers to reduce line noise.
|
2009-04-16 09:18:09 +02:00
|
|
|
void moveToStartOfLine();
|
2009-04-08 16:05:24 +02:00
|
|
|
void moveToEndOfLine();
|
2009-07-03 11:22:18 +02:00
|
|
|
void moveBehindEndOfLine();
|
2009-04-08 16:05:24 +02:00
|
|
|
void moveUp(int n = 1) { moveDown(-n); }
|
2010-09-14 16:58:31 +02:00
|
|
|
void moveDown(int n = 1);
|
2010-09-14 14:04:13 +02:00
|
|
|
void dump(const char *msg) const {
|
|
|
|
|
qDebug() << msg << "POS: " << anchor() << position()
|
|
|
|
|
<< "EXT: " << m_oldExternalAnchor << m_oldExternalPosition
|
|
|
|
|
<< "INT: " << m_oldInternalAnchor << m_oldInternalPosition
|
2010-09-14 16:58:31 +02:00
|
|
|
<< "VISUAL: " << m_visualMode;
|
2010-09-14 14:04:13 +02:00
|
|
|
}
|
|
|
|
|
void moveRight(int n = 1) {
|
|
|
|
|
//dump("RIGHT 1");
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.movePosition(Right, KeepAnchor, n);
|
|
|
|
|
setCursor(tc);
|
2010-09-14 14:04:13 +02:00
|
|
|
//dump("RIGHT 2");
|
|
|
|
|
}
|
|
|
|
|
void moveLeft(int n = 1) {
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.movePosition(Left, KeepAnchor, n);
|
|
|
|
|
setCursor(tc);
|
2010-09-14 14:04:13 +02:00
|
|
|
}
|
2010-09-13 15:23:20 +02:00
|
|
|
void setAnchor() {
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setPosition(tc.position(), MoveAnchor);
|
|
|
|
|
setCursor(tc);
|
2010-09-13 15:23:20 +02:00
|
|
|
}
|
|
|
|
|
void setAnchor(int position) {
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setPosition(tc.anchor(), MoveAnchor);
|
|
|
|
|
tc.setPosition(position, KeepAnchor);
|
|
|
|
|
setCursor(tc);
|
2010-09-13 15:23:20 +02:00
|
|
|
}
|
|
|
|
|
void setPosition(int position) {
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setPosition(position, KeepAnchor);
|
|
|
|
|
setCursor(tc);
|
2010-09-13 15:23:20 +02:00
|
|
|
}
|
2010-09-14 14:04:13 +02:00
|
|
|
void setAnchorAndPosition(int anchor, int position) {
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setPosition(anchor, MoveAnchor);
|
|
|
|
|
tc.setPosition(position, KeepAnchor);
|
|
|
|
|
setCursor(tc);
|
2010-09-13 15:23:20 +02:00
|
|
|
}
|
|
|
|
|
QTextCursor cursor() const { return EDITOR(textCursor()); }
|
|
|
|
|
void setCursor(const QTextCursor &tc) { EDITOR(setTextCursor(tc)); }
|
2009-01-16 16:15:01 +01:00
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
bool handleFfTt(QString key);
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
// Helper function for handleExCommand returning 1 based line index.
|
2008-12-28 02:15:26 +01:00
|
|
|
int readLineCode(QString &cmd);
|
|
|
|
|
|
2009-01-07 17:41:09 +01:00
|
|
|
void enterInsertMode();
|
2010-05-06 12:10:57 +02:00
|
|
|
void enterReplaceMode();
|
2009-01-06 13:03:59 +01:00
|
|
|
void enterCommandMode();
|
2009-01-26 10:31:49 +01:00
|
|
|
void enterExMode();
|
2012-09-10 22:10:23 +02:00
|
|
|
void showMessage(MessageLevel level, const QString &msg);
|
|
|
|
|
void clearMessage() { showMessage(MessageInfo, QString()); }
|
2009-01-15 17:29:30 +01:00
|
|
|
void notImplementedYet();
|
2009-01-07 17:41:09 +01:00
|
|
|
void updateMiniBuffer();
|
|
|
|
|
void updateSelection();
|
2012-09-27 21:09:13 +02:00
|
|
|
void updateHighlights();
|
2010-09-13 15:23:20 +02:00
|
|
|
void updateCursorShape();
|
2009-01-09 12:21:53 +01:00
|
|
|
QWidget *editor() const;
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextDocument *document() const { return EDITOR(document()); }
|
2009-03-12 14:36:58 +01:00
|
|
|
QChar characterAtCursor() const
|
2010-09-13 15:23:20 +02:00
|
|
|
{ return document()->characterAt(position()); }
|
2012-09-29 19:09:08 +02:00
|
|
|
|
|
|
|
|
void joinPreviousEditBlock();
|
|
|
|
|
void beginEditBlock(bool rememberPosition = true);
|
|
|
|
|
void beginLargeEditBlock() { beginEditBlock(false); }
|
|
|
|
|
void endEditBlock();
|
2012-08-26 18:39:48 +02:00
|
|
|
void breakEditBlock() { m_breakEditBlock = true; }
|
2009-01-06 13:03:59 +01:00
|
|
|
|
2009-12-11 18:59:05 +01:00
|
|
|
bool isVisualMode() const { return m_visualMode != NoVisualMode; }
|
|
|
|
|
bool isNoVisualMode() const { return m_visualMode == NoVisualMode; }
|
|
|
|
|
bool isVisualCharMode() const { return m_visualMode == VisualCharMode; }
|
|
|
|
|
bool isVisualLineMode() const { return m_visualMode == VisualLineMode; }
|
|
|
|
|
bool isVisualBlockMode() const { return m_visualMode == VisualBlockMode; }
|
2012-09-01 07:47:25 +02:00
|
|
|
char currentModeCode() const;
|
2010-03-09 16:12:08 +01:00
|
|
|
void updateEditor();
|
2009-12-11 13:24:53 +01:00
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
void selectTextObject(bool simple, bool inner);
|
2010-03-18 17:45:15 +01:00
|
|
|
void selectWordTextObject(bool inner);
|
|
|
|
|
void selectWORDTextObject(bool inner);
|
|
|
|
|
void selectSentenceTextObject(bool inner);
|
|
|
|
|
void selectParagraphTextObject(bool inner);
|
|
|
|
|
void selectBlockTextObject(bool inner, char left, char right);
|
2011-12-27 14:54:49 +01:00
|
|
|
void changeNumberTextObject(bool doIncrement);
|
2012-07-19 21:12:13 +02:00
|
|
|
void selectQuotedStringTextObject(bool inner, const QString "e);
|
2010-03-18 17:45:15 +01:00
|
|
|
|
2010-05-07 19:46:16 +02:00
|
|
|
Q_SLOT void importSelection();
|
2010-08-11 13:41:54 +02:00
|
|
|
void exportSelection();
|
2010-07-06 09:20:40 +02:00
|
|
|
void insertInInsertMode(const QString &text);
|
2010-05-07 19:46:16 +02:00
|
|
|
|
2009-01-06 11:52:05 +01:00
|
|
|
public:
|
|
|
|
|
QTextEdit *m_textedit;
|
|
|
|
|
QPlainTextEdit *m_plaintextedit;
|
2009-01-09 12:51:10 +01:00
|
|
|
bool m_wasReadOnly; // saves read-only state of document
|
2009-01-06 11:52:05 +01:00
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
FakeVimHandler *q;
|
|
|
|
|
Mode m_mode;
|
2009-03-05 11:06:25 +01:00
|
|
|
bool m_passing; // let the core see the next event
|
2011-12-26 15:16:37 +01:00
|
|
|
bool m_firstKeyPending;
|
2008-12-19 12:20:04 +01:00
|
|
|
SubMode m_submode;
|
2008-12-26 00:18:03 +01:00
|
|
|
SubSubMode m_subsubmode;
|
2010-04-28 14:00:44 +02:00
|
|
|
Input m_subsubdata;
|
2010-09-14 14:04:13 +02:00
|
|
|
int m_oldExternalPosition; // copy from last event to check for external changes
|
|
|
|
|
int m_oldExternalAnchor;
|
|
|
|
|
int m_oldInternalPosition; // copy from last event to check for external changes
|
|
|
|
|
int m_oldInternalAnchor;
|
2010-09-16 15:28:31 +02:00
|
|
|
int m_oldPosition; // FIXME: Merge with above.
|
2008-12-19 12:20:04 +01:00
|
|
|
int m_register;
|
2008-12-25 22:41:09 +01:00
|
|
|
QString m_mvcount;
|
|
|
|
|
QString m_opcount;
|
2009-08-11 14:39:44 +02:00
|
|
|
MoveType m_movetype;
|
|
|
|
|
RangeMode m_rangemode;
|
2010-02-12 15:24:54 +01:00
|
|
|
int m_visualInsertCount;
|
2008-12-19 12:20:04 +01:00
|
|
|
|
|
|
|
|
bool m_fakeEnd;
|
2010-01-21 17:42:46 +01:00
|
|
|
bool m_anchorPastEnd;
|
|
|
|
|
bool m_positionPastEnd; // '$' & 'l' in visual mode can move past eol
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2008-12-27 13:39:34 +01:00
|
|
|
int m_gflag; // whether current command started with 'g'
|
2009-01-08 13:16:04 +01:00
|
|
|
|
2008-12-28 01:02:54 +01:00
|
|
|
QString m_currentFileName;
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-10-26 10:56:32 +02:00
|
|
|
int m_findStartPosition;
|
2008-12-27 12:24:50 +01:00
|
|
|
QString m_lastInsertion;
|
2010-05-06 12:10:57 +02:00
|
|
|
QString m_lastDeletion;
|
2008-12-26 17:01:21 +01:00
|
|
|
|
2012-08-26 18:39:48 +02:00
|
|
|
bool m_breakEditBlock;
|
|
|
|
|
|
2010-09-13 15:23:20 +02:00
|
|
|
int anchor() const { return cursor().anchor(); }
|
|
|
|
|
int position() const { return cursor().position(); }
|
2009-08-11 14:39:44 +02:00
|
|
|
|
2010-05-06 15:20:30 +02:00
|
|
|
struct TransformationData
|
|
|
|
|
{
|
|
|
|
|
TransformationData(const QString &s, const QVariant &d)
|
|
|
|
|
: from(s), extraData(d) {}
|
|
|
|
|
QString from;
|
|
|
|
|
QString to;
|
|
|
|
|
QVariant extraData;
|
|
|
|
|
};
|
|
|
|
|
typedef void (Private::*Transformation)(TransformationData *td);
|
|
|
|
|
void transformText(const Range &range, Transformation transformation,
|
|
|
|
|
const QVariant &extraData = QVariant());
|
2010-01-21 17:38:26 +01:00
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
void insertText(const Register ®);
|
2009-08-11 14:39:44 +02:00
|
|
|
void removeText(const Range &range);
|
2010-05-06 15:20:30 +02:00
|
|
|
void removeTransform(TransformationData *td);
|
2010-01-21 17:38:26 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void invertCase(const Range &range);
|
2010-05-06 15:20:30 +02:00
|
|
|
void invertCaseTransform(TransformationData *td);
|
2010-01-21 17:38:26 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void upCase(const Range &range);
|
2010-05-06 15:20:30 +02:00
|
|
|
void upCaseTransform(TransformationData *td);
|
2010-01-21 17:38:26 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void downCase(const Range &range);
|
2010-05-06 15:20:30 +02:00
|
|
|
void downCaseTransform(TransformationData *td);
|
2009-08-11 14:39:44 +02:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void replaceText(const Range &range, const QString &str);
|
2010-05-28 13:57:35 +02:00
|
|
|
void replaceByStringTransform(TransformationData *td);
|
|
|
|
|
void replaceByCharTransform(TransformationData *td);
|
2010-03-18 13:15:59 +01:00
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
QString selectText(const Range &range) const;
|
|
|
|
|
void setCurrentRange(const Range &range);
|
|
|
|
|
Range currentRange() const { return Range(position(), anchor(), m_rangemode); }
|
2011-03-28 13:24:25 +02:00
|
|
|
Range rangeFromCurrentLine() const;
|
2009-08-11 14:39:44 +02:00
|
|
|
|
|
|
|
|
void yankText(const Range &range, int toregister = '"');
|
|
|
|
|
|
|
|
|
|
void pasteText(bool afterCursor);
|
2009-02-05 17:06:45 +01:00
|
|
|
|
2009-04-01 15:11:26 +02:00
|
|
|
// undo handling
|
2012-08-26 18:39:48 +02:00
|
|
|
int revision() const { return document()->availableUndoSteps(); }
|
2009-01-06 11:45:56 +01:00
|
|
|
void undo();
|
|
|
|
|
void redo();
|
2012-08-26 18:39:48 +02:00
|
|
|
void setUndoPosition(bool overwrite = true);
|
|
|
|
|
// revision -> state
|
|
|
|
|
QStack<State> m_undo;
|
|
|
|
|
QStack<State> m_redo;
|
2009-01-06 11:45:56 +01:00
|
|
|
|
2009-01-06 11:43:49 +01:00
|
|
|
// extra data for '.'
|
2009-04-08 16:05:24 +02:00
|
|
|
void replay(const QString &text, int count);
|
2010-05-05 15:50:05 +02:00
|
|
|
void setDotCommand(const QString &cmd) { g.dotCommand = cmd; }
|
|
|
|
|
void setDotCommand(const QString &cmd, int n) { g.dotCommand = cmd.arg(n); }
|
2012-09-28 17:01:24 +02:00
|
|
|
QString visualDotCommand() const;
|
2009-01-06 11:43:49 +01:00
|
|
|
|
2009-01-26 10:48:37 +01:00
|
|
|
// extra data for ';'
|
|
|
|
|
QString m_semicolonCount;
|
2010-04-28 14:00:44 +02:00
|
|
|
Input m_semicolonType; // 'f', 'F', 't', 'T'
|
|
|
|
|
QString m_semicolonKey;
|
2009-01-26 10:48:37 +01:00
|
|
|
|
2011-08-02 17:59:05 +02:00
|
|
|
// visual modes
|
|
|
|
|
void toggleVisualMode(VisualMode visualMode);
|
2009-01-06 11:52:05 +01:00
|
|
|
void leaveVisualMode();
|
|
|
|
|
VisualMode m_visualMode;
|
2010-09-14 14:04:13 +02:00
|
|
|
VisualMode m_oldVisualMode;
|
2009-01-06 11:42:44 +01:00
|
|
|
|
2008-12-28 03:07:52 +01:00
|
|
|
// marks as lines
|
2010-05-11 14:26:37 +02:00
|
|
|
int mark(int code) const;
|
|
|
|
|
void setMark(int code, int position);
|
2010-09-15 13:47:52 +02:00
|
|
|
typedef QHashIterator<int, QTextCursor> MarksIterator;
|
|
|
|
|
Marks m_marks;
|
2008-12-28 03:07:52 +01:00
|
|
|
|
2008-12-27 21:28:22 +01:00
|
|
|
// vi style configuration
|
2009-03-30 12:40:08 +02:00
|
|
|
QVariant config(int code) const { return theFakeVimSetting(code)->value(); }
|
|
|
|
|
bool hasConfig(int code) const { return config(code).toBool(); }
|
|
|
|
|
bool hasConfig(int code, const char *value) const // FIXME
|
|
|
|
|
{ return config(code).toString().contains(value); }
|
2008-12-23 21:34:21 +01:00
|
|
|
|
2010-01-21 17:38:31 +01:00
|
|
|
int m_targetColumn; // -1 if past end of line
|
|
|
|
|
int m_visualTargetColumn; // 'l' can move past eol in visual mode only
|
2009-01-28 19:22:54 +01:00
|
|
|
|
2009-04-03 11:54:29 +02:00
|
|
|
// auto-indent
|
2009-12-11 13:24:53 +01:00
|
|
|
QString tabExpand(int len) const;
|
2010-03-09 16:44:36 +01:00
|
|
|
Column indentation(const QString &line) const;
|
2009-04-03 11:54:29 +02:00
|
|
|
void insertAutomaticIndentation(bool goingDown);
|
|
|
|
|
bool removeAutomaticIndentation(); // true if something removed
|
|
|
|
|
// number of autoindented characters
|
|
|
|
|
int m_justAutoIndented;
|
2009-04-03 14:58:41 +02:00
|
|
|
void handleStartOfLine();
|
2009-04-03 11:54:29 +02:00
|
|
|
|
2011-11-12 02:31:52 +01:00
|
|
|
// register handling
|
|
|
|
|
QString registerContents(int reg) const;
|
2012-08-09 17:32:39 +02:00
|
|
|
void setRegister(int reg, const QString &contents, RangeMode mode);
|
2011-11-12 02:31:52 +01:00
|
|
|
RangeMode registerRangeMode(int reg) const;
|
2012-08-02 19:35:45 +02:00
|
|
|
void getRegisterType(int reg, bool *isClipboard, bool *isSelection) const;
|
2011-11-12 02:31:52 +01:00
|
|
|
|
2009-01-28 19:22:54 +01:00
|
|
|
void recordJump();
|
2012-08-11 14:31:42 +02:00
|
|
|
void jump(int distance);
|
|
|
|
|
QStack<CursorPosition> m_jumpListUndo;
|
|
|
|
|
QStack<CursorPosition> m_jumpListRedo;
|
2011-11-28 15:43:57 +01:00
|
|
|
int m_lastChangePosition;
|
2009-03-12 18:05:36 +01:00
|
|
|
|
2012-09-27 21:09:13 +02:00
|
|
|
QList<QTextEdit::ExtraSelection> m_extraSelections;
|
2010-05-18 18:24:00 +02:00
|
|
|
QTextCursor m_searchCursor;
|
2012-09-01 10:44:02 +02:00
|
|
|
int m_searchStartPosition;
|
|
|
|
|
int m_searchFromScreenLine;
|
2010-05-11 14:26:37 +02:00
|
|
|
QString m_oldNeedle;
|
2011-11-28 17:59:30 +01:00
|
|
|
QString m_lastSubstituteFlags;
|
|
|
|
|
QRegExp m_lastSubstitutePattern;
|
|
|
|
|
QString m_lastSubstituteReplacement;
|
2012-08-11 10:59:29 +02:00
|
|
|
QTextCursor m_lastSelectionCursor;
|
|
|
|
|
VisualMode m_lastSelectionMode;
|
2010-03-19 14:31:21 +01:00
|
|
|
|
2012-09-29 19:09:08 +02:00
|
|
|
bool handleExCommandHelper(ExCommand &cmd); // Returns success.
|
2010-05-18 14:48:12 +02:00
|
|
|
bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin?
|
2010-05-11 14:26:37 +02:00
|
|
|
bool handleExBangCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExDeleteCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExGotoCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExHistoryCommand(const ExCommand &cmd);
|
2010-05-20 14:08:11 +02:00
|
|
|
bool handleExRegisterCommand(const ExCommand &cmd);
|
2010-05-11 14:26:37 +02:00
|
|
|
bool handleExMapCommand(const ExCommand &cmd);
|
2010-07-14 16:04:10 +02:00
|
|
|
bool handleExNohlsearchCommand(const ExCommand &cmd);
|
2010-05-11 14:26:37 +02:00
|
|
|
bool handleExNormalCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExReadCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExRedoCommand(const ExCommand &cmd);
|
2012-08-26 18:39:48 +02:00
|
|
|
bool handleExUndoCommand(const ExCommand &cmd);
|
2010-05-11 14:26:37 +02:00
|
|
|
bool handleExSetCommand(const ExCommand &cmd);
|
2010-05-18 14:48:12 +02:00
|
|
|
bool handleExShiftCommand(const ExCommand &cmd);
|
2010-05-11 14:26:37 +02:00
|
|
|
bool handleExSourceCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExSubstituteCommand(const ExCommand &cmd);
|
|
|
|
|
bool handleExWriteCommand(const ExCommand &cmd);
|
2011-04-05 16:32:18 +02:00
|
|
|
bool handleExEchoCommand(const ExCommand &cmd);
|
2010-04-16 16:30:45 +02:00
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
void timerEvent(QTimerEvent *ev);
|
2010-04-28 16:19:51 +02:00
|
|
|
|
|
|
|
|
void setupCharClass();
|
|
|
|
|
int charClass(QChar c, bool simple) const;
|
|
|
|
|
signed char m_charClass[256];
|
2010-07-06 09:20:40 +02:00
|
|
|
bool m_ctrlVActive;
|
2010-05-05 15:50:05 +02:00
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void miniBufferTextEdited(const QString &text, int cursorPos);
|
|
|
|
|
|
2010-05-05 15:50:05 +02:00
|
|
|
static struct GlobalData
|
|
|
|
|
{
|
2012-09-10 22:10:23 +02:00
|
|
|
GlobalData()
|
2012-10-03 16:40:05 +02:00
|
|
|
: mappings(), currentMap(&mappings), inputTimer(-1), currentMessageLevel(MessageInfo),
|
|
|
|
|
lastSearchForward(false), findPending(false)
|
2010-05-05 16:05:49 +02:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
// default mapping state - shouldn't be removed
|
|
|
|
|
mapStates << MappingState();
|
2012-09-17 17:44:05 +02:00
|
|
|
commandBuffer.setPrompt(':');
|
2010-05-05 16:05:49 +02:00
|
|
|
}
|
2010-05-05 15:50:05 +02:00
|
|
|
|
|
|
|
|
// Repetition.
|
|
|
|
|
QString dotCommand;
|
|
|
|
|
|
|
|
|
|
QHash<int, Register> registers;
|
|
|
|
|
|
|
|
|
|
// All mappings.
|
|
|
|
|
Mappings mappings;
|
2012-09-01 07:47:25 +02:00
|
|
|
|
|
|
|
|
// Input.
|
|
|
|
|
Inputs pendingInput;
|
|
|
|
|
MappingsIterator currentMap;
|
|
|
|
|
int inputTimer;
|
|
|
|
|
QStack<MappingState> mapStates;
|
2012-09-17 17:44:05 +02:00
|
|
|
|
|
|
|
|
// Command line buffers.
|
|
|
|
|
CommandBuffer commandBuffer;
|
|
|
|
|
CommandBuffer searchBuffer;
|
|
|
|
|
|
|
|
|
|
// Current mini buffer message.
|
|
|
|
|
QString currentMessage;
|
2012-09-10 22:10:23 +02:00
|
|
|
MessageLevel currentMessageLevel;
|
2012-10-03 16:40:05 +02:00
|
|
|
|
|
|
|
|
// Search state
|
|
|
|
|
QString lastSearch;
|
|
|
|
|
bool lastSearchForward;
|
|
|
|
|
bool findPending;
|
2010-05-05 15:50:05 +02:00
|
|
|
} g;
|
2008-12-19 12:20:04 +01:00
|
|
|
};
|
|
|
|
|
|
2010-05-05 15:50:05 +02:00
|
|
|
FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g;
|
2009-03-25 15:31:50 +01:00
|
|
|
|
2009-01-23 15:12:04 +01:00
|
|
|
FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-04-28 16:19:51 +02:00
|
|
|
//static PythonHighlighterRules pythonRules;
|
2008-12-19 12:20:04 +01:00
|
|
|
q = parent;
|
2009-01-23 15:12:04 +01:00
|
|
|
m_textedit = qobject_cast<QTextEdit *>(widget);
|
|
|
|
|
m_plaintextedit = qobject_cast<QPlainTextEdit *>(widget);
|
2010-09-14 14:04:13 +02:00
|
|
|
//new Highlighter(document(), &pythonRules);
|
2009-04-08 16:05:24 +02:00
|
|
|
init();
|
|
|
|
|
}
|
2009-01-23 15:12:04 +01:00
|
|
|
|
2009-04-08 16:05:24 +02:00
|
|
|
void FakeVimHandler::Private::init()
|
|
|
|
|
{
|
2008-12-19 12:20:04 +01:00
|
|
|
m_mode = CommandMode;
|
2008-12-26 00:18:03 +01:00
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
2009-03-05 11:06:25 +01:00
|
|
|
m_passing = false;
|
2011-12-26 15:16:37 +01:00
|
|
|
m_firstKeyPending = false;
|
2012-10-03 16:40:05 +02:00
|
|
|
g.findPending = false;
|
2010-10-26 10:56:32 +02:00
|
|
|
m_findStartPosition = -1;
|
2008-12-19 12:20:04 +01:00
|
|
|
m_fakeEnd = false;
|
2010-09-14 14:04:13 +02:00
|
|
|
m_positionPastEnd = false;
|
|
|
|
|
m_anchorPastEnd = false;
|
2012-10-03 16:40:05 +02:00
|
|
|
g.lastSearchForward = true;
|
2008-12-19 12:20:04 +01:00
|
|
|
m_register = '"';
|
2008-12-27 13:39:34 +01:00
|
|
|
m_gflag = false;
|
2009-01-06 11:52:05 +01:00
|
|
|
m_visualMode = NoVisualMode;
|
2010-09-14 14:04:13 +02:00
|
|
|
m_oldVisualMode = NoVisualMode;
|
2009-04-03 14:58:41 +02:00
|
|
|
m_targetColumn = 0;
|
2010-01-21 17:38:31 +01:00
|
|
|
m_visualTargetColumn = 0;
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2009-04-03 11:54:29 +02:00
|
|
|
m_justAutoIndented = 0;
|
2009-08-11 14:39:44 +02:00
|
|
|
m_rangemode = RangeCharMode;
|
2010-07-06 09:20:40 +02:00
|
|
|
m_ctrlVActive = false;
|
2010-09-14 14:04:13 +02:00
|
|
|
m_oldInternalAnchor = -1;
|
|
|
|
|
m_oldInternalPosition = -1;
|
|
|
|
|
m_oldExternalAnchor = -1;
|
|
|
|
|
m_oldExternalPosition = -1;
|
2010-09-16 15:28:31 +02:00
|
|
|
m_oldPosition = -1;
|
2011-11-28 15:43:57 +01:00
|
|
|
m_lastChangePosition = -1;
|
2012-08-26 18:39:48 +02:00
|
|
|
m_breakEditBlock = false;
|
2012-09-01 10:44:02 +02:00
|
|
|
m_searchStartPosition = 0;
|
|
|
|
|
m_searchFromScreenLine = 0;
|
2010-04-28 16:19:51 +02:00
|
|
|
|
|
|
|
|
setupCharClass();
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-05 11:06:25 +01:00
|
|
|
bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2009-03-05 11:06:25 +01:00
|
|
|
const int key = ev->key();
|
|
|
|
|
const int mods = ev->modifiers();
|
|
|
|
|
KEY_DEBUG("SHORTCUT OVERRIDE" << key << " PASSING: " << m_passing);
|
2009-01-09 12:51:10 +01:00
|
|
|
|
2010-03-18 13:15:59 +01:00
|
|
|
if (key == Key_Escape) {
|
2010-05-05 16:59:58 +02:00
|
|
|
if (m_subsubmode == SearchSubSubMode)
|
2010-05-04 17:58:53 +02:00
|
|
|
return true;
|
2011-08-03 11:58:59 +02:00
|
|
|
// Not sure this feels good. People often hit Esc several times.
|
|
|
|
|
if (isNoVisualMode()
|
|
|
|
|
&& m_mode == CommandMode
|
|
|
|
|
&& m_submode == NoSubMode
|
|
|
|
|
&& m_opcount.isEmpty()
|
|
|
|
|
&& m_mvcount.isEmpty())
|
2010-03-18 13:15:58 +01:00
|
|
|
return false;
|
|
|
|
|
return true;
|
2009-03-05 11:06:25 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-03 11:58:59 +02:00
|
|
|
// We are interested in overriding most Ctrl key combinations.
|
2012-09-07 13:31:29 +02:00
|
|
|
if (mods == int(HostOsInfo::controlModifier())
|
2010-09-24 09:07:08 +02:00
|
|
|
&& !config(ConfigPassControlKey).toBool()
|
2010-03-18 13:15:59 +01:00
|
|
|
&& ((key >= Key_A && key <= Key_Z && key != Key_K)
|
|
|
|
|
|| key == Key_BracketLeft || key == Key_BracketRight)) {
|
2009-10-16 11:30:46 +02:00
|
|
|
// Ctrl-K is special as it is the Core's default notion of Locator
|
2009-03-05 11:06:25 +01:00
|
|
|
if (m_passing) {
|
|
|
|
|
KEY_DEBUG(" PASSING CTRL KEY");
|
|
|
|
|
// We get called twice on the same key
|
|
|
|
|
//m_passing = false;
|
|
|
|
|
return false;
|
2009-01-09 17:57:48 +01:00
|
|
|
}
|
2009-03-05 11:06:25 +01:00
|
|
|
KEY_DEBUG(" NOT PASSING CTRL KEY");
|
|
|
|
|
//updateMiniBuffer();
|
|
|
|
|
return true;
|
2009-01-09 12:51:10 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-03 11:58:59 +02:00
|
|
|
// Let other shortcuts trigger.
|
2009-03-05 11:06:25 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
|
|
|
|
|
{
|
2010-04-28 14:00:44 +02:00
|
|
|
const int key = ev->key();
|
2009-03-05 11:06:25 +01:00
|
|
|
const int mods = ev->modifiers();
|
|
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
if (key == Key_Shift || key == Key_Alt || key == Key_Control
|
2009-03-05 11:06:25 +01:00
|
|
|
|| key == Key_Alt || key == Key_AltGr || key == Key_Meta)
|
|
|
|
|
{
|
|
|
|
|
KEY_DEBUG("PLAIN MODIFIER");
|
|
|
|
|
return EventUnhandled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_passing) {
|
2010-01-05 15:30:22 +01:00
|
|
|
passShortcuts(false);
|
2009-03-05 11:06:25 +01:00
|
|
|
KEY_DEBUG("PASSING PLAIN KEY..." << ev->key() << ev->text());
|
2010-04-28 14:00:44 +02:00
|
|
|
//if (input.is(',')) { // use ',,' to leave, too.
|
2009-03-05 11:06:25 +01:00
|
|
|
// qDebug() << "FINISHED...";
|
|
|
|
|
// return EventHandled;
|
|
|
|
|
//}
|
|
|
|
|
m_passing = false;
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
KEY_DEBUG(" PASS TO CORE");
|
|
|
|
|
return EventPassedToCore;
|
|
|
|
|
}
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2011-04-06 14:55:26 +02:00
|
|
|
bool inSnippetMode = false;
|
|
|
|
|
QMetaObject::invokeMethod(editor(),
|
|
|
|
|
"inSnippetMode", Q_ARG(bool *, &inSnippetMode));
|
|
|
|
|
|
|
|
|
|
if (inSnippetMode)
|
|
|
|
|
return EventPassedToCore;
|
|
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
// Fake "End of line"
|
2010-09-14 14:04:13 +02:00
|
|
|
//m_tc = cursor();
|
2008-12-26 18:29:38 +01:00
|
|
|
|
2010-09-13 13:53:18 +02:00
|
|
|
//bool hasBlock = false;
|
|
|
|
|
//emit q->requestHasBlockSelection(&hasBlock);
|
|
|
|
|
//qDebug() << "IMPORT BLOCK 2:" << hasBlock;
|
|
|
|
|
|
|
|
|
|
//if (0 && hasBlock) {
|
|
|
|
|
// (pos > anc) ? --pos : --anc;
|
|
|
|
|
|
2010-09-13 15:23:20 +02:00
|
|
|
importSelection();
|
|
|
|
|
|
2010-09-16 15:28:31 +02:00
|
|
|
// Position changed externally, e.g. by code completion.
|
2010-09-13 15:23:20 +02:00
|
|
|
if (position() != m_oldPosition) {
|
2009-04-03 14:58:41 +02:00
|
|
|
setTargetColumn();
|
2010-09-16 15:28:31 +02:00
|
|
|
//qDebug() << "POSITION CHANGED EXTERNALLY";
|
2009-12-15 13:38:20 +01:00
|
|
|
if (m_mode == InsertMode) {
|
2010-09-13 15:23:20 +02:00
|
|
|
int dist = position() - m_oldPosition;
|
2009-12-15 13:38:20 +01:00
|
|
|
// Try to compensate for code completion
|
2010-07-06 10:12:21 +02:00
|
|
|
if (dist > 0 && dist <= physicalCursorColumn()) {
|
2010-09-13 15:23:20 +02:00
|
|
|
Range range(m_oldPosition, position());
|
2010-05-12 11:18:18 +02:00
|
|
|
m_lastInsertion.append(selectText(range));
|
2009-12-15 13:38:20 +01:00
|
|
|
}
|
2010-02-19 13:01:39 +01:00
|
|
|
} else if (!isVisualMode()) {
|
|
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2009-12-15 13:38:20 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-09-16 15:28:31 +02:00
|
|
|
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setVisualNavigation(true);
|
2011-12-26 15:16:37 +01:00
|
|
|
if (m_firstKeyPending) {
|
|
|
|
|
m_firstKeyPending = false;
|
|
|
|
|
recordJump();
|
|
|
|
|
}
|
2012-08-11 14:31:42 +02:00
|
|
|
setCursor(tc);
|
2011-12-26 15:16:37 +01:00
|
|
|
|
2008-12-27 22:50:58 +01:00
|
|
|
if (m_fakeEnd)
|
2009-01-16 17:38:15 +01:00
|
|
|
moveRight();
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2011-04-07 17:59:12 +02:00
|
|
|
//if ((mods & RealControlModifier) != 0) {
|
2010-04-28 14:00:44 +02:00
|
|
|
// if (key >= Key_A && key <= Key_Z)
|
|
|
|
|
// key = shift(key); // make it lower case
|
|
|
|
|
// key = control(key);
|
|
|
|
|
//} else if (key >= Key_A && key <= Key_Z && (mods & Qt::ShiftModifier) == 0) {
|
|
|
|
|
// key = shift(key);
|
|
|
|
|
//}
|
2009-02-09 08:45:02 +01:00
|
|
|
|
2010-08-11 13:41:54 +02:00
|
|
|
//QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
|
2010-09-14 14:04:13 +02:00
|
|
|
// || !atBlockEnd() || block().length() <= 1,
|
2010-08-11 13:41:54 +02:00
|
|
|
// qDebug() << "Cursor at EOL before key handler");
|
2010-01-21 17:38:28 +01:00
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
EventResult result = handleKey(Input(key, mods, ev->text()));
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-08-11 13:41:54 +02:00
|
|
|
// The command might have destroyed the editor.
|
2010-01-22 13:56:50 +01:00
|
|
|
if (m_textedit || m_plaintextedit) {
|
|
|
|
|
// We fake vi-style end-of-line behaviour
|
|
|
|
|
m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode();
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-08-11 13:41:54 +02:00
|
|
|
//QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
|
2010-09-14 14:04:13 +02:00
|
|
|
// || !atBlockEnd() || block().length() <= 1,
|
2010-08-11 13:41:54 +02:00
|
|
|
// qDebug() << "Cursor at EOL after key handler");
|
2010-01-22 13:56:50 +01:00
|
|
|
if (m_fakeEnd)
|
|
|
|
|
moveLeft();
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-09-16 15:28:31 +02:00
|
|
|
m_oldPosition = position();
|
2010-09-15 16:19:25 +02:00
|
|
|
if (hasConfig(ConfigShowMarks))
|
|
|
|
|
updateSelection();
|
2010-05-10 16:30:46 +02:00
|
|
|
|
2010-09-15 16:19:25 +02:00
|
|
|
exportSelection();
|
2010-09-28 16:56:20 +02:00
|
|
|
updateCursorShape();
|
2010-09-15 16:19:25 +02:00
|
|
|
}
|
2010-08-11 13:41:54 +02:00
|
|
|
|
2009-03-05 11:06:25 +01:00
|
|
|
return result;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-30 16:54:25 +02:00
|
|
|
void FakeVimHandler::Private::installEventFilter()
|
|
|
|
|
{
|
2010-05-07 19:46:16 +02:00
|
|
|
EDITOR(viewport()->installEventFilter(q));
|
2009-03-30 16:54:25 +02:00
|
|
|
EDITOR(installEventFilter(q));
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-23 15:12:04 +01:00
|
|
|
void FakeVimHandler::Private::setupWidget()
|
|
|
|
|
{
|
|
|
|
|
enterCommandMode();
|
|
|
|
|
if (m_textedit) {
|
|
|
|
|
m_textedit->setLineWrapMode(QTextEdit::NoWrap);
|
|
|
|
|
} else if (m_plaintextedit) {
|
|
|
|
|
m_plaintextedit->setLineWrapMode(QPlainTextEdit::NoWrap);
|
|
|
|
|
}
|
2009-01-26 10:31:49 +01:00
|
|
|
m_wasReadOnly = EDITOR(isReadOnly());
|
2011-12-26 15:16:37 +01:00
|
|
|
m_firstKeyPending = true;
|
2009-02-05 17:06:45 +01:00
|
|
|
|
2010-03-09 16:12:08 +01:00
|
|
|
updateEditor();
|
2010-05-07 19:46:16 +02:00
|
|
|
importSelection();
|
|
|
|
|
updateMiniBuffer();
|
2010-09-13 15:23:20 +02:00
|
|
|
updateCursorShape();
|
2010-05-07 19:46:16 +02:00
|
|
|
}
|
2010-03-09 16:12:08 +01:00
|
|
|
|
2010-08-11 13:41:54 +02:00
|
|
|
void FakeVimHandler::Private::exportSelection()
|
|
|
|
|
{
|
|
|
|
|
int pos = position();
|
|
|
|
|
int anc = anchor();
|
2010-09-14 14:04:13 +02:00
|
|
|
m_oldInternalPosition = pos;
|
|
|
|
|
m_oldInternalAnchor = anc;
|
|
|
|
|
if (isVisualMode()) {
|
|
|
|
|
if (pos >= anc)
|
|
|
|
|
setAnchorAndPosition(anc, pos + 1);
|
|
|
|
|
else
|
|
|
|
|
setAnchorAndPosition(anc + 1, pos);
|
|
|
|
|
|
|
|
|
|
if (m_visualMode == VisualBlockMode) {
|
|
|
|
|
emit q->requestSetBlockSelection(false);
|
|
|
|
|
emit q->requestSetBlockSelection(true);
|
|
|
|
|
} else if (m_visualMode == VisualLineMode) {
|
|
|
|
|
const int posLine = lineForPosition(pos);
|
|
|
|
|
const int ancLine = lineForPosition(anc);
|
|
|
|
|
if (anc < pos) {
|
|
|
|
|
pos = lastPositionInLine(posLine);
|
|
|
|
|
anc = firstPositionInLine(ancLine);
|
|
|
|
|
} else {
|
|
|
|
|
pos = firstPositionInLine(posLine);
|
|
|
|
|
anc = lastPositionInLine(ancLine);
|
|
|
|
|
}
|
|
|
|
|
setAnchorAndPosition(anc, pos);
|
|
|
|
|
} else if (m_visualMode == VisualCharMode) {
|
|
|
|
|
/* Nothing */
|
2010-08-11 13:41:54 +02:00
|
|
|
} else {
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(false);
|
2010-08-11 13:41:54 +02:00
|
|
|
}
|
2010-09-14 14:04:13 +02:00
|
|
|
} else {
|
2012-09-27 21:09:13 +02:00
|
|
|
if (m_subsubmode == SearchSubSubMode && !m_searchCursor.isNull())
|
|
|
|
|
setCursor(m_searchCursor);
|
|
|
|
|
else
|
|
|
|
|
setAnchorAndPosition(pos, pos);
|
2010-08-11 13:41:54 +02:00
|
|
|
}
|
2010-09-14 14:04:13 +02:00
|
|
|
m_oldExternalPosition = position();
|
|
|
|
|
m_oldExternalAnchor = anchor();
|
|
|
|
|
m_oldVisualMode = m_visualMode;
|
2010-08-11 13:41:54 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-07 19:46:16 +02:00
|
|
|
void FakeVimHandler::Private::importSelection()
|
|
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
bool hasBlock = false;
|
|
|
|
|
emit q->requestHasBlockSelection(&hasBlock);
|
2010-09-14 14:04:13 +02:00
|
|
|
|
|
|
|
|
if (position() == m_oldExternalPosition
|
|
|
|
|
&& anchor() == m_oldExternalAnchor) {
|
|
|
|
|
// Undo drawing correction.
|
|
|
|
|
m_visualMode = m_oldVisualMode;
|
|
|
|
|
setAnchorAndPosition(m_oldInternalAnchor, m_oldInternalPosition);
|
|
|
|
|
//setMark('<', m_oldInternalAnchor);
|
|
|
|
|
//setMark('>', m_oldInternalPosition);
|
|
|
|
|
} else {
|
|
|
|
|
// Import new selection.
|
|
|
|
|
Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();
|
|
|
|
|
if (cursor().hasSelection()) {
|
2012-09-07 13:31:29 +02:00
|
|
|
if (mods & HostOsInfo::controlModifier())
|
2010-09-14 14:04:13 +02:00
|
|
|
m_visualMode = VisualBlockMode;
|
|
|
|
|
else if (mods & Qt::AltModifier)
|
|
|
|
|
m_visualMode = VisualBlockMode;
|
|
|
|
|
else if (mods & Qt::ShiftModifier)
|
|
|
|
|
m_visualMode = VisualLineMode;
|
|
|
|
|
else
|
|
|
|
|
m_visualMode = VisualCharMode;
|
|
|
|
|
} else {
|
|
|
|
|
m_visualMode = NoVisualMode;
|
|
|
|
|
}
|
|
|
|
|
//dump("IS @");
|
|
|
|
|
//setMark('<', tc.anchor());
|
|
|
|
|
//setMark('>', tc.position());
|
|
|
|
|
}
|
2009-01-23 15:12:04 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-09 16:12:08 +01:00
|
|
|
void FakeVimHandler::Private::updateEditor()
|
|
|
|
|
{
|
|
|
|
|
const int charWidth = QFontMetrics(EDITOR(font())).width(QChar(' '));
|
|
|
|
|
EDITOR(setTabStopWidth(charWidth * config(ConfigTabStop).toInt()));
|
2010-04-28 16:19:51 +02:00
|
|
|
setupCharClass();
|
2010-03-09 16:12:08 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 17:55:43 +01:00
|
|
|
void FakeVimHandler::Private::restoreWidget(int tabSize)
|
2009-01-23 15:12:04 +01:00
|
|
|
{
|
2012-09-10 22:10:23 +02:00
|
|
|
//clearMessage();
|
2009-01-23 15:12:04 +01:00
|
|
|
//updateMiniBuffer();
|
2009-03-30 16:54:25 +02:00
|
|
|
//EDITOR(removeEventFilter(q));
|
2010-05-04 11:00:40 +02:00
|
|
|
//EDITOR(setReadOnly(m_wasReadOnly));
|
2010-03-26 17:55:43 +01:00
|
|
|
const int charWidth = QFontMetrics(EDITOR(font())).width(QChar(' '));
|
|
|
|
|
EDITOR(setTabStopWidth(charWidth * tabSize));
|
2009-02-05 17:06:45 +01:00
|
|
|
m_visualMode = NoVisualMode;
|
2010-05-04 11:00:40 +02:00
|
|
|
// Force "ordinary" cursor.
|
|
|
|
|
m_mode = InsertMode;
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
2010-09-13 15:23:20 +02:00
|
|
|
updateCursorShape();
|
2009-02-05 17:06:45 +01:00
|
|
|
updateSelection();
|
2012-09-27 21:09:13 +02:00
|
|
|
updateHighlights();
|
2009-01-23 15:12:04 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult FakeVimHandler::Private::handleKey(const Input &input)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2011-04-05 16:32:18 +02:00
|
|
|
KEY_DEBUG("HANDLE INPUT: " << input << " MODE: " << mode);
|
2012-09-01 07:47:25 +02:00
|
|
|
|
2012-09-13 18:44:36 +02:00
|
|
|
bool handleMapped = true;
|
|
|
|
|
bool hasInput = input.isValid();
|
|
|
|
|
|
|
|
|
|
if (hasInput)
|
|
|
|
|
g.pendingInput.append(input);
|
|
|
|
|
|
|
|
|
|
// Waiting on input to complete mapping?
|
2012-09-01 07:47:25 +02:00
|
|
|
if (g.inputTimer != -1) {
|
|
|
|
|
killTimer(g.inputTimer);
|
|
|
|
|
g.inputTimer = -1;
|
2012-09-13 18:44:36 +02:00
|
|
|
// If there is a new input add it to incomplete input or
|
|
|
|
|
// if the mapped input can be completed complete.
|
|
|
|
|
if (hasInput && g.currentMap.walk(input)) {
|
|
|
|
|
if (g.currentMap.canExtend()) {
|
|
|
|
|
g.inputTimer = startTimer(1000);
|
|
|
|
|
return EventHandled;
|
|
|
|
|
} else {
|
|
|
|
|
hasInput = false;
|
2012-09-01 07:47:25 +02:00
|
|
|
handleMappedKeys();
|
2012-09-13 18:44:36 +02:00
|
|
|
}
|
|
|
|
|
} else if (g.currentMap.isComplete()) {
|
|
|
|
|
handleMappedKeys();
|
|
|
|
|
} else {
|
|
|
|
|
g.currentMap.reset();
|
|
|
|
|
handleMapped = false;
|
2012-09-01 07:47:25 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-13 18:44:36 +02:00
|
|
|
EventResult r = EventUnhandled;
|
2012-09-01 07:47:25 +02:00
|
|
|
while (!g.pendingInput.isEmpty()) {
|
|
|
|
|
const Input &in = g.pendingInput.front();
|
|
|
|
|
|
|
|
|
|
// invalid input is used to pop mapping state
|
|
|
|
|
if (!in.isValid()) {
|
|
|
|
|
g.mapStates.pop_back();
|
|
|
|
|
QTC_CHECK(!g.mapStates.empty());
|
|
|
|
|
endEditBlock();
|
|
|
|
|
if (g.mapStates.size() == 1)
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.setHistoryAutoSave(true);
|
2012-09-01 07:47:25 +02:00
|
|
|
if (m_mode == ExMode || m_subsubmode == SearchSubSubMode)
|
|
|
|
|
updateMiniBuffer(); // update cursor position on command line
|
|
|
|
|
} else {
|
2012-09-13 18:44:36 +02:00
|
|
|
if (handleMapped && !g.mapStates.last().noremap && m_subsubmode != SearchSubSubMode) {
|
2012-09-01 07:47:25 +02:00
|
|
|
if (!g.currentMap.isValid()) {
|
|
|
|
|
g.currentMap.reset(currentModeCode());
|
|
|
|
|
if (!g.currentMap.walk(g.pendingInput) && g.currentMap.isComplete()) {
|
|
|
|
|
handleMappedKeys();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle user mapping
|
|
|
|
|
if (g.currentMap.canExtend()) {
|
2012-09-13 18:44:36 +02:00
|
|
|
// wait for user to press any key or trigger complete mapping after interval
|
2012-09-01 07:47:25 +02:00
|
|
|
g.inputTimer = startTimer(1000);
|
|
|
|
|
return EventHandled;
|
|
|
|
|
} else if (g.currentMap.isComplete()) {
|
|
|
|
|
handleMappedKeys();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = handleDefaultKey(in);
|
|
|
|
|
// TODO: Unhadled events!
|
|
|
|
|
}
|
2012-09-13 18:44:36 +02:00
|
|
|
handleMapped = true;
|
2012-09-01 07:47:25 +02:00
|
|
|
g.pendingInput.pop_front();
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
2012-09-01 07:47:25 +02:00
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventResult FakeVimHandler::Private::handleDefaultKey(const Input &input)
|
|
|
|
|
{
|
|
|
|
|
if (input == Nop)
|
|
|
|
|
return EventHandled;
|
|
|
|
|
else if (m_subsubmode == SearchSubSubMode)
|
|
|
|
|
return handleSearchSubSubMode(input);
|
|
|
|
|
else if (m_mode == CommandMode)
|
|
|
|
|
return handleCommandMode(input);
|
|
|
|
|
else if (m_mode == InsertMode)
|
|
|
|
|
return handleInsertMode(input);
|
|
|
|
|
else if (m_mode == ReplaceMode)
|
|
|
|
|
return handleReplaceMode(input);
|
|
|
|
|
else if (m_mode == ExMode)
|
|
|
|
|
return handleExMode(input);
|
2009-03-05 11:06:25 +01:00
|
|
|
return EventUnhandled;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
void FakeVimHandler::Private::handleMappedKeys()
|
2010-03-26 13:22:06 +01:00
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
int maxMapDepth = g.mapStates.last().maxMapDepth - 1;
|
|
|
|
|
|
|
|
|
|
int invalidCount = g.currentMap.invalidInputCount();
|
|
|
|
|
if (invalidCount > 0) {
|
|
|
|
|
g.mapStates.remove(g.mapStates.size() - invalidCount, invalidCount);
|
|
|
|
|
QTC_CHECK(!g.mapStates.empty());
|
|
|
|
|
for (int i = 0; i < invalidCount; ++i)
|
|
|
|
|
endEditBlock();
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
2012-09-01 07:47:25 +02:00
|
|
|
|
|
|
|
|
if (maxMapDepth <= 0) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, "recursive mapping");
|
2012-09-01 07:47:25 +02:00
|
|
|
g.pendingInput.remove(0, g.currentMap.mapLength() + invalidCount);
|
|
|
|
|
} else {
|
|
|
|
|
const Inputs &inputs = g.currentMap.inputs();
|
|
|
|
|
QVector<Input> rest = g.pendingInput.mid(g.currentMap.mapLength() + invalidCount);
|
|
|
|
|
g.pendingInput.clear();
|
|
|
|
|
g.pendingInput << inputs << Input() << rest;
|
|
|
|
|
g.mapStates << MappingState(maxMapDepth, inputs.noremap(), inputs.silent());
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.setHistoryAutoSave(false);
|
2012-09-29 19:09:08 +02:00
|
|
|
beginLargeEditBlock();
|
2012-09-01 07:47:25 +02:00
|
|
|
}
|
|
|
|
|
g.currentMap.reset();
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::timerEvent(QTimerEvent *ev)
|
|
|
|
|
{
|
2012-09-01 07:47:25 +02:00
|
|
|
if (ev->timerId() == g.inputTimer) {
|
|
|
|
|
if (g.currentMap.isComplete())
|
|
|
|
|
handleMappedKeys();
|
|
|
|
|
handleKey(Input());
|
|
|
|
|
}
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:23:30 +01:00
|
|
|
void FakeVimHandler::Private::stopIncrementalFind()
|
|
|
|
|
{
|
2012-10-03 16:40:05 +02:00
|
|
|
if (g.findPending) {
|
|
|
|
|
g.findPending = false;
|
2010-09-14 14:04:13 +02:00
|
|
|
QTextCursor tc = cursor();
|
2010-10-26 10:56:32 +02:00
|
|
|
setAnchorAndPosition(m_findStartPosition, tc.selectionStart());
|
|
|
|
|
finishMovement();
|
|
|
|
|
setAnchor();
|
2010-01-21 17:23:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void FakeVimHandler::Private::updateFind(bool isComplete)
|
|
|
|
|
{
|
|
|
|
|
if (!isComplete && !hasConfig(ConfigIncSearch))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g.currentMessage.clear();
|
|
|
|
|
|
|
|
|
|
const QString &needle = g.searchBuffer.contents();
|
|
|
|
|
SearchData sd;
|
|
|
|
|
sd.needle = needle;
|
2012-10-03 16:40:05 +02:00
|
|
|
sd.forward = g.lastSearchForward;
|
2012-09-10 22:10:23 +02:00
|
|
|
sd.highlightMatches = isComplete;
|
|
|
|
|
search(sd, isComplete);
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
bool FakeVimHandler::Private::atEmptyLine(const QTextCursor &tc) const
|
|
|
|
|
{
|
|
|
|
|
if (tc.isNull())
|
|
|
|
|
return atEmptyLine(cursor());
|
|
|
|
|
return tc.block().length() == 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::atBoundary(bool end, bool simple, bool onlyWords,
|
|
|
|
|
const QTextCursor &tc) const
|
|
|
|
|
{
|
|
|
|
|
if (tc.isNull())
|
|
|
|
|
return atBoundary(end, simple, onlyWords, cursor());
|
|
|
|
|
if (atEmptyLine(tc))
|
|
|
|
|
return true;
|
|
|
|
|
int pos = tc.position();
|
|
|
|
|
QChar c1 = document()->characterAt(pos);
|
|
|
|
|
QChar c2 = document()->characterAt(pos + (end ? 1 : -1));
|
|
|
|
|
int thisClass = charClass(c1, simple);
|
|
|
|
|
return (!onlyWords || thisClass != 0)
|
|
|
|
|
&& (c2.isNull() || c2 == ParagraphSeparator || thisClass != charClass(c2, simple));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::atWordBoundary(bool end, bool simple, const QTextCursor &tc) const
|
|
|
|
|
{
|
|
|
|
|
return atBoundary(end, simple, true, tc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::atWordStart(bool simple, const QTextCursor &tc) const
|
|
|
|
|
{
|
|
|
|
|
return atWordBoundary(false, simple, tc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::atWordEnd(bool simple, const QTextCursor &tc) const
|
|
|
|
|
{
|
|
|
|
|
return atWordBoundary(true, simple, tc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::isFirstNonBlankOnLine(int pos)
|
|
|
|
|
{
|
|
|
|
|
for (int i = document()->findBlock(pos).position(); i < pos; ++i) {
|
|
|
|
|
if (!document()->characterAt(i).isSpace())
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-26 18:39:48 +02:00
|
|
|
void FakeVimHandler::Private::setUndoPosition(bool overwrite)
|
2009-11-30 13:58:57 +01:00
|
|
|
{
|
2012-08-26 18:39:48 +02:00
|
|
|
const int rev = revision();
|
|
|
|
|
if (!overwrite && !m_undo.empty() && m_undo.top().revision >= rev)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
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();
|
2012-09-29 15:36:18 +02:00
|
|
|
if (m_submode == ShiftLeftSubMode || m_submode == ShiftRightSubMode
|
|
|
|
|
|| m_submode == IndentSubMode) {
|
|
|
|
|
pos = qMin(pos, anchor());
|
|
|
|
|
}
|
|
|
|
|
tc.setPosition(pos);
|
2012-08-26 18:39:48 +02:00
|
|
|
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;
|
2009-11-30 13:58:57 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:05:24 +02:00
|
|
|
void FakeVimHandler::Private::moveDown(int n)
|
|
|
|
|
{
|
2009-04-09 13:48:59 +02:00
|
|
|
#if 0
|
|
|
|
|
// does not work for "hidden" documents like in the autotests
|
2010-09-14 14:04:13 +02:00
|
|
|
tc.movePosition(Down, MoveAnchor, n);
|
2009-04-09 13:48:59 +02:00
|
|
|
#else
|
2010-09-13 15:23:20 +02:00
|
|
|
const int col = position() - block().position();
|
2010-09-13 14:16:18 +02:00
|
|
|
const int lastLine = document()->lastBlock().blockNumber();
|
2010-09-13 15:23:20 +02:00
|
|
|
const int targetLine = qMax(0, qMin(lastLine, block().blockNumber() + n));
|
2010-09-13 14:16:18 +02:00
|
|
|
const QTextBlock &block = document()->findBlockByNumber(targetLine);
|
2009-04-09 15:44:51 +02:00
|
|
|
const int pos = block.position();
|
2010-09-14 16:58:31 +02:00
|
|
|
setPosition(pos + qMax(0, qMin(block.length() - 2, col)));
|
2009-04-09 15:44:51 +02:00
|
|
|
moveToTargetColumn();
|
2009-04-09 13:48:59 +02:00
|
|
|
#endif
|
2009-04-08 16:05:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToEndOfLine()
|
|
|
|
|
{
|
2009-04-09 13:48:59 +02:00
|
|
|
#if 0
|
|
|
|
|
// does not work for "hidden" documents like in the autotests
|
2010-09-14 14:04:13 +02:00
|
|
|
tc.movePosition(EndOfLine, MoveAnchor);
|
2009-04-09 13:48:59 +02:00
|
|
|
#else
|
2010-09-13 15:23:20 +02:00
|
|
|
const int pos = block().position() + block().length() - 2;
|
|
|
|
|
setPosition(qMax(block().position(), pos));
|
2009-04-09 13:48:59 +02:00
|
|
|
#endif
|
2009-04-08 16:05:24 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-03 11:22:18 +02:00
|
|
|
void FakeVimHandler::Private::moveBehindEndOfLine()
|
|
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
int pos = qMin(block().position() + block().length() - 1,
|
|
|
|
|
lastPositionInDocument());
|
2009-07-03 11:22:18 +02:00
|
|
|
setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-16 09:18:09 +02:00
|
|
|
void FakeVimHandler::Private::moveToStartOfLine()
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
// does not work for "hidden" documents like in the autotests
|
2010-09-14 14:04:13 +02:00
|
|
|
tc.movePosition(StartOfLine, MoveAnchor);
|
2009-04-16 09:18:09 +02:00
|
|
|
#else
|
2010-09-13 15:23:20 +02:00
|
|
|
setPosition(block().position());
|
2009-04-16 09:18:09 +02:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-28 17:01:24 +02:00
|
|
|
void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement, int count)
|
2010-01-21 17:38:24 +01:00
|
|
|
{
|
2012-09-28 17:01:24 +02:00
|
|
|
finishMovement(dotCommandMovement.arg(count));
|
2010-01-21 17:38:24 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-28 17:01:24 +02:00
|
|
|
void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-09-14 14:04:13 +02:00
|
|
|
//dump("FINISH MOVEMENT");
|
2009-01-08 17:21:51 +01:00
|
|
|
if (m_submode == FilterSubMode) {
|
2009-01-16 16:15:01 +01:00
|
|
|
int beginLine = lineForPosition(anchor());
|
|
|
|
|
int endLine = lineForPosition(position());
|
2009-03-06 11:22:16 +01:00
|
|
|
setPosition(qMin(anchor(), position()));
|
2009-01-26 12:08:39 +01:00
|
|
|
enterExMode();
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage.clear();
|
|
|
|
|
g.commandBuffer.setContents(QString(".,+%1!").arg(qAbs(endLine - beginLine)));
|
2009-01-08 17:21:51 +01:00
|
|
|
updateMiniBuffer();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-14 14:04:13 +02:00
|
|
|
//if (isVisualMode())
|
|
|
|
|
// setMark('>', position());
|
2009-01-15 16:42:10 +01:00
|
|
|
|
2010-01-21 17:38:28 +01:00
|
|
|
if (m_submode == ChangeSubMode
|
|
|
|
|
|| m_submode == DeleteSubMode
|
|
|
|
|
|| m_submode == YankSubMode
|
|
|
|
|
|| m_submode == TransformSubMode) {
|
2010-09-14 14:04:13 +02:00
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
if (m_movetype == MoveExclusive) {
|
|
|
|
|
if (anchor() != position() && atBlockStart()) {
|
|
|
|
|
// Exlusive motion ending at the beginning of line
|
|
|
|
|
// becomes inclusive and end is moved to end of previous line.
|
|
|
|
|
m_movetype = MoveInclusive;
|
|
|
|
|
moveToStartOfLine();
|
|
|
|
|
moveLeft();
|
|
|
|
|
|
|
|
|
|
// Exclusive motion ending at the beginning of line and
|
|
|
|
|
// starting at or before first non-blank on a line becomes linewise.
|
|
|
|
|
if (anchor() < block().position() && isFirstNonBlankOnLine(anchor())) {
|
|
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:38:28 +01:00
|
|
|
if (m_submode != YankSubMode)
|
|
|
|
|
beginEditBlock();
|
2010-09-14 14:04:13 +02:00
|
|
|
|
2010-01-21 17:38:27 +01:00
|
|
|
if (m_movetype == MoveLineWise)
|
2010-01-21 17:38:28 +01:00
|
|
|
m_rangemode = (m_submode == ChangeSubMode)
|
|
|
|
|
? RangeLineModeExclusive
|
|
|
|
|
: RangeLineMode;
|
|
|
|
|
|
|
|
|
|
if (m_movetype == MoveInclusive) {
|
|
|
|
|
if (anchor() <= position()) {
|
2012-08-19 19:08:04 +02:00
|
|
|
if (!atBlockEnd())
|
2010-09-14 14:04:13 +02:00
|
|
|
setPosition(position() + 1); // correction
|
2012-08-19 19:08:04 +02:00
|
|
|
|
|
|
|
|
// If more than one line is selected and all are selected completely
|
|
|
|
|
// movement becomes linewise.
|
|
|
|
|
int start = anchor();
|
|
|
|
|
if (start < block().position() && isFirstNonBlankOnLine(start) && atBlockEnd()) {
|
|
|
|
|
moveRight();
|
|
|
|
|
if (atEmptyLine())
|
|
|
|
|
moveRight();
|
|
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
}
|
2010-01-21 17:38:28 +01:00
|
|
|
} else {
|
2010-09-14 14:04:13 +02:00
|
|
|
setAnchorAndPosition(anchor() + 1, position());
|
2010-01-21 17:38:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:38:31 +01:00
|
|
|
if (m_positionPastEnd) {
|
2010-09-14 14:04:13 +02:00
|
|
|
const int anc = anchor();
|
2010-01-21 17:38:31 +01:00
|
|
|
moveBehindEndOfLine();
|
|
|
|
|
moveRight();
|
2010-09-14 14:04:13 +02:00
|
|
|
setAnchorAndPosition(anc, position());
|
2010-01-21 17:38:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_anchorPastEnd) {
|
2010-09-14 14:04:13 +02:00
|
|
|
setAnchorAndPosition(anchor() + 1, position());
|
2010-01-21 17:38:31 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:38:28 +01:00
|
|
|
if (m_submode != TransformSubMode) {
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
2010-01-21 17:38:28 +01:00
|
|
|
if (m_movetype == MoveLineWise)
|
2012-08-09 17:32:39 +02:00
|
|
|
setRegister(m_register, registerContents(m_register), RangeLineMode);
|
2010-01-21 17:38:27 +01:00
|
|
|
}
|
2010-01-21 17:38:31 +01:00
|
|
|
|
|
|
|
|
m_positionPastEnd = m_anchorPastEnd = false;
|
2010-01-21 17:38:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_submode == ChangeSubMode) {
|
2010-04-19 11:35:48 +02:00
|
|
|
if (m_rangemode == RangeLineMode)
|
|
|
|
|
m_rangemode = RangeLineModeExclusive;
|
2010-05-12 11:18:18 +02:00
|
|
|
removeText(currentRange());
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand(QLatin1Char('c') + dotCommandMovement);
|
2010-04-19 11:35:48 +02:00
|
|
|
if (m_movetype == MoveLineWise)
|
2010-01-21 17:38:28 +01:00
|
|
|
insertAutomaticIndentation(true);
|
2010-01-21 17:38:27 +01:00
|
|
|
endEditBlock();
|
2009-06-04 16:07:09 +02:00
|
|
|
enterInsertMode();
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
} else if (m_submode == DeleteSubMode) {
|
2012-08-26 18:39:48 +02:00
|
|
|
setUndoPosition();
|
2012-08-19 19:08:04 +02:00
|
|
|
Range range = currentRange();
|
|
|
|
|
removeText(range);
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand(QLatin1Char('d') + dotCommandMovement);
|
2010-01-05 18:42:26 +01:00
|
|
|
if (m_movetype == MoveLineWise)
|
|
|
|
|
handleStartOfLine();
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = NoSubMode;
|
2009-01-23 10:13:12 +01:00
|
|
|
if (atEndOfLine())
|
2009-01-16 17:38:15 +01:00
|
|
|
moveLeft();
|
2009-06-11 15:41:20 +02:00
|
|
|
else
|
|
|
|
|
setTargetColumn();
|
2010-01-21 17:38:28 +01:00
|
|
|
endEditBlock();
|
2008-12-23 21:34:21 +01:00
|
|
|
} else if (m_submode == YankSubMode) {
|
|
|
|
|
m_submode = NoSubMode;
|
2010-01-21 17:38:31 +01:00
|
|
|
const int la = lineForPosition(anchor());
|
|
|
|
|
const int lp = lineForPosition(position());
|
2009-09-16 14:16:21 +02:00
|
|
|
if (m_register != '"') {
|
2010-05-11 14:26:37 +02:00
|
|
|
setPosition(mark(m_register));
|
2009-09-16 14:16:21 +02:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
} else {
|
2010-01-21 17:38:31 +01:00
|
|
|
if (anchor() <= position())
|
|
|
|
|
setPosition(anchor());
|
2009-09-16 14:16:21 +02:00
|
|
|
}
|
2010-01-21 17:38:31 +01:00
|
|
|
if (la != lp)
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, QString("%1 lines yanked").arg(qAbs(la - lp) + 1));
|
2010-01-21 17:38:26 +01:00
|
|
|
} else if (m_submode == TransformSubMode) {
|
|
|
|
|
if (m_subsubmode == InvertCaseSubSubMode) {
|
2010-05-12 11:18:18 +02:00
|
|
|
invertCase(currentRange());
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand(QLatin1Char('~') + dotCommandMovement);
|
2010-01-21 17:38:26 +01:00
|
|
|
} else if (m_subsubmode == UpCaseSubSubMode) {
|
2010-05-12 11:18:18 +02:00
|
|
|
upCase(currentRange());
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand("gU" + dotCommandMovement);
|
2010-01-21 17:38:26 +01:00
|
|
|
} else if (m_subsubmode == DownCaseSubSubMode) {
|
2010-05-12 11:18:18 +02:00
|
|
|
downCase(currentRange());
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand("gu" + dotCommandMovement);
|
2010-01-21 17:38:26 +01:00
|
|
|
}
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
setPosition(qMin(anchor(), position()));
|
|
|
|
|
if (m_movetype == MoveLineWise)
|
|
|
|
|
handleStartOfLine();
|
|
|
|
|
endEditBlock();
|
2008-12-26 10:36:40 +01:00
|
|
|
} else if (m_submode == IndentSubMode) {
|
2009-05-05 09:06:36 +02:00
|
|
|
recordJump();
|
2012-08-11 14:31:42 +02:00
|
|
|
setUndoPosition();
|
2010-01-06 14:57:46 +01:00
|
|
|
indentSelectedText();
|
2008-12-26 10:36:40 +01:00
|
|
|
m_submode = NoSubMode;
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand('=' + dotCommandMovement);
|
2009-03-06 11:22:16 +01:00
|
|
|
} else if (m_submode == ShiftRightSubMode) {
|
2009-04-01 15:11:26 +02:00
|
|
|
recordJump();
|
2012-08-11 14:31:42 +02:00
|
|
|
setUndoPosition();
|
2009-03-06 12:12:35 +01:00
|
|
|
shiftRegionRight(1);
|
2009-03-06 11:22:16 +01:00
|
|
|
m_submode = NoSubMode;
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand('>' + dotCommandMovement);
|
2009-03-06 11:22:16 +01:00
|
|
|
} else if (m_submode == ShiftLeftSubMode) {
|
2009-04-01 15:11:26 +02:00
|
|
|
recordJump();
|
2012-08-11 14:31:42 +02:00
|
|
|
setUndoPosition();
|
2009-03-06 12:12:35 +01:00
|
|
|
shiftRegionLeft(1);
|
2009-03-06 11:22:16 +01:00
|
|
|
m_submode = NoSubMode;
|
2012-09-28 17:01:24 +02:00
|
|
|
if (!dotCommandMovement.isEmpty())
|
|
|
|
|
setDotCommand('<' + dotCommandMovement);
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
2009-03-06 11:22:16 +01:00
|
|
|
|
2010-01-21 17:38:24 +01:00
|
|
|
resetCommandMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::resetCommandMode()
|
|
|
|
|
{
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2008-12-25 22:41:09 +01:00
|
|
|
m_mvcount.clear();
|
|
|
|
|
m_opcount.clear();
|
2008-12-27 13:39:34 +01:00
|
|
|
m_gflag = false;
|
2008-12-19 12:20:04 +01:00
|
|
|
m_register = '"';
|
2010-09-13 15:23:20 +02:00
|
|
|
//m_tc.clearSelection();
|
2009-08-11 14:39:44 +02:00
|
|
|
m_rangemode = RangeCharMode;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 11:52:05 +01:00
|
|
|
void FakeVimHandler::Private::updateSelection()
|
|
|
|
|
{
|
2012-09-27 21:09:13 +02:00
|
|
|
QList<QTextEdit::ExtraSelection> selections = m_extraSelections;
|
2010-05-10 16:30:46 +02:00
|
|
|
if (hasConfig(ConfigShowMarks)) {
|
2010-09-15 13:47:52 +02:00
|
|
|
for (MarksIterator it(m_marks); it.hasNext(); ) {
|
2010-05-10 16:30:46 +02:00
|
|
|
it.next();
|
|
|
|
|
QTextEdit::ExtraSelection sel;
|
2010-09-15 13:47:52 +02:00
|
|
|
const int pos = it.value().position();
|
2010-09-13 15:23:20 +02:00
|
|
|
sel.cursor = cursor();
|
2010-09-15 13:47:52 +02:00
|
|
|
sel.cursor.setPosition(pos, MoveAnchor);
|
|
|
|
|
sel.cursor.setPosition(pos + 1, KeepAnchor);
|
2010-09-13 15:23:20 +02:00
|
|
|
sel.format = cursor().blockCharFormat();
|
2010-05-10 16:30:46 +02:00
|
|
|
sel.format.setForeground(Qt::blue);
|
|
|
|
|
sel.format.setBackground(Qt::green);
|
|
|
|
|
selections.append(sel);
|
|
|
|
|
}
|
2010-05-07 15:17:44 +02:00
|
|
|
}
|
2010-09-14 14:04:13 +02:00
|
|
|
//qDebug() << "SELECTION: " << selections;
|
2009-01-23 15:12:04 +01:00
|
|
|
emit q->selectionChanged(selections);
|
2009-01-06 11:52:05 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-27 21:09:13 +02:00
|
|
|
void FakeVimHandler::Private::updateHighlights()
|
|
|
|
|
{
|
|
|
|
|
if (!hasConfig(ConfigUseCoreSearch))
|
|
|
|
|
emit q->highlightMatches(m_oldNeedle);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-27 21:01:05 +01:00
|
|
|
void FakeVimHandler::Private::updateMiniBuffer()
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-01-22 13:56:50 +01:00
|
|
|
if (!m_textedit && !m_plaintextedit)
|
|
|
|
|
return;
|
|
|
|
|
|
2008-12-27 21:01:05 +01:00
|
|
|
QString msg;
|
2011-07-15 13:22:38 +02:00
|
|
|
int cursorPos = -1;
|
2012-09-10 22:10:23 +02:00
|
|
|
MessageLevel messageLevel = MessageMode;
|
2012-09-01 07:47:25 +02:00
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
if (g.mapStates.last().silent && g.currentMessageLevel < MessageInfo)
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage.clear();
|
|
|
|
|
|
2009-03-05 11:06:25 +01:00
|
|
|
if (m_passing) {
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "PASSING";
|
2012-09-01 07:47:25 +02:00
|
|
|
} else if (m_subsubmode == SearchSubSubMode) {
|
2012-09-17 17:44:05 +02:00
|
|
|
msg = g.searchBuffer.display();
|
2012-09-01 07:47:25 +02:00
|
|
|
if (g.mapStates.size() == 1)
|
2012-09-17 17:44:05 +02:00
|
|
|
cursorPos = g.searchBuffer.cursorPos() + 1;
|
2012-09-01 07:47:25 +02:00
|
|
|
} else if (m_mode == ExMode) {
|
2012-09-17 17:44:05 +02:00
|
|
|
msg = g.commandBuffer.display();
|
2012-09-01 07:47:25 +02:00
|
|
|
if (g.mapStates.size() == 1)
|
2012-09-17 17:44:05 +02:00
|
|
|
cursorPos = g.commandBuffer.cursorPos() + 1;
|
|
|
|
|
} else if (!g.currentMessage.isEmpty()) {
|
|
|
|
|
msg = g.currentMessage;
|
|
|
|
|
g.currentMessage.clear();
|
2012-09-10 22:10:23 +02:00
|
|
|
messageLevel = g.currentMessageLevel;
|
2012-09-01 07:47:25 +02:00
|
|
|
} else if (g.mapStates.size() > 1 && !g.mapStates.last().silent) {
|
|
|
|
|
// Do not reset previous message when after running a mapped command.
|
|
|
|
|
return;
|
2009-12-11 18:59:05 +01:00
|
|
|
} else if (m_mode == CommandMode && isVisualMode()) {
|
|
|
|
|
if (isVisualCharMode()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "VISUAL";
|
2009-12-11 18:59:05 +01:00
|
|
|
} else if (isVisualLineMode()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "VISUAL LINE";
|
2009-12-11 18:59:05 +01:00
|
|
|
} else if (isVisualBlockMode()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "VISUAL BLOCK";
|
2009-01-08 17:21:51 +01:00
|
|
|
}
|
2009-01-06 11:49:33 +01:00
|
|
|
} else if (m_mode == InsertMode) {
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "INSERT";
|
2010-05-06 12:10:57 +02:00
|
|
|
} else if (m_mode == ReplaceMode) {
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "REPLACE";
|
2010-05-18 18:24:00 +02:00
|
|
|
} else {
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(m_mode == CommandMode && m_subsubmode != SearchSubSubMode);
|
2012-09-10 22:10:23 +02:00
|
|
|
msg = "COMMAND";
|
2008-12-27 22:41:47 +01:00
|
|
|
}
|
2009-03-05 11:06:25 +01:00
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
emit q->commandBufferChanged(msg, cursorPos, messageLevel, q);
|
2009-01-07 18:05:45 +01:00
|
|
|
|
|
|
|
|
int linesInDoc = linesInDocument();
|
2010-07-06 10:12:21 +02:00
|
|
|
int l = cursorLine();
|
2009-01-07 18:05:45 +01:00
|
|
|
QString status;
|
2010-05-10 09:01:30 +02:00
|
|
|
const QString pos = QString::fromLatin1("%1,%2")
|
2010-07-06 10:12:21 +02:00
|
|
|
.arg(l + 1).arg(physicalCursorColumn() + 1);
|
2008-12-27 21:01:05 +01:00
|
|
|
// FIXME: physical "-" logical
|
2009-01-06 11:51:03 +01:00
|
|
|
if (linesInDoc != 0) {
|
2009-10-16 11:30:46 +02:00
|
|
|
status = FakeVimHandler::tr("%1%2%").arg(pos, -10).arg(l * 100 / linesInDoc, 4);
|
2009-01-06 11:51:03 +01:00
|
|
|
} else {
|
2009-10-16 11:30:46 +02:00
|
|
|
status = FakeVimHandler::tr("%1All").arg(pos, -10);
|
2009-01-06 11:51:03 +01:00
|
|
|
}
|
2009-01-07 18:05:45 +01:00
|
|
|
emit q->statusDataChanged(status);
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void FakeVimHandler::Private::showMessage(MessageLevel level, const QString &msg)
|
2009-01-08 17:40:27 +01:00
|
|
|
{
|
|
|
|
|
//qDebug() << "MSG: " << msg;
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage = msg;
|
2012-09-10 22:10:23 +02:00
|
|
|
g.currentMessageLevel = level;
|
2009-01-08 17:40:27 +01:00
|
|
|
updateMiniBuffer();
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 17:29:30 +01:00
|
|
|
void FakeVimHandler::Private::notImplementedYet()
|
|
|
|
|
{
|
2009-03-20 13:36:54 +01:00
|
|
|
qDebug() << "Not implemented in FakeVim";
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, FakeVimHandler::tr("Not implemented in FakeVim"));
|
2009-01-15 17:29:30 +01:00
|
|
|
updateMiniBuffer();
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-05 15:30:22 +01:00
|
|
|
void FakeVimHandler::Private::passShortcuts(bool enable)
|
|
|
|
|
{
|
|
|
|
|
m_passing = enable;
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
if (enable)
|
|
|
|
|
QCoreApplication::instance()->installEventFilter(q);
|
|
|
|
|
else
|
|
|
|
|
QCoreApplication::instance()->removeEventFilter(q);
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-18 17:45:15 +01:00
|
|
|
static bool subModeCanUseTextObjects(int submode)
|
|
|
|
|
{
|
2010-04-19 11:44:49 +02:00
|
|
|
return submode == DeleteSubMode
|
|
|
|
|
|| submode == YankSubMode
|
2010-06-03 16:54:45 +02:00
|
|
|
|| submode == ChangeSubMode
|
|
|
|
|
|| submode == IndentSubMode
|
|
|
|
|
|| submode == ShiftLeftSubMode
|
|
|
|
|
|| submode == ShiftRightSubMode;
|
2010-03-18 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-04-28 14:00:44 +02:00
|
|
|
//const int key = input.key;
|
2009-03-05 11:06:25 +01:00
|
|
|
EventResult handled = EventHandled;
|
2010-03-19 08:44:57 +01:00
|
|
|
if (m_subsubmode == FtSubSubMode) {
|
2010-02-19 13:01:38 +01:00
|
|
|
m_semicolonType = m_subsubdata;
|
2010-04-28 14:00:44 +02:00
|
|
|
m_semicolonKey = input.text();
|
|
|
|
|
bool valid = handleFfTt(m_semicolonKey);
|
2010-02-19 13:01:38 +01:00
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
if (!valid) {
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
finishMovement();
|
|
|
|
|
} else {
|
|
|
|
|
finishMovement(QString("%1%2%3")
|
|
|
|
|
.arg(count())
|
2010-04-28 14:00:44 +02:00
|
|
|
.arg(m_semicolonType.text())
|
|
|
|
|
.arg(m_semicolonKey));
|
2010-02-19 13:01:38 +01:00
|
|
|
}
|
2010-03-18 17:45:15 +01:00
|
|
|
} else if (m_subsubmode == TextObjectSubSubMode) {
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('w'))
|
|
|
|
|
selectWordTextObject(m_subsubdata.is('i'));
|
|
|
|
|
else if (input.is('W'))
|
|
|
|
|
selectWORDTextObject(m_subsubdata.is('i'));
|
|
|
|
|
else if (input.is('s'))
|
|
|
|
|
selectSentenceTextObject(m_subsubdata.is('i'));
|
|
|
|
|
else if (input.is('p'))
|
|
|
|
|
selectParagraphTextObject(m_subsubdata.is('i'));
|
|
|
|
|
else if (input.is('[') || input.is(']'))
|
|
|
|
|
selectBlockTextObject(m_subsubdata.is('i'), '[', ']');
|
|
|
|
|
else if (input.is('(') || input.is(')') || input.is('b'))
|
|
|
|
|
selectBlockTextObject(m_subsubdata.is('i'), '(', ')');
|
|
|
|
|
else if (input.is('<') || input.is('>'))
|
|
|
|
|
selectBlockTextObject(m_subsubdata.is('i'), '<', '>');
|
2010-06-03 16:54:45 +02:00
|
|
|
else if (input.is('{') || input.is('}') || input.is('B'))
|
|
|
|
|
selectBlockTextObject(m_subsubdata.is('i'), '{', '}');
|
2010-04-28 14:00:44 +02:00
|
|
|
else if (input.is('"') || input.is('\'') || input.is('`'))
|
2012-07-19 21:12:13 +02:00
|
|
|
selectQuotedStringTextObject(m_subsubdata.is('i'), input.asChar());
|
2010-03-18 17:45:15 +01:00
|
|
|
m_subsubmode = NoSubSubMode;
|
2012-02-18 01:57:14 +01:00
|
|
|
finishMovement(QString("%1%2%3")
|
|
|
|
|
.arg(count())
|
|
|
|
|
.arg(m_subsubdata.text())
|
|
|
|
|
.arg(input.text()));
|
2010-03-19 08:44:57 +01:00
|
|
|
} else if (m_subsubmode == MarkSubSubMode) {
|
2010-09-13 15:23:20 +02:00
|
|
|
setMark(input.asChar().unicode(), position());
|
2010-03-19 08:44:57 +01:00
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
} else if (m_subsubmode == BackTickSubSubMode
|
|
|
|
|
|| m_subsubmode == TickSubSubMode) {
|
2012-08-11 14:31:42 +02:00
|
|
|
ushort markChar = input.asChar().unicode();
|
|
|
|
|
int m = mark(markChar);
|
2010-05-11 14:26:37 +02:00
|
|
|
if (m != -1) {
|
2012-08-11 14:31:42 +02:00
|
|
|
if (markChar == '\'' && !m_jumpListUndo.isEmpty())
|
|
|
|
|
m_jumpListUndo.pop();
|
|
|
|
|
recordJump();
|
2010-05-11 14:26:37 +02:00
|
|
|
setPosition(m);
|
2010-03-19 08:44:57 +01:00
|
|
|
if (m_subsubmode == TickSubSubMode)
|
|
|
|
|
moveToFirstNonBlankOnLine();
|
|
|
|
|
finishMovement();
|
|
|
|
|
} else {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, msgMarkNotSet(input.text()));
|
2010-03-19 08:44:57 +01:00
|
|
|
}
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
} else {
|
|
|
|
|
handled = EventUnhandled;
|
|
|
|
|
}
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 13:02:17 +02:00
|
|
|
EventResult FakeVimHandler::Private::handleOpenSquareSubMode(const Input &input)
|
|
|
|
|
{
|
|
|
|
|
EventResult handled = EventHandled;
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
if (input.is('{')) {
|
|
|
|
|
searchBalanced(false, '{', '}');
|
2010-07-14 13:21:35 +02:00
|
|
|
} else if (input.is('(')) {
|
|
|
|
|
searchBalanced(false, '(', ')');
|
2010-07-14 13:02:17 +02:00
|
|
|
} else {
|
|
|
|
|
handled = EventUnhandled;
|
|
|
|
|
}
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventResult FakeVimHandler::Private::handleCloseSquareSubMode(const Input &input)
|
|
|
|
|
{
|
|
|
|
|
EventResult handled = EventHandled;
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
if (input.is('}')) {
|
|
|
|
|
searchBalanced(true, '}', '{');
|
2010-07-14 13:21:35 +02:00
|
|
|
} else if (input.is(')')) {
|
|
|
|
|
searchBalanced(true, ')', '(');
|
2010-07-14 13:02:17 +02:00
|
|
|
} else {
|
|
|
|
|
handled = EventUnhandled;
|
|
|
|
|
}
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
2010-03-19 08:44:57 +01:00
|
|
|
{
|
|
|
|
|
EventResult handled = EventHandled;
|
|
|
|
|
|
2010-05-18 18:24:00 +02:00
|
|
|
if (input.isEscape()) {
|
2010-03-19 08:44:57 +01:00
|
|
|
if (isVisualMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
} else if (m_submode != NoSubMode) {
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
finishMovement();
|
|
|
|
|
} else {
|
|
|
|
|
resetCommandMode();
|
2010-05-04 17:58:53 +02:00
|
|
|
updateMiniBuffer();
|
2010-03-19 08:44:57 +01:00
|
|
|
}
|
|
|
|
|
} else if (m_subsubmode != NoSubSubMode) {
|
2010-03-26 13:22:06 +01:00
|
|
|
handleCommandSubSubMode(input);
|
2010-07-14 13:02:17 +02:00
|
|
|
} else if (m_submode == OpenSquareSubMode) {
|
|
|
|
|
handled = handleOpenSquareSubMode(input);
|
|
|
|
|
} else if (m_submode == CloseSquareSubMode) {
|
|
|
|
|
handled = handleCloseSquareSubMode(input);
|
2010-02-19 13:01:38 +01:00
|
|
|
} else if (m_submode == WindowSubMode) {
|
2010-04-28 14:00:44 +02:00
|
|
|
emit q->windowCommandRequested(input.key());
|
2009-04-03 16:33:28 +02:00
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
} else if (m_submode == RegisterSubMode) {
|
2010-05-20 14:08:11 +02:00
|
|
|
m_register = input.asChar().unicode();
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = NoSubMode;
|
2009-09-16 14:16:21 +02:00
|
|
|
m_rangemode = RangeLineMode;
|
2010-05-28 13:09:24 +02:00
|
|
|
} else if (m_submode == ReplaceSubMode) {
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand(visualDotCommand() + 'r' + input.asChar());
|
2010-05-28 13:09:24 +02:00
|
|
|
if (isVisualMode()) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-05-28 13:09:24 +02:00
|
|
|
if (isVisualLineMode())
|
|
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
else if (isVisualBlockMode())
|
|
|
|
|
m_rangemode = RangeBlockMode;
|
|
|
|
|
else
|
|
|
|
|
m_rangemode = RangeCharMode;
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
Range range = currentRange();
|
2010-05-28 13:57:35 +02:00
|
|
|
Transformation tr =
|
|
|
|
|
&FakeVimHandler::Private::replaceByCharTransform;
|
2010-05-28 13:09:24 +02:00
|
|
|
transformText(range, tr, input.asChar());
|
|
|
|
|
setPosition(range.beginPos);
|
|
|
|
|
} else if (count() <= rightDist()) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-05-28 13:09:24 +02:00
|
|
|
setAnchor();
|
|
|
|
|
moveRight(count());
|
2011-11-28 15:43:57 +01:00
|
|
|
Range range = currentRange();
|
2011-07-14 11:40:59 +02:00
|
|
|
if (input.isReturn()) {
|
|
|
|
|
beginEditBlock();
|
2011-11-28 15:43:57 +01:00
|
|
|
replaceText(range, QString());
|
2011-07-14 11:40:59 +02:00
|
|
|
insertText(QString("\n"));
|
|
|
|
|
endEditBlock();
|
|
|
|
|
} else {
|
2011-11-28 15:43:57 +01:00
|
|
|
replaceText(range, QString(count(), input.asChar()));
|
2011-07-14 11:40:59 +02:00
|
|
|
moveLeft();
|
|
|
|
|
}
|
2010-05-28 13:57:35 +02:00
|
|
|
setTargetColumn();
|
2010-05-28 13:09:24 +02:00
|
|
|
setDotCommand("%1r" + input.text(), count());
|
|
|
|
|
}
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (m_submode == ChangeSubMode && input.is('c')) { // tested
|
2012-08-26 18:39:48 +02:00
|
|
|
m_movetype = MoveLineWise;
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-01-05 18:42:25 +01:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
setAnchor();
|
2009-04-16 09:18:09 +02:00
|
|
|
moveDown(count() - 1);
|
|
|
|
|
moveToEndOfLine();
|
|
|
|
|
m_lastInsertion.clear();
|
|
|
|
|
setDotCommand("%1cc", count());
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (m_submode == DeleteSubMode && input.is('d')) { // tested
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveLineWise;
|
2012-08-26 18:39:48 +02:00
|
|
|
setUndoPosition();
|
2009-08-18 09:46:42 +02:00
|
|
|
int endPos = firstPositionInLine(lineForPosition(position()) + count() - 1);
|
|
|
|
|
Range range(position(), endPos, RangeLineMode);
|
|
|
|
|
yankText(range);
|
|
|
|
|
removeText(range);
|
2009-04-29 15:29:03 +02:00
|
|
|
setDotCommand("%1dd", count());
|
2009-08-18 09:46:42 +02:00
|
|
|
m_submode = NoSubMode;
|
2010-02-19 13:01:37 +01:00
|
|
|
handleStartOfLine();
|
2009-10-16 11:30:46 +02:00
|
|
|
setTargetColumn();
|
2009-04-29 15:29:03 +02:00
|
|
|
finishMovement();
|
2010-04-19 11:35:48 +02:00
|
|
|
} else if ((subModeCanUseTextObjects(m_submode) || isVisualMode())
|
2010-04-28 14:00:44 +02:00
|
|
|
&& (input.is('a') || input.is('i'))) {
|
2010-03-18 17:45:15 +01:00
|
|
|
m_subsubmode = TextObjectSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
m_subsubdata = input;
|
2012-09-29 15:36:18 +02:00
|
|
|
} else if ((m_submode == ShiftLeftSubMode && input.is('<'))
|
|
|
|
|
|| (m_submode == ShiftRightSubMode && input.is('>'))
|
|
|
|
|
|| (m_submode == IndentSubMode && input.is('='))) {
|
2012-08-26 18:39:48 +02:00
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
setUndoPosition();
|
2009-03-06 11:22:16 +01:00
|
|
|
moveDown(count() - 1);
|
2012-09-29 15:36:18 +02:00
|
|
|
setDotCommand(QString("%2%1%1").arg(input.asChar()), count());
|
2008-12-26 14:19:33 +01:00
|
|
|
finishMovement();
|
2008-12-19 16:20:39 +01:00
|
|
|
} else if (m_submode == ZSubMode) {
|
2010-07-06 10:12:21 +02:00
|
|
|
//qDebug() << "Z_MODE " << cursorLine() << linesOnScreen();
|
2010-05-10 16:41:35 +02:00
|
|
|
if (input.isReturn() || input.is('t')) {
|
2010-04-28 14:00:44 +02:00
|
|
|
// Cursor line to top of window.
|
2009-01-27 12:44:42 +01:00
|
|
|
if (!m_mvcount.isEmpty())
|
2009-03-06 11:22:16 +01:00
|
|
|
setPosition(firstPositionInLine(count()));
|
2009-03-20 08:44:52 +01:00
|
|
|
scrollUp(- cursorLineOnScreen());
|
2010-05-10 16:41:35 +02:00
|
|
|
if (input.isReturn())
|
2009-01-27 12:44:42 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2008-12-19 16:20:39 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('.') || input.is('z')) {
|
|
|
|
|
// Cursor line to center of window.
|
2009-01-27 12:44:42 +01:00
|
|
|
if (!m_mvcount.isEmpty())
|
2009-03-06 11:22:16 +01:00
|
|
|
setPosition(firstPositionInLine(count()));
|
2009-03-20 08:44:52 +01:00
|
|
|
scrollUp(linesOnScreen() / 2 - cursorLineOnScreen());
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('.'))
|
2009-01-27 12:44:42 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2009-01-27 12:11:08 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('-') || input.is('b')) {
|
|
|
|
|
// Cursor line to bottom of window.
|
2009-01-27 12:44:42 +01:00
|
|
|
if (!m_mvcount.isEmpty())
|
2009-03-06 11:22:16 +01:00
|
|
|
setPosition(firstPositionInLine(count()));
|
2009-03-20 08:44:52 +01:00
|
|
|
scrollUp(linesOnScreen() - cursorLineOnScreen());
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('-'))
|
2009-01-27 12:44:42 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2009-01-27 12:29:14 +01:00
|
|
|
finishMovement();
|
2008-12-25 13:20:09 +01:00
|
|
|
} else {
|
2010-04-28 14:00:44 +02:00
|
|
|
qDebug() << "IGNORED Z_MODE " << input.key() << input.text();
|
2008-12-19 16:20:39 +01:00
|
|
|
}
|
|
|
|
|
m_submode = NoSubMode;
|
2009-05-29 09:22:00 +10:00
|
|
|
} else if (m_submode == CapitalZSubMode) {
|
|
|
|
|
// Recognize ZZ and ZQ as aliases for ":x" and ":q!".
|
|
|
|
|
m_submode = NoSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('Z'))
|
2010-03-18 13:15:59 +01:00
|
|
|
handleExCommand(QString(QLatin1Char('x')));
|
2010-04-28 14:00:44 +02:00
|
|
|
else if (input.is('Q'))
|
2010-03-18 13:15:59 +01:00
|
|
|
handleExCommand("q!");
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isDigit()) {
|
|
|
|
|
if (input.is('0') && m_mvcount.isEmpty()) {
|
2010-01-21 17:38:28 +01:00
|
|
|
m_movetype = MoveExclusive;
|
2009-02-05 16:07:40 +01:00
|
|
|
moveToStartOfLine();
|
2009-04-07 17:13:15 +02:00
|
|
|
setTargetColumn();
|
2010-02-02 17:09:41 +01:00
|
|
|
finishMovement(QString(QLatin1Char('0')));
|
2008-12-19 12:20:04 +01:00
|
|
|
} else {
|
2010-04-28 14:00:44 +02:00
|
|
|
m_mvcount.append(input.text());
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
2011-05-16 10:31:29 +02:00
|
|
|
} else {
|
2011-05-16 17:21:43 +02:00
|
|
|
handled = handleCommandMode1(input);
|
2011-05-16 10:31:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-16 17:21:43 +02:00
|
|
|
EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
|
2011-05-16 10:31:29 +02:00
|
|
|
{
|
|
|
|
|
EventResult handled = EventHandled;
|
|
|
|
|
|
|
|
|
|
if (input.is('^') || input.is('_')) {
|
2009-02-05 16:07:40 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2010-02-19 13:01:37 +01:00
|
|
|
setTargetColumn();
|
2010-01-21 17:38:28 +01:00
|
|
|
m_movetype = MoveExclusive;
|
2010-04-28 14:00:44 +02:00
|
|
|
finishMovement(input.text());
|
|
|
|
|
} else if (0 && input.is(',')) {
|
2009-01-26 10:48:37 +01:00
|
|
|
// FIXME: fakevim uses ',' by itself, so it is incompatible
|
|
|
|
|
m_subsubmode = FtSubSubMode;
|
|
|
|
|
// HACK: toggle 'f' <-> 'F', 't' <-> 'T'
|
2010-04-28 14:00:44 +02:00
|
|
|
//m_subsubdata = m_semicolonType ^ 32;
|
2009-01-26 10:48:37 +01:00
|
|
|
handleFfTt(m_semicolonKey);
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is(';')) {
|
2009-01-26 10:48:37 +01:00
|
|
|
m_subsubmode = FtSubSubMode;
|
|
|
|
|
m_subsubdata = m_semicolonType;
|
|
|
|
|
handleFfTt(m_semicolonKey);
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
finishMovement();
|
2011-11-28 17:59:30 +01:00
|
|
|
} else if (input.is('&')) {
|
|
|
|
|
handleExCommand(m_gflag ? "%s//~/&" : "s");
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is(':')) {
|
2009-01-26 12:08:39 +01:00
|
|
|
enterExMode();
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage.clear();
|
|
|
|
|
g.commandBuffer.clear();
|
2009-12-11 18:59:05 +01:00
|
|
|
if (isVisualMode())
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.setContents("'<,'>");
|
2009-01-06 16:04:34 +01:00
|
|
|
updateMiniBuffer();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('/') || input.is('?')) {
|
2012-10-03 16:40:05 +02:00
|
|
|
g.lastSearchForward = input.is('/');
|
2010-04-08 08:34:55 +02:00
|
|
|
if (hasConfig(ConfigUseCoreSearch)) {
|
2009-06-02 11:56:58 +02:00
|
|
|
// re-use the core dialog.
|
2012-10-03 16:40:05 +02:00
|
|
|
g.findPending = true;
|
2010-10-26 10:56:32 +02:00
|
|
|
m_findStartPosition = position();
|
|
|
|
|
m_movetype = MoveExclusive;
|
2010-12-16 12:05:48 +01:00
|
|
|
setAnchor(); // clear selection: otherwise, search is restricted to selection
|
2012-10-03 16:40:05 +02:00
|
|
|
emit q->findRequested(!g.lastSearchForward);
|
2009-06-02 11:56:58 +02:00
|
|
|
} else {
|
|
|
|
|
// FIXME: make core find dialog sufficiently flexible to
|
|
|
|
|
// produce the "default vi" behaviour too. For now, roll our own.
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage.clear();
|
2010-05-06 14:16:41 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2010-05-05 16:59:58 +02:00
|
|
|
m_subsubmode = SearchSubSubMode;
|
2012-10-03 16:40:05 +02:00
|
|
|
g.searchBuffer.setPrompt(g.lastSearchForward ? '/' : '?');
|
2012-09-01 10:44:02 +02:00
|
|
|
m_searchStartPosition = position();
|
|
|
|
|
m_searchFromScreenLine = firstVisibleLine();
|
2012-09-27 21:09:13 +02:00
|
|
|
m_searchCursor = QTextCursor();
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.clear();
|
2009-06-02 11:56:58 +02:00
|
|
|
updateMiniBuffer();
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('`')) {
|
2008-12-28 03:07:52 +01:00
|
|
|
m_subsubmode = BackTickSubSubMode;
|
2010-08-11 15:14:33 +02:00
|
|
|
if (m_submode != NoSubMode)
|
|
|
|
|
m_movetype = MoveLineWise;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('#') || input.is('*')) {
|
2009-01-16 09:56:08 +01:00
|
|
|
// FIXME: That's not proper vim behaviour
|
2010-09-13 15:23:20 +02:00
|
|
|
QString needle;
|
2010-09-14 16:58:31 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.select(QTextCursor::WordUnderCursor);
|
2012-10-01 17:37:34 +02:00
|
|
|
if (m_gflag)
|
|
|
|
|
needle = tc.selection().toPlainText();
|
|
|
|
|
else
|
|
|
|
|
needle = "\\<" + tc.selection().toPlainText() + "\\>";
|
2010-09-16 14:32:29 +02:00
|
|
|
setAnchorAndPosition(tc.position(), tc.anchor());
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.historyPush(needle);
|
2012-10-03 16:40:05 +02:00
|
|
|
g.lastSearch = needle;
|
|
|
|
|
g.lastSearchForward = input.is('*');
|
2012-09-01 10:44:02 +02:00
|
|
|
searchNext();
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('\'')) {
|
2008-12-28 03:07:52 +01:00
|
|
|
m_subsubmode = TickSubSubMode;
|
2010-08-11 15:14:33 +02:00
|
|
|
if (m_submode != NoSubMode)
|
|
|
|
|
m_movetype = MoveLineWise;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('|')) {
|
2009-01-16 16:15:01 +01:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
moveRight(qMin(count(), rightDist()) - 1);
|
2009-04-07 17:13:15 +02:00
|
|
|
setTargetColumn();
|
2008-12-19 12:20:04 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('!') && isNoVisualMode()) {
|
2009-01-08 17:21:51 +01:00
|
|
|
m_submode = FilterSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('!') && isVisualMode()) {
|
2009-01-26 12:08:39 +01:00
|
|
|
enterExMode();
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage.clear();
|
|
|
|
|
g.commandBuffer.setContents("'<,'>!");
|
2009-01-08 17:21:51 +01:00
|
|
|
updateMiniBuffer();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('"')) {
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = RegisterSubMode;
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.isReturn()) {
|
2009-01-16 16:15:01 +01:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
moveDown();
|
2009-01-15 16:57:11 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2010-01-21 17:38:24 +01:00
|
|
|
m_movetype = MoveLineWise;
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1j", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('-')) {
|
2009-05-29 08:04:13 +10:00
|
|
|
moveToStartOfLine();
|
2010-01-05 18:42:26 +01:00
|
|
|
moveUp(count());
|
|
|
|
|
moveToFirstNonBlankOnLine();
|
2010-01-21 17:38:24 +01:00
|
|
|
m_movetype = MoveLineWise;
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1-", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('+')) {
|
2010-01-05 18:42:26 +01:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
moveDown(count());
|
2009-05-29 08:04:13 +10:00
|
|
|
moveToFirstNonBlankOnLine();
|
2010-01-21 17:38:24 +01:00
|
|
|
m_movetype = MoveLineWise;
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1+", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Home)) {
|
2009-01-16 16:15:01 +01:00
|
|
|
moveToStartOfLine();
|
2009-04-07 17:13:15 +02:00
|
|
|
setTargetColumn();
|
2008-12-19 12:20:04 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('$') || input.isKey(Key_End)) {
|
2010-01-21 17:38:25 +01:00
|
|
|
if (count() > 1)
|
|
|
|
|
moveDown(count() - 1);
|
2009-01-16 16:15:01 +01:00
|
|
|
moveToEndOfLine();
|
2010-01-05 18:42:25 +01:00
|
|
|
m_movetype = MoveInclusive;
|
2009-04-07 17:13:15 +02:00
|
|
|
setTargetColumn();
|
2010-01-05 18:42:25 +01:00
|
|
|
if (m_submode == NoSubMode)
|
2009-04-03 14:58:41 +02:00
|
|
|
m_targetColumn = -1;
|
2010-01-21 17:38:31 +01:00
|
|
|
if (isVisualMode())
|
|
|
|
|
m_visualTargetColumn = -1;
|
2010-01-21 17:38:25 +01:00
|
|
|
finishMovement("%1$", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is(',')) {
|
2010-01-05 15:30:22 +01:00
|
|
|
passShortcuts(true);
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('.')) {
|
2010-05-05 15:50:05 +02:00
|
|
|
//qDebug() << "REPEATING" << quoteUnprintable(g.dotCommand) << count()
|
2010-05-04 17:58:53 +02:00
|
|
|
// << input;
|
2010-05-05 15:50:05 +02:00
|
|
|
QString savedCommand = g.dotCommand;
|
|
|
|
|
g.dotCommand.clear();
|
2012-09-28 17:01:24 +02:00
|
|
|
replay(savedCommand, 1);
|
2009-03-05 14:08:42 +01:00
|
|
|
enterCommandMode();
|
2010-05-05 15:50:05 +02:00
|
|
|
g.dotCommand = savedCommand;
|
2011-12-27 17:39:56 +01:00
|
|
|
} else if (input.is('<')) {
|
|
|
|
|
if (isNoVisualMode()) {
|
|
|
|
|
m_submode = ShiftLeftSubMode;
|
2012-09-29 15:36:18 +02:00
|
|
|
setAnchor();
|
2011-12-27 17:39:56 +01:00
|
|
|
} else {
|
2012-04-11 08:38:05 +02:00
|
|
|
shiftRegionLeft(count());
|
2011-12-27 17:39:56 +01:00
|
|
|
leaveVisualMode();
|
|
|
|
|
}
|
|
|
|
|
} else if (input.is('>')) {
|
|
|
|
|
if (isNoVisualMode()) {
|
|
|
|
|
m_submode = ShiftRightSubMode;
|
2012-09-29 15:36:18 +02:00
|
|
|
setAnchor();
|
2011-12-27 17:39:56 +01:00
|
|
|
} else {
|
2012-04-11 08:38:05 +02:00
|
|
|
shiftRegionRight(count());
|
2011-12-27 17:39:56 +01:00
|
|
|
leaveVisualMode();
|
|
|
|
|
}
|
|
|
|
|
} else if (input.is('=')) {
|
|
|
|
|
if (isNoVisualMode()) {
|
|
|
|
|
m_submode = IndentSubMode;
|
2012-09-29 15:36:18 +02:00
|
|
|
setAnchor();
|
2011-12-27 17:39:56 +01:00
|
|
|
} else {
|
|
|
|
|
indentSelectedText();
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('%')) {
|
2009-01-13 12:35:43 +01:00
|
|
|
moveToMatchingParanthesis();
|
2008-12-25 10:43:28 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((!isVisualMode() && input.is('a')) || (isVisualMode() && input.is('A'))) {
|
2010-03-18 13:15:59 +01:00
|
|
|
leaveVisualMode();
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2009-06-04 16:07:09 +02:00
|
|
|
enterInsertMode();
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand(QString(QLatin1Char('a')));
|
2008-12-27 21:51:06 +01:00
|
|
|
m_lastInsertion.clear();
|
2009-01-23 10:13:12 +01:00
|
|
|
if (!atEndOfLine())
|
|
|
|
|
moveRight();
|
2009-01-06 11:49:33 +01:00
|
|
|
updateMiniBuffer();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('A')) {
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2010-01-21 17:38:28 +01:00
|
|
|
moveBehindEndOfLine();
|
2012-08-26 18:39:48 +02:00
|
|
|
setUndoPosition();
|
2010-09-14 18:48:04 +02:00
|
|
|
setAnchor();
|
2010-09-14 18:30:49 +02:00
|
|
|
enterInsertMode();
|
2010-02-02 17:09:41 +01:00
|
|
|
setDotCommand(QString(QLatin1Char('A')));
|
2008-12-27 21:51:06 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-01-05 18:42:24 +01:00
|
|
|
updateMiniBuffer();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('a')) {
|
2011-12-27 14:54:49 +01:00
|
|
|
changeNumberTextObject(true);
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand("%1<c-a>", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('b') || input.isShift(Key_Left)) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), false, false);
|
2010-12-21 11:36:42 +01:00
|
|
|
setTargetColumn();
|
2008-12-25 19:50:14 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('B')) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), true, false);
|
2010-12-21 11:36:42 +01:00
|
|
|
setTargetColumn();
|
2008-12-25 19:50:14 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('c') && isNoVisualMode()) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-01-05 18:42:25 +01:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2009-01-16 16:15:01 +01:00
|
|
|
setAnchor();
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = ChangeSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((input.is('c') || input.is('C') || input.is('s') || input.is('R'))
|
2010-03-18 13:15:59 +01:00
|
|
|
&& (isVisualCharMode() || isVisualLineMode())) {
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand(visualDotCommand() + input.asChar());
|
2010-04-28 14:00:44 +02:00
|
|
|
if ((input.is('c')|| input.is('s')) && isVisualCharMode()) {
|
2010-03-18 13:15:59 +01:00
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeCharMode;
|
|
|
|
|
} else {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
// leaveVisualMode() has set this to MoveInclusive for visual character mode
|
2010-01-21 17:38:28 +01:00
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
}
|
2009-03-19 11:58:59 +01:00
|
|
|
m_submode = ChangeSubMode;
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('C')) {
|
2009-01-16 16:15:01 +01:00
|
|
|
setAnchor();
|
|
|
|
|
moveToEndOfLine();
|
2010-01-21 17:38:28 +01:00
|
|
|
m_submode = ChangeSubMode;
|
2010-02-02 17:09:41 +01:00
|
|
|
setDotCommand(QString(QLatin1Char('C')));
|
2008-12-19 12:20:04 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('c')) {
|
2010-01-05 17:50:15 +01:00
|
|
|
if (isNoVisualMode())
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, "Type Alt-v,Alt-v to quit FakeVim mode");
|
2010-01-05 17:50:15 +01:00
|
|
|
else
|
|
|
|
|
leaveVisualMode();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('d') && isNoVisualMode()) {
|
2009-09-16 14:16:21 +02:00
|
|
|
if (m_rangemode == RangeLineMode) {
|
2010-09-13 15:23:20 +02:00
|
|
|
int pos = position();
|
2009-09-16 14:16:21 +02:00
|
|
|
moveToEndOfLine();
|
|
|
|
|
setAnchor();
|
2010-01-21 17:38:31 +01:00
|
|
|
setPosition(pos);
|
2009-09-16 14:16:21 +02:00
|
|
|
} else {
|
|
|
|
|
setAnchor();
|
|
|
|
|
}
|
2009-01-06 11:43:49 +01:00
|
|
|
m_opcount = m_mvcount;
|
|
|
|
|
m_mvcount.clear();
|
|
|
|
|
m_submode = DeleteSubMode;
|
2010-07-06 16:38:12 +02:00
|
|
|
} else if ((input.is('d') || input.is('x') || input.isKey(Key_Delete))
|
|
|
|
|
&& isVisualMode()) {
|
2012-08-26 18:39:48 +02:00
|
|
|
setUndoPosition();
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand(visualDotCommand() + 'x');
|
2010-07-06 16:38:12 +02:00
|
|
|
if (isVisualCharMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_submode = DeleteSubMode;
|
|
|
|
|
finishMovement();
|
|
|
|
|
} else if (isVisualLineMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
yankText(currentRange(), m_register);
|
|
|
|
|
removeText(currentRange());
|
|
|
|
|
handleStartOfLine();
|
|
|
|
|
} else if (isVisualBlockMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeBlockMode;
|
|
|
|
|
yankText(currentRange(), m_register);
|
|
|
|
|
removeText(currentRange());
|
|
|
|
|
setPosition(qMin(position(), anchor()));
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('D') && isNoVisualMode()) {
|
2012-08-26 18:39:48 +02:00
|
|
|
setUndoPosition();
|
2010-01-05 18:42:25 +01:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = DeleteSubMode;
|
2010-09-14 16:58:31 +02:00
|
|
|
setAnchor();
|
2009-01-16 16:15:01 +01:00
|
|
|
moveDown(qMax(count() - 1, 0));
|
2010-01-05 18:42:25 +01:00
|
|
|
m_movetype = MoveInclusive;
|
2009-02-16 02:13:33 +01:00
|
|
|
moveToEndOfLine();
|
2010-02-02 17:09:41 +01:00
|
|
|
setDotCommand(QString(QLatin1Char('D')));
|
2008-12-19 12:20:04 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((input.is('D') || input.is('X')) &&
|
2009-12-11 18:59:05 +01:00
|
|
|
(isVisualCharMode() || isVisualLineMode())) {
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand(visualDotCommand() + 'X');
|
2009-12-11 18:49:47 +01:00
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
m_submode = NoSubMode;
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
|
|
|
|
removeText(currentRange());
|
2009-12-11 18:49:47 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((input.is('D') || input.is('X')) && isVisualBlockMode()) {
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand(visualDotCommand() + 'X');
|
2009-12-11 18:49:47 +01:00
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeBlockAndTailMode;
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
|
|
|
|
removeText(currentRange());
|
2009-12-11 18:49:47 +01:00
|
|
|
setPosition(qMin(position(), anchor()));
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('d')) {
|
2009-01-27 14:08:17 +01:00
|
|
|
int sline = cursorLineOnScreen();
|
|
|
|
|
// FIXME: this should use the "scroll" option, and "count"
|
|
|
|
|
moveDown(linesOnScreen() / 2);
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2010-07-06 10:12:21 +02:00
|
|
|
scrollToLine(cursorLine() - sline);
|
2009-01-27 14:08:17 +01:00
|
|
|
finishMovement();
|
2012-08-19 19:08:04 +02:00
|
|
|
} else if (input.is('e') && m_gflag) {
|
|
|
|
|
m_movetype = MoveInclusive;
|
|
|
|
|
moveToNextWordEnd(count(), false, false);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
finishMovement("%1ge", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('e') || input.isShift(Key_Right)) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordEnd(count(), false, true, false);
|
2010-12-21 11:36:42 +01:00
|
|
|
setTargetColumn();
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1e", count());
|
2012-08-19 19:08:04 +02:00
|
|
|
} else if (input.is('E') && m_gflag) {
|
|
|
|
|
m_movetype = MoveInclusive;
|
|
|
|
|
moveToNextWordEnd(count(), true, false);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
finishMovement("%1gE", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('E')) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordEnd(count(), true, true, false);
|
2010-12-21 11:36:42 +01:00
|
|
|
setTargetColumn();
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1E", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('e')) {
|
2009-03-20 08:44:52 +01:00
|
|
|
// FIXME: this should use the "scroll" option, and "count"
|
|
|
|
|
if (cursorLineOnScreen() == 0)
|
|
|
|
|
moveDown(1);
|
|
|
|
|
scrollDown(1);
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('f')) {
|
2008-12-26 00:18:03 +01:00
|
|
|
m_subsubmode = FtSubSubMode;
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2010-04-28 14:00:44 +02:00
|
|
|
m_subsubdata = input;
|
|
|
|
|
} else if (input.is('F')) {
|
2009-03-12 15:04:50 +01:00
|
|
|
m_subsubmode = FtSubSubMode;
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2010-04-28 14:00:44 +02:00
|
|
|
m_subsubdata = input;
|
|
|
|
|
} else if (input.is('g') && !m_gflag) {
|
2010-01-05 18:42:26 +01:00
|
|
|
m_gflag = true;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('g') || input.is('G')) {
|
2010-01-21 17:38:25 +01:00
|
|
|
QString dotCommand = QString("%1G").arg(count());
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('G') && m_mvcount.isEmpty())
|
2010-02-02 17:09:41 +01:00
|
|
|
dotCommand = QString(QLatin1Char('G'));
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('g'))
|
2009-02-01 21:35:14 +01:00
|
|
|
m_gflag = false;
|
2010-04-28 14:00:44 +02:00
|
|
|
int n = (input.is('g')) ? 1 : linesInDocument();
|
2010-01-05 18:42:26 +01:00
|
|
|
n = m_mvcount.isEmpty() ? n : count();
|
|
|
|
|
if (m_submode == NoSubMode || m_submode == ZSubMode
|
|
|
|
|
|| m_submode == CapitalZSubMode || m_submode == RegisterSubMode) {
|
2010-09-13 15:23:20 +02:00
|
|
|
setPosition(firstPositionInLine(n));
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2009-02-01 21:35:14 +01:00
|
|
|
} else {
|
2010-01-05 18:42:26 +01:00
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
setAnchor();
|
2010-09-13 15:23:20 +02:00
|
|
|
setPosition(firstPositionInLine(n));
|
2009-02-01 21:35:14 +01:00
|
|
|
}
|
2010-01-05 18:42:26 +01:00
|
|
|
finishMovement(dotCommand);
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.is('h') || input.isKey(Key_Left) || input.isBackspace()) {
|
2010-01-21 17:38:28 +01:00
|
|
|
m_movetype = MoveExclusive;
|
2008-12-19 12:20:04 +01:00
|
|
|
int n = qMin(count(), leftDist());
|
2010-09-13 15:23:20 +02:00
|
|
|
if (m_fakeEnd && block().length() > 1)
|
2008-12-19 12:20:04 +01:00
|
|
|
++n;
|
2009-01-16 16:15:01 +01:00
|
|
|
moveLeft(n);
|
2009-04-03 14:58:41 +02:00
|
|
|
setTargetColumn();
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1h", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('H')) {
|
2010-09-14 14:04:13 +02:00
|
|
|
setCursor(EDITOR(cursorForPosition(QPoint(0, 0))));
|
2009-01-16 16:15:01 +01:00
|
|
|
moveDown(qMax(count() - 1, 0));
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2008-12-19 14:35:57 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (!isVisualMode() && (input.is('i') || input.isKey(Key_Insert))) {
|
2010-02-02 17:09:41 +01:00
|
|
|
setDotCommand(QString(QLatin1Char('i'))); // setDotCommand("%1i", count());
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2009-01-06 13:03:59 +01:00
|
|
|
enterInsertMode();
|
2009-01-06 11:49:33 +01:00
|
|
|
updateMiniBuffer();
|
2009-01-23 10:13:12 +01:00
|
|
|
if (atEndOfLine())
|
2009-01-16 17:38:15 +01:00
|
|
|
moveLeft();
|
2011-05-16 17:21:43 +02:00
|
|
|
} else {
|
|
|
|
|
handled = handleCommandMode2(input);
|
|
|
|
|
}
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input)
|
|
|
|
|
{
|
|
|
|
|
EventResult handled = EventHandled;
|
|
|
|
|
|
|
|
|
|
if (input.is('I')) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-02-02 17:09:41 +01:00
|
|
|
setDotCommand(QString(QLatin1Char('I'))); // setDotCommand("%1I", count());
|
2010-02-12 15:24:54 +01:00
|
|
|
if (isVisualMode()) {
|
|
|
|
|
int beginLine = lineForPosition(anchor());
|
|
|
|
|
int endLine = lineForPosition(position());
|
|
|
|
|
m_visualInsertCount = qAbs(endLine - beginLine);
|
|
|
|
|
setPosition(qMin(position(), anchor()));
|
|
|
|
|
} else {
|
|
|
|
|
if (m_gflag)
|
|
|
|
|
moveToStartOfLine();
|
|
|
|
|
else
|
|
|
|
|
moveToFirstNonBlankOnLine();
|
|
|
|
|
m_gflag = false;
|
2010-09-13 15:23:20 +02:00
|
|
|
//m_tc.clearSelection();
|
2010-02-12 15:24:54 +01:00
|
|
|
}
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2010-03-08 11:44:43 +01:00
|
|
|
enterInsertMode();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('i')) {
|
2012-08-11 14:31:42 +02:00
|
|
|
jump(count());
|
2010-07-14 13:34:15 +02:00
|
|
|
} else if (input.is('j') || input.isKey(Key_Down)
|
|
|
|
|
|| input.isControl('j') || input.isControl('n')) {
|
2010-01-21 17:38:27 +01:00
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
moveDown(count());
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1j", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('J')) {
|
2009-11-19 08:36:21 +01:00
|
|
|
beginEditBlock();
|
2008-12-27 13:39:34 +01:00
|
|
|
if (m_submode == NoSubMode) {
|
|
|
|
|
for (int i = qMax(count(), 2) - 1; --i >= 0; ) {
|
2010-01-21 17:38:28 +01:00
|
|
|
moveBehindEndOfLine();
|
2010-09-14 16:58:31 +02:00
|
|
|
setAnchor();
|
2009-04-01 15:11:26 +02:00
|
|
|
moveRight();
|
2009-12-11 19:09:35 +01:00
|
|
|
if (m_gflag) {
|
2010-09-14 16:58:31 +02:00
|
|
|
removeText(currentRange());
|
2009-12-11 19:09:35 +01:00
|
|
|
} else {
|
|
|
|
|
while (characterAtCursor() == ' '
|
|
|
|
|
|| characterAtCursor() == '\t')
|
|
|
|
|
moveRight();
|
2010-09-14 16:58:31 +02:00
|
|
|
removeText(currentRange());
|
2010-09-14 14:04:13 +02:00
|
|
|
cursor().insertText(QString(QLatin1Char(' ')));
|
2009-12-11 19:09:35 +01:00
|
|
|
}
|
2008-12-27 13:39:34 +01:00
|
|
|
}
|
2008-12-27 13:50:52 +01:00
|
|
|
if (!m_gflag)
|
2009-01-16 16:15:01 +01:00
|
|
|
moveLeft();
|
2008-12-27 13:39:34 +01:00
|
|
|
}
|
2009-11-19 08:36:21 +01:00
|
|
|
endEditBlock();
|
2012-09-28 17:01:24 +02:00
|
|
|
finishMovement("%1J");
|
2010-07-14 13:34:15 +02:00
|
|
|
} else if (input.is('k') || input.isKey(Key_Up) || input.isControl('p')) {
|
2010-01-21 17:38:27 +01:00
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
moveUp(count());
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1k", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('l') || input.isKey(Key_Right) || input.is(' ')) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2010-01-21 17:38:31 +01:00
|
|
|
bool pastEnd = count() >= rightDist() - 1;
|
2010-03-18 16:58:55 +01:00
|
|
|
moveRight(qMax(0, qMin(count(), rightDist() - (m_submode == NoSubMode))));
|
2009-04-03 14:58:41 +02:00
|
|
|
setTargetColumn();
|
2010-09-14 14:04:13 +02:00
|
|
|
if (pastEnd && isVisualMode())
|
2010-01-21 17:38:31 +01:00
|
|
|
m_visualTargetColumn = -1;
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1l", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('L')) {
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextCursor tc = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()))));
|
2010-09-14 14:04:13 +02:00
|
|
|
setCursor(tc);
|
2009-01-16 16:15:01 +01:00
|
|
|
moveUp(qMax(count(), 1));
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2008-12-19 14:43:14 +01:00
|
|
|
finishMovement();
|
2012-09-28 17:01:24 +02:00
|
|
|
finishMovement("%1L");
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('l')) {
|
2009-03-05 11:06:25 +01:00
|
|
|
// screen redraw. should not be needed
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('m')) {
|
2011-11-28 16:35:27 +01:00
|
|
|
if (m_gflag) {
|
|
|
|
|
moveToStartOfLine();
|
|
|
|
|
moveRight(qMin(columnsOnScreen() / 2, rightDist()) - 1);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
finishMovement();
|
|
|
|
|
} else {
|
|
|
|
|
m_subsubmode = MarkSubSubMode;
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('M')) {
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextCursor tc = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2)));
|
2010-09-14 14:04:13 +02:00
|
|
|
setCursor(tc);
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2008-12-19 15:00:06 +01:00
|
|
|
finishMovement();
|
2010-05-18 18:24:00 +02:00
|
|
|
} else if (input.is('n') || input.is('N')) {
|
2010-10-26 10:56:32 +02:00
|
|
|
if (hasConfig(ConfigUseCoreSearch)) {
|
2012-10-03 16:40:05 +02:00
|
|
|
bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward;
|
2010-10-26 10:56:32 +02:00
|
|
|
int pos = position();
|
|
|
|
|
emit q->findNextRequested(!forward);
|
|
|
|
|
if (forward && pos == cursor().selectionStart()) {
|
|
|
|
|
// if cursor is already positioned at the start of a find result, this is returned
|
|
|
|
|
emit q->findNextRequested(false);
|
|
|
|
|
}
|
|
|
|
|
setPosition(cursor().selectionStart());
|
|
|
|
|
} else {
|
2012-09-01 10:44:02 +02:00
|
|
|
searchNext(input.is('n'));
|
|
|
|
|
finishMovement();
|
2010-10-26 10:56:32 +02:00
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (isVisualMode() && (input.is('o') || input.is('O'))) {
|
2010-01-21 17:38:25 +01:00
|
|
|
int pos = position();
|
2010-09-14 14:04:13 +02:00
|
|
|
setAnchorAndPosition(pos, anchor());
|
2010-01-21 17:38:31 +01:00
|
|
|
std::swap(m_positionPastEnd, m_anchorPastEnd);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
if (m_positionPastEnd)
|
|
|
|
|
m_visualTargetColumn = -1;
|
2010-05-17 16:25:58 +02:00
|
|
|
} else if (input.is('o')) {
|
2009-04-16 09:18:09 +02:00
|
|
|
setDotCommand("%1o", count());
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
|
|
|
|
beginEditBlock();
|
2008-12-26 10:36:40 +01:00
|
|
|
moveToFirstNonBlankOnLine();
|
2010-05-17 16:25:58 +02:00
|
|
|
moveBehindEndOfLine();
|
2011-11-12 02:31:52 +01:00
|
|
|
insertText(QString("\n"));
|
2010-05-17 16:25:58 +02:00
|
|
|
insertAutomaticIndentation(true);
|
|
|
|
|
endEditBlock();
|
2012-08-26 18:39:48 +02:00
|
|
|
enterInsertMode();
|
2010-05-17 16:25:58 +02:00
|
|
|
} else if (input.is('O')) {
|
|
|
|
|
setDotCommand("%1O", count());
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2010-05-17 16:25:58 +02:00
|
|
|
enterInsertMode();
|
2011-12-27 17:39:56 +01:00
|
|
|
beginEditBlock();
|
2010-05-17 16:25:58 +02:00
|
|
|
moveToFirstNonBlankOnLine();
|
|
|
|
|
moveToStartOfLine();
|
2011-11-12 02:31:52 +01:00
|
|
|
insertText(QString("\n"));
|
2010-05-17 16:25:58 +02:00
|
|
|
moveUp();
|
|
|
|
|
insertAutomaticIndentation(false);
|
2009-08-18 11:32:11 +02:00
|
|
|
endEditBlock();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('o')) {
|
2012-08-11 14:31:42 +02:00
|
|
|
jump(-count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('p') || input.is('P')) {
|
|
|
|
|
pasteText(input.is('p'));
|
2009-08-11 14:39:44 +02:00
|
|
|
setTargetColumn();
|
2009-04-16 09:18:09 +02:00
|
|
|
setDotCommand("%1p", count());
|
2009-01-22 15:38:03 +01:00
|
|
|
finishMovement();
|
2010-05-06 12:10:57 +02:00
|
|
|
} else if (input.is('r')) {
|
2010-05-28 13:09:24 +02:00
|
|
|
m_submode = ReplaceSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (!isVisualMode() && input.is('R')) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2010-05-06 12:10:57 +02:00
|
|
|
enterReplaceMode();
|
2010-01-21 17:38:23 +01:00
|
|
|
updateMiniBuffer();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('r')) {
|
2012-08-26 18:39:48 +02:00
|
|
|
int repeat = count();
|
|
|
|
|
while (--repeat >= 0)
|
|
|
|
|
redo();
|
|
|
|
|
finishMovement();
|
2010-12-21 15:14:24 +01:00
|
|
|
} else if (input.is('s') && isVisualBlockMode()) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-12-21 15:14:24 +01:00
|
|
|
Range range(position(), anchor(), RangeBlockMode);
|
|
|
|
|
int beginLine = lineForPosition(anchor());
|
|
|
|
|
int endLine = lineForPosition(position());
|
|
|
|
|
m_visualInsertCount = qAbs(endLine - beginLine);
|
|
|
|
|
setPosition(qMin(position(), anchor()));
|
|
|
|
|
yankText(range, m_register);
|
|
|
|
|
removeText(range);
|
|
|
|
|
setDotCommand("%1s", count());
|
|
|
|
|
breakEditBlock();
|
|
|
|
|
enterInsertMode();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('s')) {
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-03-18 13:15:59 +01:00
|
|
|
leaveVisualMode();
|
2009-04-01 15:52:48 +02:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2009-01-27 09:46:57 +01:00
|
|
|
setAnchor();
|
2009-01-16 16:15:01 +01:00
|
|
|
moveRight(qMin(count(), rightDist()));
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
|
|
|
|
removeText(currentRange());
|
2009-08-20 10:21:35 +02:00
|
|
|
setDotCommand("%1s", count());
|
2009-01-27 09:46:57 +01:00
|
|
|
m_opcount.clear();
|
|
|
|
|
m_mvcount.clear();
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2009-01-27 09:46:57 +01:00
|
|
|
enterInsertMode();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('S')) {
|
2012-08-26 18:39:48 +02:00
|
|
|
m_movetype = MoveLineWise;
|
2011-12-27 17:39:56 +01:00
|
|
|
setUndoPosition();
|
2010-09-14 14:04:13 +02:00
|
|
|
beginEditBlock();
|
2010-03-18 13:16:32 +01:00
|
|
|
if (!isVisualMode()) {
|
2010-07-06 10:12:21 +02:00
|
|
|
const int line = cursorLine() + 1;
|
2010-09-14 14:04:13 +02:00
|
|
|
const int anc = firstPositionInLine(line);
|
|
|
|
|
const int pos = lastPositionInLine(line + count() - 1);
|
|
|
|
|
setAnchorAndPosition(anc, pos);
|
2010-03-18 13:15:59 +01:00
|
|
|
}
|
2010-01-05 17:42:36 +01:00
|
|
|
setDotCommand("%1S", count());
|
2010-05-20 16:32:54 +02:00
|
|
|
breakEditBlock();
|
2010-01-05 17:42:36 +01:00
|
|
|
enterInsertMode();
|
2010-01-21 17:38:28 +01:00
|
|
|
m_submode = ChangeSubMode;
|
2010-09-14 14:04:13 +02:00
|
|
|
endEditBlock();
|
2010-01-21 17:38:28 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (m_gflag && input.is('t')) {
|
2010-01-22 13:56:50 +01:00
|
|
|
m_gflag = false;
|
2010-03-18 13:15:59 +01:00
|
|
|
handleExCommand("tabnext");
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('t')) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2009-03-12 15:04:50 +01:00
|
|
|
m_subsubmode = FtSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
m_subsubdata = input;
|
|
|
|
|
} else if (m_gflag && input.is('T')) {
|
2010-01-22 13:56:50 +01:00
|
|
|
m_gflag = false;
|
2010-03-18 13:15:59 +01:00
|
|
|
handleExCommand("tabprev");
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('T')) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2008-12-26 00:18:03 +01:00
|
|
|
m_subsubmode = FtSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
m_subsubdata = input;
|
|
|
|
|
} else if (input.isControl('t')) {
|
2010-03-18 13:15:59 +01:00
|
|
|
handleExCommand("pop");
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (!m_gflag && input.is('u')) {
|
2012-08-26 18:39:48 +02:00
|
|
|
int repeat = count();
|
|
|
|
|
while (--repeat >= 0)
|
|
|
|
|
undo();
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('u')) {
|
2009-01-27 14:08:17 +01:00
|
|
|
int sline = cursorLineOnScreen();
|
|
|
|
|
// FIXME: this should use the "scroll" option, and "count"
|
|
|
|
|
moveUp(linesOnScreen() / 2);
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2010-07-06 10:12:21 +02:00
|
|
|
scrollToLine(cursorLine() - sline);
|
2009-01-27 14:08:17 +01:00
|
|
|
finishMovement();
|
2012-08-11 10:59:29 +02:00
|
|
|
} else if (m_gflag && input.is('v')) {
|
|
|
|
|
if (m_lastSelectionCursor.hasSelection()) {
|
|
|
|
|
toggleVisualMode(m_lastSelectionMode);
|
|
|
|
|
setCursor(m_lastSelectionCursor);
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('v')) {
|
2011-08-02 17:59:05 +02:00
|
|
|
toggleVisualMode(VisualCharMode);
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('V')) {
|
2011-08-02 17:59:05 +02:00
|
|
|
toggleVisualMode(VisualLineMode);
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('v')) {
|
2011-08-02 17:59:05 +02:00
|
|
|
toggleVisualMode(VisualBlockMode);
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('w')) { // tested
|
2009-01-16 16:42:31 +01:00
|
|
|
// Special case: "cw" and "cW" work the same as "ce" and "cE" if the
|
2010-03-18 16:58:55 +01:00
|
|
|
// cursor is on a non-blank - except if the cursor is on the last
|
|
|
|
|
// character of a word: only the current word will be changed
|
2009-01-28 18:42:43 +01:00
|
|
|
if (m_submode == ChangeSubMode) {
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToWordEnd(count(), false, true);
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2009-01-28 18:42:43 +01:00
|
|
|
} else {
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), false, true);
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2009-01-28 18:42:43 +01:00
|
|
|
}
|
2012-08-19 19:08:04 +02:00
|
|
|
setTargetColumn();
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1w", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('W')) {
|
2009-01-28 18:48:22 +01:00
|
|
|
if (m_submode == ChangeSubMode) {
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToWordEnd(count(), true, true);
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2009-01-28 18:48:22 +01:00
|
|
|
} else {
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), true, true);
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2009-01-28 18:48:22 +01:00
|
|
|
}
|
2012-08-19 19:08:04 +02:00
|
|
|
setTargetColumn();
|
2010-01-21 17:38:24 +01:00
|
|
|
finishMovement("%1W", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('w')) {
|
2009-04-03 16:33:28 +02:00
|
|
|
m_submode = WindowSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('x') && isNoVisualMode()) { // = "dl"
|
2009-08-11 14:39:44 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2008-12-19 12:20:04 +01:00
|
|
|
m_submode = DeleteSubMode;
|
2010-09-14 14:04:13 +02:00
|
|
|
const int n = qMin(count(), rightDist());
|
|
|
|
|
setAnchorAndPosition(position(), position() + n);
|
2009-04-16 09:18:09 +02:00
|
|
|
setDotCommand("%1x", count());
|
2009-03-05 14:08:42 +01:00
|
|
|
finishMovement();
|
2011-12-27 14:54:49 +01:00
|
|
|
} else if (input.isControl('x')) {
|
|
|
|
|
changeNumberTextObject(false);
|
2012-09-28 17:01:24 +02:00
|
|
|
setDotCommand("%1<c-a>", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('X')) {
|
2008-12-19 12:20:04 +01:00
|
|
|
if (leftDist() > 0) {
|
2009-01-16 16:15:01 +01:00
|
|
|
setAnchor();
|
|
|
|
|
moveLeft(qMin(count(), leftDist()));
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
|
|
|
|
removeText(currentRange());
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((m_submode == YankSubMode && input.is('y'))
|
|
|
|
|
|| (input.is('Y') && isNoVisualMode())) {
|
2010-01-21 17:38:31 +01:00
|
|
|
setAnchor();
|
2009-10-16 11:30:46 +02:00
|
|
|
if (count() > 1)
|
2010-01-21 17:38:31 +01:00
|
|
|
moveDown(count()-1);
|
2009-09-16 14:16:21 +02:00
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
m_submode = YankSubMode;
|
|
|
|
|
finishMovement();
|
2011-05-13 18:56:25 +02:00
|
|
|
} else if (input.isControl('y')) {
|
|
|
|
|
// FIXME: this should use the "scroll" option, and "count"
|
|
|
|
|
if (cursorLineOnScreen() == linesOnScreen() - 1)
|
|
|
|
|
moveUp(1);
|
|
|
|
|
scrollUp(1);
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('y') && isNoVisualMode()) {
|
2010-01-21 17:38:28 +01:00
|
|
|
setAnchor();
|
2008-12-23 21:34:21 +01:00
|
|
|
m_submode = YankSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('y') && isVisualCharMode()) {
|
2009-08-11 14:39:44 +02:00
|
|
|
Range range(position(), anchor(), RangeCharMode);
|
|
|
|
|
range.endPos++; // MoveInclusive
|
|
|
|
|
yankText(range, m_register);
|
2009-08-10 11:43:35 +02:00
|
|
|
setPosition(qMin(position(), anchor()));
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((input.is('y') && isVisualLineMode())
|
|
|
|
|
|| (input.is('Y') && isVisualLineMode())
|
|
|
|
|
|| (input.is('Y') && isVisualCharMode())) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_rangemode = RangeLineMode;
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
2009-03-06 11:22:16 +01:00
|
|
|
setPosition(qMin(position(), anchor()));
|
2009-01-26 12:08:39 +01:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
leaveVisualMode();
|
2009-01-16 17:38:15 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((input.is('y') || input.is('Y')) && isVisualBlockMode()) {
|
2009-08-11 14:39:44 +02:00
|
|
|
m_rangemode = RangeBlockMode;
|
2010-05-12 11:18:18 +02:00
|
|
|
yankText(currentRange(), m_register);
|
2009-08-11 14:39:44 +02:00
|
|
|
setPosition(qMin(position(), anchor()));
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('z')) {
|
2008-12-19 16:20:39 +01:00
|
|
|
m_submode = ZSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('Z')) {
|
2009-05-29 09:22:00 +10:00
|
|
|
m_submode = CapitalZSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (!m_gflag && input.is('~') && !isVisualMode()) {
|
2010-05-12 12:29:05 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2010-01-21 17:38:26 +01:00
|
|
|
if (!atEndOfLine()) {
|
|
|
|
|
beginEditBlock();
|
|
|
|
|
setAnchor();
|
|
|
|
|
moveRight(qMin(count(), rightDist()));
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('~')) {
|
2010-05-12 11:18:18 +02:00
|
|
|
invertCase(currentRange());
|
2010-01-21 17:38:26 +01:00
|
|
|
setDotCommand("%1~", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('u')) {
|
2010-05-12 11:18:18 +02:00
|
|
|
downCase(currentRange());
|
2010-01-21 17:38:26 +01:00
|
|
|
setDotCommand("%1gu", count());
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.is('U')) {
|
2010-05-12 11:18:18 +02:00
|
|
|
upCase(currentRange());
|
2010-01-21 17:38:26 +01:00
|
|
|
setDotCommand("%1gU", count());
|
|
|
|
|
}
|
|
|
|
|
endEditBlock();
|
2008-12-25 22:22:41 +01:00
|
|
|
}
|
2010-01-21 17:38:26 +01:00
|
|
|
finishMovement();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((m_gflag && input.is('~') && !isVisualMode())
|
|
|
|
|
|| (m_gflag && input.is('u') && !isVisualMode())
|
|
|
|
|
|| (m_gflag && input.is('U') && !isVisualMode())) {
|
2010-01-21 17:38:31 +01:00
|
|
|
m_gflag = false;
|
2010-05-12 12:29:05 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2010-01-21 17:38:26 +01:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
|
|
|
|
setAnchor();
|
|
|
|
|
m_submode = TransformSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('~'))
|
2010-01-21 17:38:26 +01:00
|
|
|
m_subsubmode = InvertCaseSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('u'))
|
2010-01-21 17:38:26 +01:00
|
|
|
m_subsubmode = DownCaseSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
else if (input.is('U'))
|
2010-01-21 17:38:26 +01:00
|
|
|
m_subsubmode = UpCaseSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if ((input.is('~') && isVisualMode())
|
|
|
|
|
|| (m_gflag && input.is('u') && isVisualMode())
|
|
|
|
|
|| (m_gflag && input.is('U') && isVisualMode())) {
|
2010-01-21 17:38:31 +01:00
|
|
|
m_gflag = false;
|
2010-05-12 12:29:05 +02:00
|
|
|
m_movetype = MoveExclusive;
|
2010-01-21 17:38:26 +01:00
|
|
|
if (isVisualLineMode())
|
|
|
|
|
m_rangemode = RangeLineMode;
|
|
|
|
|
else if (isVisualBlockMode())
|
|
|
|
|
m_rangemode = RangeBlockMode;
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_submode = TransformSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.is('~'))
|
2010-01-21 17:38:26 +01:00
|
|
|
m_subsubmode = InvertCaseSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
else if (input.is('u'))
|
2010-01-21 17:38:26 +01:00
|
|
|
m_subsubmode = DownCaseSubSubMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
else if (input.is('U'))
|
2010-01-21 17:38:26 +01:00
|
|
|
m_subsubmode = UpCaseSubSubMode;
|
|
|
|
|
finishMovement();
|
2010-07-14 13:02:17 +02:00
|
|
|
} else if (input.is('[')) {
|
|
|
|
|
m_submode = OpenSquareSubMode;
|
|
|
|
|
} else if (input.is(']')) {
|
|
|
|
|
m_submode = CloseSquareSubMode;
|
2010-06-23 15:13:51 +02:00
|
|
|
} else if (input.isKey(Key_PageDown) || input.isControl('f')) {
|
2009-03-25 15:17:58 +01:00
|
|
|
moveDown(count() * (linesOnScreen() - 2) - cursorLineOnScreen());
|
2010-07-06 10:12:21 +02:00
|
|
|
scrollToLine(cursorLine());
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2012-09-28 17:01:24 +02:00
|
|
|
finishMovement("%1f", count());
|
2010-06-23 15:13:51 +02:00
|
|
|
} else if (input.isKey(Key_PageUp) || input.isControl('b')) {
|
2009-03-25 15:17:58 +01:00
|
|
|
moveUp(count() * (linesOnScreen() - 2) + cursorLineOnScreen());
|
2010-07-06 10:12:21 +02:00
|
|
|
scrollToLine(cursorLine() + linesOnScreen() - 2);
|
2009-04-03 14:58:41 +02:00
|
|
|
handleStartOfLine();
|
2012-09-28 17:01:24 +02:00
|
|
|
finishMovement("%1b", count());
|
2010-06-23 15:13:51 +02:00
|
|
|
} else if (input.isKey(Key_Delete)) {
|
2009-01-22 13:44:25 +01:00
|
|
|
setAnchor();
|
|
|
|
|
moveRight(qMin(1, rightDist()));
|
2010-05-12 11:18:18 +02:00
|
|
|
removeText(currentRange());
|
2010-07-06 16:38:12 +02:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2010-06-23 15:13:51 +02:00
|
|
|
} else if (input.isKey(Key_BracketLeft) || input.isKey(Key_BracketRight)) {
|
2009-11-27 14:48:37 +01:00
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl(Key_BracketRight)) {
|
2010-03-18 13:15:59 +01:00
|
|
|
handleExCommand("tag");
|
2008-12-19 12:20:04 +01:00
|
|
|
} else {
|
2010-01-07 16:20:51 +01:00
|
|
|
//qDebug() << "IGNORED IN COMMAND MODE: " << key << text
|
|
|
|
|
// << " VISUAL: " << m_visualMode;
|
2010-01-21 17:38:24 +01:00
|
|
|
|
|
|
|
|
// if a key which produces text was pressed, don't mark it as unhandled
|
|
|
|
|
// - otherwise the text would be inserted while being in command mode
|
2010-04-28 14:00:44 +02:00
|
|
|
if (input.text().isEmpty()) {
|
2010-01-21 17:38:24 +01:00
|
|
|
handled = EventUnhandled;
|
|
|
|
|
}
|
2009-01-08 13:16:04 +01:00
|
|
|
}
|
2008-12-23 22:28:46 +01:00
|
|
|
|
2010-01-21 17:38:31 +01:00
|
|
|
m_positionPastEnd = (m_visualTargetColumn == -1) && isVisualMode();
|
|
|
|
|
|
2008-12-23 22:28:46 +01:00
|
|
|
return handled;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-06 12:10:57 +02:00
|
|
|
EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
|
|
|
|
|
{
|
2010-05-18 18:24:00 +02:00
|
|
|
if (input.isEscape()) {
|
2010-05-06 12:10:57 +02:00
|
|
|
moveLeft(qMin(1, leftDist()));
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_mode = CommandMode;
|
|
|
|
|
finishMovement();
|
2012-09-10 22:10:23 +02:00
|
|
|
updateMiniBuffer();
|
2011-08-03 11:40:45 +02:00
|
|
|
} else if (input.isKey(Key_Left)) {
|
|
|
|
|
breakEditBlock();
|
|
|
|
|
moveLeft(1);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
} else if (input.isKey(Key_Right)) {
|
|
|
|
|
breakEditBlock();
|
|
|
|
|
moveRight(1);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
} else if (input.isKey(Key_Up)) {
|
|
|
|
|
breakEditBlock();
|
|
|
|
|
moveUp(1);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
} else if (input.isKey(Key_Down)) {
|
|
|
|
|
breakEditBlock();
|
|
|
|
|
moveDown(1);
|
2010-05-06 12:10:57 +02:00
|
|
|
} else {
|
2010-05-06 16:05:44 +02:00
|
|
|
joinPreviousEditBlock();
|
2010-05-06 12:10:57 +02:00
|
|
|
if (!atEndOfLine()) {
|
|
|
|
|
setAnchor();
|
|
|
|
|
moveRight();
|
2010-05-12 11:18:18 +02:00
|
|
|
m_lastDeletion += selectText(Range(position(), anchor()));
|
|
|
|
|
removeText(currentRange());
|
2010-05-06 12:10:57 +02:00
|
|
|
}
|
|
|
|
|
const QString text = input.text();
|
|
|
|
|
m_lastInsertion += text;
|
2010-09-16 16:56:11 +02:00
|
|
|
setAnchor();
|
2010-05-11 14:26:37 +02:00
|
|
|
insertText(text);
|
2010-05-06 12:10:57 +02:00
|
|
|
endEditBlock();
|
2011-12-30 23:21:45 +01:00
|
|
|
setTargetColumn();
|
2010-05-06 12:10:57 +02:00
|
|
|
}
|
|
|
|
|
return EventHandled;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-26 13:22:06 +01:00
|
|
|
EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-04-28 14:00:44 +02:00
|
|
|
//const int key = input.key;
|
|
|
|
|
//const QString &text = input.text;
|
2010-03-26 13:22:06 +01:00
|
|
|
|
2010-05-18 18:24:00 +02:00
|
|
|
if (input.isEscape()) {
|
2010-02-12 15:24:54 +01:00
|
|
|
if (isVisualBlockMode() && !m_lastInsertion.contains('\n')) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
joinPreviousEditBlock();
|
|
|
|
|
moveLeft(m_lastInsertion.size());
|
|
|
|
|
setAnchor();
|
|
|
|
|
int pos = position();
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
for (int i = 0; i < m_visualInsertCount; ++i) {
|
|
|
|
|
moveDown();
|
2010-05-11 14:26:37 +02:00
|
|
|
insertText(m_lastInsertion);
|
2010-02-12 15:24:54 +01:00
|
|
|
}
|
|
|
|
|
moveLeft(1);
|
|
|
|
|
Range range(pos, position(), RangeBlockMode);
|
|
|
|
|
yankText(range);
|
|
|
|
|
setPosition(pos);
|
|
|
|
|
setDotCommand("p");
|
|
|
|
|
endEditBlock();
|
|
|
|
|
} else {
|
2010-05-11 14:26:37 +02:00
|
|
|
// Normal insertion. Start with '1', as one instance was
|
|
|
|
|
// already physically inserted while typing.
|
|
|
|
|
QString data;
|
|
|
|
|
for (int i = 1; i < count(); ++i)
|
2010-02-12 15:24:54 +01:00
|
|
|
data += m_lastInsertion;
|
2010-05-11 14:26:37 +02:00
|
|
|
insertText(data);
|
2010-02-12 15:24:54 +01:00
|
|
|
moveLeft(qMin(1, leftDist()));
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
leaveVisualMode();
|
2011-12-26 16:38:31 +01:00
|
|
|
breakEditBlock();
|
2010-02-12 15:24:54 +01:00
|
|
|
}
|
2010-05-05 15:50:05 +02:00
|
|
|
g.dotCommand += m_lastInsertion;
|
|
|
|
|
g.dotCommand += QChar(27);
|
2009-01-06 13:03:59 +01:00
|
|
|
enterCommandMode();
|
2010-01-21 17:38:23 +01:00
|
|
|
m_submode = NoSubMode;
|
2010-07-06 09:20:40 +02:00
|
|
|
m_ctrlVActive = false;
|
2010-10-01 18:42:00 +02:00
|
|
|
m_opcount.clear();
|
|
|
|
|
m_mvcount.clear();
|
2010-07-06 09:20:40 +02:00
|
|
|
} else if (m_ctrlVActive) {
|
|
|
|
|
insertInInsertMode(input.raw());
|
|
|
|
|
} else if (input.isControl('v')) {
|
|
|
|
|
m_ctrlVActive = true;
|
2010-10-08 12:51:19 +02:00
|
|
|
} else if (input.isControl('w')) {
|
|
|
|
|
int endPos = position();
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), false, false);
|
2010-12-21 11:36:42 +01:00
|
|
|
setTargetColumn();
|
2010-10-08 12:51:19 +02:00
|
|
|
int beginPos = position();
|
|
|
|
|
Range range(beginPos, endPos, RangeCharMode);
|
|
|
|
|
removeText(range);
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Insert)) {
|
2010-05-06 12:10:57 +02:00
|
|
|
if (m_mode == ReplaceMode)
|
|
|
|
|
m_mode = InsertMode;
|
2010-05-04 11:00:40 +02:00
|
|
|
else
|
2010-05-06 12:10:57 +02:00
|
|
|
m_mode = ReplaceMode;
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Left)) {
|
2009-01-16 16:15:01 +01:00
|
|
|
moveLeft(count());
|
2009-07-29 10:41:28 +02:00
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-10-08 12:51:19 +02:00
|
|
|
} else if (input.isControl(Key_Left)) {
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), false, false);
|
2010-10-08 12:51:19 +02:00
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2010-10-08 12:51:19 +02:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Down)) {
|
2009-07-29 10:41:28 +02:00
|
|
|
//removeAutomaticIndentation();
|
2008-12-26 14:31:34 +01:00
|
|
|
m_submode = NoSubMode;
|
2009-01-16 16:15:01 +01:00
|
|
|
moveDown(count());
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Up)) {
|
2009-07-29 10:41:28 +02:00
|
|
|
//removeAutomaticIndentation();
|
2008-12-26 14:31:34 +01:00
|
|
|
m_submode = NoSubMode;
|
2009-01-16 16:15:01 +01:00
|
|
|
moveUp(count());
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Right)) {
|
2009-01-16 16:15:01 +01:00
|
|
|
moveRight(count());
|
2009-07-29 10:41:28 +02:00
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-10-08 12:51:19 +02:00
|
|
|
} else if (input.isControl(Key_Right)) {
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), false, true);
|
2010-10-08 12:51:19 +02:00
|
|
|
moveRight(); // we need one more move since we are in insert mode
|
|
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2010-10-08 12:51:19 +02:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Home)) {
|
2010-04-07 18:08:08 +02:00
|
|
|
moveToStartOfLine();
|
|
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2010-04-07 18:08:08 +02:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_End)) {
|
2010-04-07 18:08:08 +02:00
|
|
|
if (count() > 1)
|
|
|
|
|
moveDown(count() - 1);
|
|
|
|
|
moveBehindEndOfLine();
|
|
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
breakEditBlock();
|
2010-04-07 18:08:08 +02:00
|
|
|
m_lastInsertion.clear();
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.isReturn()) {
|
2011-12-26 16:38:31 +01:00
|
|
|
joinPreviousEditBlock();
|
2008-12-26 14:31:34 +01:00
|
|
|
m_submode = NoSubMode;
|
2011-11-12 02:31:52 +01:00
|
|
|
insertText(QString("\n"));
|
2011-02-23 15:28:39 +01:00
|
|
|
m_lastInsertion += '\n';
|
2009-04-03 11:54:29 +02:00
|
|
|
insertAutomaticIndentation(true);
|
2009-07-29 10:41:28 +02:00
|
|
|
setTargetColumn();
|
2011-12-26 16:38:31 +01:00
|
|
|
endEditBlock();
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.isBackspace()) {
|
2010-01-05 18:42:24 +01:00
|
|
|
joinPreviousEditBlock();
|
2010-02-15 17:55:26 +01:00
|
|
|
m_justAutoIndented = 0;
|
2011-11-30 10:07:25 +01:00
|
|
|
if (!m_lastInsertion.isEmpty()
|
|
|
|
|
|| hasConfig(ConfigBackspace, "start")
|
|
|
|
|
|| hasConfig(ConfigBackspace, "2")) {
|
2010-07-06 10:12:21 +02:00
|
|
|
const int line = cursorLine() + 1;
|
|
|
|
|
const Column col = cursorColumn();
|
2010-03-09 16:44:36 +01:00
|
|
|
QString data = lineContents(line);
|
|
|
|
|
const Column ind = indentation(data);
|
|
|
|
|
if (col.logical <= ind.logical && col.logical
|
|
|
|
|
&& startsWithWhitespace(data, col.physical)) {
|
2010-02-15 17:55:26 +01:00
|
|
|
const int ts = config(ConfigTabStop).toInt();
|
2010-07-06 16:17:27 +02:00
|
|
|
const int newl = col.logical - 1 - (col.logical - 1) % ts;
|
|
|
|
|
const QString prefix = tabExpand(newl);
|
|
|
|
|
setLineContents(line, prefix + data.mid(col.physical));
|
2010-04-07 18:08:09 +02:00
|
|
|
moveToStartOfLine();
|
2010-07-06 16:17:27 +02:00
|
|
|
moveRight(prefix.size());
|
2010-02-15 17:55:26 +01:00
|
|
|
m_lastInsertion.clear(); // FIXME
|
|
|
|
|
} else {
|
2010-09-15 16:35:59 +02:00
|
|
|
setAnchor();
|
2010-09-14 16:58:31 +02:00
|
|
|
cursor().deletePreviousChar();
|
2010-02-15 17:55:26 +01:00
|
|
|
m_lastInsertion.chop(1);
|
2009-04-03 11:54:29 +02:00
|
|
|
}
|
2010-02-15 17:55:26 +01:00
|
|
|
setTargetColumn();
|
|
|
|
|
}
|
2010-01-05 18:42:24 +01:00
|
|
|
endEditBlock();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Delete)) {
|
2010-10-11 10:10:24 +02:00
|
|
|
setAnchor();
|
2010-09-14 16:58:31 +02:00
|
|
|
cursor().deleteChar();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_PageDown) || input.isControl('f')) {
|
2009-04-03 11:54:29 +02:00
|
|
|
removeAutomaticIndentation();
|
2009-01-16 16:15:01 +01:00
|
|
|
moveDown(count() * (linesOnScreen() - 2));
|
2012-09-03 20:58:05 +02:00
|
|
|
breakEditBlock();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_PageUp) || input.isControl('b')) {
|
2009-04-03 11:54:29 +02:00
|
|
|
removeAutomaticIndentation();
|
2009-01-16 16:15:01 +01:00
|
|
|
moveUp(count() * (linesOnScreen() - 2));
|
2012-09-03 20:58:05 +02:00
|
|
|
breakEditBlock();
|
2008-12-27 12:24:50 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-07-06 15:12:24 +02:00
|
|
|
} else if (input.isKey(Key_Tab)) {
|
2010-02-12 11:05:21 +01:00
|
|
|
m_justAutoIndented = 0;
|
2010-07-06 15:12:24 +02:00
|
|
|
if (hasConfig(ConfigExpandTab)) {
|
|
|
|
|
const int ts = config(ConfigTabStop).toInt();
|
|
|
|
|
const int col = logicalCursorColumn();
|
|
|
|
|
QString str = QString(ts - col % ts, ' ');
|
|
|
|
|
m_lastInsertion.append(str);
|
|
|
|
|
insertText(str);
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
} else {
|
|
|
|
|
insertInInsertMode(input.raw());
|
|
|
|
|
}
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isControl('d')) {
|
2010-02-19 13:01:38 +01:00
|
|
|
// remove one level of indentation from the current line
|
|
|
|
|
int shift = config(ConfigShiftWidth).toInt();
|
|
|
|
|
int tab = config(ConfigTabStop).toInt();
|
2010-07-06 10:12:21 +02:00
|
|
|
int line = cursorLine() + 1;
|
2010-02-19 13:01:38 +01:00
|
|
|
int pos = firstPositionInLine(line);
|
|
|
|
|
QString text = lineContents(line);
|
|
|
|
|
int amount = 0;
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (; i < text.size() && amount < shift; ++i) {
|
|
|
|
|
if (text.at(i) == ' ')
|
|
|
|
|
++amount;
|
|
|
|
|
else if (text.at(i) == '\t')
|
|
|
|
|
amount += tab; // FIXME: take position into consideration
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
removeText(Range(pos, pos+i));
|
2010-04-28 14:00:44 +02:00
|
|
|
//} else if (key >= control('a') && key <= control('z')) {
|
|
|
|
|
// // ignore these
|
2010-12-21 11:36:42 +01:00
|
|
|
} else if (input.isControl('p') || input.isControl('n')) {
|
|
|
|
|
QTextCursor tc = EDITOR(textCursor());
|
2012-08-19 19:08:04 +02:00
|
|
|
moveToNextWordStart(count(), false, false);
|
2010-12-21 11:36:42 +01:00
|
|
|
QString str = selectText(Range(position(), tc.position()));
|
|
|
|
|
EDITOR(setTextCursor(tc));
|
|
|
|
|
emit q->simpleCompletionRequested(str, input.isControl('n'));
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (!input.text().isEmpty()) {
|
2010-07-06 09:20:40 +02:00
|
|
|
insertInInsertMode(input.text());
|
2009-01-08 13:16:04 +01:00
|
|
|
} else {
|
2010-09-27 15:38:17 +02:00
|
|
|
// We don't want fancy stuff in insert mode.
|
|
|
|
|
return EventHandled;
|
2009-01-06 11:49:33 +01:00
|
|
|
}
|
|
|
|
|
updateMiniBuffer();
|
2009-03-05 11:06:25 +01:00
|
|
|
return EventHandled;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-06 09:20:40 +02:00
|
|
|
void FakeVimHandler::Private::insertInInsertMode(const QString &text)
|
|
|
|
|
{
|
|
|
|
|
joinPreviousEditBlock();
|
|
|
|
|
m_justAutoIndented = 0;
|
|
|
|
|
m_lastInsertion.append(text);
|
|
|
|
|
insertText(text);
|
|
|
|
|
if (hasConfig(ConfigSmartIndent) && isElectricCharacter(text.at(0))) {
|
2010-09-13 15:23:20 +02:00
|
|
|
const QString leftText = block().text()
|
|
|
|
|
.left(position() - 1 - block().position());
|
2010-07-06 09:20:40 +02:00
|
|
|
if (leftText.simplified().isEmpty()) {
|
|
|
|
|
Range range(position(), position(), m_rangemode);
|
|
|
|
|
indentText(range, text.at(0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
endEditBlock();
|
|
|
|
|
m_ctrlVActive = false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-05 16:23:39 +02:00
|
|
|
EventResult FakeVimHandler::Private::handleExMode(const Input &input)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2010-05-18 18:24:00 +02:00
|
|
|
if (input.isEscape()) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.clear();
|
2009-01-06 13:03:59 +01:00
|
|
|
enterCommandMode();
|
2010-07-06 09:20:40 +02:00
|
|
|
m_ctrlVActive = false;
|
|
|
|
|
} else if (m_ctrlVActive) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.insertChar(input.raw());
|
2010-07-06 09:20:40 +02:00
|
|
|
m_ctrlVActive = false;
|
|
|
|
|
} else if (input.isControl('v')) {
|
|
|
|
|
m_ctrlVActive = true;
|
2012-09-09 10:32:45 +02:00
|
|
|
return EventHandled;
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.isBackspace()) {
|
2012-09-17 17:44:05 +02:00
|
|
|
if (g.commandBuffer.isEmpty())
|
2009-01-06 13:03:59 +01:00
|
|
|
enterCommandMode();
|
2012-09-09 10:32:45 +02:00
|
|
|
else
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.deleteChar();
|
2010-09-20 18:04:35 +02:00
|
|
|
} else if (input.isKey(Key_Tab)) {
|
2012-09-09 10:32:45 +02:00
|
|
|
// FIXME: Complete actual commands.
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.historyUp();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Left)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.moveLeft();
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.isReturn()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageCommand, g.commandBuffer.display());
|
|
|
|
|
handleExCommand(g.commandBuffer.contents());
|
|
|
|
|
g.commandBuffer.clear();
|
|
|
|
|
if (m_textedit || m_plaintextedit)
|
|
|
|
|
leaveVisualMode();
|
2010-05-05 16:23:39 +02:00
|
|
|
} else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.historyUp();
|
2010-05-05 16:23:39 +02:00
|
|
|
} else if (input.isKey(Key_Down) || input.isKey(Key_PageDown)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.commandBuffer.historyDown();
|
|
|
|
|
} else if (!g.commandBuffer.handleInput(input)) {
|
2010-05-05 16:23:39 +02:00
|
|
|
qDebug() << "IGNORED IN EX-MODE: " << input.key() << input.text();
|
|
|
|
|
return EventUnhandled;
|
|
|
|
|
}
|
2012-09-09 10:32:45 +02:00
|
|
|
updateMiniBuffer();
|
2010-05-05 16:23:39 +02:00
|
|
|
return EventHandled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input)
|
|
|
|
|
{
|
2010-05-18 18:24:00 +02:00
|
|
|
if (input.isEscape()) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.currentMessage.clear();
|
|
|
|
|
g.searchBuffer.clear();
|
2012-09-27 21:09:13 +02:00
|
|
|
setAnchorAndPosition(m_searchStartPosition, m_searchStartPosition);
|
2012-09-01 10:44:02 +02:00
|
|
|
scrollToLine(m_searchFromScreenLine);
|
2010-05-05 16:23:39 +02:00
|
|
|
enterCommandMode();
|
2010-05-10 16:41:35 +02:00
|
|
|
} else if (input.isBackspace()) {
|
2012-09-17 17:44:05 +02:00
|
|
|
if (g.searchBuffer.isEmpty()) {
|
2010-05-05 16:23:39 +02:00
|
|
|
enterCommandMode();
|
2010-05-18 18:24:00 +02:00
|
|
|
} else {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.deleteChar();
|
2010-05-18 18:24:00 +02:00
|
|
|
}
|
2010-05-05 16:23:39 +02:00
|
|
|
} else if (input.isKey(Key_Left)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.moveLeft();
|
2011-07-15 13:22:38 +02:00
|
|
|
} else if (input.isKey(Key_Right)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.moveRight();
|
2010-05-18 18:24:00 +02:00
|
|
|
} else if (input.isReturn()) {
|
2012-09-17 17:44:05 +02:00
|
|
|
const QString &needle = g.searchBuffer.contents();
|
2012-09-30 13:20:48 +02:00
|
|
|
if (!needle.isEmpty())
|
2012-10-03 16:40:05 +02:00
|
|
|
g.lastSearch = needle;
|
2012-09-30 13:20:48 +02:00
|
|
|
else
|
2012-10-03 16:40:05 +02:00
|
|
|
g.searchBuffer.setContents(g.lastSearch);
|
|
|
|
|
if (!g.lastSearch.isEmpty()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
updateFind(true);
|
2012-10-03 16:40:05 +02:00
|
|
|
finishMovement(g.searchBuffer.prompt() + g.lastSearch + '\n');
|
2012-09-01 10:44:02 +02:00
|
|
|
} else {
|
|
|
|
|
finishMovement();
|
2008-12-28 00:32:07 +01:00
|
|
|
}
|
2012-09-17 17:44:05 +02:00
|
|
|
if (g.currentMessage.isEmpty())
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageCommand, g.searchBuffer.display());
|
2009-01-06 13:03:59 +01:00
|
|
|
enterCommandMode();
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.clear();
|
2010-05-05 16:23:39 +02:00
|
|
|
} else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.historyUp();
|
2010-05-05 16:23:39 +02:00
|
|
|
} else if (input.isKey(Key_Down) || input.isKey(Key_PageDown)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.historyDown();
|
2010-04-28 14:00:44 +02:00
|
|
|
} else if (input.isKey(Key_Tab)) {
|
2012-09-17 17:44:05 +02:00
|
|
|
g.searchBuffer.insertChar(QChar(9));
|
|
|
|
|
} else if (!g.searchBuffer.handleInput(input)) {
|
2012-09-10 22:10:23 +02:00
|
|
|
//qDebug() << "IGNORED IN SEARCH MODE: " << input.key() << input.text();
|
2012-09-09 10:32:45 +02:00
|
|
|
return EventUnhandled;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
2012-09-10 22:10:23 +02:00
|
|
|
|
2012-09-09 10:32:45 +02:00
|
|
|
updateMiniBuffer();
|
2010-05-18 18:24:00 +02:00
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
if (!input.isReturn() && !input.isEscape())
|
|
|
|
|
updateFind(false);
|
2010-05-18 18:24:00 +02:00
|
|
|
|
2009-03-05 11:06:25 +01:00
|
|
|
return EventHandled;
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
// This uses 1 based line counting.
|
2008-12-28 02:15:26 +01:00
|
|
|
int FakeVimHandler::Private::readLineCode(QString &cmd)
|
|
|
|
|
{
|
|
|
|
|
//qDebug() << "CMD: " << cmd;
|
|
|
|
|
if (cmd.isEmpty())
|
|
|
|
|
return -1;
|
|
|
|
|
QChar c = cmd.at(0);
|
|
|
|
|
cmd = cmd.mid(1);
|
2010-05-11 14:26:37 +02:00
|
|
|
if (c == '.') {
|
|
|
|
|
if (cmd.isEmpty())
|
2010-07-06 10:12:21 +02:00
|
|
|
return cursorLine() + 1;
|
2010-05-11 14:26:37 +02:00
|
|
|
QChar c1 = cmd.at(0);
|
|
|
|
|
if (c1 == '+' || c1 == '-') {
|
|
|
|
|
// Repeat for things like .+4
|
|
|
|
|
cmd = cmd.mid(1);
|
2010-07-06 10:12:21 +02:00
|
|
|
return cursorLine() + readLineCode(cmd);
|
2010-05-11 14:26:37 +02:00
|
|
|
}
|
2010-07-06 10:12:21 +02:00
|
|
|
return cursorLine() + 1;
|
2010-05-11 14:26:37 +02:00
|
|
|
}
|
2008-12-28 02:15:26 +01:00
|
|
|
if (c == '$')
|
|
|
|
|
return linesInDocument();
|
2008-12-29 14:47:42 +01:00
|
|
|
if (c == '\'' && !cmd.isEmpty()) {
|
2010-05-11 14:26:37 +02:00
|
|
|
if (cmd.isEmpty()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, msgMarkNotSet(QString()));
|
2010-05-11 14:26:37 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
int m = mark(cmd.at(0).unicode());
|
|
|
|
|
if (m == -1) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, msgMarkNotSet(cmd.at(0)));
|
2009-01-15 17:29:30 +01:00
|
|
|
cmd = cmd.mid(1);
|
2008-12-29 14:47:42 +01:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
cmd = cmd.mid(1);
|
2010-05-11 14:26:37 +02:00
|
|
|
return lineForPosition(m);
|
2008-12-29 14:47:42 +01:00
|
|
|
}
|
2008-12-28 02:15:26 +01:00
|
|
|
if (c == '-') {
|
|
|
|
|
int n = readLineCode(cmd);
|
2010-07-06 10:12:21 +02:00
|
|
|
return cursorLine() + 1 - (n == -1 ? 1 : n);
|
2008-12-28 02:15:26 +01:00
|
|
|
}
|
|
|
|
|
if (c == '+') {
|
|
|
|
|
int n = readLineCode(cmd);
|
2010-07-06 10:12:21 +02:00
|
|
|
return cursorLine() + 1 + (n == -1 ? 1 : n);
|
2008-12-28 02:15:26 +01:00
|
|
|
}
|
2009-01-06 11:42:44 +01:00
|
|
|
if (c == '\'' && !cmd.isEmpty()) {
|
2010-05-11 14:26:37 +02:00
|
|
|
int pos = mark(cmd.at(0).unicode());
|
2009-01-08 17:21:51 +01:00
|
|
|
if (pos == -1) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, msgMarkNotSet(cmd.at(0)));
|
2009-01-15 17:29:30 +01:00
|
|
|
cmd = cmd.mid(1);
|
|
|
|
|
return -1;
|
2009-01-06 11:42:44 +01:00
|
|
|
}
|
|
|
|
|
cmd = cmd.mid(1);
|
|
|
|
|
return lineForPosition(pos);
|
|
|
|
|
}
|
2008-12-28 02:15:26 +01:00
|
|
|
if (c.isDigit()) {
|
|
|
|
|
int n = c.unicode() - '0';
|
|
|
|
|
while (!cmd.isEmpty()) {
|
|
|
|
|
c = cmd.at(0);
|
|
|
|
|
if (!c.isDigit())
|
|
|
|
|
break;
|
|
|
|
|
cmd = cmd.mid(1);
|
|
|
|
|
n = n * 10 + (c.unicode() - '0');
|
|
|
|
|
}
|
2010-05-18 12:54:18 +02:00
|
|
|
//qDebug() << "N: " << n;
|
2008-12-28 02:15:26 +01:00
|
|
|
return n;
|
|
|
|
|
}
|
2010-05-11 14:26:37 +02:00
|
|
|
// Parsing failed.
|
2008-12-28 02:15:26 +01:00
|
|
|
cmd = c + cmd;
|
2009-01-08 13:16:04 +01:00
|
|
|
return -1;
|
2008-12-28 02:15:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void FakeVimHandler::Private::setCurrentRange(const Range &range)
|
2009-01-06 11:33:07 +01:00
|
|
|
{
|
2010-09-14 16:58:31 +02:00
|
|
|
setAnchorAndPosition(range.beginPos, range.endPos);
|
2010-05-12 11:18:18 +02:00
|
|
|
m_rangemode = range.rangemode;
|
2009-01-06 11:33:07 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-28 13:24:25 +02:00
|
|
|
Range FakeVimHandler::Private::rangeFromCurrentLine() const
|
|
|
|
|
{
|
|
|
|
|
Range range;
|
|
|
|
|
int line = cursorLine() + 1;
|
|
|
|
|
range.beginPos = firstPositionInLine(line);
|
2011-11-29 08:17:02 +01:00
|
|
|
range.endPos = lastPositionInLine(line);
|
2011-03-28 13:24:25 +02:00
|
|
|
return range;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-18 13:15:59 +01:00
|
|
|
// use handleExCommand for invoking commands that might move the cursor
|
2009-04-06 10:58:48 +02:00
|
|
|
void FakeVimHandler::Private::handleCommand(const QString &cmd)
|
|
|
|
|
{
|
|
|
|
|
handleExCommand(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
// :substitute
|
|
|
|
|
{
|
2011-11-28 17:59:30 +01:00
|
|
|
QString flags;
|
|
|
|
|
QRegExp pattern;
|
|
|
|
|
QString replacement;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
if (cmd.cmd.startsWith("&&")) {
|
|
|
|
|
flags = cmd.cmd.mid(2);
|
|
|
|
|
if (flags.isEmpty())
|
|
|
|
|
flags = m_lastSubstituteFlags;
|
|
|
|
|
pattern = m_lastSubstitutePattern;
|
|
|
|
|
replacement = m_lastSubstituteReplacement;
|
|
|
|
|
count = cmd.args.section(QLatin1Char(' '), 1, 1).toInt();
|
2012-03-06 19:27:49 +01:00
|
|
|
} else if (cmd.cmd.startsWith(QLatin1Char('&'))) {
|
2011-11-28 17:59:30 +01:00
|
|
|
flags = cmd.cmd.mid(1);
|
|
|
|
|
if (flags.isEmpty())
|
|
|
|
|
flags = m_lastSubstituteFlags;
|
|
|
|
|
pattern = m_lastSubstitutePattern;
|
|
|
|
|
replacement = m_lastSubstituteReplacement;
|
|
|
|
|
count = cmd.args.section(QLatin1Char(' '), 1, 1).toInt();
|
|
|
|
|
} else if (cmd.matches("s", "substitute")) {
|
|
|
|
|
flags = m_lastSubstituteFlags;
|
|
|
|
|
if (flags.isEmpty())
|
|
|
|
|
flags = m_lastSubstituteFlags;
|
|
|
|
|
pattern = m_lastSubstitutePattern;
|
|
|
|
|
replacement = m_lastSubstituteReplacement;
|
|
|
|
|
count = cmd.args.section(QLatin1Char(' '), 2, 2).toInt();
|
|
|
|
|
} else {
|
|
|
|
|
QString line = cmd.cmd + ' ' + cmd.args;
|
|
|
|
|
line = line.trimmed();
|
|
|
|
|
if (line.startsWith(_("substitute")))
|
|
|
|
|
line = line.mid(10);
|
|
|
|
|
else if (line.startsWith('s') && line.size() > 1
|
|
|
|
|
&& !isalpha(line.at(1).unicode()))
|
|
|
|
|
line = line.mid(1);
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
// we have /{pattern}/{string}/[flags] now
|
|
|
|
|
if (line.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
const QChar separator = line.at(0);
|
|
|
|
|
int pos1 = -1;
|
|
|
|
|
int pos2 = -1;
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 1; i < line.size(); ++i) {
|
|
|
|
|
if (line.at(i) == separator && line.at(i - 1) != '\\') {
|
|
|
|
|
pos1 = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-12-09 17:40:00 +01:00
|
|
|
}
|
2011-11-28 17:59:30 +01:00
|
|
|
if (pos1 == -1)
|
|
|
|
|
return false;
|
|
|
|
|
for (++i; i < line.size(); ++i) {
|
|
|
|
|
if (line.at(i) == separator && line.at(i - 1) != '\\') {
|
|
|
|
|
pos2 = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-12-09 17:40:00 +01:00
|
|
|
}
|
2011-11-28 17:59:30 +01:00
|
|
|
if (pos2 == -1)
|
|
|
|
|
pos2 = line.size();
|
|
|
|
|
|
|
|
|
|
QString needle = line.mid(1, pos1 - 1);
|
|
|
|
|
replacement = line.mid(pos1 + 1, pos2 - pos1 - 1);
|
|
|
|
|
flags = line.mid(pos2 + 1);
|
|
|
|
|
|
2012-07-22 14:30:56 +02:00
|
|
|
pattern = vimPatternToQtPattern(needle, hasConfig(ConfigSmartCase));
|
2011-11-28 17:59:30 +01:00
|
|
|
|
|
|
|
|
m_lastSubstituteFlags = flags;
|
|
|
|
|
m_lastSubstitutePattern = pattern;
|
|
|
|
|
m_lastSubstituteReplacement = replacement;
|
2009-12-09 17:40:00 +01:00
|
|
|
}
|
|
|
|
|
|
2011-11-28 17:59:30 +01:00
|
|
|
if (count == 0)
|
|
|
|
|
count = 1;
|
2010-04-16 16:30:45 +02:00
|
|
|
|
|
|
|
|
if (flags.contains('i'))
|
|
|
|
|
pattern.setCaseSensitivity(Qt::CaseInsensitive);
|
2011-11-28 17:59:30 +01:00
|
|
|
|
2012-09-29 19:09:08 +02:00
|
|
|
int lastLine = -1;
|
|
|
|
|
int firstLine = -1;
|
2011-11-28 17:59:30 +01:00
|
|
|
const bool global = flags.contains('g');
|
|
|
|
|
for (int a = 0; a != count; ++a) {
|
|
|
|
|
const Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range;
|
|
|
|
|
const int beginLine = lineForPosition(range.beginPos);
|
|
|
|
|
const int endLine = lineForPosition(range.endPos);
|
|
|
|
|
for (int line = endLine; line >= beginLine; --line) {
|
|
|
|
|
QString origText = lineContents(line);
|
|
|
|
|
QString text = origText;
|
|
|
|
|
int pos = 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
pos = pattern.indexIn(text, pos, QRegExp::CaretAtZero);
|
|
|
|
|
if (pos == -1)
|
|
|
|
|
break;
|
|
|
|
|
if (pattern.cap(0).isEmpty())
|
|
|
|
|
break;
|
|
|
|
|
QStringList caps = pattern.capturedTexts();
|
|
|
|
|
QString matched = text.mid(pos, caps.at(0).size());
|
|
|
|
|
QString repl = replacement;
|
|
|
|
|
for (int i = 1; i < caps.size(); ++i)
|
|
|
|
|
repl.replace("\\" + QString::number(i), caps.at(i));
|
|
|
|
|
for (int i = 0; i < repl.size(); ++i) {
|
|
|
|
|
if (repl.at(i) == '&' && (i == 0 || repl.at(i - 1) != '\\')) {
|
|
|
|
|
repl.replace(i, 1, caps.at(0));
|
|
|
|
|
i += caps.at(0).size();
|
|
|
|
|
}
|
2010-04-16 16:30:45 +02:00
|
|
|
}
|
2011-11-28 17:59:30 +01:00
|
|
|
repl.replace("\\&", "&");
|
|
|
|
|
text = text.left(pos) + repl + text.mid(pos + matched.size());
|
|
|
|
|
pos += repl.size();
|
2012-09-29 19:09:08 +02:00
|
|
|
|
|
|
|
|
firstLine = line;
|
|
|
|
|
if (lastLine == -1) {
|
|
|
|
|
lastLine = line;
|
|
|
|
|
beginEditBlock();
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-28 17:59:30 +01:00
|
|
|
if (!global)
|
|
|
|
|
break;
|
2010-04-16 16:30:45 +02:00
|
|
|
}
|
2011-11-28 17:59:30 +01:00
|
|
|
if (text != origText)
|
|
|
|
|
setLineContents(line, text);
|
2010-04-16 16:30:45 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-29 19:09:08 +02:00
|
|
|
|
|
|
|
|
if (lastLine != -1) {
|
|
|
|
|
State &state = m_undo.top();
|
|
|
|
|
state.line = firstLine;
|
|
|
|
|
state.position = firstPositionInLine(firstLine);
|
|
|
|
|
|
|
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setPosition(firstPositionInLine(lastLine));
|
|
|
|
|
setCursor(tc);
|
|
|
|
|
moveToFirstNonBlankOnLine();
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
|
|
|
|
|
endEditBlock();
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-09 17:40:00 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
bool FakeVimHandler::Private::handleExMapCommand(const ExCommand &cmd0) // :map
|
2010-03-19 14:31:21 +01:00
|
|
|
{
|
|
|
|
|
QByteArray modes;
|
|
|
|
|
enum Type { Map, Noremap, Unmap } type;
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
QByteArray cmd = cmd0.cmd.toLatin1();
|
2010-03-19 14:31:21 +01:00
|
|
|
|
|
|
|
|
// Strange formatting. But everything else is even uglier.
|
|
|
|
|
if (cmd == "map") { modes = "nvo"; type = Map; } else
|
|
|
|
|
if (cmd == "nm" || cmd == "nmap") { modes = "n"; type = Map; } else
|
|
|
|
|
if (cmd == "vm" || cmd == "vmap") { modes = "v"; type = Map; } else
|
|
|
|
|
if (cmd == "xm" || cmd == "xmap") { modes = "x"; type = Map; } else
|
|
|
|
|
if (cmd == "smap") { modes = "s"; type = Map; } else
|
|
|
|
|
if (cmd == "map!") { modes = "ic"; type = Map; } else
|
|
|
|
|
if (cmd == "im" || cmd == "imap") { modes = "i"; type = Map; } else
|
|
|
|
|
if (cmd == "lm" || cmd == "lmap") { modes = "l"; type = Map; } else
|
|
|
|
|
if (cmd == "cm" || cmd == "cmap") { modes = "c"; type = Map; } else
|
|
|
|
|
|
|
|
|
|
if (cmd == "no" || cmd == "noremap") { modes = "nvo"; type = Noremap; } else
|
|
|
|
|
if (cmd == "nn" || cmd == "nnoremap") { modes = "n"; type = Noremap; } else
|
|
|
|
|
if (cmd == "vn" || cmd == "vnoremap") { modes = "v"; type = Noremap; } else
|
|
|
|
|
if (cmd == "xn" || cmd == "xnoremap") { modes = "x"; type = Noremap; } else
|
|
|
|
|
if (cmd == "snor" || cmd == "snoremap") { modes = "s"; type = Noremap; } else
|
|
|
|
|
if (cmd == "ono" || cmd == "onoremap") { modes = "o"; type = Noremap; } else
|
|
|
|
|
if (cmd == "no!" || cmd == "noremap!") { modes = "ic"; type = Noremap; } else
|
|
|
|
|
if (cmd == "ino" || cmd == "inoremap") { modes = "i"; type = Noremap; } else
|
|
|
|
|
if (cmd == "ln" || cmd == "lnoremap") { modes = "l"; type = Noremap; } else
|
|
|
|
|
if (cmd == "cno" || cmd == "cnoremap") { modes = "c"; type = Noremap; } else
|
|
|
|
|
|
|
|
|
|
if (cmd == "unm" || cmd == "unmap") { modes = "nvo"; type = Unmap; } else
|
|
|
|
|
if (cmd == "nun" || cmd == "nunmap") { modes = "n"; type = Unmap; } else
|
|
|
|
|
if (cmd == "vu" || cmd == "vunmap") { modes = "v"; type = Unmap; } else
|
|
|
|
|
if (cmd == "xu" || cmd == "xunmap") { modes = "x"; type = Unmap; } else
|
|
|
|
|
if (cmd == "sunm" || cmd == "sunmap") { modes = "s"; type = Unmap; } else
|
|
|
|
|
if (cmd == "ou" || cmd == "ounmap") { modes = "o"; type = Unmap; } else
|
|
|
|
|
if (cmd == "unm!" || cmd == "unmap!") { modes = "ic"; type = Unmap; } else
|
|
|
|
|
if (cmd == "iu" || cmd == "iunmap") { modes = "i"; type = Unmap; } else
|
|
|
|
|
if (cmd == "lu" || cmd == "lunmap") { modes = "l"; type = Unmap; } else
|
|
|
|
|
if (cmd == "cu" || cmd == "cunmap") { modes = "c"; type = Unmap; }
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
QString args = cmd0.args;
|
|
|
|
|
bool silent = false;
|
|
|
|
|
bool unique = false;
|
|
|
|
|
forever {
|
|
|
|
|
if (eatString("<silent>", &args)) {
|
|
|
|
|
silent = true;
|
|
|
|
|
} else if (eatString("<unique>", &args)) {
|
|
|
|
|
continue;
|
|
|
|
|
} else if (eatString("<special>", &args)) {
|
|
|
|
|
continue;
|
|
|
|
|
} else if (eatString("<buffer>", &args)) {
|
|
|
|
|
notImplementedYet();
|
|
|
|
|
continue;
|
|
|
|
|
} else if (eatString("<script>", &args)) {
|
|
|
|
|
notImplementedYet();
|
|
|
|
|
continue;
|
|
|
|
|
} else if (eatString("<expr>", &args)) {
|
|
|
|
|
notImplementedYet();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QString lhs = args.section(QRegExp("\\s+"), 0, 0);
|
|
|
|
|
const QString rhs = args.section(QRegExp("\\s+"), 1);
|
|
|
|
|
if ((rhs.isNull() && type != Unmap) || (!rhs.isNull() && type == Unmap)) {
|
2010-05-10 09:01:30 +02:00
|
|
|
// FIXME: Dump mappings here.
|
|
|
|
|
//qDebug() << g.mappings;
|
2011-04-05 16:32:18 +02:00
|
|
|
return true;
|
2010-05-10 09:01:30 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
Inputs key(lhs);
|
2010-04-16 15:16:48 +02:00
|
|
|
//qDebug() << "MAPPING: " << modes << lhs << rhs;
|
2010-03-19 14:31:21 +01:00
|
|
|
switch (type) {
|
|
|
|
|
case Unmap:
|
|
|
|
|
foreach (char c, modes)
|
2012-09-01 07:47:25 +02:00
|
|
|
MappingsIterator(&g.mappings, c, key).remove();
|
2010-03-19 14:31:21 +01:00
|
|
|
break;
|
2012-09-01 07:47:25 +02:00
|
|
|
case Map: // fall through
|
2010-03-26 13:22:06 +01:00
|
|
|
case Noremap: {
|
2012-09-01 07:47:25 +02:00
|
|
|
Inputs inputs(rhs, type == Noremap, silent);
|
|
|
|
|
// TODO: Use MappingsIterator to insert mapping!
|
2010-03-19 14:31:21 +01:00
|
|
|
foreach (char c, modes)
|
2012-09-01 07:47:25 +02:00
|
|
|
MappingsIterator(&g.mappings, c).setInputs(key, inputs, unique);
|
2010-03-19 14:31:21 +01:00
|
|
|
break;
|
2010-03-26 13:22:06 +01:00
|
|
|
}
|
2010-03-19 14:31:21 +01:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExHistoryCommand(const ExCommand &cmd)
|
2008-12-27 16:42:07 +01:00
|
|
|
{
|
2010-07-14 18:15:17 +02:00
|
|
|
// :his[tory]
|
|
|
|
|
if (!cmd.matches("his", "history"))
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
2009-04-01 15:52:48 +02:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
if (cmd.args.isEmpty()) {
|
2010-04-16 16:30:45 +02:00
|
|
|
QString info;
|
|
|
|
|
info += "# command history\n";
|
|
|
|
|
int i = 0;
|
2012-09-17 17:44:05 +02:00
|
|
|
foreach (const QString &item, g.commandBuffer.historyItems()) {
|
2010-04-16 16:30:45 +02:00
|
|
|
++i;
|
|
|
|
|
info += QString("%1 %2\n").arg(i, -8).arg(item);
|
|
|
|
|
}
|
|
|
|
|
emit q->extraInformationChanged(info);
|
|
|
|
|
} else {
|
|
|
|
|
notImplementedYet();
|
|
|
|
|
}
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2008-12-28 02:15:26 +01:00
|
|
|
|
2010-05-20 14:08:11 +02:00
|
|
|
bool FakeVimHandler::Private::handleExRegisterCommand(const ExCommand &cmd)
|
|
|
|
|
{
|
2010-07-14 18:15:17 +02:00
|
|
|
// :reg[isters] and :di[splay]
|
|
|
|
|
if (!cmd.matches("reg", "registers") && !cmd.matches("di", "display"))
|
2010-05-20 14:08:11 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
QByteArray regs = cmd.args.toLatin1();
|
|
|
|
|
if (regs.isEmpty()) {
|
|
|
|
|
regs = "\"0123456789";
|
|
|
|
|
QHashIterator<int, Register> it(g.registers);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
if (it.key() > '9')
|
|
|
|
|
regs += char(it.key());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QString info;
|
|
|
|
|
info += "--- Registers ---\n";
|
|
|
|
|
foreach (char reg, regs) {
|
2011-11-12 02:31:52 +01:00
|
|
|
QString value = quoteUnprintable(registerContents(reg));
|
2010-05-20 14:08:11 +02:00
|
|
|
info += QString("\"%1 %2\n").arg(reg).arg(value);
|
|
|
|
|
}
|
|
|
|
|
emit q->extraInformationChanged(info);
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-07-14 18:15:17 +02:00
|
|
|
// :se[t]
|
|
|
|
|
if (!cmd.matches("se", "set"))
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
2009-01-08 13:16:04 +01:00
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
clearMessage();
|
2010-05-18 14:48:12 +02:00
|
|
|
SavedAction *act = theFakeVimSettings()->item(cmd.args);
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(!cmd.args.isEmpty()); // Handled by plugin.
|
2012-08-26 18:39:48 +02:00
|
|
|
if (act && act->value().canConvert(QVariant::Bool)) {
|
2010-05-18 14:48:12 +02:00
|
|
|
// Boolean config to be switched on.
|
2010-04-16 16:30:45 +02:00
|
|
|
bool oldValue = act->value().toBool();
|
|
|
|
|
if (oldValue == false)
|
|
|
|
|
act->setValue(true);
|
|
|
|
|
else if (oldValue == true)
|
|
|
|
|
{} // nothing to do
|
|
|
|
|
} else if (act) {
|
2010-05-18 14:48:12 +02:00
|
|
|
// Non-boolean to show.
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, cmd.args + '=' + act->value().toString());
|
2010-05-18 14:48:12 +02:00
|
|
|
} else if (cmd.args.startsWith(_("no"))
|
|
|
|
|
&& (act = theFakeVimSettings()->item(cmd.args.mid(2)))) {
|
|
|
|
|
// Boolean config to be switched off.
|
2010-04-16 16:30:45 +02:00
|
|
|
bool oldValue = act->value().toBool();
|
|
|
|
|
if (oldValue == true)
|
|
|
|
|
act->setValue(false);
|
|
|
|
|
else if (oldValue == false)
|
|
|
|
|
{} // nothing to do
|
2010-05-18 14:48:12 +02:00
|
|
|
} else if (cmd.args.contains('=')) {
|
|
|
|
|
// Non-boolean config to set.
|
|
|
|
|
int p = cmd.args.indexOf('=');
|
2012-05-03 10:43:04 +02:00
|
|
|
QString error = theFakeVimSettings()
|
|
|
|
|
->trySetValue(cmd.args.left(p), cmd.args.mid(p + 1));
|
|
|
|
|
if (!error.isEmpty())
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, error);
|
2010-04-16 16:30:45 +02:00
|
|
|
} else {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, FakeVimHandler::tr("Unknown option: ") + cmd.args);
|
2008-12-28 02:15:26 +01:00
|
|
|
}
|
2010-04-16 16:30:45 +02:00
|
|
|
updateMiniBuffer();
|
|
|
|
|
updateEditor();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExNormalCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-07-14 18:15:17 +02:00
|
|
|
// :norm[al]
|
|
|
|
|
if (!cmd.matches("norm", "normal"))
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
2010-05-04 17:58:53 +02:00
|
|
|
//qDebug() << "REPLAY NORMAL: " << quoteUnprintable(reNormal.cap(3));
|
2010-05-18 14:48:12 +02:00
|
|
|
replay(cmd.args, 1);
|
2010-04-16 16:30:45 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
2008-12-28 02:15:26 +01:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-07-14 18:15:17 +02:00
|
|
|
// :d[elete]
|
|
|
|
|
if (!cmd.matches("d", "delete"))
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
2009-10-16 11:30:46 +02:00
|
|
|
|
2011-03-28 13:24:25 +02:00
|
|
|
Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range;
|
|
|
|
|
setCurrentRange(range);
|
2010-05-18 14:48:12 +02:00
|
|
|
QString reg = cmd.args;
|
2011-03-28 13:24:25 +02:00
|
|
|
QString text = selectText(range);
|
2010-05-12 11:18:18 +02:00
|
|
|
removeText(currentRange());
|
2010-04-16 16:30:45 +02:00
|
|
|
if (!reg.isEmpty()) {
|
2011-11-12 02:31:52 +01:00
|
|
|
const int r = reg.at(0).unicode();
|
2012-08-09 17:32:39 +02:00
|
|
|
setRegister(r, text, RangeLineMode);
|
2010-04-16 16:30:45 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2008-12-28 02:15:26 +01:00
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
bool FakeVimHandler::Private::handleExWriteCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
// :w, :x, :wq, ...
|
|
|
|
|
//static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
|
|
|
|
|
if (cmd.cmd != "w" && cmd.cmd != "x" && cmd.cmd != "wq")
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
int beginLine = lineForPosition(cmd.range.beginPos);
|
|
|
|
|
int endLine = lineForPosition(cmd.range.endPos);
|
|
|
|
|
const bool noArgs = (beginLine == -1);
|
2010-04-16 16:30:45 +02:00
|
|
|
if (beginLine == -1)
|
|
|
|
|
beginLine = 0;
|
|
|
|
|
if (endLine == -1)
|
|
|
|
|
endLine = linesInDocument();
|
|
|
|
|
//qDebug() << "LINES: " << beginLine << endLine;
|
2011-12-27 17:39:56 +01:00
|
|
|
//QString prefix = cmd.args;
|
2010-05-18 14:48:12 +02:00
|
|
|
const bool forced = cmd.hasBang;
|
|
|
|
|
//const bool quit = prefix.contains(QChar('q')) || prefix.contains(QChar('x'));
|
|
|
|
|
//const bool quitAll = quit && prefix.contains(QChar('a'));
|
|
|
|
|
QString fileName = cmd.args;
|
2010-04-16 16:30:45 +02:00
|
|
|
if (fileName.isEmpty())
|
|
|
|
|
fileName = m_currentFileName;
|
|
|
|
|
QFile file1(fileName);
|
2010-05-18 11:09:38 +02:00
|
|
|
const bool exists = file1.exists();
|
2010-04-16 16:30:45 +02:00
|
|
|
if (exists && !forced && !noArgs) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, FakeVimHandler::tr
|
2010-05-18 11:09:38 +02:00
|
|
|
("File \"%1\" exists (add ! to override)").arg(fileName));
|
2010-04-16 16:30:45 +02:00
|
|
|
} else if (file1.open(QIODevice::ReadWrite)) {
|
2010-05-18 14:48:12 +02:00
|
|
|
// Nobody cared, so act ourselves.
|
2010-04-16 16:30:45 +02:00
|
|
|
file1.close();
|
|
|
|
|
Range range(firstPositionInLine(beginLine),
|
|
|
|
|
firstPositionInLine(endLine), RangeLineMode);
|
2010-05-12 11:18:18 +02:00
|
|
|
QString contents = selectText(range);
|
2010-05-18 14:48:12 +02:00
|
|
|
QFile::remove(fileName);
|
|
|
|
|
QFile file2(fileName);
|
|
|
|
|
if (file2.open(QIODevice::ReadWrite)) {
|
|
|
|
|
QTextStream ts(&file2);
|
|
|
|
|
ts << contents;
|
|
|
|
|
} else {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, FakeVimHandler::tr
|
2010-05-18 14:48:12 +02:00
|
|
|
("Cannot open file \"%1\" for writing").arg(fileName));
|
2009-01-09 15:36:02 +01:00
|
|
|
}
|
2010-05-18 11:09:38 +02:00
|
|
|
// Check result by reading back.
|
2010-04-16 16:30:45 +02:00
|
|
|
QFile file3(fileName);
|
|
|
|
|
file3.open(QIODevice::ReadOnly);
|
|
|
|
|
QByteArray ba = file3.readAll();
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
|
2010-08-19 14:04:15 +02:00
|
|
|
.arg(fileName).arg(exists ? " " : tr(" [New] "))
|
2010-04-16 16:30:45 +02:00
|
|
|
.arg(ba.count('\n')).arg(ba.size()));
|
2010-05-18 14:48:12 +02:00
|
|
|
//if (quitAll)
|
|
|
|
|
// passUnknownExCommand(forced ? "qa!" : "qa");
|
|
|
|
|
//else if (quit)
|
|
|
|
|
// passUnknownExCommand(forced ? "q!" : "q");
|
2008-12-28 02:15:26 +01:00
|
|
|
} else {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, FakeVimHandler::tr
|
2010-05-18 11:09:38 +02:00
|
|
|
("Cannot open file \"%1\" for reading").arg(fileName));
|
2010-04-16 16:30:45 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExReadCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-07-14 18:15:17 +02:00
|
|
|
// :r[ead]
|
|
|
|
|
if (!cmd.matches("r", "read"))
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
beginEditBlock();
|
|
|
|
|
moveToStartOfLine();
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
moveDown();
|
2010-05-18 14:48:12 +02:00
|
|
|
m_currentFileName = cmd.args;
|
2010-04-16 16:30:45 +02:00
|
|
|
QFile file(m_currentFileName);
|
|
|
|
|
file.open(QIODevice::ReadOnly);
|
|
|
|
|
QTextStream ts(&file);
|
|
|
|
|
QString data = ts.readAll();
|
2010-09-14 16:58:31 +02:00
|
|
|
insertText(data);
|
2010-04-29 15:47:02 +02:00
|
|
|
endEditBlock();
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, FakeVimHandler::tr("\"%1\" %2L, %3C")
|
2010-04-16 16:30:45 +02:00
|
|
|
.arg(m_currentFileName).arg(data.count('\n')).arg(data.size()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
if (!cmd.cmd.startsWith(QLatin1Char('!')))
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
setCurrentRange(cmd.range);
|
|
|
|
|
int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos));
|
2010-05-18 14:48:12 +02:00
|
|
|
QString command = QString(cmd.cmd.mid(1) + ' ' + cmd.args).trimmed();
|
2010-05-12 11:18:18 +02:00
|
|
|
QString text = selectText(cmd.range);
|
2010-04-16 16:30:45 +02:00
|
|
|
QProcess proc;
|
2010-05-04 22:24:48 +02:00
|
|
|
proc.start(command);
|
2010-04-16 16:30:45 +02:00
|
|
|
proc.waitForStarted();
|
2012-08-23 15:53:58 +02:00
|
|
|
if (Utils::HostOsInfo::isWindowsHost())
|
|
|
|
|
text.replace(_("\n"), _("\r\n"));
|
2010-04-16 16:30:45 +02:00
|
|
|
proc.write(text.toUtf8());
|
|
|
|
|
proc.closeWriteChannel();
|
|
|
|
|
proc.waitForFinished();
|
|
|
|
|
QString result = QString::fromUtf8(proc.readAllStandardOutput());
|
2012-05-08 18:10:05 +02:00
|
|
|
if (text.isEmpty()) {
|
|
|
|
|
emit q->extraInformationChanged(result);
|
|
|
|
|
} else {
|
|
|
|
|
beginEditBlock();
|
|
|
|
|
removeText(currentRange());
|
|
|
|
|
insertText(result);
|
|
|
|
|
setPosition(targetPosition);
|
|
|
|
|
endEditBlock();
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
//qDebug() << "FILTER: " << command;
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, FakeVimHandler::tr("%n lines filtered", 0,
|
2012-05-08 18:10:05 +02:00
|
|
|
text.count('\n')));
|
|
|
|
|
}
|
2010-04-16 16:30:45 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExShiftCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
if (cmd.cmd != "<" && cmd.cmd != ">")
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
2011-03-28 13:24:25 +02:00
|
|
|
Range range = cmd.range;
|
2011-11-29 08:17:02 +01:00
|
|
|
if (cmd.range.endPos == 0)
|
2011-03-28 13:24:25 +02:00
|
|
|
range = rangeFromCurrentLine();
|
|
|
|
|
setCurrentRange(range);
|
|
|
|
|
int count = qMax(1, cmd.args.toInt());
|
2010-05-18 14:48:12 +02:00
|
|
|
if (cmd.cmd == "<")
|
|
|
|
|
shiftRegionLeft(count);
|
|
|
|
|
else
|
|
|
|
|
shiftRegionRight(count);
|
2010-04-16 16:30:45 +02:00
|
|
|
leaveVisualMode();
|
2011-03-28 13:24:25 +02:00
|
|
|
const int beginLine = lineForPosition(range.beginPos);
|
|
|
|
|
const int endLine = lineForPosition(range.endPos);
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, FakeVimHandler::tr("%n lines %1ed %2 time", 0,
|
2010-05-18 14:48:12 +02:00
|
|
|
(endLine - beginLine + 1)).arg(cmd.cmd).arg(count));
|
2010-04-16 16:30:45 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-14 16:04:10 +02:00
|
|
|
bool FakeVimHandler::Private::handleExNohlsearchCommand(const ExCommand &cmd)
|
|
|
|
|
{
|
|
|
|
|
// :nohlsearch
|
|
|
|
|
if (!cmd.cmd.startsWith("noh"))
|
|
|
|
|
return false;
|
|
|
|
|
|
2012-09-27 21:09:13 +02:00
|
|
|
highlightMatches(QString());
|
2010-07-14 16:04:10 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExRedoCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
// :redo
|
|
|
|
|
if (cmd.cmd != "red" && cmd.cmd != "redo")
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
redo();
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-26 18:39:48 +02:00
|
|
|
bool FakeVimHandler::Private::handleExUndoCommand(const ExCommand &cmd)
|
|
|
|
|
{
|
|
|
|
|
// :undo
|
|
|
|
|
if (cmd.cmd != "u" && cmd.cmd != "un" && cmd.cmd != "undo")
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
undo();
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExGotoCommand(const ExCommand &cmd)
|
2010-04-16 16:30:45 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
// :<nr>
|
|
|
|
|
if (!cmd.cmd.isEmpty())
|
2010-04-16 16:30:45 +02:00
|
|
|
return false;
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
const int beginLine = lineForPosition(cmd.range.beginPos);
|
|
|
|
|
setPosition(firstPositionInLine(beginLine));
|
2012-09-10 22:10:23 +02:00
|
|
|
clearMessage();
|
2010-04-16 16:30:45 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd)
|
2010-04-16 17:47:02 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
// :source
|
|
|
|
|
if (cmd.cmd != "so" && cmd.cmd != "source")
|
2010-04-16 17:47:02 +02:00
|
|
|
return false;
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
QString fileName = cmd.args;
|
2010-04-16 17:47:02 +02:00
|
|
|
QFile file(fileName);
|
|
|
|
|
if (!file.open(QIODevice::ReadOnly)) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, FakeVimHandler::tr("Cannot open file %1").arg(fileName));
|
2010-04-16 17:47:02 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool inFunction = false;
|
2012-09-29 19:09:08 +02:00
|
|
|
QByteArray line;
|
|
|
|
|
while (!file.atEnd() || !line.isEmpty()) {
|
|
|
|
|
QByteArray nextline = !file.atEnd() ? file.readLine() : QByteArray();
|
|
|
|
|
|
|
|
|
|
// remove comment
|
|
|
|
|
int i = nextline.lastIndexOf('"');
|
|
|
|
|
if (i != -1)
|
|
|
|
|
nextline = nextline.remove(i, nextline.size() - i);
|
|
|
|
|
|
|
|
|
|
nextline = nextline.trimmed();
|
|
|
|
|
|
|
|
|
|
// multi-line command?
|
|
|
|
|
if (nextline.startsWith('\\')) {
|
|
|
|
|
line += nextline.mid(1);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-16 17:47:02 +02:00
|
|
|
if (line.startsWith("function")) {
|
|
|
|
|
//qDebug() << "IGNORING FUNCTION" << line;
|
2010-04-28 14:00:44 +02:00
|
|
|
inFunction = true;
|
2010-04-16 17:47:02 +02:00
|
|
|
} else if (inFunction && line.startsWith("endfunction")) {
|
|
|
|
|
inFunction = false;
|
|
|
|
|
} else if (!line.isEmpty() && !inFunction) {
|
|
|
|
|
//qDebug() << "EXECUTING: " << line;
|
2011-11-10 15:47:17 +01:00
|
|
|
ExCommand cmd;
|
|
|
|
|
cmd.setContentsFromLine(QString::fromLocal8Bit(line));
|
2012-09-29 19:09:08 +02:00
|
|
|
while (cmd.nextSubcommand()) {
|
|
|
|
|
if (!handleExCommandHelper(cmd))
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-04-16 17:47:02 +02:00
|
|
|
}
|
2012-09-29 19:09:08 +02:00
|
|
|
|
|
|
|
|
line = nextline;
|
2010-04-16 17:47:02 +02:00
|
|
|
}
|
|
|
|
|
file.close();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-05 16:32:18 +02:00
|
|
|
bool FakeVimHandler::Private::handleExEchoCommand(const ExCommand &cmd)
|
|
|
|
|
{
|
|
|
|
|
// :echo
|
|
|
|
|
if (cmd.cmd != "echo")
|
|
|
|
|
return false;
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, cmd.args);
|
2011-04-05 16:32:18 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-16 16:30:45 +02:00
|
|
|
void FakeVimHandler::Private::handleExCommand(const QString &line0)
|
|
|
|
|
{
|
|
|
|
|
QString line = line0; // Make sure we have a copy to prevent aliasing.
|
2011-10-28 14:16:01 +02:00
|
|
|
|
|
|
|
|
if (line.endsWith(QLatin1Char('%'))) {
|
|
|
|
|
line.chop(1);
|
|
|
|
|
int percent = line.toInt();
|
|
|
|
|
setPosition(firstPositionInLine(percent * linesInDocument() / 100));
|
2012-09-10 22:10:23 +02:00
|
|
|
clearMessage();
|
2011-10-28 14:16:01 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-29 19:09:08 +02:00
|
|
|
ExCommand cmd;
|
|
|
|
|
cmd.setContentsFromLine(line);
|
|
|
|
|
//qDebug() << "CMD: " << cmd;
|
|
|
|
|
|
2012-09-29 19:09:08 +02:00
|
|
|
beginLargeEditBlock();
|
2012-09-29 19:09:08 +02:00
|
|
|
while (cmd.nextSubcommand()) {
|
|
|
|
|
if (!handleExCommandHelper(cmd)) {
|
|
|
|
|
showMessage(MessageError,
|
|
|
|
|
tr("Not an editor command: %1").arg(cmd.printCommand()));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
endEditBlock();
|
|
|
|
|
|
|
|
|
|
enterCommandMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::handleExCommandHelper(ExCommand &cmd)
|
|
|
|
|
{
|
|
|
|
|
// parse range first
|
|
|
|
|
QString &line = cmd.cmd;
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
// FIXME: that seems to be different for %w and %s
|
|
|
|
|
if (line.startsWith(QLatin1Char('%')))
|
2012-09-29 19:09:08 +02:00
|
|
|
line.replace(0, 1, "1,$");
|
2010-05-11 14:26:37 +02:00
|
|
|
|
2010-07-14 14:33:26 +02:00
|
|
|
const int beginLine = readLineCode(line);
|
2010-05-12 11:18:18 +02:00
|
|
|
int endLine = -1;
|
2010-05-11 14:26:37 +02:00
|
|
|
if (line.startsWith(',')) {
|
|
|
|
|
line = line.mid(1);
|
2010-05-12 11:18:18 +02:00
|
|
|
endLine = readLineCode(line);
|
2010-05-11 14:26:37 +02:00
|
|
|
}
|
2010-05-18 12:54:18 +02:00
|
|
|
if (beginLine != -1 && endLine == -1)
|
|
|
|
|
endLine = beginLine;
|
2012-05-08 18:10:05 +02:00
|
|
|
if (beginLine != -1) {
|
|
|
|
|
const int beginPos = firstPositionInLine(beginLine);
|
|
|
|
|
const int endPos = lastPositionInLine(endLine);
|
|
|
|
|
cmd.range = Range(beginPos, endPos, RangeLineMode);
|
2010-07-14 14:33:26 +02:00
|
|
|
cmd.count = beginLine;
|
2012-05-08 18:10:05 +02:00
|
|
|
}
|
2010-05-11 14:26:37 +02:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
return handleExPluginCommand(cmd)
|
|
|
|
|
|| handleExGotoCommand(cmd)
|
2010-05-11 14:26:37 +02:00
|
|
|
|| handleExBangCommand(cmd)
|
|
|
|
|
|| handleExHistoryCommand(cmd)
|
2010-05-20 14:08:11 +02:00
|
|
|
|| handleExRegisterCommand(cmd)
|
2010-05-11 14:26:37 +02:00
|
|
|
|| handleExDeleteCommand(cmd)
|
|
|
|
|
|| handleExMapCommand(cmd)
|
2010-07-14 16:04:10 +02:00
|
|
|
|| handleExNohlsearchCommand(cmd)
|
2010-05-11 14:26:37 +02:00
|
|
|
|| handleExNormalCommand(cmd)
|
|
|
|
|
|| handleExReadCommand(cmd)
|
|
|
|
|
|| handleExRedoCommand(cmd)
|
2012-08-26 18:39:48 +02:00
|
|
|
|| handleExUndoCommand(cmd)
|
2010-05-11 14:26:37 +02:00
|
|
|
|| handleExSetCommand(cmd)
|
2010-05-18 14:48:12 +02:00
|
|
|
|| handleExShiftCommand(cmd)
|
2010-05-11 14:26:37 +02:00
|
|
|
|| handleExSourceCommand(cmd)
|
|
|
|
|
|| handleExSubstituteCommand(cmd)
|
2011-04-05 16:32:18 +02:00
|
|
|
|| handleExWriteCommand(cmd)
|
|
|
|
|
|| handleExEchoCommand(cmd);
|
2008-12-27 16:42:07 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
bool FakeVimHandler::Private::handleExPluginCommand(const ExCommand &cmd)
|
2009-06-15 15:14:16 +02:00
|
|
|
{
|
2010-05-18 14:48:12 +02:00
|
|
|
bool handled = false;
|
|
|
|
|
emit q->handleExCommandRequested(&handled, cmd);
|
|
|
|
|
//qDebug() << "HANDLER REQUEST: " << cmd.cmd << handled;
|
|
|
|
|
return handled;
|
2010-01-21 17:23:32 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-14 13:02:17 +02:00
|
|
|
void FakeVimHandler::Private::searchBalanced(bool forward, QChar needle, QChar other)
|
|
|
|
|
{
|
|
|
|
|
int level = 1;
|
2010-09-13 15:23:20 +02:00
|
|
|
int pos = position();
|
2010-07-14 13:02:17 +02:00
|
|
|
const int npos = forward ? lastPositionInDocument() : 0;
|
|
|
|
|
while (true) {
|
|
|
|
|
if (forward)
|
|
|
|
|
++pos;
|
|
|
|
|
else
|
|
|
|
|
--pos;
|
|
|
|
|
if (pos == npos)
|
|
|
|
|
return;
|
2010-09-13 14:16:18 +02:00
|
|
|
QChar c = document()->characterAt(pos);
|
2010-07-14 13:02:17 +02:00
|
|
|
if (c == other)
|
|
|
|
|
++level;
|
|
|
|
|
else if (c == needle)
|
|
|
|
|
--level;
|
|
|
|
|
if (level == 0) {
|
|
|
|
|
const int oldLine = cursorLine() - cursorLineOnScreen();
|
|
|
|
|
// Making this unconditional feels better, but is not "vim like".
|
|
|
|
|
if (oldLine != cursorLine() - cursorLineOnScreen())
|
|
|
|
|
scrollToLine(cursorLine() - linesOnScreen() / 2);
|
2012-08-11 14:31:42 +02:00
|
|
|
recordJump();
|
2011-11-17 01:10:53 +01:00
|
|
|
setPosition(pos);
|
2010-07-14 13:02:17 +02:00
|
|
|
setTargetColumn();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void FakeVimHandler::Private::search(const SearchData &sd, bool showMessages)
|
2008-12-19 12:20:04 +01:00
|
|
|
{
|
2008-12-26 17:01:21 +01:00
|
|
|
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
|
2010-05-18 18:24:00 +02:00
|
|
|
if (!sd.forward)
|
2009-01-16 09:56:08 +01:00
|
|
|
flags |= QTextDocument::FindBackward;
|
|
|
|
|
|
2012-07-22 14:30:56 +02:00
|
|
|
QRegExp needleExp = vimPatternToQtPattern(sd.needle, hasConfig(ConfigSmartCase));
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
const int oldLine = cursorLine() - cursorLineOnScreen();
|
2008-12-25 13:20:09 +01:00
|
|
|
|
2012-09-01 10:44:02 +02:00
|
|
|
int startPos = m_searchStartPosition + (sd.forward ? 1 : -1);
|
2009-01-27 13:23:02 +01:00
|
|
|
|
2012-09-01 10:44:02 +02:00
|
|
|
int repeat = count();
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextCursor tc = document()->find(needleExp, startPos, flags);
|
2012-09-01 10:44:02 +02:00
|
|
|
while (!tc.isNull() && --repeat >= 1)
|
|
|
|
|
tc = document()->find(needleExp, tc, flags);
|
|
|
|
|
|
2010-05-18 18:24:00 +02:00
|
|
|
if (tc.isNull()) {
|
2012-09-01 10:44:02 +02:00
|
|
|
if (hasConfig(ConfigWrapScan)) {
|
|
|
|
|
int startPos = sd.forward ? 0 : lastPositionInDocument();
|
|
|
|
|
tc = document()->find(needleExp, startPos, flags);
|
|
|
|
|
while (!tc.isNull() && --repeat >= 1)
|
|
|
|
|
tc = document()->find(needleExp, tc, flags);
|
|
|
|
|
if (tc.isNull()) {
|
2012-09-10 22:10:23 +02:00
|
|
|
if (showMessages) {
|
|
|
|
|
showMessage(MessageError,
|
|
|
|
|
FakeVimHandler::tr("Pattern not found: %1").arg(sd.needle));
|
|
|
|
|
}
|
|
|
|
|
} else if (showMessages) {
|
2012-09-08 19:21:46 +02:00
|
|
|
QString msg = sd.forward
|
|
|
|
|
? FakeVimHandler::tr("search hit BOTTOM, continuing at TOP")
|
|
|
|
|
: FakeVimHandler::tr("search hit TOP, continuing at BOTTOM");
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageWarning, msg);
|
2010-05-18 18:24:00 +02:00
|
|
|
}
|
2012-09-10 22:10:23 +02:00
|
|
|
} else if (showMessages) {
|
2012-09-01 10:44:02 +02:00
|
|
|
QString msg = sd.forward
|
|
|
|
|
? FakeVimHandler::tr("search hit BOTTOM without match for: %1")
|
|
|
|
|
: FakeVimHandler::tr("search hit TOP without match for: %1");
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, msg.arg(sd.needle));
|
2009-03-20 09:26:34 +01:00
|
|
|
}
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
2010-05-18 18:24:00 +02:00
|
|
|
|
2012-09-08 19:21:46 +02:00
|
|
|
if (tc.isNull()) {
|
|
|
|
|
tc = cursor();
|
|
|
|
|
tc.setPosition(m_searchStartPosition);
|
2012-09-27 21:09:13 +02:00
|
|
|
if (!needleExp.isValid() && showMessages) {
|
|
|
|
|
QString error = needleExp.errorString();
|
|
|
|
|
showMessage(MessageError,
|
|
|
|
|
FakeVimHandler::tr("Invalid regular expression: %1").arg(error));
|
|
|
|
|
}
|
2012-09-08 19:21:46 +02:00
|
|
|
}
|
2012-08-11 14:31:42 +02:00
|
|
|
|
2012-09-08 19:21:46 +02:00
|
|
|
recordJump();
|
|
|
|
|
if (isVisualMode()) {
|
|
|
|
|
int d = tc.anchor() - tc.position();
|
|
|
|
|
setPosition(tc.position() + d);
|
|
|
|
|
} else {
|
|
|
|
|
// Set Cursor. In contrast to the main editor we have the cursor
|
|
|
|
|
// position before the anchor position.
|
|
|
|
|
setAnchorAndPosition(tc.position(), tc.anchor());
|
|
|
|
|
}
|
2010-05-18 18:24:00 +02:00
|
|
|
|
|
|
|
|
// Making this unconditional feels better, but is not "vim like".
|
2010-07-06 10:12:21 +02:00
|
|
|
if (oldLine != cursorLine() - cursorLineOnScreen())
|
|
|
|
|
scrollToLine(cursorLine() - linesOnScreen() / 2);
|
2010-05-18 18:24:00 +02:00
|
|
|
|
2012-09-27 21:09:13 +02:00
|
|
|
m_searchCursor = cursor();
|
2010-09-14 14:04:13 +02:00
|
|
|
|
2010-04-20 15:24:36 +02:00
|
|
|
setTargetColumn();
|
2010-05-18 18:24:00 +02:00
|
|
|
|
|
|
|
|
if (sd.highlightMatches)
|
2012-09-27 21:09:13 +02:00
|
|
|
highlightMatches(needleExp.pattern());
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-01 10:44:02 +02:00
|
|
|
void FakeVimHandler::Private::searchNext(bool forward)
|
|
|
|
|
{
|
|
|
|
|
SearchData sd;
|
2012-10-03 16:40:05 +02:00
|
|
|
sd.needle = g.lastSearch;
|
|
|
|
|
sd.forward = forward ? g.lastSearchForward : !g.lastSearchForward;
|
2012-09-01 10:44:02 +02:00
|
|
|
sd.highlightMatches = true;
|
|
|
|
|
m_searchStartPosition = position();
|
2012-10-03 16:40:05 +02:00
|
|
|
showMessage(MessageCommand, (g.lastSearchForward ? '/' : '?') + sd.needle);
|
2012-09-01 10:44:02 +02:00
|
|
|
search(sd);
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-03 11:20:58 +02:00
|
|
|
void FakeVimHandler::Private::highlightMatches(const QString &needle)
|
2009-03-12 18:05:36 +01:00
|
|
|
{
|
2012-09-27 21:09:13 +02:00
|
|
|
if (!hasConfig(ConfigHlSearch) || needle == m_oldNeedle)
|
2009-03-12 18:05:36 +01:00
|
|
|
return;
|
2011-05-03 11:20:58 +02:00
|
|
|
m_oldNeedle = needle;
|
2012-08-01 14:42:13 +02:00
|
|
|
|
2012-09-27 21:09:13 +02:00
|
|
|
updateHighlights();
|
2009-03-12 18:05:36 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-19 14:35:57 +01:00
|
|
|
void FakeVimHandler::Private::moveToFirstNonBlankOnLine()
|
|
|
|
|
{
|
2012-08-26 18:39:48 +02:00
|
|
|
QTextCursor tc2 = cursor();
|
|
|
|
|
moveToFirstNonBlankOnLine(&tc2);
|
|
|
|
|
setPosition(tc2.position());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToFirstNonBlankOnLine(QTextCursor *tc)
|
|
|
|
|
{
|
|
|
|
|
QTextDocument *doc = tc->document();
|
|
|
|
|
int firstPos = tc->block().position();
|
2010-09-13 15:23:20 +02:00
|
|
|
for (int i = firstPos, n = firstPos + block().length(); i < n; ++i) {
|
2010-01-21 17:38:25 +01:00
|
|
|
if (!doc->characterAt(i).isSpace() || i == n - 1) {
|
2012-08-26 18:39:48 +02:00
|
|
|
tc->setPosition(i);
|
2008-12-19 14:35:57 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-26 18:39:48 +02:00
|
|
|
tc->setPosition(block().position());
|
2008-12-19 14:35:57 +01:00
|
|
|
}
|
2008-12-19 12:20:04 +01:00
|
|
|
|
2010-01-06 14:57:46 +01:00
|
|
|
void FakeVimHandler::Private::indentSelectedText(QChar typedChar)
|
2008-12-26 10:36:40 +01:00
|
|
|
{
|
2011-12-27 17:39:56 +01:00
|
|
|
beginEditBlock();
|
2010-02-19 13:01:38 +01:00
|
|
|
setTargetColumn();
|
2010-01-06 14:57:46 +01:00
|
|
|
int beginLine = qMin(lineForPosition(position()), lineForPosition(anchor()));
|
|
|
|
|
int endLine = qMax(lineForPosition(position()), lineForPosition(anchor()));
|
|
|
|
|
|
2010-05-06 15:20:30 +02:00
|
|
|
Range range(anchor(), position(), m_rangemode);
|
2010-01-06 14:57:46 +01:00
|
|
|
indentText(range, typedChar);
|
|
|
|
|
|
|
|
|
|
setPosition(firstPositionInLine(beginLine));
|
2010-02-19 13:01:38 +01:00
|
|
|
handleStartOfLine();
|
2010-01-06 14:57:46 +01:00
|
|
|
setTargetColumn();
|
|
|
|
|
setDotCommand("%1==", endLine - beginLine + 1);
|
2011-12-27 17:39:56 +01:00
|
|
|
endEditBlock();
|
2010-01-06 14:57:46 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-02 15:27:10 +02:00
|
|
|
void FakeVimHandler::Private::indentText(const Range &range, QChar typedChar)
|
2010-01-06 14:57:46 +01:00
|
|
|
{
|
|
|
|
|
int beginLine = lineForPosition(range.beginPos);
|
|
|
|
|
int endLine = lineForPosition(range.endPos);
|
2009-03-06 13:03:33 +01:00
|
|
|
if (beginLine > endLine)
|
|
|
|
|
qSwap(beginLine, endLine);
|
2009-05-05 09:06:36 +02:00
|
|
|
|
2010-06-02 15:27:10 +02:00
|
|
|
// LineForPosition has returned 1-based line numbers.
|
|
|
|
|
emit q->indentRegion(beginLine - 1, endLine - 1, typedChar);
|
2010-05-17 16:25:58 +02:00
|
|
|
if (beginLine != endLine)
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageError, "MARKS ARE OFF NOW");
|
2008-12-26 10:36:40 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-06 14:57:46 +01:00
|
|
|
bool FakeVimHandler::Private::isElectricCharacter(QChar c) const
|
|
|
|
|
{
|
|
|
|
|
bool result = false;
|
|
|
|
|
emit q->checkForElectricCharacter(&result, c);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-06 12:12:35 +01:00
|
|
|
void FakeVimHandler::Private::shiftRegionRight(int repeat)
|
2009-03-06 11:22:16 +01:00
|
|
|
{
|
|
|
|
|
int beginLine = lineForPosition(anchor());
|
|
|
|
|
int endLine = lineForPosition(position());
|
2010-04-29 13:30:12 +02:00
|
|
|
int targetPos = anchor();
|
|
|
|
|
if (beginLine > endLine) {
|
2009-03-06 11:22:16 +01:00
|
|
|
qSwap(beginLine, endLine);
|
2010-04-29 13:30:12 +02:00
|
|
|
targetPos = position();
|
|
|
|
|
}
|
|
|
|
|
if (hasConfig(ConfigStartOfLine))
|
|
|
|
|
targetPos = firstPositionInLine(beginLine);
|
|
|
|
|
|
2010-07-06 15:11:35 +02:00
|
|
|
const int sw = config(ConfigShiftWidth).toInt();
|
2012-08-26 18:39:48 +02:00
|
|
|
m_movetype = MoveLineWise;
|
2011-12-27 17:39:56 +01:00
|
|
|
beginEditBlock();
|
2009-03-06 11:22:16 +01:00
|
|
|
for (int line = beginLine; line <= endLine; ++line) {
|
2010-07-06 15:11:35 +02:00
|
|
|
QString data = lineContents(line);
|
|
|
|
|
const Column col = indentation(data);
|
|
|
|
|
data = tabExpand(col.logical + sw * repeat) + data.mid(col.physical);
|
|
|
|
|
setLineContents(line, data);
|
2009-03-06 11:22:16 +01:00
|
|
|
}
|
2009-11-30 13:58:57 +01:00
|
|
|
endEditBlock();
|
2009-03-06 13:03:33 +01:00
|
|
|
|
2010-04-29 13:30:12 +02:00
|
|
|
setPosition(targetPos);
|
2010-02-19 13:01:38 +01:00
|
|
|
handleStartOfLine();
|
2009-05-05 09:06:36 +02:00
|
|
|
setTargetColumn();
|
2009-04-16 09:18:09 +02:00
|
|
|
setDotCommand("%1>>", endLine - beginLine + 1);
|
2009-03-06 11:22:16 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-06 12:12:35 +01:00
|
|
|
void FakeVimHandler::Private::shiftRegionLeft(int repeat)
|
2009-03-06 11:22:16 +01:00
|
|
|
{
|
|
|
|
|
int beginLine = lineForPosition(anchor());
|
|
|
|
|
int endLine = lineForPosition(position());
|
2010-04-29 13:30:12 +02:00
|
|
|
int targetPos = anchor();
|
|
|
|
|
if (beginLine > endLine) {
|
2009-03-06 11:22:16 +01:00
|
|
|
qSwap(beginLine, endLine);
|
2010-05-04 17:58:53 +02:00
|
|
|
targetPos = position();
|
2010-04-29 13:30:12 +02:00
|
|
|
}
|
2010-02-08 13:31:59 +01:00
|
|
|
const int shift = config(ConfigShiftWidth).toInt() * repeat;
|
|
|
|
|
const int tab = config(ConfigTabStop).toInt();
|
2010-04-29 13:30:12 +02:00
|
|
|
if (hasConfig(ConfigStartOfLine))
|
|
|
|
|
targetPos = firstPositionInLine(beginLine);
|
2009-03-06 11:22:16 +01:00
|
|
|
|
2012-08-26 18:39:48 +02:00
|
|
|
m_movetype = MoveLineWise;
|
2011-12-27 17:39:56 +01:00
|
|
|
beginEditBlock();
|
2010-02-08 13:31:59 +01:00
|
|
|
for (int line = endLine; line >= beginLine; --line) {
|
2009-03-06 11:22:16 +01:00
|
|
|
int pos = firstPositionInLine(line);
|
2010-02-08 13:31:59 +01:00
|
|
|
const QString text = lineContents(line);
|
2009-03-06 11:22:16 +01:00
|
|
|
int amount = 0;
|
|
|
|
|
int i = 0;
|
2010-02-08 13:31:59 +01:00
|
|
|
for (; i < text.size() && amount < shift; ++i) {
|
2009-03-06 11:22:16 +01:00
|
|
|
if (text.at(i) == ' ')
|
|
|
|
|
amount++;
|
|
|
|
|
else if (text.at(i) == '\t')
|
|
|
|
|
amount += tab; // FIXME: take position into consideration
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-02-08 13:31:59 +01:00
|
|
|
removeText(Range(pos, pos + i));
|
2009-03-06 11:22:16 +01:00
|
|
|
setPosition(pos);
|
|
|
|
|
}
|
2009-11-30 13:58:57 +01:00
|
|
|
endEditBlock();
|
2009-03-06 13:03:33 +01:00
|
|
|
|
2010-04-29 13:30:12 +02:00
|
|
|
setPosition(targetPos);
|
2010-02-19 13:01:38 +01:00
|
|
|
handleStartOfLine();
|
2009-05-05 09:06:36 +02:00
|
|
|
setTargetColumn();
|
2009-04-16 09:18:09 +02:00
|
|
|
setDotCommand("%1<<", endLine - beginLine + 1);
|
2009-03-06 11:22:16 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-03 14:58:41 +02:00
|
|
|
void FakeVimHandler::Private::moveToTargetColumn()
|
2008-12-24 18:35:53 +01:00
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
const QTextBlock &bl = block();
|
2010-07-06 10:12:21 +02:00
|
|
|
//Column column = cursorColumn();
|
|
|
|
|
//int logical = logical
|
2010-09-13 15:23:20 +02:00
|
|
|
const int maxcol = bl.length() - 2;
|
2010-07-06 10:12:21 +02:00
|
|
|
if (m_targetColumn == -1) {
|
2010-09-14 16:58:31 +02:00
|
|
|
setPosition(bl.position() + qMax(0, maxcol));
|
2009-04-16 09:18:09 +02:00
|
|
|
return;
|
2010-07-06 10:12:21 +02:00
|
|
|
}
|
2010-09-13 15:23:20 +02:00
|
|
|
const int physical = logicalToPhysicalColumn(m_targetColumn, bl.text());
|
2010-07-06 10:12:21 +02:00
|
|
|
//qDebug() << "CORRECTING COLUMN FROM: " << logical << "TO" << m_targetColumn;
|
|
|
|
|
if (physical >= maxcol)
|
2010-09-14 16:58:31 +02:00
|
|
|
setPosition(bl.position() + qMax(0, maxcol));
|
2009-04-16 09:18:09 +02:00
|
|
|
else
|
2010-09-14 16:58:31 +02:00
|
|
|
setPosition(bl.position() + physical);
|
2008-12-24 18:35:53 +01:00
|
|
|
}
|
|
|
|
|
|
2009-04-09 16:20:49 +02:00
|
|
|
/* if simple is given:
|
|
|
|
|
* class 0: spaces
|
|
|
|
|
* class 1: non-spaces
|
|
|
|
|
* else
|
|
|
|
|
* class 0: spaces
|
|
|
|
|
* class 1: non-space-or-letter-or-number
|
|
|
|
|
* class 2: letter-or-number
|
|
|
|
|
*/
|
2010-04-28 16:19:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
int FakeVimHandler::Private::charClass(QChar c, bool simple) const
|
2008-12-25 19:11:21 +01:00
|
|
|
{
|
|
|
|
|
if (simple)
|
|
|
|
|
return c.isSpace() ? 0 : 1;
|
2010-04-28 16:19:51 +02:00
|
|
|
// FIXME: This means that only characters < 256 in the
|
|
|
|
|
// ConfigIsKeyword setting are handled properly.
|
|
|
|
|
if (c.unicode() < 256) {
|
|
|
|
|
//int old = (c.isLetterOrNumber() || c.unicode() == '_') ? 2
|
|
|
|
|
// : c.isSpace() ? 0 : 1;
|
|
|
|
|
//qDebug() << c.unicode() << old << m_charClass[c.unicode()];
|
|
|
|
|
return m_charClass[c.unicode()];
|
|
|
|
|
}
|
2008-12-25 19:11:21 +01:00
|
|
|
if (c.isLetterOrNumber() || c.unicode() == '_')
|
|
|
|
|
return 2;
|
|
|
|
|
return c.isSpace() ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void FakeVimHandler::Private::miniBufferTextEdited(const QString &text, int cursorPos)
|
|
|
|
|
{
|
|
|
|
|
if (m_subsubmode != SearchSubSubMode && m_mode != ExMode) {
|
|
|
|
|
editor()->setFocus();
|
|
|
|
|
} else if (text.isEmpty()) {
|
|
|
|
|
// editing cancelled
|
|
|
|
|
handleDefaultKey(Input(Qt::Key_Escape, Qt::NoModifier, QString()));
|
|
|
|
|
editor()->setFocus();
|
|
|
|
|
updateCursorShape();
|
|
|
|
|
} else {
|
|
|
|
|
CommandBuffer &cmdBuf = (m_mode == ExMode) ? g.commandBuffer : g.searchBuffer;
|
|
|
|
|
// prepend prompt character if missing
|
|
|
|
|
if (!text.startsWith(cmdBuf.prompt())) {
|
|
|
|
|
emit q->commandBufferChanged(cmdBuf.prompt() + text, cmdBuf.cursorPos() + 1, 0, q);
|
|
|
|
|
cmdBuf.setContents(text, cursorPos - 1);
|
|
|
|
|
} else {
|
|
|
|
|
cmdBuf.setContents(text.mid(1), cursorPos - 1);
|
|
|
|
|
}
|
|
|
|
|
// update search expression
|
|
|
|
|
if (m_subsubmode == SearchSubSubMode) {
|
|
|
|
|
updateFind(false);
|
|
|
|
|
exportSelection();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-28 16:19:51 +02:00
|
|
|
// Helper to parse a-z,A-Z,48-57,_
|
|
|
|
|
static int someInt(const QString &str)
|
|
|
|
|
{
|
|
|
|
|
if (str.toInt())
|
|
|
|
|
return str.toInt();
|
|
|
|
|
if (str.size())
|
|
|
|
|
return str.at(0).unicode();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::setupCharClass()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < 256; ++i) {
|
|
|
|
|
const QChar c = QChar(QLatin1Char(i));
|
|
|
|
|
m_charClass[i] = c.isSpace() ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
const QString conf = config(ConfigIsKeyword).toString();
|
|
|
|
|
foreach (const QString &part, conf.split(QLatin1Char(','))) {
|
|
|
|
|
if (part.contains(QLatin1Char('-'))) {
|
|
|
|
|
const int from = someInt(part.section(QLatin1Char('-'), 0, 0));
|
|
|
|
|
const int to = someInt(part.section(QLatin1Char('-'), 1, 1));
|
|
|
|
|
for (int i = qMax(0, from); i <= qMin(255, to); ++i)
|
|
|
|
|
m_charClass[i] = 2;
|
|
|
|
|
} else {
|
|
|
|
|
m_charClass[qMin(255, someInt(part))] = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
void FakeVimHandler::Private::moveToBoundary(bool simple, bool forward)
|
2008-12-25 19:50:14 +01:00
|
|
|
{
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextDocument *doc = document();
|
2012-08-19 19:08:04 +02:00
|
|
|
QTextCursor tc(doc);
|
|
|
|
|
tc.setPosition(position());
|
|
|
|
|
if (forward ? tc.atBlockEnd() : tc.atBlockStart())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QChar c = document()->characterAt(tc.position() + (forward ? -1 : 1));
|
|
|
|
|
int lastClass = tc.atStart() ? -1 : charClass(c, simple);
|
|
|
|
|
QTextCursor::MoveOperation op = forward ? Right : Left;
|
|
|
|
|
while (true) {
|
|
|
|
|
c = doc->characterAt(tc.position());
|
2008-12-25 19:50:14 +01:00
|
|
|
int thisClass = charClass(c, simple);
|
2012-08-19 19:08:04 +02:00
|
|
|
if (thisClass != lastClass || (forward ? tc.atBlockEnd() : tc.atBlockStart())) {
|
|
|
|
|
if (tc != cursor())
|
|
|
|
|
tc.movePosition(forward ? Left : Right);
|
2008-12-25 20:12:17 +01:00
|
|
|
break;
|
2012-08-19 19:08:04 +02:00
|
|
|
}
|
2008-12-25 19:50:14 +01:00
|
|
|
lastClass = thisClass;
|
2012-08-19 19:08:04 +02:00
|
|
|
tc.movePosition(op);
|
|
|
|
|
}
|
|
|
|
|
setPosition(tc.position());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToNextBoundary(bool end, int count, bool simple, bool forward)
|
|
|
|
|
{
|
|
|
|
|
int repeat = count;
|
|
|
|
|
while (repeat > 0 && !(forward ? atDocumentEnd() : atDocumentStart())) {
|
|
|
|
|
setPosition(position() + (forward ? 1 : -1));
|
|
|
|
|
moveToBoundary(simple, forward);
|
|
|
|
|
if (atBoundary(end, simple))
|
|
|
|
|
--repeat;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToNextBoundaryStart(int count, bool simple, bool forward)
|
|
|
|
|
{
|
|
|
|
|
moveToNextBoundary(false, count, simple, forward);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToNextBoundaryEnd(int count, bool simple, bool forward)
|
|
|
|
|
{
|
|
|
|
|
moveToNextBoundary(true, count, simple, forward);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToBoundaryStart(int count, bool simple, bool forward)
|
|
|
|
|
{
|
|
|
|
|
moveToNextBoundaryStart(atBoundary(false, simple) ? count - 1 : count, simple, forward);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToBoundaryEnd(int count, bool simple, bool forward)
|
|
|
|
|
{
|
|
|
|
|
moveToNextBoundaryEnd(atBoundary(true, simple) ? count - 1 : count, simple, forward);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToNextWord(bool end, int count, bool simple, bool forward, bool emptyLines)
|
|
|
|
|
{
|
|
|
|
|
int repeat = count;
|
|
|
|
|
while (repeat > 0 && !(forward ? atDocumentEnd() : atDocumentStart())) {
|
|
|
|
|
setPosition(position() + (forward ? 1 : -1));
|
|
|
|
|
moveToBoundary(simple, forward);
|
|
|
|
|
if (atWordBoundary(end, simple) && (emptyLines || !atEmptyLine()) )
|
2010-01-21 17:38:27 +01:00
|
|
|
--repeat;
|
2008-12-25 19:50:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
void FakeVimHandler::Private::moveToNextWordStart(int count, bool simple, bool forward, bool emptyLines)
|
|
|
|
|
{
|
|
|
|
|
moveToNextWord(false, count, simple, forward, emptyLines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToNextWordEnd(int count, bool simple, bool forward, bool emptyLines)
|
|
|
|
|
{
|
|
|
|
|
moveToNextWord(true, count, simple, forward, emptyLines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToWordStart(int count, bool simple, bool forward, bool emptyLines)
|
|
|
|
|
{
|
|
|
|
|
moveToNextWordStart(atWordStart(simple) ? count - 1 : count, simple, forward, emptyLines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::moveToWordEnd(int count, bool simple, bool forward, bool emptyLines)
|
|
|
|
|
{
|
|
|
|
|
moveToNextWordEnd(atWordEnd(simple) ? count - 1 : count, simple, forward, emptyLines);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-28 14:00:44 +02:00
|
|
|
bool FakeVimHandler::Private::handleFfTt(QString key)
|
2008-12-25 19:50:14 +01:00
|
|
|
{
|
2010-04-28 14:00:44 +02:00
|
|
|
int key0 = key.size() == 1 ? key.at(0).unicode() : 0;
|
2010-02-19 13:01:37 +01:00
|
|
|
int oldPos = position();
|
2008-12-26 00:18:03 +01:00
|
|
|
// m_subsubmode \in { 'f', 'F', 't', 'T' }
|
2010-04-28 14:00:44 +02:00
|
|
|
bool forward = m_subsubdata.is('f') || m_subsubdata.is('t');
|
2008-12-26 00:18:03 +01:00
|
|
|
int repeat = count();
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextDocument *doc = document();
|
2010-09-14 16:58:31 +02:00
|
|
|
int n = block().position();
|
2008-12-26 00:18:03 +01:00
|
|
|
if (forward)
|
2010-09-14 16:58:31 +02:00
|
|
|
n += block().length();
|
2010-09-13 15:23:20 +02:00
|
|
|
int pos = position();
|
2010-01-21 17:38:31 +01:00
|
|
|
while (pos != n) {
|
2008-12-26 00:18:03 +01:00
|
|
|
pos += forward ? 1 : -1;
|
|
|
|
|
if (pos == n)
|
|
|
|
|
break;
|
|
|
|
|
int uc = doc->characterAt(pos).unicode();
|
|
|
|
|
if (uc == ParagraphSeparator)
|
|
|
|
|
break;
|
2010-04-28 14:00:44 +02:00
|
|
|
if (uc == key0)
|
2008-12-25 19:50:14 +01:00
|
|
|
--repeat;
|
2008-12-25 20:12:17 +01:00
|
|
|
if (repeat == 0) {
|
2010-04-28 14:00:44 +02:00
|
|
|
if (m_subsubdata.is('t'))
|
2008-12-26 00:18:03 +01:00
|
|
|
--pos;
|
2010-04-28 14:00:44 +02:00
|
|
|
else if (m_subsubdata.is('T'))
|
2008-12-26 00:18:03 +01:00
|
|
|
++pos;
|
2008-12-26 00:25:38 +01:00
|
|
|
|
2008-12-26 00:18:03 +01:00
|
|
|
if (forward)
|
2010-09-14 16:58:31 +02:00
|
|
|
moveRight(pos - position());
|
2008-12-26 00:18:03 +01:00
|
|
|
else
|
2010-09-14 16:58:31 +02:00
|
|
|
moveLeft(position() - pos);
|
2008-12-25 20:12:17 +01:00
|
|
|
break;
|
2008-12-25 19:50:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-19 13:01:37 +01:00
|
|
|
if (repeat == 0) {
|
|
|
|
|
setTargetColumn();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-09-14 16:58:31 +02:00
|
|
|
setPosition(oldPos);
|
2010-09-13 15:23:20 +02:00
|
|
|
return false;
|
2008-12-25 19:50:14 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-13 12:35:43 +01:00
|
|
|
void FakeVimHandler::Private::moveToMatchingParanthesis()
|
|
|
|
|
{
|
2009-01-28 22:03:51 +01:00
|
|
|
bool moved = false;
|
|
|
|
|
bool forward = false;
|
|
|
|
|
|
2010-09-27 15:25:18 +02:00
|
|
|
const int anc = anchor();
|
2010-09-14 14:04:13 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
emit q->moveToMatchingParenthesis(&moved, &forward, &tc);
|
|
|
|
|
if (moved && forward)
|
|
|
|
|
tc.movePosition(Left, KeepAnchor, 1);
|
2010-09-27 15:25:18 +02:00
|
|
|
setAnchorAndPosition(anc, tc.position());
|
2009-04-09 16:20:49 +02:00
|
|
|
setTargetColumn();
|
2009-01-13 12:35:43 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-25 16:27:47 +01:00
|
|
|
int FakeVimHandler::Private::cursorLineOnScreen() const
|
|
|
|
|
{
|
2009-01-06 11:50:30 +01:00
|
|
|
if (!editor())
|
|
|
|
|
return 0;
|
2009-01-06 11:11:31 +01:00
|
|
|
QRect rect = EDITOR(cursorRect());
|
|
|
|
|
return rect.y() / rect.height();
|
2008-12-25 16:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int FakeVimHandler::Private::linesOnScreen() const
|
|
|
|
|
{
|
2009-01-06 11:50:30 +01:00
|
|
|
if (!editor())
|
|
|
|
|
return 1;
|
2009-01-06 11:11:31 +01:00
|
|
|
QRect rect = EDITOR(cursorRect());
|
|
|
|
|
return EDITOR(height()) / rect.height();
|
2008-12-25 16:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-27 21:01:05 +01:00
|
|
|
int FakeVimHandler::Private::columnsOnScreen() const
|
|
|
|
|
{
|
2009-01-06 11:50:30 +01:00
|
|
|
if (!editor())
|
|
|
|
|
return 1;
|
2009-01-06 11:11:31 +01:00
|
|
|
QRect rect = EDITOR(cursorRect());
|
2009-01-07 18:11:40 +01:00
|
|
|
// qDebug() << "WID: " << EDITOR(width()) << "RECT: " << rect;
|
2009-01-06 11:11:31 +01:00
|
|
|
return EDITOR(width()) / rect.width();
|
2008-12-27 21:01:05 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
int FakeVimHandler::Private::cursorLine() const
|
2008-12-25 16:27:47 +01:00
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
return block().blockNumber();
|
2008-12-25 16:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
int FakeVimHandler::Private::physicalCursorColumn() const
|
2008-12-27 21:01:05 +01:00
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
return position() - block().position();
|
2008-12-27 21:01:05 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
int FakeVimHandler::Private::physicalToLogicalColumn
|
|
|
|
|
(const int physical, const QString &line) const
|
2010-03-09 16:44:36 +01:00
|
|
|
{
|
|
|
|
|
const int ts = config(ConfigTabStop).toInt();
|
2010-07-06 10:12:21 +02:00
|
|
|
int p = 0;
|
2010-03-09 16:44:36 +01:00
|
|
|
int logical = 0;
|
2010-07-06 10:12:21 +02:00
|
|
|
while (p < physical) {
|
|
|
|
|
QChar c = line.at(p);
|
|
|
|
|
//if (c == QLatin1Char(' '))
|
|
|
|
|
// ++logical;
|
|
|
|
|
//else
|
|
|
|
|
if (c == QLatin1Char('\t'))
|
2010-03-09 16:44:36 +01:00
|
|
|
logical += ts - logical % ts;
|
|
|
|
|
else
|
2010-07-06 10:12:21 +02:00
|
|
|
++logical;
|
|
|
|
|
//break;
|
|
|
|
|
++p;
|
2010-03-09 16:44:36 +01:00
|
|
|
}
|
|
|
|
|
return logical;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
int FakeVimHandler::Private::logicalToPhysicalColumn
|
|
|
|
|
(const int logical, const QString &line) const
|
|
|
|
|
{
|
|
|
|
|
const int ts = config(ConfigTabStop).toInt();
|
|
|
|
|
int physical = 0;
|
|
|
|
|
for (int l = 0; l < logical && physical < line.size(); ++physical) {
|
|
|
|
|
QChar c = line.at(physical);
|
|
|
|
|
if (c == QLatin1Char('\t'))
|
|
|
|
|
l += ts - l % ts;
|
|
|
|
|
else
|
|
|
|
|
++l;
|
|
|
|
|
}
|
|
|
|
|
return physical;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int FakeVimHandler::Private::logicalCursorColumn() const
|
|
|
|
|
{
|
|
|
|
|
const int physical = physicalCursorColumn();
|
2010-09-13 15:23:20 +02:00
|
|
|
const QString line = block().text();
|
2010-07-06 10:12:21 +02:00
|
|
|
return physicalToLogicalColumn(physical, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Column FakeVimHandler::Private::cursorColumn() const
|
2010-03-09 16:44:36 +01:00
|
|
|
{
|
2010-07-06 10:12:21 +02:00
|
|
|
return Column(physicalCursorColumn(), logicalCursorColumn());
|
2010-03-09 16:44:36 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-28 02:15:26 +01:00
|
|
|
int FakeVimHandler::Private::linesInDocument() const
|
|
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
if (cursor().isNull())
|
2010-01-21 17:38:29 +01:00
|
|
|
return 0;
|
2010-09-13 14:16:18 +02:00
|
|
|
const int count = document()->blockCount();
|
2010-03-09 16:44:36 +01:00
|
|
|
// Qt inserts an empty line if the last character is a '\n',
|
|
|
|
|
// but that's not how vi does it.
|
2010-09-13 14:16:18 +02:00
|
|
|
return document()->lastBlock().length() <= 1 ? count - 1 : count;
|
2008-12-28 02:15:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
void FakeVimHandler::Private::scrollToLine(int line)
|
2008-12-25 16:27:47 +01:00
|
|
|
{
|
2009-01-06 11:11:31 +01:00
|
|
|
// FIXME: works only for QPlainTextEdit
|
|
|
|
|
QScrollBar *scrollBar = EDITOR(verticalScrollBar());
|
2009-03-20 08:44:52 +01:00
|
|
|
//qDebug() << "SCROLL: " << scrollBar->value() << line;
|
2009-01-06 11:11:31 +01:00
|
|
|
scrollBar->setValue(line);
|
2011-07-29 12:00:11 +02:00
|
|
|
//QTC_CHECK(firstVisibleLine() == line);
|
2009-07-13 14:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-06 10:12:21 +02:00
|
|
|
int FakeVimHandler::Private::firstVisibleLine() const
|
2009-07-13 14:04:47 +02:00
|
|
|
{
|
|
|
|
|
QScrollBar *scrollBar = EDITOR(verticalScrollBar());
|
2010-07-06 10:12:21 +02:00
|
|
|
if (0 && scrollBar->value() != cursorLine() - cursorLineOnScreen()) {
|
2009-07-13 14:04:47 +02:00
|
|
|
qDebug() << "SCROLLBAR: " << scrollBar->value()
|
2010-07-06 10:12:21 +02:00
|
|
|
<< "CURSORLINE IN DOC" << cursorLine()
|
2009-07-13 14:04:47 +02:00
|
|
|
<< "CURSORLINE ON SCREEN" << cursorLineOnScreen();
|
|
|
|
|
}
|
|
|
|
|
//return scrollBar->value();
|
2010-07-06 10:12:21 +02:00
|
|
|
return cursorLine() - cursorLineOnScreen();
|
2008-12-25 16:27:47 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-20 08:44:52 +01:00
|
|
|
void FakeVimHandler::Private::scrollUp(int count)
|
|
|
|
|
{
|
2010-07-06 10:12:21 +02:00
|
|
|
scrollToLine(cursorLine() - cursorLineOnScreen() - count);
|
2009-03-20 08:44:52 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-25 19:11:21 +01:00
|
|
|
int FakeVimHandler::Private::lastPositionInDocument() const
|
|
|
|
|
{
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextBlock block = document()->lastBlock();
|
2009-07-03 11:22:18 +02:00
|
|
|
return block.position() + block.length() - 1;
|
2008-12-25 19:11:21 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
QString FakeVimHandler::Private::selectText(const Range &range) const
|
2009-08-11 14:39:44 +02:00
|
|
|
{
|
|
|
|
|
if (range.rangemode == RangeCharMode) {
|
2012-08-18 20:40:15 +02:00
|
|
|
QTextCursor tc(document());
|
2009-08-11 14:39:44 +02:00
|
|
|
tc.setPosition(range.beginPos, MoveAnchor);
|
|
|
|
|
tc.setPosition(range.endPos, KeepAnchor);
|
|
|
|
|
return tc.selection().toPlainText();
|
|
|
|
|
}
|
2009-09-16 14:16:21 +02:00
|
|
|
if (range.rangemode == RangeLineMode) {
|
2012-08-18 20:40:15 +02:00
|
|
|
QTextCursor tc(document());
|
2009-11-10 09:25:22 +01:00
|
|
|
int firstPos = firstPositionInLine(lineForPosition(range.beginPos));
|
|
|
|
|
int lastLine = lineForPosition(range.endPos);
|
2011-03-28 13:25:15 +02:00
|
|
|
bool endOfDoc = lastLine == document()->lastBlock().blockNumber() + 1;
|
2011-12-27 17:39:56 +01:00
|
|
|
int lastPos = endOfDoc ? lastPositionInDocument() : firstPositionInLine(lastLine + 1);
|
2009-11-10 09:25:22 +01:00
|
|
|
tc.setPosition(firstPos, MoveAnchor);
|
|
|
|
|
tc.setPosition(lastPos, KeepAnchor);
|
2011-03-28 13:25:15 +02:00
|
|
|
return tc.selection().toPlainText() + QString((endOfDoc? "\n" : ""));
|
2009-09-16 14:16:21 +02:00
|
|
|
}
|
2009-08-11 14:39:44 +02:00
|
|
|
// FIXME: Performance?
|
|
|
|
|
int beginLine = lineForPosition(range.beginPos);
|
|
|
|
|
int endLine = lineForPosition(range.endPos);
|
|
|
|
|
int beginColumn = 0;
|
|
|
|
|
int endColumn = INT_MAX;
|
|
|
|
|
if (range.rangemode == RangeBlockMode) {
|
2009-10-16 11:30:46 +02:00
|
|
|
int column1 = range.beginPos - firstPositionInLine(beginLine);
|
|
|
|
|
int column2 = range.endPos - firstPositionInLine(endLine);
|
2009-08-11 14:39:44 +02:00
|
|
|
beginColumn = qMin(column1, column2);
|
|
|
|
|
endColumn = qMax(column1, column2);
|
2009-10-16 11:30:46 +02:00
|
|
|
}
|
2009-08-11 14:39:44 +02:00
|
|
|
int len = endColumn - beginColumn + 1;
|
|
|
|
|
QString contents;
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextBlock block = document()->findBlockByNumber(beginLine - 1);
|
2009-08-11 14:39:44 +02:00
|
|
|
for (int i = beginLine; i <= endLine && block.isValid(); ++i) {
|
|
|
|
|
QString line = block.text();
|
|
|
|
|
if (range.rangemode == RangeBlockMode) {
|
|
|
|
|
line = line.mid(beginColumn, len);
|
|
|
|
|
if (line.size() < len)
|
|
|
|
|
line += QString(len - line.size(), QChar(' '));
|
|
|
|
|
}
|
|
|
|
|
contents += line;
|
|
|
|
|
if (!contents.endsWith('\n'))
|
|
|
|
|
contents += '\n';
|
|
|
|
|
block = block.next();
|
|
|
|
|
}
|
|
|
|
|
//qDebug() << "SELECTED: " << contents;
|
|
|
|
|
return contents;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-12 02:31:52 +01:00
|
|
|
void FakeVimHandler::Private::yankText(const Range &range, int reg)
|
2009-08-11 14:39:44 +02:00
|
|
|
{
|
2012-08-09 17:32:39 +02:00
|
|
|
setRegister(reg, selectText(range), range.rangemode);
|
2009-08-11 14:39:44 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:42:46 +01:00
|
|
|
void FakeVimHandler::Private::transformText(const Range &range,
|
2010-05-06 15:20:30 +02:00
|
|
|
Transformation transformFunc, const QVariant &extra)
|
2009-01-16 16:15:01 +01:00
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextCursor tc = cursor();
|
2009-08-11 14:39:44 +02:00
|
|
|
switch (range.rangemode) {
|
|
|
|
|
case RangeCharMode: {
|
2010-05-28 13:09:24 +02:00
|
|
|
// This can span multiple lines.
|
|
|
|
|
beginEditBlock();
|
2009-08-11 14:39:44 +02:00
|
|
|
tc.setPosition(range.beginPos, MoveAnchor);
|
|
|
|
|
tc.setPosition(range.endPos, KeepAnchor);
|
2010-05-06 15:20:30 +02:00
|
|
|
TransformationData td(tc.selectedText(), extra);
|
|
|
|
|
(this->*transformFunc)(&td);
|
|
|
|
|
tc.removeSelectedText();
|
|
|
|
|
tc.insertText(td.to);
|
2010-05-28 13:09:24 +02:00
|
|
|
endEditBlock();
|
2009-08-11 14:39:44 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-01-21 17:38:27 +01:00
|
|
|
case RangeLineMode:
|
|
|
|
|
case RangeLineModeExclusive: {
|
2011-12-27 17:39:56 +01:00
|
|
|
beginEditBlock();
|
2009-08-11 14:39:44 +02:00
|
|
|
tc.setPosition(range.beginPos, MoveAnchor);
|
|
|
|
|
tc.movePosition(StartOfLine, MoveAnchor);
|
|
|
|
|
tc.setPosition(range.endPos, KeepAnchor);
|
|
|
|
|
tc.movePosition(EndOfLine, KeepAnchor);
|
2010-01-21 17:38:27 +01:00
|
|
|
if (range.rangemode != RangeLineModeExclusive) {
|
|
|
|
|
// make sure that complete lines are removed
|
|
|
|
|
// - also at the beginning and at the end of the document
|
|
|
|
|
if (tc.atEnd()) {
|
|
|
|
|
tc.setPosition(range.beginPos, MoveAnchor);
|
|
|
|
|
tc.movePosition(StartOfLine, MoveAnchor);
|
|
|
|
|
if (!tc.atStart()) {
|
|
|
|
|
// also remove first line if it is the only one
|
|
|
|
|
tc.movePosition(Left, MoveAnchor, 1);
|
|
|
|
|
tc.movePosition(EndOfLine, MoveAnchor, 1);
|
|
|
|
|
}
|
|
|
|
|
tc.setPosition(range.endPos, KeepAnchor);
|
|
|
|
|
tc.movePosition(EndOfLine, KeepAnchor);
|
|
|
|
|
} else {
|
|
|
|
|
tc.movePosition(Right, KeepAnchor, 1);
|
2010-01-05 18:42:26 +01:00
|
|
|
}
|
|
|
|
|
}
|
2010-05-06 15:20:30 +02:00
|
|
|
TransformationData td(tc.selectedText(), extra);
|
|
|
|
|
(this->*transformFunc)(&td);
|
|
|
|
|
tc.removeSelectedText();
|
|
|
|
|
tc.insertText(td.to);
|
2010-05-28 13:09:24 +02:00
|
|
|
endEditBlock();
|
2009-08-11 14:39:44 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2010-01-21 17:38:26 +01:00
|
|
|
case RangeBlockAndTailMode:
|
2009-08-11 14:39:44 +02:00
|
|
|
case RangeBlockMode: {
|
|
|
|
|
int beginLine = lineForPosition(range.beginPos);
|
|
|
|
|
int endLine = lineForPosition(range.endPos);
|
2009-10-16 11:30:46 +02:00
|
|
|
int column1 = range.beginPos - firstPositionInLine(beginLine);
|
|
|
|
|
int column2 = range.endPos - firstPositionInLine(endLine);
|
2009-08-11 14:39:44 +02:00
|
|
|
int beginColumn = qMin(column1, column2);
|
|
|
|
|
int endColumn = qMax(column1, column2);
|
2009-12-11 18:49:47 +01:00
|
|
|
if (range.rangemode == RangeBlockAndTailMode)
|
|
|
|
|
endColumn = INT_MAX - 1;
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextBlock block = document()->findBlockByNumber(endLine - 1);
|
2011-12-27 17:39:56 +01:00
|
|
|
beginEditBlock();
|
2009-08-11 14:39:44 +02:00
|
|
|
for (int i = beginLine; i <= endLine && block.isValid(); ++i) {
|
|
|
|
|
int bCol = qMin(beginColumn, block.length() - 1);
|
2009-11-10 10:07:36 +01:00
|
|
|
int eCol = qMin(endColumn + 1, block.length() - 1);
|
2009-08-11 14:39:44 +02:00
|
|
|
tc.setPosition(block.position() + bCol, MoveAnchor);
|
|
|
|
|
tc.setPosition(block.position() + eCol, KeepAnchor);
|
2010-05-06 15:20:30 +02:00
|
|
|
TransformationData td(tc.selectedText(), extra);
|
|
|
|
|
(this->*transformFunc)(&td);
|
|
|
|
|
tc.removeSelectedText();
|
|
|
|
|
tc.insertText(td.to);
|
2009-08-11 14:39:44 +02:00
|
|
|
block = block.previous();
|
|
|
|
|
}
|
|
|
|
|
endEditBlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
void FakeVimHandler::Private::insertText(const Register ®)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(reg.rangemode == RangeCharMode,
|
|
|
|
|
qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return);
|
2010-09-16 16:56:11 +02:00
|
|
|
setAnchor();
|
2010-09-14 16:58:31 +02:00
|
|
|
cursor().insertText(reg.contents);
|
2010-09-16 15:28:31 +02:00
|
|
|
//dump("AFTER INSERT");
|
2010-05-11 14:26:37 +02:00
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:38:26 +01:00
|
|
|
void FakeVimHandler::Private::removeText(const Range &range)
|
|
|
|
|
{
|
2010-09-14 14:04:13 +02:00
|
|
|
//qDebug() << "REMOVE: " << range;
|
2010-01-21 17:38:26 +01:00
|
|
|
transformText(range, &FakeVimHandler::Private::removeTransform);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-06 15:20:30 +02:00
|
|
|
void FakeVimHandler::Private::removeTransform(TransformationData *td)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
2010-05-06 15:20:30 +02:00
|
|
|
Q_UNUSED(td);
|
2010-01-21 17:38:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void FakeVimHandler::Private::downCase(const Range &range)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
|
|
|
|
transformText(range, &FakeVimHandler::Private::downCaseTransform);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-06 15:20:30 +02:00
|
|
|
void FakeVimHandler::Private::downCaseTransform(TransformationData *td)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
2010-05-06 15:20:30 +02:00
|
|
|
td->to = td->from.toLower();
|
2010-01-21 17:38:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void FakeVimHandler::Private::upCase(const Range &range)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
|
|
|
|
transformText(range, &FakeVimHandler::Private::upCaseTransform);
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-06 15:20:30 +02:00
|
|
|
void FakeVimHandler::Private::upCaseTransform(TransformationData *td)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
2010-05-06 15:20:30 +02:00
|
|
|
td->to = td->from.toUpper();
|
2010-01-21 17:38:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void FakeVimHandler::Private::invertCase(const Range &range)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
2010-05-12 11:18:18 +02:00
|
|
|
transformText(range, &FakeVimHandler::Private::invertCaseTransform);
|
2010-01-21 17:38:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-06 15:20:30 +02:00
|
|
|
void FakeVimHandler::Private::invertCaseTransform(TransformationData *td)
|
2010-01-21 17:38:26 +01:00
|
|
|
{
|
2010-05-06 15:20:30 +02:00
|
|
|
foreach (QChar c, td->from)
|
|
|
|
|
td->to += c.isUpper() ? c.toLower() : c.toUpper();
|
2010-01-21 17:38:26 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 11:18:18 +02:00
|
|
|
void FakeVimHandler::Private::replaceText(const Range &range, const QString &str)
|
2010-03-18 13:15:59 +01:00
|
|
|
{
|
2010-05-28 13:57:35 +02:00
|
|
|
Transformation tr = &FakeVimHandler::Private::replaceByStringTransform;
|
|
|
|
|
transformText(range, tr, str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::replaceByStringTransform(TransformationData *td)
|
|
|
|
|
{
|
|
|
|
|
td->to = td->extraData.toString();
|
2010-03-18 13:15:59 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-28 13:57:35 +02:00
|
|
|
void FakeVimHandler::Private::replaceByCharTransform(TransformationData *td)
|
2010-03-18 13:15:59 +01:00
|
|
|
{
|
2010-05-28 13:09:24 +02:00
|
|
|
td->to = QString(td->from.size(), td->extraData.toChar());
|
2010-03-18 13:15:59 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-11 14:39:44 +02:00
|
|
|
void FakeVimHandler::Private::pasteText(bool afterCursor)
|
|
|
|
|
{
|
2011-11-12 02:31:52 +01:00
|
|
|
const QString text = registerContents(m_register);
|
2012-08-09 13:05:06 +02:00
|
|
|
const RangeMode rangeMode = registerRangeMode(m_register);
|
2011-08-05 08:47:53 +02:00
|
|
|
|
|
|
|
|
beginEditBlock();
|
|
|
|
|
|
2012-08-09 13:05:06 +02:00
|
|
|
// In visual mode paste text only inside selection.
|
|
|
|
|
bool pasteAfter = isVisualMode() ? false : afterCursor;
|
|
|
|
|
|
|
|
|
|
bool visualCharMode = isVisualCharMode();
|
|
|
|
|
if (visualCharMode) {
|
2011-08-05 08:47:53 +02:00
|
|
|
leaveVisualMode();
|
2012-08-09 13:05:06 +02:00
|
|
|
m_rangemode = RangeCharMode;
|
|
|
|
|
Range range = currentRange();
|
|
|
|
|
range.endPos++;
|
|
|
|
|
yankText(range, m_register);
|
|
|
|
|
removeText(range);
|
2011-08-05 08:47:53 +02:00
|
|
|
} else if (isVisualLineMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeLineMode;
|
2012-08-09 13:05:06 +02:00
|
|
|
Range range = currentRange();
|
|
|
|
|
range.endPos++;
|
|
|
|
|
yankText(range, m_register);
|
|
|
|
|
removeText(range);
|
2011-08-05 08:47:53 +02:00
|
|
|
handleStartOfLine();
|
|
|
|
|
} else if (isVisualBlockMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
m_rangemode = RangeBlockMode;
|
2012-08-09 13:05:06 +02:00
|
|
|
Range range = currentRange();
|
|
|
|
|
yankText(range, m_register);
|
|
|
|
|
removeText(range);
|
2011-08-05 08:47:53 +02:00
|
|
|
setPosition(qMin(position(), anchor()));
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-09 13:05:06 +02:00
|
|
|
switch (rangeMode) {
|
2009-08-11 14:39:44 +02:00
|
|
|
case RangeCharMode: {
|
|
|
|
|
m_targetColumn = 0;
|
2012-08-09 13:05:06 +02:00
|
|
|
if (pasteAfter && rightDist() > 0)
|
|
|
|
|
moveRight();
|
|
|
|
|
insertText(text.repeated(count()));
|
|
|
|
|
if (!pasteAfter && atEndOfLine())
|
2009-08-11 14:39:44 +02:00
|
|
|
moveLeft();
|
2012-08-09 13:05:06 +02:00
|
|
|
moveLeft();
|
2009-08-11 14:39:44 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2010-01-21 17:38:27 +01:00
|
|
|
case RangeLineMode:
|
|
|
|
|
case RangeLineModeExclusive: {
|
2011-03-28 13:25:15 +02:00
|
|
|
QTextCursor tc = cursor();
|
2012-08-09 13:05:06 +02:00
|
|
|
if (visualCharMode)
|
|
|
|
|
tc.insertBlock();
|
|
|
|
|
else
|
|
|
|
|
moveToStartOfLine();
|
|
|
|
|
m_targetColumn = 0;
|
|
|
|
|
if (pasteAfter) {
|
2011-03-28 13:25:15 +02:00
|
|
|
bool lastLine = document()->lastBlock() == this->block();
|
2012-08-09 13:05:06 +02:00
|
|
|
if (lastLine) {
|
|
|
|
|
tc.movePosition(EndOfLine, MoveAnchor);
|
|
|
|
|
tc.insertBlock();
|
2011-03-28 13:25:15 +02:00
|
|
|
}
|
2012-08-09 13:05:06 +02:00
|
|
|
moveDown();
|
2009-08-11 14:39:44 +02:00
|
|
|
}
|
2012-08-09 13:05:06 +02:00
|
|
|
const int pos = position();
|
|
|
|
|
insertText(text.repeated(count()));
|
|
|
|
|
setPosition(pos);
|
2009-08-11 14:39:44 +02:00
|
|
|
moveToFirstNonBlankOnLine();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-12-11 18:59:05 +01:00
|
|
|
case RangeBlockAndTailMode:
|
2009-08-11 14:39:44 +02:00
|
|
|
case RangeBlockMode: {
|
2012-08-09 13:05:06 +02:00
|
|
|
const int pos = position();
|
|
|
|
|
if (pasteAfter && rightDist() > 0)
|
2009-11-10 10:07:36 +01:00
|
|
|
moveRight();
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextCursor tc = cursor();
|
2012-08-09 13:05:06 +02:00
|
|
|
const int col = tc.columnNumber();
|
|
|
|
|
QTextBlock block = tc.block();
|
|
|
|
|
const QStringList lines = text.split(QChar('\n'));
|
|
|
|
|
for (int i = 0; i < lines.size() - 1; ++i) {
|
|
|
|
|
if (!block.isValid()) {
|
|
|
|
|
tc.movePosition(EndOfDocument);
|
|
|
|
|
tc.insertBlock();
|
|
|
|
|
block = tc.block();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resize line
|
|
|
|
|
int length = block.length();
|
|
|
|
|
int begin = block.position();
|
|
|
|
|
if (col >= length) {
|
|
|
|
|
tc.setPosition(begin + length - 1);
|
|
|
|
|
tc.insertText(QString(col - length + 1, QChar(' ')));
|
2009-10-16 11:30:46 +02:00
|
|
|
} else {
|
2012-08-09 13:05:06 +02:00
|
|
|
tc.setPosition(begin + col);
|
2009-08-11 14:39:44 +02:00
|
|
|
}
|
2012-08-09 13:05:06 +02:00
|
|
|
|
|
|
|
|
// insert text
|
|
|
|
|
const QString line = lines.at(i).repeated(count());
|
2009-08-11 14:39:44 +02:00
|
|
|
tc.insertText(line);
|
2012-08-09 13:05:06 +02:00
|
|
|
|
|
|
|
|
// next line
|
2009-08-11 14:39:44 +02:00
|
|
|
block = block.next();
|
|
|
|
|
}
|
2012-08-09 13:05:06 +02:00
|
|
|
setPosition(pos);
|
|
|
|
|
if (pasteAfter)
|
|
|
|
|
moveRight();
|
2009-08-11 14:39:44 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-08-05 08:47:53 +02:00
|
|
|
|
|
|
|
|
endEditBlock();
|
2009-01-16 16:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
2009-12-09 17:40:00 +01:00
|
|
|
QString FakeVimHandler::Private::lineContents(int line) const
|
|
|
|
|
{
|
2010-09-13 14:16:18 +02:00
|
|
|
return document()->findBlockByNumber(line - 1).text();
|
2009-12-09 17:40:00 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
void FakeVimHandler::Private::setLineContents(int line, const QString &contents)
|
2009-12-09 17:40:00 +01:00
|
|
|
{
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextBlock block = document()->findBlockByNumber(line - 1);
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextCursor tc = cursor();
|
2010-07-06 16:17:27 +02:00
|
|
|
const int begin = block.position();
|
|
|
|
|
const int len = block.length();
|
|
|
|
|
tc.setPosition(begin);
|
|
|
|
|
tc.setPosition(begin + len - 1, KeepAnchor);
|
2009-12-09 17:40:00 +01:00
|
|
|
tc.removeSelectedText();
|
|
|
|
|
tc.insertText(contents);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-14 16:56:37 +02:00
|
|
|
int FakeVimHandler::Private::blockBoundary(const QString &left,
|
2012-08-14 18:53:33 +02:00
|
|
|
const QString &right, bool closing, int count) const
|
2012-07-14 16:56:37 +02:00
|
|
|
{
|
|
|
|
|
const QString &begin = closing ? left : right;
|
|
|
|
|
const QString &end = closing ? right : left;
|
|
|
|
|
|
2012-08-14 18:53:33 +02:00
|
|
|
// shift cursor if it is already on opening/closing string
|
2012-07-14 16:56:37 +02:00
|
|
|
QTextCursor tc1 = cursor();
|
|
|
|
|
int pos = tc1.position();
|
2012-08-14 18:53:33 +02:00
|
|
|
int max = document()->characterCount();
|
2012-07-14 16:56:37 +02:00
|
|
|
int sz = left.size();
|
2012-08-14 18:53:33 +02:00
|
|
|
int from = qMax(pos - sz + 1, 0);
|
|
|
|
|
int to = qMin(pos + sz, max);
|
|
|
|
|
tc1.setPosition(from);
|
|
|
|
|
tc1.setPosition(to, KeepAnchor);
|
|
|
|
|
int i = tc1.selectedText().indexOf(left);
|
|
|
|
|
if (i != -1) {
|
|
|
|
|
// - on opening string:
|
|
|
|
|
tc1.setPosition(from + i + sz);
|
2012-07-14 16:56:37 +02:00
|
|
|
} else {
|
|
|
|
|
sz = right.size();
|
2012-08-14 18:53:33 +02:00
|
|
|
from = qMax(pos - sz + 1, 0);
|
|
|
|
|
to = qMin(pos + sz, max);
|
|
|
|
|
tc1.setPosition(from);
|
|
|
|
|
tc1.setPosition(to, KeepAnchor);
|
|
|
|
|
i = tc1.selectedText().indexOf(right);
|
|
|
|
|
if (i != -1) {
|
|
|
|
|
// - on closing string:
|
|
|
|
|
tc1.setPosition(from + i);
|
2012-07-14 16:56:37 +02:00
|
|
|
} else {
|
|
|
|
|
tc1 = cursor();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTextCursor tc2 = tc1;
|
|
|
|
|
QTextDocument::FindFlags flags(closing ? 0 : QTextDocument::FindBackward);
|
|
|
|
|
int level = 0;
|
2012-08-14 18:53:33 +02:00
|
|
|
int counter = 0;
|
2012-07-14 16:56:37 +02:00
|
|
|
while (true) {
|
|
|
|
|
tc2 = document()->find(end, tc2, flags);
|
|
|
|
|
if (tc2.isNull())
|
|
|
|
|
return -1;
|
2012-08-14 18:53:33 +02:00
|
|
|
if (!tc1.isNull())
|
|
|
|
|
tc1 = document()->find(begin, tc1, flags);
|
2012-07-14 16:56:37 +02:00
|
|
|
|
|
|
|
|
while (!tc1.isNull() && (closing ? (tc1 < tc2) : (tc2 < tc1))) {
|
|
|
|
|
++level;
|
|
|
|
|
tc1 = document()->find(begin, tc1, flags);
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-20 18:53:44 +02:00
|
|
|
while (level > 0
|
|
|
|
|
&& (tc1.isNull() || (closing ? (tc2 < tc1) : (tc1 < tc2)))) {
|
2012-07-14 16:56:37 +02:00
|
|
|
--level;
|
|
|
|
|
tc2 = document()->find(end, tc2, flags);
|
|
|
|
|
if (tc2.isNull())
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (level == 0
|
|
|
|
|
&& (tc1.isNull() || (closing ? (tc2 < tc1) : (tc1 < tc2)))) {
|
2012-08-14 18:53:33 +02:00
|
|
|
++counter;
|
|
|
|
|
if (counter >= count)
|
|
|
|
|
break;
|
2012-07-14 16:56:37 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tc2.position() - end.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-02-05 17:06:45 +01:00
|
|
|
int FakeVimHandler::Private::firstPositionInLine(int line) const
|
2009-01-06 11:33:07 +01:00
|
|
|
{
|
2010-09-13 14:16:18 +02:00
|
|
|
return document()->findBlockByNumber(line - 1).position();
|
2009-01-06 11:33:07 +01:00
|
|
|
}
|
|
|
|
|
|
2009-02-05 17:06:45 +01:00
|
|
|
int FakeVimHandler::Private::lastPositionInLine(int line) const
|
|
|
|
|
{
|
2010-09-13 14:16:18 +02:00
|
|
|
QTextBlock block = document()->findBlockByNumber(line - 1);
|
2009-02-05 17:06:45 +01:00
|
|
|
return block.position() + block.length() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 11:42:44 +01:00
|
|
|
int FakeVimHandler::Private::lineForPosition(int pos) const
|
|
|
|
|
{
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextCursor tc = cursor();
|
2009-01-06 11:42:44 +01:00
|
|
|
tc.setPosition(pos);
|
|
|
|
|
return tc.block().blockNumber() + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-02 17:59:05 +02:00
|
|
|
void FakeVimHandler::Private::toggleVisualMode(VisualMode visualMode)
|
2009-01-06 11:42:44 +01:00
|
|
|
{
|
2011-08-02 17:59:05 +02:00
|
|
|
if (isVisualMode()) {
|
|
|
|
|
leaveVisualMode();
|
|
|
|
|
} else {
|
|
|
|
|
m_positionPastEnd = false;
|
|
|
|
|
m_anchorPastEnd = false;
|
|
|
|
|
m_visualMode = visualMode;
|
|
|
|
|
const int pos = position();
|
|
|
|
|
setAnchorAndPosition(pos, pos);
|
|
|
|
|
updateMiniBuffer();
|
|
|
|
|
}
|
2009-01-06 11:42:44 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-06 11:52:05 +01:00
|
|
|
void FakeVimHandler::Private::leaveVisualMode()
|
2009-01-06 11:42:44 +01:00
|
|
|
{
|
2012-09-09 10:32:45 +02:00
|
|
|
if (!isVisualMode())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_lastSelectionCursor = cursor();
|
|
|
|
|
m_lastSelectionMode = m_visualMode;
|
|
|
|
|
int from = m_lastSelectionCursor.anchor();
|
|
|
|
|
int to = m_lastSelectionCursor.position();
|
|
|
|
|
if (from > to)
|
|
|
|
|
qSwap(from, to);
|
|
|
|
|
setMark('<', from);
|
|
|
|
|
setMark('>', to);
|
|
|
|
|
if (isVisualLineMode())
|
|
|
|
|
m_movetype = MoveLineWise;
|
|
|
|
|
else if (isVisualCharMode())
|
|
|
|
|
m_movetype = MoveInclusive;
|
2010-01-21 17:38:28 +01:00
|
|
|
|
2009-01-06 11:52:05 +01:00
|
|
|
m_visualMode = NoVisualMode;
|
2009-01-06 11:42:44 +01:00
|
|
|
updateMiniBuffer();
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 11:50:30 +01:00
|
|
|
QWidget *FakeVimHandler::Private::editor() const
|
2009-01-06 11:43:27 +01:00
|
|
|
{
|
|
|
|
|
return m_textedit
|
|
|
|
|
? static_cast<QWidget *>(m_textedit)
|
|
|
|
|
: static_cast<QWidget *>(m_plaintextedit);
|
|
|
|
|
}
|
2009-01-06 11:42:44 +01:00
|
|
|
|
2012-09-29 19:09:08 +02:00
|
|
|
void FakeVimHandler::Private::joinPreviousEditBlock()
|
|
|
|
|
{
|
|
|
|
|
UNDO_DEBUG("JOIN");
|
|
|
|
|
if (m_breakEditBlock)
|
|
|
|
|
beginEditBlock();
|
|
|
|
|
else
|
|
|
|
|
cursor().joinPreviousEditBlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::beginEditBlock(bool rememberPosition)
|
|
|
|
|
{
|
|
|
|
|
UNDO_DEBUG("BEGIN EDIT BLOCK");
|
|
|
|
|
cursor().beginEditBlock();
|
|
|
|
|
if (rememberPosition)
|
|
|
|
|
setUndoPosition(false);
|
|
|
|
|
m_breakEditBlock = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::endEditBlock()
|
|
|
|
|
{
|
|
|
|
|
UNDO_DEBUG("END EDIT BLOCK");
|
|
|
|
|
cursor().endEditBlock();
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-01 07:47:25 +02:00
|
|
|
char FakeVimHandler::Private::currentModeCode() const
|
|
|
|
|
{
|
2012-09-29 13:17:21 +02:00
|
|
|
if (m_mode == ExMode)
|
|
|
|
|
return 'c';
|
|
|
|
|
else if (isVisualMode())
|
2012-09-01 07:47:25 +02:00
|
|
|
return 'v';
|
|
|
|
|
else if (m_mode == CommandMode)
|
|
|
|
|
return 'n';
|
|
|
|
|
else
|
|
|
|
|
return 'i';
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 11:45:56 +01:00
|
|
|
void FakeVimHandler::Private::undo()
|
|
|
|
|
{
|
2010-05-11 14:26:37 +02:00
|
|
|
// FIXME: That's only an approximaxtion. The real solution might
|
|
|
|
|
// be to store marks and old userData with QTextBlock setUserData
|
|
|
|
|
// and retrieve them afterward.
|
2012-08-26 18:39:48 +02:00
|
|
|
const int current = revision();
|
2009-02-09 08:45:02 +01:00
|
|
|
EDITOR(undo());
|
2012-08-26 18:39:48 +02:00
|
|
|
const int rev = revision();
|
|
|
|
|
|
|
|
|
|
// rewind to last saved revision
|
|
|
|
|
while (!m_undo.empty() && m_undo.top().revision > rev)
|
|
|
|
|
m_undo.pop();
|
|
|
|
|
|
|
|
|
|
if (current == rev) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, FakeVimHandler::tr("Already at oldest change"));
|
2012-08-26 18:39:48 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2012-09-10 22:10:23 +02:00
|
|
|
clearMessage();
|
2012-08-26 18:39:48 +02:00
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-26 12:51:25 +01:00
|
|
|
|
2010-05-17 16:25:58 +02:00
|
|
|
setTargetColumn();
|
2010-02-19 13:01:39 +01:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2009-01-06 11:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::redo()
|
|
|
|
|
{
|
2012-08-26 18:39:48 +02:00
|
|
|
const int current = revision();
|
2009-02-09 08:45:02 +01:00
|
|
|
EDITOR(redo());
|
2012-08-26 18:39:48 +02:00
|
|
|
const int rev = revision();
|
|
|
|
|
|
|
|
|
|
// forward to last saved revision
|
|
|
|
|
while (!m_redo.empty() && m_redo.top().revision < rev)
|
|
|
|
|
m_redo.pop();
|
|
|
|
|
|
|
|
|
|
if (rev == current) {
|
2012-09-10 22:10:23 +02:00
|
|
|
showMessage(MessageInfo, FakeVimHandler::tr("Already at newest change"));
|
2012-08-26 18:39:48 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2012-09-10 22:10:23 +02:00
|
|
|
clearMessage();
|
2009-10-26 12:51:25 +01:00
|
|
|
|
2012-08-26 18:39:48 +02:00
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-05-17 16:25:58 +02:00
|
|
|
setTargetColumn();
|
2012-08-26 18:39:48 +02:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2009-01-16 13:10:42 +01:00
|
|
|
}
|
|
|
|
|
|
2010-09-13 15:23:20 +02:00
|
|
|
void FakeVimHandler::Private::updateCursorShape()
|
2010-05-04 11:00:40 +02:00
|
|
|
{
|
2010-09-28 16:56:20 +02:00
|
|
|
bool thinCursor = m_mode == ExMode
|
|
|
|
|
|| m_subsubmode == SearchSubSubMode
|
|
|
|
|
|| m_mode == InsertMode
|
|
|
|
|
|| isVisualMode()
|
|
|
|
|
|| cursor().hasSelection();
|
|
|
|
|
EDITOR(setOverwriteMode(!thinCursor));
|
2010-05-04 11:00:40 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-06 12:10:57 +02:00
|
|
|
void FakeVimHandler::Private::enterReplaceMode()
|
|
|
|
|
{
|
|
|
|
|
m_mode = ReplaceMode;
|
|
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
|
|
|
|
m_lastInsertion.clear();
|
|
|
|
|
m_lastDeletion.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-06 13:03:59 +01:00
|
|
|
void FakeVimHandler::Private::enterInsertMode()
|
|
|
|
|
{
|
|
|
|
|
m_mode = InsertMode;
|
2010-05-04 17:58:53 +02:00
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
2009-01-06 13:03:59 +01:00
|
|
|
m_lastInsertion.clear();
|
2010-05-18 18:24:00 +02:00
|
|
|
m_lastDeletion.clear();
|
2009-01-06 13:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::enterCommandMode()
|
|
|
|
|
{
|
2010-02-19 13:01:39 +01:00
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveLeft();
|
2009-01-06 13:03:59 +01:00
|
|
|
m_mode = CommandMode;
|
2010-05-04 17:58:53 +02:00
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
2009-01-06 13:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-26 12:08:39 +01:00
|
|
|
void FakeVimHandler::Private::enterExMode()
|
|
|
|
|
{
|
|
|
|
|
m_mode = ExMode;
|
2010-05-04 17:58:53 +02:00
|
|
|
m_submode = NoSubMode;
|
|
|
|
|
m_subsubmode = NoSubSubMode;
|
2009-01-26 12:08:39 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-28 19:22:54 +01:00
|
|
|
void FakeVimHandler::Private::recordJump()
|
|
|
|
|
{
|
2012-08-11 14:31:42 +02:00
|
|
|
CursorPosition pos = cursorPosition();
|
|
|
|
|
setMark('\'', pos.position);
|
|
|
|
|
if (m_jumpListUndo.isEmpty() || m_jumpListUndo.top().position != pos.position)
|
|
|
|
|
m_jumpListUndo.push(pos);
|
2009-01-28 19:22:54 +01:00
|
|
|
m_jumpListRedo.clear();
|
2009-03-06 11:22:16 +01:00
|
|
|
UNDO_DEBUG("jumps: " << m_jumpListUndo);
|
2009-01-28 19:22:54 +01:00
|
|
|
}
|
|
|
|
|
|
2012-08-11 14:31:42 +02:00
|
|
|
void FakeVimHandler::Private::jump(int distance)
|
|
|
|
|
{
|
|
|
|
|
QStack<CursorPosition> &from = (distance > 0) ? m_jumpListRedo : m_jumpListUndo;
|
|
|
|
|
QStack<CursorPosition> &to = (distance > 0) ? m_jumpListUndo : m_jumpListRedo;
|
|
|
|
|
int len = qMin(qAbs(distance), from.size());
|
|
|
|
|
setMark('\'', position());
|
|
|
|
|
for (int i = 0; i < len; ++i) {
|
|
|
|
|
to.push(cursorPosition());
|
|
|
|
|
setCursorPosition(from.top());
|
|
|
|
|
from.pop();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-09 16:44:36 +01:00
|
|
|
Column FakeVimHandler::Private::indentation(const QString &line) const
|
2009-12-11 13:24:53 +01:00
|
|
|
{
|
|
|
|
|
int ts = config(ConfigTabStop).toInt();
|
|
|
|
|
int physical = 0;
|
|
|
|
|
int logical = 0;
|
|
|
|
|
int n = line.size();
|
|
|
|
|
while (physical < n) {
|
|
|
|
|
QChar c = line.at(physical);
|
|
|
|
|
if (c == QLatin1Char(' '))
|
|
|
|
|
++logical;
|
|
|
|
|
else if (c == QLatin1Char('\t'))
|
|
|
|
|
logical += ts - logical % ts;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
++physical;
|
|
|
|
|
}
|
2010-03-09 16:44:36 +01:00
|
|
|
return Column(physical, logical);
|
2009-12-11 13:24:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString FakeVimHandler::Private::tabExpand(int n) const
|
|
|
|
|
{
|
|
|
|
|
int ts = config(ConfigTabStop).toInt();
|
|
|
|
|
if (hasConfig(ConfigExpandTab) || ts < 1)
|
|
|
|
|
return QString(n, QLatin1Char(' '));
|
|
|
|
|
return QString(n / ts, QLatin1Char('\t'))
|
|
|
|
|
+ QString(n % ts, QLatin1Char(' '));
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-03 11:54:29 +02:00
|
|
|
void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown)
|
|
|
|
|
{
|
2010-01-06 14:57:46 +01:00
|
|
|
if (!hasConfig(ConfigAutoIndent) && !hasConfig(ConfigSmartIndent))
|
2009-04-03 11:54:29 +02:00
|
|
|
return;
|
2010-01-06 14:57:46 +01:00
|
|
|
|
|
|
|
|
if (hasConfig(ConfigSmartIndent)) {
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextBlock bl = block();
|
|
|
|
|
Range range(bl.position(), bl.position());
|
|
|
|
|
const int oldSize = bl.text().size();
|
2010-06-02 15:27:10 +02:00
|
|
|
indentText(range, QLatin1Char('\n'));
|
2010-09-13 15:23:20 +02:00
|
|
|
m_justAutoIndented = bl.text().size() - oldSize;
|
2010-01-06 14:57:46 +01:00
|
|
|
} else {
|
2010-09-13 15:23:20 +02:00
|
|
|
QTextBlock bl = goingDown ? block().previous() : block().next();
|
|
|
|
|
QString text = bl.text();
|
2010-01-06 14:57:46 +01:00
|
|
|
int pos = 0;
|
|
|
|
|
int n = text.size();
|
|
|
|
|
while (pos < n && text.at(pos).isSpace())
|
|
|
|
|
++pos;
|
|
|
|
|
text.truncate(pos);
|
|
|
|
|
// FIXME: handle 'smartindent' and 'cindent'
|
2010-05-11 14:26:37 +02:00
|
|
|
insertText(text);
|
2010-01-06 14:57:46 +01:00
|
|
|
m_justAutoIndented = text.size();
|
|
|
|
|
}
|
2009-04-03 11:54:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FakeVimHandler::Private::removeAutomaticIndentation()
|
|
|
|
|
{
|
|
|
|
|
if (!hasConfig(ConfigAutoIndent) || m_justAutoIndented == 0)
|
|
|
|
|
return false;
|
2010-09-13 15:23:20 +02:00
|
|
|
/*
|
2009-04-03 11:54:29 +02:00
|
|
|
m_tc.movePosition(StartOfLine, KeepAnchor);
|
|
|
|
|
m_tc.removeSelectedText();
|
|
|
|
|
m_lastInsertion.chop(m_justAutoIndented);
|
2010-09-13 15:23:20 +02:00
|
|
|
*/
|
2009-04-03 11:54:29 +02:00
|
|
|
m_justAutoIndented = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-03 14:58:41 +02:00
|
|
|
void FakeVimHandler::Private::handleStartOfLine()
|
|
|
|
|
{
|
|
|
|
|
if (hasConfig(ConfigStartOfLine))
|
|
|
|
|
moveToFirstNonBlankOnLine();
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-08 16:05:24 +02:00
|
|
|
void FakeVimHandler::Private::replay(const QString &command, int n)
|
2009-04-06 10:58:48 +02:00
|
|
|
{
|
2010-05-04 17:58:53 +02:00
|
|
|
//qDebug() << "REPLAY: " << quoteUnprintable(command);
|
2012-09-28 17:01:24 +02:00
|
|
|
Inputs inputs(command);
|
2009-06-11 15:41:20 +02:00
|
|
|
for (int i = n; --i >= 0; ) {
|
2012-09-28 17:01:24 +02:00
|
|
|
foreach (Input in, inputs) {
|
|
|
|
|
handleDefaultKey(in);
|
2009-06-11 15:41:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-04-06 10:58:48 +02:00
|
|
|
}
|
2009-03-30 16:54:25 +02:00
|
|
|
|
2012-09-28 17:01:24 +02:00
|
|
|
QString FakeVimHandler::Private::visualDotCommand() const
|
|
|
|
|
{
|
|
|
|
|
QTextCursor start(cursor());
|
|
|
|
|
QTextCursor end(start);
|
|
|
|
|
end.setPosition(end.anchor());
|
|
|
|
|
|
|
|
|
|
if (isVisualCharMode())
|
|
|
|
|
return QString("v%1l").arg(qAbs(start.position() - end.position()));
|
|
|
|
|
|
|
|
|
|
if (isVisualLineMode())
|
|
|
|
|
return QString("V%1j").arg(qAbs(start.blockNumber() - end.blockNumber()));
|
|
|
|
|
|
|
|
|
|
if (isVisualBlockMode()) {
|
|
|
|
|
return QString("<c-v>%1l%2j")
|
|
|
|
|
.arg(qAbs(start.positionInBlock() - end.positionInBlock()))
|
|
|
|
|
.arg(qAbs(start.blockNumber() - end.blockNumber()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-19 19:08:04 +02:00
|
|
|
void FakeVimHandler::Private::selectTextObject(bool simple, bool inner)
|
2010-03-18 17:45:15 +01:00
|
|
|
{
|
2012-08-19 19:08:04 +02:00
|
|
|
bool setupAnchor = (position() == anchor());
|
|
|
|
|
|
|
|
|
|
// set anchor if not already set
|
|
|
|
|
if (setupAnchor) {
|
|
|
|
|
moveToBoundaryStart(1, simple, false);
|
|
|
|
|
setAnchor();
|
|
|
|
|
} else {
|
|
|
|
|
moveRight();
|
|
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveRight();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int repeat = count();
|
|
|
|
|
if (inner) {
|
|
|
|
|
moveToBoundaryEnd(repeat, simple);
|
|
|
|
|
} else {
|
|
|
|
|
for (int i = 0; i < repeat; ++i) {
|
|
|
|
|
// select leading spaces
|
|
|
|
|
bool leadingSpace = characterAtCursor().isSpace();
|
|
|
|
|
if (leadingSpace)
|
|
|
|
|
moveToNextBoundaryStart(1, simple);
|
|
|
|
|
|
|
|
|
|
// select word
|
|
|
|
|
moveToWordEnd(1, simple);
|
|
|
|
|
|
|
|
|
|
// select trailing spaces if no leading space
|
|
|
|
|
if (!leadingSpace && document()->characterAt(position() + 1).isSpace()
|
|
|
|
|
&& !atBlockStart()) {
|
|
|
|
|
moveToNextBoundaryEnd(1, simple);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if there are no trailing spaces in selection select all leading spaces
|
|
|
|
|
// after previous character
|
|
|
|
|
if (setupAnchor && (!characterAtCursor().isSpace() || atBlockEnd())) {
|
|
|
|
|
int min = block().position();
|
|
|
|
|
int pos = anchor();
|
|
|
|
|
while (pos >= min && document()->characterAt(--pos).isSpace()) {}
|
|
|
|
|
if (pos >= min)
|
|
|
|
|
setAnchorAndPosition(pos + 1, position());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i + 1 < repeat) {
|
|
|
|
|
moveRight();
|
|
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveRight();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inner) {
|
|
|
|
|
m_movetype = MoveInclusive;
|
|
|
|
|
} else {
|
|
|
|
|
m_movetype = MoveExclusive;
|
|
|
|
|
moveRight();
|
|
|
|
|
if (atEndOfLine())
|
|
|
|
|
moveRight();
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-21 11:36:42 +01:00
|
|
|
setTargetColumn();
|
2012-08-19 19:08:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::selectWordTextObject(bool inner)
|
|
|
|
|
{
|
|
|
|
|
selectTextObject(false, inner);
|
2010-03-18 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::selectWORDTextObject(bool inner)
|
|
|
|
|
{
|
2012-08-19 19:08:04 +02:00
|
|
|
selectTextObject(true, inner);
|
2010-03-18 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::selectSentenceTextObject(bool inner)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(inner);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::selectParagraphTextObject(bool inner)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(inner);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-27 14:54:49 +01:00
|
|
|
void FakeVimHandler::Private::selectBlockTextObject(bool inner,
|
|
|
|
|
char left, char right)
|
2010-03-18 17:45:15 +01:00
|
|
|
{
|
2010-06-03 16:54:45 +02:00
|
|
|
QString sleft = QString(QLatin1Char(left));
|
|
|
|
|
QString sright = QString(QLatin1Char(right));
|
2012-07-14 16:56:37 +02:00
|
|
|
|
2012-08-14 18:53:33 +02:00
|
|
|
int p1 = blockBoundary(sleft, sright, false, count());
|
2012-07-14 16:56:37 +02:00
|
|
|
if (p1 == -1)
|
2010-06-03 16:54:45 +02:00
|
|
|
return;
|
2012-07-14 16:56:37 +02:00
|
|
|
|
2012-08-14 18:53:33 +02:00
|
|
|
int p2 = blockBoundary(sleft, sright, true, count());
|
2012-07-14 16:56:37 +02:00
|
|
|
if (p2 == -1)
|
2010-06-03 16:54:45 +02:00
|
|
|
return;
|
2012-07-14 16:56:37 +02:00
|
|
|
|
|
|
|
|
if (inner) {
|
|
|
|
|
p1 += sleft.size();
|
|
|
|
|
--p2;
|
|
|
|
|
} else {
|
|
|
|
|
p2 -= sright.size() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-20 18:53:44 +02:00
|
|
|
setAnchorAndPosition(p1, p2);
|
2010-06-03 16:54:45 +02:00
|
|
|
m_movetype = MoveInclusive;
|
2010-03-18 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2011-12-27 14:54:49 +01:00
|
|
|
static bool isSign(const QChar c)
|
|
|
|
|
{
|
|
|
|
|
return c.unicode() == '-' || c.unicode() == '+';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::changeNumberTextObject(bool doIncrement)
|
|
|
|
|
{
|
|
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
int pos = tc.position();
|
|
|
|
|
const int n = lastPositionInDocument();
|
|
|
|
|
QTextDocument *doc = document();
|
|
|
|
|
QChar c = doc->characterAt(pos);
|
|
|
|
|
if (!c.isNumber()) {
|
|
|
|
|
if (pos == n || !isSign(c))
|
|
|
|
|
return;
|
|
|
|
|
++pos;
|
|
|
|
|
c = doc->characterAt(pos);
|
|
|
|
|
if (!c.isNumber())
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int p1 = pos;
|
|
|
|
|
while (p1 >= 1 && doc->characterAt(p1 - 1).isNumber())
|
|
|
|
|
--p1;
|
|
|
|
|
if (p1 >= 1 && isSign(doc->characterAt(p1 - 1)))
|
|
|
|
|
--p1;
|
|
|
|
|
int p2 = pos;
|
|
|
|
|
while (p2 <= n - 1 && doc->characterAt(p2 + 1).isNumber())
|
|
|
|
|
++p2;
|
|
|
|
|
++p2;
|
|
|
|
|
setAnchorAndPosition(p2, p1);
|
|
|
|
|
|
|
|
|
|
QString orig = selectText(currentRange());
|
|
|
|
|
int value = orig.toInt();
|
|
|
|
|
value = doIncrement ? value + 1 : value - 1;
|
|
|
|
|
QString repl = QString::fromLatin1("%1").arg(value, orig.size(), 10, QLatin1Char('0'));
|
|
|
|
|
replaceText(currentRange(), repl);
|
|
|
|
|
moveLeft();
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-19 21:12:13 +02:00
|
|
|
void FakeVimHandler::Private::selectQuotedStringTextObject(bool inner,
|
|
|
|
|
const QString "e)
|
2010-03-18 17:45:15 +01:00
|
|
|
{
|
2012-07-19 21:12:13 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
int sz = quote.size();
|
|
|
|
|
|
|
|
|
|
QTextCursor tc1;
|
|
|
|
|
QTextCursor tc2(document());
|
|
|
|
|
while (tc2 <= tc) {
|
|
|
|
|
tc1 = document()->find(quote, tc2);
|
|
|
|
|
if (tc1.isNull() || tc1.anchor() > tc.position())
|
|
|
|
|
return;
|
|
|
|
|
tc2 = document()->find(quote, tc1);
|
|
|
|
|
if (tc2.isNull())
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int p1 = tc1.position();
|
|
|
|
|
int p2 = tc2.position();
|
|
|
|
|
if (inner) {
|
|
|
|
|
p2 -= sz + 1;
|
|
|
|
|
if (document()->characterAt(p1) == ParagraphSeparator)
|
|
|
|
|
++p1;
|
|
|
|
|
} else {
|
|
|
|
|
p1 -= sz;
|
|
|
|
|
p2 -= sz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setAnchorAndPosition(p1, p2);
|
|
|
|
|
m_movetype = MoveInclusive;
|
2010-03-18 17:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-11 14:26:37 +02:00
|
|
|
int FakeVimHandler::Private::mark(int code) const
|
|
|
|
|
{
|
|
|
|
|
// FIXME: distinguish local and global marks.
|
|
|
|
|
//qDebug() << "MARK: " << code << m_marks.value(code, -1) << m_marks;
|
2010-09-14 16:58:31 +02:00
|
|
|
if (isVisualMode()) {
|
|
|
|
|
if (code == '<')
|
|
|
|
|
return position();
|
|
|
|
|
if (code == '>')
|
|
|
|
|
return anchor();
|
|
|
|
|
}
|
2011-11-28 15:43:57 +01:00
|
|
|
if (code == '.')
|
|
|
|
|
return m_lastChangePosition;
|
2010-09-15 13:47:52 +02:00
|
|
|
QTextCursor tc = m_marks.value(code);
|
|
|
|
|
return tc.isNull() ? -1 : tc.position();
|
2010-05-11 14:26:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FakeVimHandler::Private::setMark(int code, int position)
|
|
|
|
|
{
|
|
|
|
|
// FIXME: distinguish local and global marks.
|
2010-09-15 13:47:52 +02:00
|
|
|
QTextCursor tc = cursor();
|
|
|
|
|
tc.setPosition(position, MoveAnchor);
|
|
|
|
|
m_marks[code] = tc;
|
2010-05-11 14:26:37 +02:00
|
|
|
}
|
2010-03-18 17:45:15 +01:00
|
|
|
|
2011-11-12 02:31:52 +01:00
|
|
|
RangeMode FakeVimHandler::Private::registerRangeMode(int reg) const
|
|
|
|
|
{
|
2012-08-09 10:58:08 +02:00
|
|
|
bool isClipboard;
|
|
|
|
|
bool isSelection;
|
|
|
|
|
getRegisterType(reg, &isClipboard, &isSelection);
|
|
|
|
|
|
|
|
|
|
if (isClipboard || isSelection) {
|
2012-08-09 17:32:39 +02:00
|
|
|
QClipboard *clipboard = QApplication::clipboard();
|
|
|
|
|
QClipboard::Mode mode = isClipboard ? QClipboard::Clipboard : QClipboard::Selection;
|
|
|
|
|
|
|
|
|
|
// Use range mode from Vim's clipboard data if available.
|
|
|
|
|
const QMimeData *data = clipboard->mimeData(mode);
|
|
|
|
|
if (data != 0 && data->hasFormat(vimMimeText)) {
|
|
|
|
|
QByteArray bytes = data->data(vimMimeText);
|
|
|
|
|
if (bytes.length() > 0)
|
|
|
|
|
return static_cast<RangeMode>(bytes.at(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If register content is clipboard:
|
|
|
|
|
// - return RangeLineMode if text ends with new line char,
|
|
|
|
|
// - return RangeCharMode otherwise.
|
|
|
|
|
QString text = clipboard->text(mode);
|
2012-08-09 10:58:08 +02:00
|
|
|
return (text.endsWith('\n') || text.endsWith('\r')) ? RangeLineMode : RangeCharMode;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-12 02:31:52 +01:00
|
|
|
return g.registers[reg].rangemode;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-09 17:32:39 +02:00
|
|
|
void FakeVimHandler::Private::setRegister(int reg, const QString &contents, RangeMode mode)
|
2011-11-12 02:31:52 +01:00
|
|
|
{
|
2012-08-02 19:35:45 +02:00
|
|
|
bool copyToClipboard;
|
|
|
|
|
bool copyToSelection;
|
|
|
|
|
getRegisterType(reg, ©ToClipboard, ©ToSelection);
|
2012-07-26 21:46:38 +02:00
|
|
|
|
|
|
|
|
if (copyToClipboard || copyToSelection) {
|
2012-08-09 10:58:08 +02:00
|
|
|
if (copyToClipboard)
|
2012-08-09 17:32:39 +02:00
|
|
|
setClipboardData(contents, mode, QClipboard::Clipboard);
|
2012-08-09 10:58:08 +02:00
|
|
|
if (copyToSelection)
|
2012-08-09 17:32:39 +02:00
|
|
|
setClipboardData(contents, mode, QClipboard::Selection);
|
2012-07-26 21:46:38 +02:00
|
|
|
} else {
|
|
|
|
|
g.registers[reg].contents = contents;
|
2012-08-09 17:32:39 +02:00
|
|
|
g.registers[reg].rangemode = mode;
|
2012-07-26 21:46:38 +02:00
|
|
|
}
|
2011-11-12 02:31:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString FakeVimHandler::Private::registerContents(int reg) const
|
|
|
|
|
{
|
2012-08-02 19:35:45 +02:00
|
|
|
bool copyFromClipboard;
|
|
|
|
|
bool copyFromSelection;
|
|
|
|
|
getRegisterType(reg, ©FromClipboard, ©FromSelection);
|
2012-07-26 21:46:38 +02:00
|
|
|
|
2012-08-02 19:35:45 +02:00
|
|
|
if (copyFromClipboard || copyFromSelection) {
|
2012-07-26 21:46:38 +02:00
|
|
|
QClipboard *clipboard = QApplication::clipboard();
|
2012-08-09 10:58:08 +02:00
|
|
|
if (copyFromClipboard)
|
2012-08-02 19:35:45 +02:00
|
|
|
return clipboard->text(QClipboard::Clipboard);
|
2012-08-09 10:58:08 +02:00
|
|
|
if (copyFromSelection)
|
2012-08-02 19:35:45 +02:00
|
|
|
return clipboard->text(QClipboard::Selection);
|
2012-07-26 21:46:38 +02:00
|
|
|
}
|
|
|
|
|
|
2011-11-12 02:31:52 +01:00
|
|
|
return g.registers[reg].contents;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-02 19:35:45 +02:00
|
|
|
void FakeVimHandler::Private::getRegisterType(int reg, bool *isClipboard, bool *isSelection) const
|
|
|
|
|
{
|
|
|
|
|
bool clipboard = false;
|
|
|
|
|
bool selection = false;
|
|
|
|
|
|
|
|
|
|
if (reg == '"') {
|
|
|
|
|
QStringList list = config(ConfigClipboard).toString().split(',');
|
|
|
|
|
clipboard = list.contains(QString("unnamedplus"));
|
|
|
|
|
selection = list.contains(QString("unnamed"));
|
|
|
|
|
} else if (reg == '+') {
|
|
|
|
|
clipboard = true;
|
|
|
|
|
} else if (reg == '*') {
|
|
|
|
|
selection = true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-09 10:58:08 +02:00
|
|
|
// selection (primary) is clipboard on systems without selection support
|
|
|
|
|
if (selection && !QApplication::clipboard()->supportsSelection()) {
|
|
|
|
|
clipboard = true;
|
|
|
|
|
selection = false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-02 19:35:45 +02:00
|
|
|
if (isClipboard != 0)
|
|
|
|
|
*isClipboard = clipboard;
|
|
|
|
|
if (isSelection != 0)
|
|
|
|
|
*isSelection = selection;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// FakeVimHandler
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-01-23 15:12:04 +01:00
|
|
|
FakeVimHandler::FakeVimHandler(QWidget *widget, QObject *parent)
|
|
|
|
|
: QObject(parent), d(new Private(this, widget))
|
2008-12-19 12:20:04 +01:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
FakeVimHandler::~FakeVimHandler()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-22 13:56:50 +01:00
|
|
|
// gracefully handle that the parent editor is deleted
|
|
|
|
|
void FakeVimHandler::disconnectFromEditor()
|
|
|
|
|
{
|
|
|
|
|
d->m_textedit = 0;
|
|
|
|
|
d->m_plaintextedit = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-19 12:20:04 +01:00
|
|
|
bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
|
|
|
|
|
{
|
2009-03-30 16:54:25 +02:00
|
|
|
bool active = theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
|
|
|
|
|
|
2010-05-07 19:46:16 +02:00
|
|
|
// Catch mouse events on the viewport.
|
2010-05-10 08:40:15 +02:00
|
|
|
QWidget *viewport = 0;
|
|
|
|
|
if (d->m_plaintextedit)
|
|
|
|
|
viewport = d->m_plaintextedit->viewport();
|
|
|
|
|
else if (d->m_textedit)
|
|
|
|
|
viewport = d->m_textedit->viewport();
|
|
|
|
|
if (ob == viewport) {
|
2010-05-07 19:46:16 +02:00
|
|
|
if (active && ev->type() == QEvent::MouseButtonRelease) {
|
|
|
|
|
QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
|
|
|
|
|
if (mev->button() == Qt::LeftButton) {
|
|
|
|
|
d->importSelection();
|
|
|
|
|
//return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (active && ev->type() == QEvent::MouseButtonPress) {
|
|
|
|
|
QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
|
|
|
|
|
if (mev->button() == Qt::LeftButton) {
|
|
|
|
|
d->m_visualMode = NoVisualMode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QObject::eventFilter(ob, ev);
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-05 15:30:22 +01:00
|
|
|
if (active && ev->type() == QEvent::Shortcut) {
|
|
|
|
|
d->passShortcuts(false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-15 13:29:12 +02:00
|
|
|
if (active && ev->type() == QEvent::InputMethod && ob == d->editor()) {
|
|
|
|
|
// This handles simple dead keys. The sequence of events is
|
|
|
|
|
// KeyRelease-InputMethod-KeyRelease for dead keys instead of
|
|
|
|
|
// KeyPress-KeyRelease as for simple keys. As vi acts on key presses,
|
|
|
|
|
// we have to act on the InputMethod event.
|
|
|
|
|
// FIXME: A first approximation working for e.g. ^ on a German keyboard
|
|
|
|
|
QInputMethodEvent *imev = static_cast<QInputMethodEvent *>(ev);
|
|
|
|
|
KEY_DEBUG("INPUTMETHOD" << imev->commitString() << imev->preeditString());
|
|
|
|
|
QString commitString = imev->commitString();
|
|
|
|
|
int key = commitString.size() == 1 ? commitString.at(0).unicode() : 0;
|
|
|
|
|
QKeyEvent kev(QEvent::KeyPress, key, Qt::KeyboardModifiers(), commitString);
|
|
|
|
|
EventResult res = d->handleEvent(&kev);
|
|
|
|
|
return res == EventHandled;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
if (active && ev->type() == QEvent::KeyPress) {
|
2009-03-04 16:32:33 +01:00
|
|
|
QKeyEvent *kev = static_cast<QKeyEvent *>(ev);
|
2010-04-15 13:54:35 +02:00
|
|
|
KEY_DEBUG("KEYPRESS" << kev->key() << kev->text() << QChar(kev->key()));
|
2009-03-05 11:06:25 +01:00
|
|
|
EventResult res = d->handleEvent(kev);
|
2010-09-21 08:37:23 +02:00
|
|
|
//if (d->m_mode == InsertMode)
|
|
|
|
|
// emit completionRequested();
|
2009-03-05 11:06:25 +01:00
|
|
|
// returning false core the app see it
|
2009-03-05 13:51:27 +01:00
|
|
|
//KEY_DEBUG("HANDLED CODE:" << res);
|
2009-03-05 11:06:25 +01:00
|
|
|
//return res != EventPassedToCore;
|
2009-03-05 13:51:27 +01:00
|
|
|
//return true;
|
|
|
|
|
return res == EventHandled;
|
2009-03-04 16:32:33 +01:00
|
|
|
}
|
2009-01-09 12:21:53 +01:00
|
|
|
|
2009-03-30 16:54:25 +02:00
|
|
|
if (active && ev->type() == QEvent::ShortcutOverride && ob == d->editor()) {
|
2009-01-09 12:21:53 +01:00
|
|
|
QKeyEvent *kev = static_cast<QKeyEvent *>(ev);
|
2009-03-05 11:06:25 +01:00
|
|
|
if (d->wantsOverride(kev)) {
|
|
|
|
|
KEY_DEBUG("OVERRIDING SHORTCUT" << kev->key());
|
|
|
|
|
ev->accept(); // accepting means "don't run the shortcuts"
|
2009-01-09 12:21:53 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
2009-03-05 11:06:25 +01:00
|
|
|
KEY_DEBUG("NO SHORTCUT OVERRIDE" << kev->key());
|
|
|
|
|
return true;
|
2009-01-09 12:21:53 +01:00
|
|
|
}
|
|
|
|
|
|
2010-01-21 17:23:30 +01:00
|
|
|
if (active && ev->type() == QEvent::FocusIn && ob == d->editor()) {
|
|
|
|
|
d->stopIncrementalFind();
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 12:21:53 +01:00
|
|
|
return QObject::eventFilter(ob, ev);
|
2008-12-19 12:20:04 +01:00
|
|
|
}
|
|
|
|
|
|
2009-03-30 16:54:25 +02:00
|
|
|
void FakeVimHandler::installEventFilter()
|
|
|
|
|
{
|
|
|
|
|
d->installEventFilter();
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-23 15:12:04 +01:00
|
|
|
void FakeVimHandler::setupWidget()
|
2008-12-27 16:42:07 +01:00
|
|
|
{
|
2009-01-23 15:12:04 +01:00
|
|
|
d->setupWidget();
|
2008-12-27 16:42:07 +01:00
|
|
|
}
|
|
|
|
|
|
2010-03-26 17:55:43 +01:00
|
|
|
void FakeVimHandler::restoreWidget(int tabSize)
|
2008-12-27 16:42:07 +01:00
|
|
|
{
|
2010-03-26 17:55:43 +01:00
|
|
|
d->restoreWidget(tabSize);
|
2008-12-27 16:42:07 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-23 15:12:04 +01:00
|
|
|
void FakeVimHandler::handleCommand(const QString &cmd)
|
2008-12-27 16:42:07 +01:00
|
|
|
{
|
2009-04-06 10:58:48 +02:00
|
|
|
d->handleCommand(cmd);
|
2008-12-27 16:42:07 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-18 15:31:31 +01:00
|
|
|
void FakeVimHandler::handleReplay(const QString &keys)
|
|
|
|
|
{
|
|
|
|
|
d->replay(keys, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-05 16:32:18 +02:00
|
|
|
void FakeVimHandler::handleInput(const QString &keys)
|
|
|
|
|
{
|
|
|
|
|
Mode oldMode = d->m_mode;
|
|
|
|
|
d->m_mode = CommandMode;
|
2012-09-01 07:47:25 +02:00
|
|
|
Inputs inputs(keys);
|
2011-04-05 16:32:18 +02:00
|
|
|
foreach (const Input &input, inputs)
|
|
|
|
|
d->handleKey(input);
|
|
|
|
|
d->m_mode = oldMode;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 15:27:14 +01:00
|
|
|
void FakeVimHandler::setCurrentFileName(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
d->m_currentFileName = fileName;
|
|
|
|
|
}
|
2009-01-23 15:12:04 +01:00
|
|
|
|
2010-05-18 14:48:12 +02:00
|
|
|
QString FakeVimHandler::currentFileName() const
|
|
|
|
|
{
|
|
|
|
|
return d->m_currentFileName;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void FakeVimHandler::showMessage(MessageLevel level, const QString &msg)
|
2009-06-15 15:14:16 +02:00
|
|
|
{
|
2012-09-10 22:10:23 +02:00
|
|
|
d->showMessage(level, msg);
|
2009-06-15 15:14:16 +02:00
|
|
|
}
|
|
|
|
|
|
2009-01-23 15:12:04 +01:00
|
|
|
QWidget *FakeVimHandler::widget()
|
|
|
|
|
{
|
|
|
|
|
return d->editor();
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-11 13:24:53 +01:00
|
|
|
// Test only
|
|
|
|
|
int FakeVimHandler::physicalIndentation(const QString &line) const
|
|
|
|
|
{
|
2010-03-09 16:44:36 +01:00
|
|
|
Column ind = d->indentation(line);
|
2009-12-11 13:24:53 +01:00
|
|
|
return ind.physical;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int FakeVimHandler::logicalIndentation(const QString &line) const
|
|
|
|
|
{
|
2010-03-09 16:44:36 +01:00
|
|
|
Column ind = d->indentation(line);
|
2009-12-11 13:24:53 +01:00
|
|
|
return ind.logical;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString FakeVimHandler::tabExpand(int n) const
|
|
|
|
|
{
|
|
|
|
|
return d->tabExpand(n);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-10 22:10:23 +02:00
|
|
|
void FakeVimHandler::miniBufferTextEdited(const QString &text, int cursorPos)
|
|
|
|
|
{
|
|
|
|
|
d->miniBufferTextEdited(text, cursorPos);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-28 17:01:24 +02:00
|
|
|
void FakeVimHandler::setTextCursorPosition(int position)
|
|
|
|
|
{
|
|
|
|
|
int pos = qMax(0, qMin(position, d->lastPositionInDocument()));
|
|
|
|
|
if (d->isVisualMode())
|
|
|
|
|
d->setPosition(pos);
|
|
|
|
|
else
|
|
|
|
|
d->setAnchorAndPosition(pos, pos);
|
|
|
|
|
d->setTargetColumn();
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-30 12:40:08 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace FakeVim
|
2010-03-26 13:22:06 +01:00
|
|
|
|
|
|
|
|
#include "fakevimhandler.moc"
|