fakevim: Clipboard data format compatible with Vim

Store clipboard data that can be used by Vim and vice versa.

Change-Id: If1eb436fa371afeff39fd37353fe0841dafe169a
Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
Lukas Holecek
2012-08-09 17:32:39 +02:00
committed by hjk
parent d76c5ca205
commit 20231b769d
2 changed files with 53 additions and 22 deletions

View File

@@ -141,6 +141,10 @@ enum {
const int ParagraphSeparator = 0x00002029; const int ParagraphSeparator = 0x00002029;
typedef QLatin1String _; typedef QLatin1String _;
/* Clipboard MIME types used by Vim. */
static const QString vimMimeText = "_VIM_TEXT";
static const QString vimMimeTextEncoded = "_VIMENC_TEXT";
using namespace Qt; using namespace Qt;
/*! A \e Mode represents one of the basic modes of operation of FakeVim. /*! A \e Mode represents one of the basic modes of operation of FakeVim.
@@ -406,6 +410,29 @@ static QRegExp vimPatternToQtPattern(QString needle, bool smartcase)
return QRegExp(pattern); return QRegExp(pattern);
} }
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);
}
Range::Range() Range::Range()
: beginPos(-1), endPos(-1), rangemode(RangeCharMode) : beginPos(-1), endPos(-1), rangemode(RangeCharMode)
@@ -1141,9 +1168,8 @@ public:
// register handling // register handling
QString registerContents(int reg) const; QString registerContents(int reg) const;
void setRegisterContents(int reg, const QString &contents); void setRegister(int reg, const QString &contents, RangeMode mode);
RangeMode registerRangeMode(int reg) const; RangeMode registerRangeMode(int reg) const;
void setRegisterRangeMode(int reg, RangeMode mode);
void getRegisterType(int reg, bool *isClipboard, bool *isSelection) const; void getRegisterType(int reg, bool *isClipboard, bool *isSelection) const;
void recordJump(); void recordJump();
@@ -1710,7 +1736,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
if (m_submode != TransformSubMode) { if (m_submode != TransformSubMode) {
yankText(currentRange(), m_register); yankText(currentRange(), m_register);
if (m_movetype == MoveLineWise) if (m_movetype == MoveLineWise)
setRegisterRangeMode(m_register, RangeLineMode); setRegister(m_register, registerContents(m_register), RangeLineMode);
} }
m_positionPastEnd = m_anchorPastEnd = false; m_positionPastEnd = m_anchorPastEnd = false;
@@ -3744,8 +3770,7 @@ bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd)
removeText(currentRange()); removeText(currentRange());
if (!reg.isEmpty()) { if (!reg.isEmpty()) {
const int r = reg.at(0).unicode(); const int r = reg.at(0).unicode();
setRegisterContents(r, text); setRegister(r, text, RangeLineMode);
setRegisterRangeMode(r, RangeLineMode);
} }
return true; return true;
} }
@@ -4648,8 +4673,7 @@ QString FakeVimHandler::Private::selectText(const Range &range) const
void FakeVimHandler::Private::yankText(const Range &range, int reg) void FakeVimHandler::Private::yankText(const Range &range, int reg)
{ {
setRegisterContents(reg, selectText(range)); setRegister(reg, selectText(range), range.rangemode);
setRegisterRangeMode(reg, range.rangemode);
} }
void FakeVimHandler::Private::transformText(const Range &range, void FakeVimHandler::Private::transformText(const Range &range,
@@ -5387,43 +5411,48 @@ void FakeVimHandler::Private::setMark(int code, int position)
m_marks[code] = tc; m_marks[code] = tc;
} }
void FakeVimHandler::Private::setRegisterRangeMode(int reg, RangeMode mode)
{
g.registers[reg].rangemode = mode;
}
RangeMode FakeVimHandler::Private::registerRangeMode(int reg) const RangeMode FakeVimHandler::Private::registerRangeMode(int reg) const
{ {
bool isClipboard; bool isClipboard;
bool isSelection; bool isSelection;
getRegisterType(reg, &isClipboard, &isSelection); getRegisterType(reg, &isClipboard, &isSelection);
if (isClipboard || isSelection) {
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: // If register content is clipboard:
// - return RangeLineMode if text ends with new line char, // - return RangeLineMode if text ends with new line char,
// - return RangeCharMode otherwise. // - return RangeCharMode otherwise.
if (isClipboard || isSelection) { QString text = clipboard->text(mode);
QString text = QApplication::clipboard()->text(
isClipboard ? QClipboard::Clipboard : QClipboard::Selection);
return (text.endsWith('\n') || text.endsWith('\r')) ? RangeLineMode : RangeCharMode; return (text.endsWith('\n') || text.endsWith('\r')) ? RangeLineMode : RangeCharMode;
} }
return g.registers[reg].rangemode; return g.registers[reg].rangemode;
} }
void FakeVimHandler::Private::setRegisterContents(int reg, const QString &contents) void FakeVimHandler::Private::setRegister(int reg, const QString &contents, RangeMode mode)
{ {
bool copyToClipboard; bool copyToClipboard;
bool copyToSelection; bool copyToSelection;
getRegisterType(reg, &copyToClipboard, &copyToSelection); getRegisterType(reg, &copyToClipboard, &copyToSelection);
if (copyToClipboard || copyToSelection) { if (copyToClipboard || copyToSelection) {
QClipboard *clipboard = QApplication::clipboard();
if (copyToClipboard) if (copyToClipboard)
clipboard->setText(contents, QClipboard::Clipboard); setClipboardData(contents, mode, QClipboard::Clipboard);
if (copyToSelection) if (copyToSelection)
clipboard->setText(contents, QClipboard::Selection); setClipboardData(contents, mode, QClipboard::Selection);
} else { } else {
g.registers[reg].contents = contents; g.registers[reg].contents = contents;
g.registers[reg].rangemode = mode;
} }
} }

View File

@@ -41,10 +41,12 @@ namespace Internal {
enum RangeMode enum RangeMode
{ {
// Reordering first three enum items here will break
// compatibility with clipboard format stored by Vim.
RangeCharMode, // v RangeCharMode, // v
RangeLineMode, // V RangeLineMode, // V
RangeLineModeExclusive,
RangeBlockMode, // Ctrl-v RangeBlockMode, // Ctrl-v
RangeLineModeExclusive,
RangeBlockAndTailMode // Ctrl-v for D and X RangeBlockAndTailMode // Ctrl-v for D and X
}; };