mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
vim-mode: support ~ to reverse case
This commit is contained in:
parent
a87048cac2
commit
c4683dd232
@ -123,7 +123,7 @@ VNote supports a simple but useful Vim mode, including **Normal**, **Insert**, *
|
|||||||
VNote supports following features of Vim:
|
VNote supports following features of Vim:
|
||||||
|
|
||||||
- `r`, `s`, `i`, `I`, `a`, `A`, `o`, and `O`;
|
- `r`, `s`, `i`, `I`, `a`, `A`, `o`, and `O`;
|
||||||
- Actions `d`, `c`, `y`, `p`, `<`, `>`, `gu`, and `gU`;
|
- Actions `d`, `c`, `y`, `p`, `<`, `>`, `gu`, `gU`, and `~`;
|
||||||
- Movements `h/j/k/l`, `gj/gk`, `Ctrl+U`, `Ctrl+D`, `gg`, `G`, `0`, `^`, and `$`;
|
- Movements `h/j/k/l`, `gj/gk`, `Ctrl+U`, `Ctrl+D`, `gg`, `G`, `0`, `^`, and `$`;
|
||||||
- Marks `a-z`;
|
- Marks `a-z`;
|
||||||
- Registers `"`, `_`, `+`, `a-z`(`A-Z`);
|
- Registers `"`, `_`, `+`, `a-z`(`A-Z`);
|
||||||
|
@ -123,7 +123,8 @@ VNote支持一个简单但有用的Vim模式,包括 **正常**, **插入**
|
|||||||
VNote支持以下几个Vim的特性:
|
VNote支持以下几个Vim的特性:
|
||||||
|
|
||||||
- `r`, `s`, `i`, `I`, `a`, `A`, `o`, `O`;
|
- `r`, `s`, `i`, `I`, `a`, `A`, `o`, `O`;
|
||||||
- 操作 `d`, `c`, `y`, `p`, `<`, `>`, `gu`, `gU`;
|
- 操作 `d`, `c`, `y`, `p`, `<`, `>`, `gu`, `gU`, `~`;
|
||||||
|
- 移动 `h/j/k/l`, `gj/gk`, `Ctrl+U`, `Ctrl+D`, `gg`, `G`, `0`, `^`, `$`;
|
||||||
- 标记 `a-z`;
|
- 标记 `a-z`;
|
||||||
- 寄存器 `"`, `_`, `+`, `a-z`(`A-Z`);
|
- 寄存器 `"`, `_`, `+`, `a-z`(`A-Z`);
|
||||||
- 跳转位置列表 (`Ctrl+O` and `Ctrl+I`);
|
- 跳转位置列表 (`Ctrl+O` and `Ctrl+I`);
|
||||||
|
@ -380,6 +380,46 @@ static bool replaceSelectedTextWithCharacter(QTextCursor &p_cursor, QChar p_char
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reverse the case of selected text.
|
||||||
|
// Returns true if the reverse has taken place.
|
||||||
|
// Need to setTextCursor() after calling this.
|
||||||
|
static bool reverseSelectedTextCase(QTextCursor &p_cursor)
|
||||||
|
{
|
||||||
|
if (!p_cursor.hasSelection()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextDocument *doc = p_cursor.document();
|
||||||
|
int start = p_cursor.selectionStart();
|
||||||
|
int end = p_cursor.selectionEnd();
|
||||||
|
p_cursor.setPosition(start, QTextCursor::MoveAnchor);
|
||||||
|
while (p_cursor.position() < end) {
|
||||||
|
if (p_cursor.atBlockEnd()) {
|
||||||
|
p_cursor.movePosition(QTextCursor::NextCharacter);
|
||||||
|
} else {
|
||||||
|
QChar ch = doc->characterAt(p_cursor.position());
|
||||||
|
bool changed = false;
|
||||||
|
if (ch.isLower()) {
|
||||||
|
ch = ch.toUpper();
|
||||||
|
changed = true;
|
||||||
|
} else if (ch.isUpper()) {
|
||||||
|
ch = ch.toLower();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
p_cursor.deleteChar();
|
||||||
|
// insertText() will move the cursor right after the inserted text.
|
||||||
|
p_cursor.insertText(ch);
|
||||||
|
} else {
|
||||||
|
p_cursor.movePosition(QTextCursor::NextCharacter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool VVim::handleKeyPressEvent(QKeyEvent *p_event, int *p_autoIndentPos)
|
bool VVim::handleKeyPressEvent(QKeyEvent *p_event, int *p_autoIndentPos)
|
||||||
{
|
{
|
||||||
bool ret = handleKeyPressEvent(p_event->key(), p_event->modifiers(), p_autoIndentPos);
|
bool ret = handleKeyPressEvent(p_event->key(), p_event->modifiers(), p_autoIndentPos);
|
||||||
@ -1930,6 +1970,24 @@ bool VVim::handleKeyPressEvent(int key, int modifiers, int *p_autoIndentPos)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Qt::Key_AsciiTilde:
|
||||||
|
{
|
||||||
|
if (modifiers == Qt::ShiftModifier) {
|
||||||
|
tryGetRepeatToken(m_keys, m_tokens);
|
||||||
|
if (hasActionToken() || !m_keys.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the case.
|
||||||
|
addActionToken(Action::ReverseCase);
|
||||||
|
processCommand(m_tokens);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1995,10 +2053,6 @@ void VVim::processCommand(QList<Token> &p_tokens)
|
|||||||
|
|
||||||
V_ASSERT(p_tokens.at(0).isAction());
|
V_ASSERT(p_tokens.at(0).isAction());
|
||||||
|
|
||||||
for (int i = 0; i < p_tokens.size(); ++i) {
|
|
||||||
qDebug() << "token" << i << p_tokens[i].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
Token act = p_tokens.takeFirst();
|
Token act = p_tokens.takeFirst();
|
||||||
switch (act.m_action) {
|
switch (act.m_action) {
|
||||||
case Action::Move:
|
case Action::Move:
|
||||||
@ -2073,6 +2127,10 @@ void VVim::processCommand(QList<Token> &p_tokens)
|
|||||||
processReplaceAction(p_tokens);
|
processReplaceAction(p_tokens);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Action::ReverseCase:
|
||||||
|
processReverseCaseAction(p_tokens);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p_tokens.clear();
|
p_tokens.clear();
|
||||||
break;
|
break;
|
||||||
@ -4119,6 +4177,46 @@ void VVim::processReplaceAction(QList<Token> &p_tokens)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VVim::processReverseCaseAction(QList<Token> &p_tokens)
|
||||||
|
{
|
||||||
|
int repeat = 1;
|
||||||
|
if (!p_tokens.isEmpty()) {
|
||||||
|
Token to = p_tokens.takeFirst();
|
||||||
|
Q_ASSERT(to.isRepeat() && p_tokens.isEmpty());
|
||||||
|
repeat = to.m_repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(checkMode(VimMode::Normal)
|
||||||
|
|| checkMode(VimMode::Visual)
|
||||||
|
|| checkMode(VimMode::VisualLine))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the next repeat characters' case until the end of line.
|
||||||
|
// If repeat is greater than the number of left characters in current line,
|
||||||
|
// just change the actual number of left characters.
|
||||||
|
// In visual mode, repeat is ignored and reverse the selected text.
|
||||||
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
|
cursor.beginEditBlock();
|
||||||
|
if (checkMode(VimMode::Normal)) {
|
||||||
|
// Select the characters to be replaced.
|
||||||
|
cursor.clearSelection();
|
||||||
|
int pib = cursor.positionInBlock();
|
||||||
|
int nrChar = cursor.block().length() - 1 - pib;
|
||||||
|
cursor.movePosition(QTextCursor::Right,
|
||||||
|
QTextCursor::KeepAnchor,
|
||||||
|
repeat > nrChar ? nrChar : repeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changed = reverseSelectedTextCase(cursor);
|
||||||
|
cursor.endEditBlock();
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
m_editor->setTextCursor(cursor);
|
||||||
|
setMode(VimMode::Normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool VVim::clearSelection()
|
bool VVim::clearSelection()
|
||||||
{
|
{
|
||||||
QTextCursor cursor = m_editor->textCursor();
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
|
@ -255,6 +255,7 @@ private:
|
|||||||
UnIndent,
|
UnIndent,
|
||||||
ToUpper,
|
ToUpper,
|
||||||
ToLower,
|
ToLower,
|
||||||
|
ReverseCase,
|
||||||
Undo,
|
Undo,
|
||||||
Redo,
|
Redo,
|
||||||
RedrawAtTop,
|
RedrawAtTop,
|
||||||
@ -519,6 +520,9 @@ private:
|
|||||||
// Action::Replace.
|
// Action::Replace.
|
||||||
void processReplaceAction(QList<Token> &p_tokens);
|
void processReplaceAction(QList<Token> &p_tokens);
|
||||||
|
|
||||||
|
// Action::ReverseCase.
|
||||||
|
void processReverseCaseAction(QList<Token> &p_tokens);
|
||||||
|
|
||||||
// Clear selection if there is any.
|
// Clear selection if there is any.
|
||||||
// Returns true if there is selection.
|
// Returns true if there is selection.
|
||||||
bool clearSelection();
|
bool clearSelection();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user