Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Emacs navigation key-bindings support #2829

Merged
merged 5 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/clipboardserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ void ClipboardServer::loadSettings(AppConfig *appConfig)
m_sharedData->editor = appConfig->option<Config::editor>();
m_sharedData->maxItems = appConfig->option<Config::maxitems>();
m_sharedData->textWrap = appConfig->option<Config::text_wrap>();
m_sharedData->viMode = appConfig->option<Config::vi>();
m_sharedData->navigationStyle = appConfig->option<Config::navigation_style>();
m_sharedData->saveOnReturnKey = !appConfig->option<Config::edit_ctrl_return>();
m_sharedData->moveItemOnReturnKey = appConfig->option<Config::move>();
m_sharedData->showSimpleItems = appConfig->option<Config::show_simple_items>();
Expand Down
5 changes: 3 additions & 2 deletions src/common/appconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#ifndef APPCONFIG_H
#define APPCONFIG_H

#include "common/navigationstyle.h"
#include "common/settings.h"

class QString;
Expand Down Expand Up @@ -120,8 +121,8 @@ struct confirm_exit : Config<bool> {
static Value defaultValue() { return true; }
};

struct vi : Config<bool> {
static QString name() { return QStringLiteral("vi"); }
struct navigation_style : Config<NavigationStyle> {
static QString name() { return QStringLiteral("navigation_style"); }
};

struct save_filter_history : Config<bool> {
Expand Down
65 changes: 65 additions & 0 deletions src/common/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,71 @@ bool handleViKey(QKeyEvent *event, QObject *eventReceiver)
return true;
}

bool handleEmacsKey(QKeyEvent *event, QObject *eventReceiver)
{
int key = event->key();
Qt::KeyboardModifiers mods = event->modifiers();

switch ( key ) {
case Qt::Key_V:
if (mods & Qt::ControlModifier) {
key = Qt::Key_PageDown;
mods = mods & ~Qt::ControlModifier;
break;
}
if (mods & Qt::AltModifier) {
key = Qt::Key_PageUp;
mods = mods & ~Qt::AltModifier;
break;
}
return false;
break;
case Qt::Key_N:
if (mods & Qt::ControlModifier) {
key = Qt::Key_Down;
mods = mods & ~Qt::ControlModifier;
break;
}
return false;
case Qt::Key_P:
if (mods & Qt::ControlModifier) {
key = Qt::Key_Up;
mods = mods & ~Qt::ControlModifier;
break;
}
return false;
case Qt::Key_Less:
if ((mods & Qt::AltModifier)) {
key = Qt::Key_Home;
mods = mods & ~(Qt::ShiftModifier | Qt::AltModifier);
break;
}
return false;
case Qt::Key_Greater:
if ((mods & Qt::AltModifier)) {
key = Qt::Key_End;
mods = mods & ~(Qt::ShiftModifier | Qt::AltModifier);
break;
}
return false;
case Qt::Key_G:
if (mods & Qt::ControlModifier) {
key = Qt::Key_Escape;
mods = mods & ~Qt::ControlModifier;
break;
}
return false;
default:
return false;
}

QKeyEvent event2(QEvent::KeyPress, key, mods, event->text());
QCoreApplication::sendEvent(eventReceiver, &event2);
event->accept();

return true;
}

bool canDropToTab(const QDropEvent &event)
{
const auto &data = *event.mimeData();
Expand Down
5 changes: 5 additions & 0 deletions src/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ bool isClipboardData(const QVariantMap &data);
*/
bool handleViKey(QKeyEvent *event, QObject *eventReceiver);

/**
* Handle key for Emacs mode.
*/
bool handleEmacsKey(QKeyEvent *event, QObject *eventReceiver);

/**
* Return true only if tabs can accept the drag'n'drop event.
*/
Expand Down
8 changes: 8 additions & 0 deletions src/common/navigationstyle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

enum class NavigationStyle {
Default,
Vi,
Emacs
};
6 changes: 5 additions & 1 deletion src/gui/clipboardbrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1378,11 +1378,15 @@ void ClipboardBrowser::keyPressEvent(QKeyEvent *event)
return;

// translate keys for vi mode
if (m_sharedData->viMode && handleViKey(event, this)) {
if (m_sharedData->navigationStyle == NavigationStyle::Vi && handleViKey(event, this)) {
d.updateIfNeeded();
return;
}

// translate keys for emacs mode
if (m_sharedData->navigationStyle == NavigationStyle::Emacs && handleEmacsKey(event, this))
return;

const Qt::KeyboardModifiers mods = event->modifiers();

if (mods == Qt::AltModifier)
Expand Down
3 changes: 2 additions & 1 deletion src/gui/clipboardbrowsershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#ifndef CLIPBOARDBROWSERSHARED_H
#define CLIPBOARDBROWSERSHARED_H

#include "common/navigationstyle.h"
#include "gui/menuitems.h"
#include "gui/theme.h"

Expand All @@ -17,7 +18,7 @@ struct ClipboardBrowserShared {
QString editor;
int maxItems = 100;
bool textWrap = true;
bool viMode = false;
NavigationStyle navigationStyle = NavigationStyle::Default;
bool saveOnReturnKey = false;
bool moveItemOnReturnKey = false;
bool showSimpleItems = false;
Expand Down
7 changes: 6 additions & 1 deletion src/gui/configurationmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ void ConfigurationManager::initOptions()
bind<Config::move>(m_tabHistory->checkBoxMove);
bind<Config::check_clipboard>(m_tabGeneral->checkBoxClip);
bind<Config::confirm_exit>(m_tabGeneral->checkBoxConfirmExit);
bind<Config::vi>(m_tabGeneral->checkBoxViMode);
bind<Config::navigation_style>(m_tabGeneral->comboBoxNavigationStyle);
bind<Config::save_filter_history>(m_tabGeneral->checkBoxSaveFilterHistory);
bind<Config::autocompletion>(m_tabGeneral->checkBoxAutocompleteCommands);
bind<Config::always_on_top>(m_tabGeneral->checkBoxAlwaysOnTop);
Expand Down Expand Up @@ -376,6 +376,11 @@ void ConfigurationManager::bind(const QString &optionKey, QComboBox *obj, int de
m_options[optionKey] = Option(defaultValue, "currentIndex", obj);
}

void ConfigurationManager::bind(const QString &optionKey, QComboBox *obj, NavigationStyle defaultValue)
{
m_options[optionKey] = Option(static_cast<int>(defaultValue), "currentIndex", obj);
}

void ConfigurationManager::bind(const QString &optionKey, const QVariant &defaultValue, const char *description)
{
m_options[optionKey] = Option(defaultValue, description);
Expand Down
2 changes: 2 additions & 0 deletions src/gui/configurationmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class QComboBox;
class QLineEdit;
class QListWidgetItem;
class QSpinBox;
enum class NavigationStyle;

/**
* Configuration dialog.
Expand Down Expand Up @@ -109,6 +110,7 @@ class ConfigurationManager final : public QDialog
void bind(const QString &optionKey, QSpinBox *obj, int defaultValue);
void bind(const QString &optionKey, QLineEdit *obj, const QString &defaultValue);
void bind(const QString &optionKey, QComboBox *obj, int defaultValue);
void bind(const QString &optionKey, QComboBox *obj, NavigationStyle defaultValue);
void bind(const QString &optionKey, const QVariant &defaultValue, const char *description);

void updateTabComboBoxes();
Expand Down
25 changes: 18 additions & 7 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ void MainWindow::setScriptOverrides(const QVector<int> &overrides, int actionId)

bool MainWindow::isScriptOverridden(int id) const
{
return
return
// Assume everything is overridden until collectOverrides() finishes
(m_actionCollectOverrides && m_actionCollectOverrides->isRunning() && m_overrides.isEmpty())
|| std::binary_search(m_overrides.begin(), m_overrides.end(), id);
Expand Down Expand Up @@ -1345,7 +1345,7 @@ void MainWindow::onSearchShowRequest(const QString &text)

enterSearchMode();

if (!m_options.viMode || text != "/") {
if (m_options.navigationStyle != NavigationStyle::Vi || text != "/") {
ui->searchBar->setText(text);
ui->searchBar->end(false);
}
Expand Down Expand Up @@ -2530,7 +2530,7 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
if (m_options.hideTabs && key == Qt::Key_Alt)
setHideTabs(false);

if (m_options.viMode) {
if (m_options.navigationStyle == NavigationStyle::Vi) {
if (modifiers == Qt::ControlModifier && key == Qt::Key_BracketLeft) {
onEscape();
return;
Expand All @@ -2557,6 +2557,18 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
}
}

if (m_options.navigationStyle == NavigationStyle::Emacs) {
if ((modifiers == Qt::ControlModifier && key == Qt::Key_G)
|| (key == Qt::Key_Escape)) {
onEscape();
return;
}

if (browseMode() && c && handleEmacsKey(event, c)) {
return;
}
}

if ( event->matches(QKeySequence::NextChild) ) {
nextTab();
return;
Expand Down Expand Up @@ -2702,10 +2714,9 @@ void MainWindow::loadSettings(QSettings &settings, AppConfig *appConfig)
setAlwaysOnTop(this, alwaysOnTop);
setAlwaysOnTop(m_commandDialog.data(), alwaysOnTop);

// Vi mode
m_options.viMode = appConfig->option<Config::vi>();
m_trayMenu->setViModeEnabled(m_options.viMode);
m_menu->setViModeEnabled(m_options.viMode);
m_options.navigationStyle = appConfig->option<Config::navigation_style>();
m_trayMenu->setNavigationStyle(m_options.navigationStyle);
m_menu->setNavigationStyle(m_options.navigationStyle);

// Number search
m_trayMenu->setNumberSearchEnabled(m_sharedData->numberSearch);
Expand Down
4 changes: 2 additions & 2 deletions src/gui/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "common/clipboardmode.h"
#include "common/command.h"
#include "common/navigationstyle.h"
#include "gui/clipboardbrowsershared.h"
#include "gui/menuitems.h"
#include "item/persistentdisplayitem.h"
Expand Down Expand Up @@ -34,7 +35,6 @@ class Theme;
class TrayMenu;
class ToolBar;
class QModelIndex;
struct MainWindowOptions;
struct NotificationButton;

Q_DECLARE_METATYPE(QPersistentModelIndex)
Expand Down Expand Up @@ -71,7 +71,7 @@ struct MainWindowOptions {
bool activatePastes() const { return itemActivationCommands & ActivatePastes; }

bool confirmExit = true;
bool viMode = false;
NavigationStyle navigationStyle = NavigationStyle::Default;
bool trayCommands = false;
bool trayCurrentTab = false;
QString trayTabName;
Expand Down
25 changes: 17 additions & 8 deletions src/gui/traymenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ TrayMenu::TrayMenu(QWidget *parent)
: QMenu(parent)
, m_clipboardItemActionCount(0)
, m_omitPaste(false)
, m_viMode(false)
, m_numberSearch(false)
{
m_clipboardItemActionsSeparator = addSeparator();
Expand Down Expand Up @@ -105,8 +104,13 @@ bool TrayMenu::updateIconFromData(QAction *act, const QVariantMap &data)
QAction *TrayMenu::addClipboardItemAction(const QVariantMap &data, bool showImages)
{
// Show search text at top of the menu.
if ( m_clipboardItemActionCount == 0 && m_searchText.isEmpty() )
setSearchMenuItem( m_viMode ? tr("Press '/' to search") : tr("Type to search") );
if ( m_clipboardItemActionCount == 0 && m_searchText.isEmpty() ) {
if (m_navigationStyle == NavigationStyle::Vi) {
setSearchMenuItem( tr("Press '/' to search") );
} else {
setSearchMenuItem( tr("Type to search") );
}
}

QAction *act = addAction(QString());
m_clipboardActions.append(act);
Expand Down Expand Up @@ -207,9 +211,9 @@ void TrayMenu::clearAllActions()
m_searchText.clear();
}

void TrayMenu::setViModeEnabled(bool enabled)
void TrayMenu::setNavigationStyle(NavigationStyle style)
{
m_viMode = enabled;
m_navigationStyle = style;
}

void TrayMenu::setNumberSearchEnabled(bool enabled)
Expand All @@ -220,9 +224,14 @@ void TrayMenu::setNumberSearchEnabled(bool enabled)
void TrayMenu::keyPressEvent(QKeyEvent *event)
{
const int key = event->key();
Qt::KeyboardModifiers mods = event->modifiers();
m_omitPaste = false;

if ( m_viMode && m_searchText.isEmpty() && handleViKey(event, this) ) {
bool not_searching = m_searchText.isEmpty();

if ( not_searching && m_navigationStyle == NavigationStyle::Vi && handleViKey(event, this) ) {
return;
} else if ( not_searching && m_navigationStyle == NavigationStyle::Emacs && handleEmacsKey(event, this) ) {
return;
} else {
// Movement in tray menu.
Expand Down Expand Up @@ -255,7 +264,7 @@ void TrayMenu::keyPressEvent(QKeyEvent *event)
default:
// Type text for search.
if ( (m_clipboardItemActionCount > 0 || !m_searchText.isEmpty())
&& (!m_viMode || !m_searchText.isEmpty() || key == Qt::Key_Slash)
&& (m_navigationStyle != NavigationStyle::Vi || !m_searchText.isEmpty() || key == Qt::Key_Slash)
&& !event->modifiers().testFlag(Qt::AltModifier)
&& !event->modifiers().testFlag(Qt::ControlModifier) )
{
Expand Down Expand Up @@ -341,7 +350,7 @@ void TrayMenu::search(const QString &text)
return;

m_searchText = text;
emit searchRequest(m_viMode ? m_searchText.mid(1) : m_searchText);
emit searchRequest((m_navigationStyle == NavigationStyle::Vi) ? m_searchText.mid(1) : m_searchText);
}

void TrayMenu::markItemInClipboard(const QVariantMap &clipboardData)
Expand Down
7 changes: 4 additions & 3 deletions src/gui/traymenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#ifndef TRAYMENU_H
#define TRAYMENU_H

#include "common/navigationstyle.h"

#include <QMenu>
#include <QPointer>
#include <QTimer>
Expand Down Expand Up @@ -36,8 +38,7 @@ class TrayMenu final : public QMenu
/** Clear clipboard item actions and curstom actions. */
void clearAllActions();

/** Handle Vi shortcuts. */
void setViModeEnabled(bool enabled);
void setNavigationStyle(NavigationStyle style);

/** Enable searching for numbers. */
void setNumberSearchEnabled(bool enabled);
Expand Down Expand Up @@ -82,8 +83,8 @@ class TrayMenu final : public QMenu
int m_clipboardItemActionCount;

bool m_omitPaste;
bool m_viMode;
bool m_numberSearch;
NavigationStyle m_navigationStyle = NavigationStyle::Default;

QString m_searchText;

Expand Down
Loading