mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
vim-mode: support Ctrl+R to read a register
Support `Ctrl+R` to read a register both in Insert mode and command line.
This commit is contained in:
parent
cd2ac10509
commit
eb71c8eff1
@ -177,6 +177,7 @@ VNote supports following features of Vim:
|
||||
- `/` and `?` to search
|
||||
- `n` and `N` to find next or previous occurence;
|
||||
- `Ctrl+N` and `Ctrl+P` to navigate through the search history;
|
||||
- `Ctrl+R` to read the content of a register;
|
||||
|
||||
For now, VNote does **NOT** support the macro and repeat(`.`) features of Vim.
|
||||
|
||||
|
@ -178,6 +178,7 @@ VNote支持以下几个Vim的特性:
|
||||
- `/` 和 `?` 开始查找
|
||||
- `n` 和 `N` 查找下一处或上一处;
|
||||
- `Ctrl+N` 和 `Ctrl+P` 浏览查找历史;
|
||||
- `Ctrl+R` 读取指定寄存器的值;
|
||||
|
||||
VNote目前暂时不支持Vim的宏和重复(`.`)特性。
|
||||
|
||||
|
@ -23,18 +23,24 @@ const int VVim::SearchHistory::c_capacity = 50;
|
||||
|
||||
#define ADDKEY(x, y) case (x): {ch = (y); break;}
|
||||
|
||||
// See if @p_modifiers is Control which is different on macOs and Windows.
|
||||
static bool isControlModifier(int p_modifiers)
|
||||
{
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
|
||||
return p_modifiers == Qt::MetaModifier;
|
||||
#else
|
||||
return p_modifiers == Qt::ControlModifier;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns NULL QChar if invalid.
|
||||
static QChar keyToChar(int p_key, int p_modifiers)
|
||||
{
|
||||
if (p_modifiers != Qt::NoModifier
|
||||
&& p_modifiers != Qt::ShiftModifier) {
|
||||
return QChar();
|
||||
}
|
||||
|
||||
if (p_key >= Qt::Key_0 && p_key <= Qt::Key_9) {
|
||||
return QChar('0' + (p_key - Qt::Key_0));
|
||||
} else if (p_key >= Qt::Key_A && p_key <= Qt::Key_Z) {
|
||||
if (p_modifiers == Qt::ShiftModifier) {
|
||||
if (p_modifiers == Qt::ShiftModifier
|
||||
|| isControlModifier(p_modifiers)) {
|
||||
return QChar('A' + (p_key - Qt::Key_A));
|
||||
} else {
|
||||
return QChar('a' + (p_key - Qt::Key_A));
|
||||
@ -85,11 +91,26 @@ static QChar keyToChar(int p_key, int p_modifiers)
|
||||
return ch;
|
||||
}
|
||||
|
||||
static QString keyToString(int p_key, int p_modifiers)
|
||||
{
|
||||
QChar ch = keyToChar(p_key, p_modifiers);
|
||||
if (ch.isNull()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
if (isControlModifier(p_modifiers)) {
|
||||
return QString("^") + ch;
|
||||
} else {
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
VVim::VVim(VEdit *p_editor)
|
||||
: QObject(p_editor), m_editor(p_editor),
|
||||
m_editConfig(&p_editor->getConfig()), m_mode(VimMode::Invalid),
|
||||
m_resetPositionInBlock(true), m_regName(c_unnamedRegister),
|
||||
m_leaderKey(Key(Qt::Key_Space)), m_replayLeaderSequence(false)
|
||||
m_leaderKey(Key(Qt::Key_Space)), m_replayLeaderSequence(false),
|
||||
m_registerPending(false)
|
||||
{
|
||||
Q_ASSERT(m_editConfig->m_enableVimMode);
|
||||
|
||||
@ -348,16 +369,6 @@ static int percentageToBlockNumber(const QTextDocument *p_doc, int p_percent)
|
||||
return num >= 0 ? num : 0;
|
||||
}
|
||||
|
||||
// See if @p_modifiers is Control which is different on macOs and Windows.
|
||||
static bool isControlModifier(int p_modifiers)
|
||||
{
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
|
||||
return p_modifiers == Qt::MetaModifier;
|
||||
#else
|
||||
return p_modifiers == Qt::ControlModifier;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Replace each of the character of selected text with @p_char.
|
||||
// Returns true if replacement has taken place.
|
||||
// Need to setTextCursor() after calling this.
|
||||
@ -479,6 +490,27 @@ bool VVim::handleKeyPressEvent(int key, int modifiers, int *p_autoIndentPos)
|
||||
goto clear_accept;
|
||||
}
|
||||
|
||||
if (m_registerPending) {
|
||||
// Ctrl and Shift may be sent out first.
|
||||
if (key == Qt::Key_Control || key == Qt::Key_Shift || key == Qt::Key_Meta) {
|
||||
goto accept;
|
||||
}
|
||||
|
||||
// Expecting a register name.
|
||||
QChar reg = keyToRegisterName(keyInfo);
|
||||
if (!reg.isNull()) {
|
||||
// Insert register content.
|
||||
m_editor->insertPlainText(m_registers[reg].read());
|
||||
}
|
||||
|
||||
goto clear_accept;
|
||||
} else if (key == Qt::Key_R && isControlModifier(modifiers)) {
|
||||
// Ctrl+R, insert the content of a register.
|
||||
m_pendingKeys.append(keyInfo);
|
||||
m_registerPending = true;
|
||||
goto accept;
|
||||
}
|
||||
|
||||
// Let it be handled outside VVim.
|
||||
goto exit;
|
||||
}
|
||||
@ -2101,6 +2133,7 @@ void VVim::resetState()
|
||||
m_pendingKeys.clear();
|
||||
setRegister(c_unnamedRegister);
|
||||
m_resetPositionInBlock = true;
|
||||
m_registerPending = false;
|
||||
}
|
||||
|
||||
VimMode VVim::getMode() const
|
||||
@ -4941,7 +4974,7 @@ QString VVim::getPendingKeys() const
|
||||
{
|
||||
QString str;
|
||||
for (auto const & key : m_pendingKeys) {
|
||||
str.append(keyToChar(key.m_key, key.m_modifiers));
|
||||
str.append(keyToString(key.m_key, key.m_modifiers));
|
||||
}
|
||||
|
||||
return str;
|
||||
@ -5450,3 +5483,14 @@ void VVim::clearSearchHighlight()
|
||||
{
|
||||
m_editor->clearSearchedWordHighlight();
|
||||
}
|
||||
|
||||
QString VVim::readRegister(int p_key, int p_modifiers)
|
||||
{
|
||||
Key keyInfo(p_key, p_modifiers);
|
||||
QChar reg = keyToRegisterName(keyInfo);
|
||||
if (!reg.isNull()) {
|
||||
return m_registers[reg].read();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -200,6 +200,10 @@ public:
|
||||
QString getPreviousCommandHistory(VVim::CommandLineType p_type,
|
||||
const QString &p_cmd);
|
||||
|
||||
// Read the register content.
|
||||
// Returns empty string if it is not a valid register.
|
||||
QString readRegister(int p_key, int p_modifiers);
|
||||
|
||||
signals:
|
||||
// Emit when current mode has been changed.
|
||||
void modeChanged(VimMode p_mode);
|
||||
@ -825,6 +829,9 @@ private:
|
||||
// Search history.
|
||||
SearchHistory m_searchHistory;
|
||||
|
||||
// Whether we are expecting to read a register to insert.
|
||||
bool m_registerPending;
|
||||
|
||||
static const QChar c_unnamedRegister;
|
||||
static const QChar c_blackHoleRegister;
|
||||
static const QChar c_selectionRegister;
|
||||
|
@ -29,9 +29,7 @@ VEditOperations::VEditOperations(VEdit *p_editor, VFile *p_file)
|
||||
|
||||
void VEditOperations::insertTextAtCurPos(const QString &p_text)
|
||||
{
|
||||
QTextCursor cursor = m_editor->textCursor();
|
||||
cursor.insertText(p_text);
|
||||
m_editor->setTextCursor(cursor);
|
||||
m_editor->insertPlainText(p_text);
|
||||
}
|
||||
|
||||
VEditOperations::~VEditOperations()
|
||||
|
@ -80,6 +80,16 @@ void VVimIndicator::setupUI()
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_cmdLineEdit, &VVimCmdLineEdit::requestRegister,
|
||||
this, [this](int p_key, int p_modifiers){
|
||||
if (m_vim) {
|
||||
QString val = m_vim->readRegister(p_key, p_modifiers);
|
||||
if (!val.isEmpty()) {
|
||||
m_cmdLineEdit->setText(m_cmdLineEdit->text() + val);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m_cmdLineEdit->hide();
|
||||
|
||||
m_modeLabel = new QLabel(this);
|
||||
@ -320,7 +330,8 @@ void VVimIndicator::triggerCommandLine(VVim::CommandLineType p_type)
|
||||
}
|
||||
|
||||
VVimCmdLineEdit::VVimCmdLineEdit(QWidget *p_parent)
|
||||
: QLineEdit(p_parent), m_type(VVim::CommandLineType::Invalid)
|
||||
: QLineEdit(p_parent), m_type(VVim::CommandLineType::Invalid),
|
||||
m_registerPending(false)
|
||||
{
|
||||
// When user delete all the text, cancel command input.
|
||||
connect(this, &VVimCmdLineEdit::textChanged,
|
||||
@ -340,6 +351,8 @@ VVimCmdLineEdit::VVimCmdLineEdit(QWidget *p_parent)
|
||||
m_userLastInput = p_text.right(p_text.size() - 1);
|
||||
}
|
||||
});
|
||||
|
||||
m_originStyleSheet = styleSheet();
|
||||
}
|
||||
|
||||
QString VVimCmdLineEdit::getCommand() const
|
||||
@ -404,6 +417,20 @@ void VVimCmdLineEdit::keyPressEvent(QKeyEvent *p_event)
|
||||
int key = p_event->key();
|
||||
int modifiers = p_event->modifiers();
|
||||
|
||||
if (m_registerPending) {
|
||||
// Ctrl and Shift may be sent out first.
|
||||
if (key == Qt::Key_Control || key == Qt::Key_Shift || key == Qt::Key_Meta) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Expecting a register name.
|
||||
emit requestRegister(key, modifiers);
|
||||
|
||||
p_event->accept();
|
||||
setRegisterPending(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((key == Qt::Key_Return && modifiers == Qt::NoModifier)
|
||||
|| (key == Qt::Key_Enter && modifiers == Qt::KeypadModifier)) {
|
||||
// Enter, complete the command line input.
|
||||
@ -456,10 +483,21 @@ void VVimCmdLineEdit::keyPressEvent(QKeyEvent *p_event)
|
||||
return;
|
||||
}
|
||||
|
||||
case Qt::Key_R:
|
||||
{
|
||||
if (isControlModifier(modifiers)) {
|
||||
// Ctrl+R, insert the content of a register.
|
||||
setRegisterPending(true);
|
||||
p_event->accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
QLineEdit::keyPressEvent(p_event);
|
||||
}
|
||||
|
||||
@ -479,3 +517,16 @@ void VVimCmdLineEdit::restoreUserLastInput()
|
||||
{
|
||||
setCommand(m_userLastInput);
|
||||
}
|
||||
|
||||
void VVimCmdLineEdit::setRegisterPending(bool p_pending)
|
||||
{
|
||||
if (p_pending && !m_registerPending) {
|
||||
// Going to pending.
|
||||
setStyleSheet("QLineEdit { background: #D6EACE }");
|
||||
} else if (!p_pending && m_registerPending) {
|
||||
// Leaving pending.
|
||||
setStyleSheet(m_originStyleSheet);
|
||||
}
|
||||
|
||||
m_registerPending = p_pending;
|
||||
}
|
||||
|
@ -45,6 +45,9 @@ signals:
|
||||
// Emit when the input text changed.
|
||||
void commandChanged(VVim::CommandLineType p_type, const QString &p_cmd);
|
||||
|
||||
// Emit when expecting to read a register.
|
||||
void requestRegister(int p_key, int p_modifiers);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE;
|
||||
|
||||
@ -54,10 +57,17 @@ private:
|
||||
// Return the leader of @p_type.
|
||||
QString commandLineTypeLeader(VVim::CommandLineType p_type);
|
||||
|
||||
void setRegisterPending(bool p_pending);
|
||||
|
||||
VVim::CommandLineType m_type;
|
||||
|
||||
// The latest command user input.
|
||||
QString m_userLastInput;
|
||||
|
||||
// Whether we are expecting a register name to read.
|
||||
bool m_registerPending;
|
||||
|
||||
QString m_originStyleSheet;
|
||||
};
|
||||
|
||||
class VVimIndicator : public QWidget
|
||||
|
Loading…
x
Reference in New Issue
Block a user