Commit 7c9c7a0f authored by Martin Aumüller's avatar Martin Aumüller Committed by hjk
Browse files

fakevim: configurable mapping of ex commands to actions



default mapping:
- :make -> build
- :A -> switch header/source
- :cn -> next issue item
- :cp -> previous issue item

Merge-request: 101
Reviewed-by: default avatarhjk <qtc-committer@nokia.com>
parent 4912ffe7
......@@ -246,9 +246,13 @@ QList<int> ActionManagerPrivate::defaultGroups() const
return m_defaultGroups;
}
QList<CommandPrivate *> ActionManagerPrivate::commands() const
QList<Command *> ActionManagerPrivate::commands() const
{
return m_idCmdMap.values();
// transform list of CommandPrivate into list of Command
QList<Command *> result;
foreach(Command *cmd, m_idCmdMap.values())
result << cmd;
return result;
}
QList<ActionContainerPrivate *> ActionManagerPrivate::containers() const
......
......@@ -61,6 +61,8 @@ public:
virtual Command *command(const QString &id) const = 0;
virtual ActionContainer *actionContainer(const QString &id) const = 0;
virtual QList<Command *> commands() const = 0;
};
} // namespace Core
......
......@@ -56,7 +56,7 @@ class ActionContainerPrivate;
class MainWindow;
class CommandPrivate;
class ActionManagerPrivate : public Core::ActionManager
class CORE_EXPORT ActionManagerPrivate : public Core::ActionManager
{
Q_OBJECT
......@@ -70,7 +70,7 @@ public:
void saveSettings(QSettings *settings);
QList<int> defaultGroups() const;
QList<CommandPrivate *> commands() const;
QList<Command *> commands() const;
QList<ActionContainerPrivate *> containers() const;
bool hasContext(int context) const;
......
......@@ -13,18 +13,12 @@ include(../../shared/indenter/indenter.pri)
# DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
QT += gui
SOURCES += \
fakevimactions.cpp \
SOURCES += fakevimactions.cpp \
fakevimhandler.cpp \
fakevimplugin.cpp
HEADERS += \
fakevimactions.h \
HEADERS += fakevimactions.h \
fakevimhandler.h \
fakevimplugin.h
FORMS += \
fakevimoptions.ui
FORMS += fakevimoptions.ui \
fakevimexcommands.ui
OTHER_FILES += FakeVim.pluginspec
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FakeVimExCommandsPage</class>
<widget class="QWidget" name="FakeVimExCommandsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>568</width>
<height>451</height>
</rect>
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Ex Command Mapping</string>
</property>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="filterLabel">
<property name="text">
<string>Filter:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="filterEdit"/>
</item>
</layout>
</item>
<item>
<widget class="QTreeWidget" name="commandList">
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>3</number>
</property>
<column>
<property name="text">
<string>Command</string>
</property>
</column>
<column>
<property name="text">
<string>Label</string>
</property>
</column>
<column>
<property name="text">
<string>Ex Trigger Expression</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QPushButton" name="defaultButton">
<property name="text">
<string>Defaults</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="seqGrp">
<property name="title">
<string>Ex Command</string>
</property>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="regexLabel">
<property name="text">
<string>Regular Expression:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="regexEdit"/>
</item>
<item>
<widget class="QToolButton" name="resetButton">
<property name="toolTip">
<string>Reset</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../coreplugin/core.qrc">
<normaloff>:/core/images/reset.png</normaloff>:/core/images/reset.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeButton">
<property name="toolTip">
<string>Remove</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../coreplugin/core.qrc">
<normaloff>:/core/images/clear.png</normaloff>:/core/images/clear.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="infoLabel">
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../coreplugin/core.qrc"/>
</resources>
<connections/>
</ui>
......@@ -31,6 +31,7 @@
#include "fakevimhandler.h"
#include "ui_fakevimoptions.h"
#include "ui_fakevimexcommands.h"
#include <coreplugin/actionmanager/actionmanager.h>
......@@ -62,6 +63,8 @@
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
#include <cpptools/cpptoolsconstants.h>
#include <indenter.h>
#include <QtCore/QDebug>
......@@ -73,6 +76,7 @@
#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QShortcut>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
#include <QtGui/QTextEdit>
......@@ -92,6 +96,7 @@ const char * const MINI_BUFFER = "TextEditor.FakeVimMiniBuffer";
const char * const INSTALL_KEY = "Alt+V,Alt+V";
const char * const SETTINGS_CATEGORY = "D.FakeVim";
const char * const SETTINGS_ID = "General";
const char * const SETTINGS_EX_CMDS_ID = "ExCommands";
} // namespace Constants
} // namespace FakeVim
......@@ -242,6 +247,239 @@ bool FakeVimOptionPage::matches(const QString &s) const
} // namespace FakeVim
///////////////////////////////////////////////////////////////////////
//
// FakeVimExCommandsPage
//
///////////////////////////////////////////////////////////////////////
struct CommandItem
{
Command *m_cmd;
QString m_regex;
QTreeWidgetItem *m_item;
};
Q_DECLARE_METATYPE(CommandItem*);
namespace FakeVim {
namespace Internal {
static QMap<QString, QRegExp> s_exCommandMap;
static QMap<QString, QRegExp> s_defaultExCommandMap;
class FakeVimExCommandsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
FakeVimExCommandsPage() {}
// IOptionsPage
QString id() const { return QLatin1String(Constants::SETTINGS_EX_CMDS_ID); }
QString displayName() const { return tr("Ex Command Mapping"); }
QString category() const { return QLatin1String(Constants::SETTINGS_CATEGORY); }
QString displayCategory() const { return tr("FakeVim"); }
QWidget *createPage(QWidget *parent);
void initialize();
void apply() {}
void finish() {}
virtual bool matches(const QString &) const;
bool filter(const QString &f, const QTreeWidgetItem *item);
public slots:
void filterChanged(const QString &f);
void commandChanged(QTreeWidgetItem *current);
void regexChanged();
void resetRegex();
void removeRegex();
void defaultAction();
private:
Ui::FakeVimExCommandsPage m_ui;
QString m_searchKeywords;
void setRegex(const QString &regex);
QList<CommandItem *> m_citems;
};
QWidget *FakeVimExCommandsPage::createPage(QWidget *parent)
{
QWidget *w = new QWidget(parent);
m_ui.setupUi(w);
connect(m_ui.resetButton, SIGNAL(clicked()),
this, SLOT(resetRegex()));
connect(m_ui.removeButton, SIGNAL(clicked()),
this, SLOT(removeRegex()));
connect(m_ui.defaultButton, SIGNAL(clicked()),
this, SLOT(defaultAction()));
initialize();
m_ui.commandList->sortByColumn(0, Qt::AscendingOrder);
connect(m_ui.filterEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString)));
connect(m_ui.commandList, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
this, SLOT(commandChanged(QTreeWidgetItem *)));
connect(m_ui.regexEdit, SIGNAL(textChanged(QString)), this, SLOT(regexChanged()));
if (m_searchKeywords.isEmpty()) {
QTextStream(&m_searchKeywords)
<< ' ' << m_ui.groupBox->title();
m_searchKeywords.remove(QLatin1Char('&'));
}
return w;
}
void FakeVimExCommandsPage::initialize()
{
Core::ActionManager *am = Core::ICore::instance()->actionManager();
QTC_ASSERT(am, return);
UniqueIDManager *uidm = UniqueIDManager::instance();
QTC_ASSERT(uidm, return);
foreach (Command *c, am->commands()) {
if (c->action() && c->action()->isSeparator())
continue;
CommandItem *ci = new CommandItem;
QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.commandList);
ci->m_cmd = c;
ci->m_item = item;
m_citems << ci;
const QString name = uidm->stringForUniqueIdentifier(c->id());
item->setText(0, name);
if (c->action()) {
QString text = c->hasAttribute(Command::CA_UpdateText) && !c->defaultText().isNull() ? c->defaultText() : c->action()->text();
text.remove(QRegExp("&(?!&)"));
item->setText(1, text);
} else {
item->setText(1, c->shortcut()->whatsThis());
}
if (s_exCommandMap.contains(name)) {
ci->m_regex = s_exCommandMap[name].pattern();
} else {
ci->m_regex = "";
}
item->setText(2, ci->m_regex);
item->setData(0, Qt::UserRole, qVariantFromValue(ci));
}
commandChanged(0);
}
void FakeVimExCommandsPage::commandChanged(QTreeWidgetItem *current)
{
if (!current || !current->data(0, Qt::UserRole).isValid()) {
m_ui.regexEdit->setText("");
m_ui.seqGrp->setEnabled(false);
return;
}
m_ui.seqGrp->setEnabled(true);
CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
m_ui.regexEdit->setText(citem->m_regex);
}
void FakeVimExCommandsPage::filterChanged(const QString &f)
{
for (int i=0; i<m_ui.commandList->topLevelItemCount(); ++i) {
QTreeWidgetItem *item = m_ui.commandList->topLevelItem(i);
item->setHidden(filter(f, item));
}
}
void FakeVimExCommandsPage::regexChanged()
{
UniqueIDManager *uidm = UniqueIDManager::instance();
QTreeWidgetItem *current = m_ui.commandList->currentItem();
if (current && current->data(0, Qt::UserRole).isValid()) {
CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
citem->m_regex = m_ui.regexEdit->text();
current->setText(2, citem->m_regex);
s_exCommandMap[uidm->stringForUniqueIdentifier(citem->m_cmd->id())] = QRegExp(citem->m_regex);
}
}
void FakeVimExCommandsPage::setRegex(const QString &regex)
{
m_ui.regexEdit->setText(regex);
}
bool FakeVimExCommandsPage::filter(const QString &f, const QTreeWidgetItem *item)
{
if (item->childCount() == 0) {
if (f.isEmpty())
return false;
for (int i = 0; i < item->columnCount(); ++i) {
if (item->text(i).contains(f, Qt::CaseInsensitive))
return false;
}
return true;
}
bool found = false;
for (int i = 0; i < item->childCount(); ++i) {
QTreeWidgetItem *citem = item->child(i);
if (filter(f, citem)) {
citem->setHidden(true);
} else {
citem->setHidden(false);
found = true;
}
}
return !found;
}
void FakeVimExCommandsPage::resetRegex()
{
UniqueIDManager *uidm = UniqueIDManager::instance();
QTreeWidgetItem *current = m_ui.commandList->currentItem();
if (current && current->data(0, Qt::UserRole).isValid()) {
CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
const QString &name = uidm->stringForUniqueIdentifier(citem->m_cmd->id());
if (s_defaultExCommandMap.contains(name))
setRegex(s_defaultExCommandMap[name].pattern());
else
setRegex("");
}
}
void FakeVimExCommandsPage::removeRegex()
{
m_ui.regexEdit->clear();
}
void FakeVimExCommandsPage::defaultAction()
{
UniqueIDManager *uidm = UniqueIDManager::instance();
foreach (CommandItem *item, m_citems) {
const QString &name = uidm->stringForUniqueIdentifier(item->m_cmd->id());
if (s_defaultExCommandMap.contains(name)) {
item->m_regex = s_defaultExCommandMap[name].pattern();
} else {
item->m_regex = "";
}
item->m_item->setText(2, item->m_regex);
if (item->m_item == m_ui.commandList->currentItem())
commandChanged(item->m_item);
}
}
bool FakeVimExCommandsPage::matches(const QString &s) const
{
return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
} // namespace Internal
} // namespace FakeVim
///////////////////////////////////////////////////////////////////////
//
// FakeVimPluginPrivate
......@@ -295,10 +533,14 @@ signals:
private:
FakeVimPlugin *q;
FakeVimOptionPage *m_fakeVimOptionsPage;
FakeVimExCommandsPage *m_fakeVimExCommandsPage;
QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
void triggerAction(const QString& code);
void setActionChecked(const QString& code, bool check);
void readSettings(QSettings *settings);
void writeSettings(QSettings *settings);
};
} // namespace Internal
......@@ -308,6 +550,12 @@ FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
{
q = plugin;
m_fakeVimOptionsPage = 0;
m_fakeVimExCommandsPage = 0;
s_defaultExCommandMap[CppTools::Constants::SWITCH_HEADER_SOURCE] = QRegExp("^A$");
s_defaultExCommandMap[ProjectExplorer::Constants::BUILD] = QRegExp("^make$");
s_defaultExCommandMap["Coreplugin.OutputPane.previtem"] = QRegExp("^(cN(ext)?|cp(revious)?)!?( (.*))?$");
s_defaultExCommandMap["Coreplugin.OutputPane.nextitem"] = QRegExp("^cn(ext)?!?( (.*))?$");
}
FakeVimPluginPrivate::~FakeVimPluginPrivate()
......@@ -321,6 +569,11 @@ void FakeVimPluginPrivate::shutdown()
m_fakeVimOptionsPage = 0;
theFakeVimSettings()->writeSettings(Core::ICore::instance()->settings());
delete theFakeVimSettings();
q->removeObject(m_fakeVimExCommandsPage);
delete m_fakeVimExCommandsPage;
m_fakeVimExCommandsPage = 0;
writeSettings(Core::ICore::instance()->settings());
}
bool FakeVimPluginPrivate::initialize()
......@@ -334,6 +587,10 @@ bool FakeVimPluginPrivate::initialize()
m_fakeVimOptionsPage = new FakeVimOptionPage;
q->addObject(m_fakeVimOptionsPage);
theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
m_fakeVimExCommandsPage = new FakeVimExCommandsPage;
q->addObject(m_fakeVimExCommandsPage);
readSettings(Core::ICore::instance()->settings());
Core::Command *cmd = 0;
cmd = actionManager->registerAction(theFakeVimSetting(ConfigUseFakeVim),
......@@ -365,6 +622,46 @@ bool FakeVimPluginPrivate::initialize()
return true;
}
static const char *exCommandMapGroup = "FakeVimExCommand";
static const char *reKey = "RegEx";
static const char *idKey = "Command";
void FakeVimPluginPrivate::writeSettings(QSettings *settings)
{
settings->beginWriteArray(QLatin1String(exCommandMapGroup));
int count = 0;
const QMap<QString, QRegExp>::const_iterator end = s_exCommandMap.constEnd();
for (QMap<QString, QRegExp>::const_iterator it = s_exCommandMap.constBegin(); it != end; ++it) {
const QString &id = it.key();
const QRegExp &re = it.value();
if ((s_defaultExCommandMap.contains(id) && s_defaultExCommandMap[id] != re)
|| (!s_defaultExCommandMap.contains(id) && !re.pattern().isEmpty())) {
settings->setArrayIndex(count);
settings->setValue(QLatin1String(idKey), id);
settings->setValue(QLatin1String(reKey), re.pattern());
++count;
}
}
settings->endArray();
}
void FakeVimPluginPrivate::readSettings(QSettings *settings)
{
s_exCommandMap = s_defaultExCommandMap;
int size = settings->beginReadArray(QLatin1String(exCommandMapGroup));
for (int i=0; i<size; ++i) {
settings->setArrayIndex(i);
const QString id = settings->value(QLatin1String(idKey)).toString();
const QString re = settings->value(QLatin1String(reKey)).toString();
s_exCommandMap[id] = QRegExp(re);
}
settings->endArray();
}
void FakeVimPluginPrivate::showSettingsDialog()
{
Core::ICore::instance()->showOptionsDialog(QLatin1String(Constants::SETTINGS_CATEGORY),
......@@ -610,6 +907,17 @@ void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
bool forced = cmd.contains(QChar('!'));
emit delayedQuitAllRequested(forced);
} else {
const QMap<QString, QRegExp>::const_iterator end = s_exCommandMap.constEnd();
for (QMap<QString, QRegExp>::const_iterator it = s_exCommandMap.constBegin(); it != end; ++it) {
const QString &id = it.key();
const QRegExp &re = it.value();
if (re.indexIn(cmd) != -1) {
triggerAction(id);
return;
}