fakevimplugin.cpp 47.8 KB
Newer Older
1
/**************************************************************************
hjk's avatar
hjk committed
2 3 4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
hjk's avatar
hjk committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
hjk's avatar
hjk committed
8
**
con's avatar
con committed
9
** No Commercial Usage
hjk's avatar
hjk committed
10
**
con's avatar
con committed
11 12 13 14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
hjk's avatar
hjk committed
15
**
16
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
**
18 19 20 21 22 23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
con's avatar
con committed
25 26 27 28 29 30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
hjk's avatar
hjk committed
31
**
32
**************************************************************************/
hjk's avatar
hjk committed
33 34 35

#include "fakevimplugin.h"

36
#include "fakevimhandler.h"
hjk's avatar
hjk committed
37 38
#include "ui_fakevimoptions.h"

39
#include <coreplugin/actionmanager/actioncontainer.h>
40
#include <coreplugin/actionmanager/actionmanager.h>
41 42
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/command.h>
43
#include <coreplugin/actionmanager/commandmappings.h>
hjk's avatar
hjk committed
44
#include <coreplugin/coreconstants.h>
45
#include <coreplugin/dialogs/ioptionspage.h>
hjk's avatar
hjk committed
46
#include <coreplugin/editormanager/editormanager.h>
47
#include <coreplugin/editormanager/openeditorsmodel.h>
48
#include <coreplugin/filemanager.h>
hjk's avatar
hjk committed
49
#include <coreplugin/icore.h>
50
#include <coreplugin/ifile.h>
hjk's avatar
hjk committed
51 52
#include <coreplugin/messagemanager.h>
#include <coreplugin/uniqueidmanager.h>
53 54
#include <coreplugin/statusbarwidget.h>
#include <coreplugin/statusbarmanager.h>
hjk's avatar
hjk committed
55 56 57

#include <projectexplorer/projectexplorerconstants.h>

58
#include <texteditor/basetextdocumentlayout.h>
hjk's avatar
hjk committed
59 60
#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
hjk's avatar
hjk committed
61
#include <texteditor/completionsupport.h>
hjk's avatar
hjk committed
62
#include <texteditor/texteditorconstants.h>
63 64
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
65
#include <texteditor/indenter.h>
66
#include <texteditor/icompletioncollector.h>
hjk's avatar
hjk committed
67

68
#include <find/findplugin.h>
69 70
#include <find/textfindconstants.h>

hjk's avatar
hjk committed
71
#include <utils/qtcassert.h>
hjk's avatar
hjk committed
72
#include <utils/savedaction.h>
73
#include <utils/treewidgetcolumnstretcher.h>
hjk's avatar
hjk committed
74

75 76
#include <cppeditor/cppeditorconstants.h>

77 78
#include <cpptools/cpptoolsconstants.h>

hjk's avatar
hjk committed
79
#include <QtCore/QDebug>
80
#include <QtCore/QFile>
81
#include <QtCore/QtPlugin>
hjk's avatar
hjk committed
82 83
#include <QtCore/QObject>
#include <QtCore/QSettings>
84
#include <QtCore/QTextStream>
hjk's avatar
hjk committed
85

86
#include <QtGui/QDesktopServices>
87
#include <QtGui/QMessageBox>
hjk's avatar
hjk committed
88
#include <QtGui/QPlainTextEdit>
89
#include <QtGui/QShortcut>
hjk's avatar
hjk committed
90 91
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
92
#include <QtGui/QTextEdit>
93
#include <QtGui/QTreeWidgetItem>
hjk's avatar
hjk committed
94 95 96 97 98 99 100 101

using namespace FakeVim::Internal;
using namespace TextEditor;
using namespace Core;

namespace FakeVim {
namespace Constants {

con's avatar
con committed
102 103 104 105 106 107 108
const char * const INSTALL_HANDLER                = "TextEditor.FakeVimHandler";
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_CATEGORY_FAKEVIM_ICON = ":/core/images/category_fakevim.png";
const char * const SETTINGS_ID                    = "A.General";
const char * const SETTINGS_EX_CMDS_ID            = "B.ExCommands";
hjk's avatar
hjk committed
109 110 111 112 113

} // namespace Constants
} // namespace FakeVim


hjk's avatar
hjk committed
114 115 116 117 118 119 120 121 122
///////////////////////////////////////////////////////////////////////
//
// FakeVimOptionPage
//
///////////////////////////////////////////////////////////////////////

namespace FakeVim {
namespace Internal {

123
typedef QMap<QString, QRegExp> CommandMap;
hjk's avatar
hjk committed
124
typedef QLatin1String _;
125

hjk's avatar
hjk committed
126 127 128 129 130 131 132 133
class FakeVimOptionPage : public Core::IOptionsPage
{
    Q_OBJECT

public:
    FakeVimOptionPage() {}

    // IOptionsPage
hjk's avatar
hjk committed
134
    QString id() const { return _(Constants::SETTINGS_ID); }
135
    QString displayName() const { return tr("General"); }
hjk's avatar
hjk committed
136
    QString category() const { return _(Constants::SETTINGS_CATEGORY); }
137
    QString displayCategory() const { return tr("FakeVim"); }
hjk's avatar
hjk committed
138 139
    QIcon categoryIcon() const
        { return QIcon(_(Constants::SETTINGS_CATEGORY_FAKEVIM_ICON)); }
hjk's avatar
hjk committed
140 141 142 143

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(ICore::instance()->settings()); }
    void finish() { m_group.finish(); }
144
    virtual bool matches(const QString &) const;
hjk's avatar
hjk committed
145 146 147 148 149 150 151 152 153

private slots:
    void copyTextEditorSettings();
    void setQtStyle();
    void setPlainStyle();

private:
    friend class DebuggerPlugin;
    Ui::FakeVimOptionPage m_ui;
154
    QString m_searchKeywords;
155
    Utils::SavedActionSet m_group;
hjk's avatar
hjk committed
156 157 158 159 160 161 162 163
};

QWidget *FakeVimOptionPage::createPage(QWidget *parent)
{
    QWidget *w = new QWidget(parent);
    m_ui.setupUi(w);

    m_group.clear();
164
    m_group.insert(theFakeVimSetting(ConfigUseFakeVim),
165
        m_ui.checkBoxUseFakeVim);
166 167
    m_group.insert(theFakeVimSetting(ConfigReadVimRc),
        m_ui.checkBoxReadVimRc);
hjk's avatar
hjk committed
168

169
    m_group.insert(theFakeVimSetting(ConfigExpandTab),
hjk's avatar
hjk committed
170
        m_ui.checkBoxExpandTab);
171
    m_group.insert(theFakeVimSetting(ConfigHlSearch),
hjk's avatar
hjk committed
172
        m_ui.checkBoxHlSearch);
173
    m_group.insert(theFakeVimSetting(ConfigShiftWidth),
174
        m_ui.spinBoxShiftWidth);
175 176
    m_group.insert(theFakeVimSetting(ConfigShowMarks),
        m_ui.checkBoxShowMarks);
hjk's avatar
hjk committed
177

178
    m_group.insert(theFakeVimSetting(ConfigSmartTab),
hjk's avatar
hjk committed
179
        m_ui.checkBoxSmartTab);
180
    m_group.insert(theFakeVimSetting(ConfigStartOfLine),
hjk's avatar
hjk committed
181
        m_ui.checkBoxStartOfLine);
182
    m_group.insert(theFakeVimSetting(ConfigTabStop),
183
        m_ui.spinBoxTabStop);
184
    m_group.insert(theFakeVimSetting(ConfigBackspace),
hjk's avatar
hjk committed
185
        m_ui.lineEditBackspace);
186 187
    m_group.insert(theFakeVimSetting(ConfigIsKeyword),
        m_ui.lineEditIsKeyword);
hjk's avatar
hjk committed
188

189 190
    m_group.insert(theFakeVimSetting(ConfigPassControlKey),
        m_ui.checkBoxPassControlKey);
191
    m_group.insert(theFakeVimSetting(ConfigAutoIndent),
hjk's avatar
hjk committed
192
        m_ui.checkBoxAutoIndent);
193
    m_group.insert(theFakeVimSetting(ConfigSmartIndent),
194
        m_ui.checkBoxSmartIndent);
195
    m_group.insert(theFakeVimSetting(ConfigIncSearch),
196
        m_ui.checkBoxIncSearch);
197 198
    m_group.insert(theFakeVimSetting(ConfigUseCoreSearch),
        m_ui.checkBoxUseCoreSearch);
hjk's avatar
hjk committed
199 200

    connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
hjk's avatar
hjk committed
201
        this, SLOT(copyTextEditorSettings()));
hjk's avatar
hjk committed
202 203 204 205
    connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
        this, SLOT(setQtStyle()));
    connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
        this, SLOT(setPlainStyle()));
206
    if (m_searchKeywords.isEmpty()) {
207
        QLatin1Char sep(' ');
208
        QTextStream(&m_searchKeywords)
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
                << sep << m_ui.checkBoxUseFakeVim->text()
                << sep << m_ui.checkBoxReadVimRc->text()
                << sep << m_ui.checkBoxAutoIndent->text()
                << sep << m_ui.checkBoxSmartIndent->text()
                << sep << m_ui.checkBoxExpandTab->text()
                << sep << m_ui.checkBoxSmartTab->text()
                << sep << m_ui.checkBoxHlSearch->text()
                << sep << m_ui.checkBoxIncSearch->text()
                << sep << m_ui.checkBoxStartOfLine->text()
                << sep << m_ui.checkBoxUseCoreSearch->text()
                << sep << m_ui.checkBoxShowMarks->text()
                << sep << m_ui.checkBoxPassControlKey->text()
                << sep << m_ui.labelShiftWidth->text()
                << sep << m_ui.labelTabulator->text()
                << sep << m_ui.labelBackspace->text()
                << sep << m_ui.labelIsKeyword->text();
225 226
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
227 228 229 230 231
    return w;
}

void FakeVimOptionPage::copyTextEditorSettings()
{
232
    TextEditor::TabSettings ts =
hjk's avatar
hjk committed
233
        TextEditor::TextEditorSettings::instance()->tabSettings();
234

hjk's avatar
hjk committed
235
    m_ui.checkBoxExpandTab->setChecked(ts.m_spacesForTabs);
236 237
    m_ui.spinBoxTabStop->setValue(ts.m_tabSize);
    m_ui.spinBoxShiftWidth->setValue(ts.m_indentSize);
hjk's avatar
hjk committed
238
    m_ui.checkBoxSmartTab->setChecked(ts.m_smartBackspace);
239 240
    m_ui.checkBoxAutoIndent->setChecked(true);
    m_ui.checkBoxSmartIndent->setChecked(ts.m_autoIndent);
241
    m_ui.checkBoxIncSearch->setChecked(true);
hjk's avatar
hjk committed
242 243 244 245 246
}

void FakeVimOptionPage::setQtStyle()
{
    m_ui.checkBoxExpandTab->setChecked(true);
247 248
    m_ui.spinBoxTabStop->setValue(4);
    m_ui.spinBoxShiftWidth->setValue(4);
hjk's avatar
hjk committed
249 250
    m_ui.checkBoxSmartTab->setChecked(true);
    m_ui.checkBoxAutoIndent->setChecked(true);
251
    m_ui.checkBoxSmartIndent->setChecked(true);
252
    m_ui.checkBoxIncSearch->setChecked(true);
hjk's avatar
hjk committed
253
    m_ui.lineEditBackspace->setText(_("indent,eol,start"));
hjk's avatar
hjk committed
254 255 256 257 258
}

void FakeVimOptionPage::setPlainStyle()
{
    m_ui.checkBoxExpandTab->setChecked(false);
259 260
    m_ui.spinBoxTabStop->setValue(8);
    m_ui.spinBoxShiftWidth->setValue(8);
hjk's avatar
hjk committed
261 262
    m_ui.checkBoxSmartTab->setChecked(false);
    m_ui.checkBoxAutoIndent->setChecked(false);
263
    m_ui.checkBoxSmartIndent->setChecked(false);
264
    m_ui.checkBoxIncSearch->setChecked(false);
hjk's avatar
hjk committed
265
    m_ui.lineEditBackspace->setText(QString());
hjk's avatar
hjk committed
266 267
}

268 269 270 271 272
bool FakeVimOptionPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
273 274 275
} // namespace Internal
} // namespace FakeVim

276
//const char *FAKEVIM_CONTEXT = "FakeVim";
hjk's avatar
hjk committed
277

278 279 280 281 282 283 284 285 286 287 288 289 290
///////////////////////////////////////////////////////////////////////
//
// FakeVimExCommandsPage
//
///////////////////////////////////////////////////////////////////////

struct CommandItem
{
    Command *m_cmd;
    QString m_regex;
    QTreeWidgetItem *m_item;
};

291
Q_DECLARE_METATYPE(CommandItem *)
292 293 294 295

namespace FakeVim {
namespace Internal {

296
class FakeVimExCommandsPage : public Core::CommandMappings
297 298 299 300
{
    Q_OBJECT

public:
301
    FakeVimExCommandsPage(FakeVimPluginPrivate *q) : m_q(q) {}
302 303

    // IOptionsPage
hjk's avatar
hjk committed
304
    QString id() const { return _(Constants::SETTINGS_EX_CMDS_ID); }
305
    QString displayName() const { return tr("Ex Command Mapping"); }
hjk's avatar
hjk committed
306
    QString category() const { return _(Constants::SETTINGS_CATEGORY); }
307
    QString displayCategory() const { return tr("FakeVim"); }
308
    QIcon categoryIcon() const { return QIcon(); } // TODO: Icon for FakeVim
309 310 311

    QWidget *createPage(QWidget *parent);
    void initialize();
312 313
    CommandMap &exCommandMap();
    CommandMap &defaultExCommandMap();
314 315 316

public slots:
    void commandChanged(QTreeWidgetItem *current);
317 318 319
    void targetIdentifierChanged();
    void resetTargetIdentifier();
    void removeTargetIdentifier();
320 321 322 323 324
    void defaultAction();

private:
    void setRegex(const QString &regex);
    QList<CommandItem *> m_citems;
325
    FakeVimPluginPrivate *m_q;
326 327 328 329
};

QWidget *FakeVimExCommandsPage::createPage(QWidget *parent)
{
330 331 332
    QWidget *w = CommandMappings::createPage(parent);
    setPageTitle(tr("Ex Command Mapping"));
    setTargetHeader(tr("Ex Trigger Expression"));
333
    setTargetLabelText(tr("Regular expression:"));
334
    setTargetEditTitle(tr("Ex Command"));
335

336
    setImportExportEnabled(false);
337 338 339 340 341 342

    return w;
}

void FakeVimExCommandsPage::initialize()
{
hjk's avatar
hjk committed
343
    ActionManager *am = ICore::instance()->actionManager();
344 345 346 347
    QTC_ASSERT(am, return);
    UniqueIDManager *uidm = UniqueIDManager::instance();
    QTC_ASSERT(uidm, return);

348 349
    QMap<QString, QTreeWidgetItem *> sections;

350 351 352 353 354
    foreach (Command *c, am->commands()) {
        if (c->action() && c->action()->isSeparator())
            continue;

        CommandItem *ci = new CommandItem;
355
        QTreeWidgetItem *item = new QTreeWidgetItem;
356 357
        ci->m_cmd = c;
        ci->m_item = item;
358
        m_citems.append(ci);
359 360

        const QString name = uidm->stringForUniqueIdentifier(c->id());
361 362
        const int pos = name.indexOf(QLatin1Char('.'));
        const QString section = name.left(pos);
363
        const QString subId = name.mid(pos + 1);
364 365

        if (!sections.contains(section)) {
366 367
            QTreeWidgetItem *categoryItem =
                new QTreeWidgetItem(commandList(), QStringList() << section);
368 369 370 371
            QFont f = categoryItem->font(0);
            f.setBold(true);
            categoryItem->setFont(0, f);
            sections.insert(section, categoryItem);
372
            commandList()->expandItem(categoryItem);
373 374 375 376
        }
        sections[section]->addChild(item);

        item->setText(0, subId);
377 378

        if (c->action()) {
379 380 381
            QString text = c->hasAttribute(Command::CA_UpdateText)
                    && !c->defaultText().isNull()
                ? c->defaultText() : c->action()->text();
382 383 384 385 386
            text.remove(QRegExp("&(?!&)"));
            item->setText(1, text);
        } else {
            item->setText(1, c->shortcut()->whatsThis());
        }
387 388
        if (exCommandMap().contains(name)) {
            ci->m_regex = exCommandMap()[name].pattern();
389
        } else {
hjk's avatar
hjk committed
390
            ci->m_regex.clear();
391 392 393 394
        }

        item->setText(2, ci->m_regex);
        item->setData(0, Qt::UserRole, qVariantFromValue(ci));
395

396
        if (ci->m_regex != defaultExCommandMap()[name].pattern())
397
            setModified(item, true);
398 399 400 401 402 403 404
    }

    commandChanged(0);
}

void FakeVimExCommandsPage::commandChanged(QTreeWidgetItem *current)
{
405 406 407
    CommandMappings::commandChanged(current);

    if (!current || !current->data(0, Qt::UserRole).isValid())
408
        return;
409

410
    CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
411
    targetEdit()->setText(citem->m_regex);
412 413
}

414
void FakeVimExCommandsPage::targetIdentifierChanged()
415
{
416
    QTreeWidgetItem *current = commandList()->currentItem();
417 418 419 420 421 422 423 424
    if (!current)
        return;

    UniqueIDManager *uidm = UniqueIDManager::instance();
    CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
    const QString name = uidm->stringForUniqueIdentifier(citem->m_cmd->id());

    if (current->data(0, Qt::UserRole).isValid()) {
425
        citem->m_regex = targetEdit()->text();
426
        current->setText(2, citem->m_regex);
427
        exCommandMap()[name] = QRegExp(citem->m_regex);
428
    }
429

430
    if (citem->m_regex != defaultExCommandMap()[name].pattern())
431 432 433
        setModified(current, true);
    else
        setModified(current, false);
434

435 436 437 438
}

void FakeVimExCommandsPage::setRegex(const QString &regex)
{
439
    targetEdit()->setText(regex);
440 441
}

442
void FakeVimExCommandsPage::resetTargetIdentifier()
443 444
{
    UniqueIDManager *uidm = UniqueIDManager::instance();
445
    QTreeWidgetItem *current = commandList()->currentItem();
446 447 448
    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());
449 450
        if (defaultExCommandMap().contains(name))
            setRegex(defaultExCommandMap()[name].pattern());
451
        else
hjk's avatar
hjk committed
452
            setRegex(QString());
453 454 455
    }
}

456
void FakeVimExCommandsPage::removeTargetIdentifier()
457
{
458
    targetEdit()->clear();
459 460 461 462 463 464 465
}

void FakeVimExCommandsPage::defaultAction()
{
    UniqueIDManager *uidm = UniqueIDManager::instance();
    foreach (CommandItem *item, m_citems) {
        const QString &name = uidm->stringForUniqueIdentifier(item->m_cmd->id());
466 467
        if (defaultExCommandMap().contains(name)) {
            item->m_regex = defaultExCommandMap()[name].pattern();
468
        } else {
hjk's avatar
hjk committed
469
            item->m_regex.clear();
470
        }
471
        setModified(item->m_item, false);
472
        item->m_item->setText(2, item->m_regex);
473
        if (item->m_item == commandList()->currentItem())
474 475 476 477 478 479 480 481
            commandChanged(item->m_item);
    }
}

} // namespace Internal
} // namespace FakeVim


hjk's avatar
hjk committed
482 483
///////////////////////////////////////////////////////////////////////
//
484
// FakeVimPluginPrivate
hjk's avatar
hjk committed
485 486 487
//
///////////////////////////////////////////////////////////////////////

488 489 490 491
namespace FakeVim {
namespace Internal {

class FakeVimPluginPrivate : public QObject
hjk's avatar
hjk committed
492
{
493 494 495 496 497 498
    Q_OBJECT

public:
    FakeVimPluginPrivate(FakeVimPlugin *);
    ~FakeVimPluginPrivate();
    friend class FakeVimPlugin;
499
    friend class FakeVimExCommandsPage;
500

501
    bool initialize();
502
    void aboutToShutdown();
503 504

private slots:
505
    void onCoreAboutToClose();
506 507
    void editorOpened(Core::IEditor *);
    void editorAboutToClose(Core::IEditor *);
508

509
    void setUseFakeVim(const QVariant &value);
510
    void quitFakeVim();
511
    void triggerCompletions();
512
    void triggerSimpleCompletions(const QString &needle, bool forward);
hjk's avatar
hjk committed
513
    void windowCommand(int key);
514
    void find(bool reverse);
515
    void findNext(bool reverse);
hjk's avatar
hjk committed
516
    void showSettingsDialog();
517
    void maybeReadVimRc();
hjk's avatar
hjk committed
518 519
    void setBlockSelection(bool);
    void hasBlockSelection(bool*);
520 521 522 523

    void showCommandBuffer(const QString &contents);
    void showExtraInformation(const QString &msg);
    void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
524
    void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
525
    void checkForElectricCharacter(bool *result, QChar c);
526
    void indentRegion(int beginLine, int endLine, QChar typedChar);
527
    void handleExCommand(bool *handled, const ExCommand &cmd);
528 529 530 531

    void handleDelayedQuitAll(bool forced);
    void handleDelayedQuit(bool forced, Core::IEditor *editor);

532 533
    void switchToFile(int n);
    int currentFile() const;
534

535 536 537
signals:
    void delayedQuitRequested(bool forced, Core::IEditor *editor);
    void delayedQuitAllRequested(bool forced);
538 539 540

private:
    FakeVimPlugin *q;
hjk's avatar
hjk committed
541
    FakeVimOptionPage *m_fakeVimOptionsPage;
542
    FakeVimExCommandsPage *m_fakeVimExCommandsPage;
543
    QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
hjk's avatar
hjk committed
544 545 546 547
    QPointer<Core::ICore> m_core;
    QPointer<Core::EditorManager> m_editorManager;
    QPointer<Core::ActionManager> m_actionManager;
    ICore *core() const { return m_core; }
hjk's avatar
hjk committed
548
    EditorManager *editorManager() const { return m_editorManager; }
hjk's avatar
hjk committed
549
    ActionManager *actionManager() const { return m_actionManager; }
550

551 552
    void triggerAction(const QString &code);
    void setActionChecked(const QString &code, bool check);
553 554 555

    void readSettings(QSettings *settings);
    void writeSettings(QSettings *settings);
556

557 558 559
    typedef int (*DistFunction)(const QRect &cursor, const QRect &other);
    void moveSomewhere(DistFunction f);

560 561 562 563
    CommandMap &exCommandMap() { return m_exCommandMap; }
    CommandMap &defaultExCommandMap() { return m_exCommandMap; }
    CommandMap m_exCommandMap;
    CommandMap m_defaultExCommandMap;
564
    Core::StatusBarWidget *m_statusBar;
565 566 567 568 569 570
};

} // namespace Internal
} // namespace FakeVim

FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
571
{
572
    q = plugin;
hjk's avatar
hjk committed
573
    m_fakeVimOptionsPage = 0;
574
    m_fakeVimExCommandsPage = 0;
575
    defaultExCommandMap()[CppTools::Constants::SWITCH_HEADER_SOURCE] =
576
        QRegExp("^A$");
577
    defaultExCommandMap()["Coreplugin.OutputPane.previtem"] =
578
        QRegExp("^(cN(ext)?|cp(revious)?)!?( (.*))?$");
579
    defaultExCommandMap()["Coreplugin.OutputPane.nextitem"] =
580
        QRegExp("^cn(ext)?!?( (.*))?$");
581
    defaultExCommandMap()[CppEditor::Constants::JUMP_TO_DEFINITION] =
582
        QRegExp("^tag?$");
583
    defaultExCommandMap()[Core::Constants::GO_BACK] =
584
        QRegExp("^pop?$");
hjk's avatar
hjk committed
585
    defaultExCommandMap()[_("QtCreator.Locate")] =
586
        QRegExp("^e$");
587
    m_statusBar = 0;
hjk's avatar
hjk committed
588 589
}

590
FakeVimPluginPrivate::~FakeVimPluginPrivate()
hjk's avatar
hjk committed
591
{
hjk's avatar
hjk committed
592 593 594
    q->removeObject(m_fakeVimOptionsPage);
    delete m_fakeVimOptionsPage;
    m_fakeVimOptionsPage = 0;
dt's avatar
dt committed
595
    delete theFakeVimSettings();
596 597 598 599

    q->removeObject(m_fakeVimExCommandsPage);
    delete m_fakeVimExCommandsPage;
    m_fakeVimExCommandsPage = 0;
600 601
}

602 603 604 605 606 607 608
void FakeVimPluginPrivate::onCoreAboutToClose()
{
    // don't attach to editors any more
    disconnect(editorManager(), SIGNAL(editorOpened(Core::IEditor*)),
        this, SLOT(editorOpened(Core::IEditor*)));
}

609 610
void FakeVimPluginPrivate::aboutToShutdown()
{
hjk's avatar
hjk committed
611 612
    theFakeVimSettings()->writeSettings(ICore::instance()->settings());
    writeSettings(ICore::instance()->settings());
hjk's avatar
hjk committed
613 614
}

615
bool FakeVimPluginPrivate::initialize()
hjk's avatar
hjk committed
616
{
hjk's avatar
hjk committed
617 618 619 620
    m_core = Core::ICore::instance();
    m_editorManager = core()->editorManager();
    m_actionManager = core()->actionManager();
    QTC_ASSERT(actionManager(), return false);
hjk's avatar
hjk committed
621

hjk's avatar
hjk committed
622
    Context globalcontext(Core::Constants::C_GLOBAL);
hjk's avatar
hjk committed
623

hjk's avatar
hjk committed
624 625
    m_fakeVimOptionsPage = new FakeVimOptionPage;
    q->addObject(m_fakeVimOptionsPage);
hjk's avatar
hjk committed
626
    theFakeVimSettings()->readSettings(ICore::instance()->settings());
627

628
    m_fakeVimExCommandsPage = new FakeVimExCommandsPage(this);
629
    q->addObject(m_fakeVimExCommandsPage);
hjk's avatar
hjk committed
630
    readSettings(core()->settings());
631

con's avatar
con committed
632
    Core::Command *cmd = 0;
hjk's avatar
hjk committed
633
    cmd = actionManager()->registerAction(theFakeVimSetting(ConfigUseFakeVim),
hjk's avatar
hjk committed
634 635 636
        Constants::INSTALL_HANDLER, globalcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::INSTALL_KEY));

637
    ActionContainer *advancedMenu =
hjk's avatar
hjk committed
638
        actionManager()->actionContainer(Core::Constants::M_EDIT_ADVANCED);
639
    advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
640

641 642
    connect(m_core, SIGNAL(coreAboutToClose()), this, SLOT(onCoreAboutToClose()));

643
    // EditorManager
hjk's avatar
hjk committed
644
    connect(editorManager(), SIGNAL(editorAboutToClose(Core::IEditor*)),
645
        this, SLOT(editorAboutToClose(Core::IEditor*)));
hjk's avatar
hjk committed
646
    connect(editorManager(), SIGNAL(editorOpened(Core::IEditor*)),
647 648
        this, SLOT(editorOpened(Core::IEditor*)));

649 650
    connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
        this, SLOT(setUseFakeVim(QVariant)));
651 652
    connect(theFakeVimSetting(ConfigReadVimRc), SIGNAL(valueChanged(QVariant)),
        this, SLOT(maybeReadVimRc()));
hjk's avatar
hjk committed
653

654
    // Delayed operations.
655 656 657 658
    connect(this, SIGNAL(delayedQuitRequested(bool,Core::IEditor*)),
        this, SLOT(handleDelayedQuit(bool,Core::IEditor*)), Qt::QueuedConnection);
    connect(this, SIGNAL(delayedQuitAllRequested(bool)),
        this, SLOT(handleDelayedQuitAll(bool)), Qt::QueuedConnection);
659 660
    maybeReadVimRc();
    //    << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
661

hjk's avatar
hjk committed
662 663 664
    return true;
}

665 666 667 668 669 670
static const char *exCommandMapGroup = "FakeVimExCommand";
static const char *reKey = "RegEx";
static const char *idKey = "Command";

void FakeVimPluginPrivate::writeSettings(QSettings *settings)
{
hjk's avatar
hjk committed
671
    settings->beginWriteArray(_(exCommandMapGroup));
672 673

    int count = 0;
674 675 676
    typedef CommandMap::const_iterator Iterator;
    const Iterator end = exCommandMap().constEnd();
    for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
677 678 679
        const QString &id = it.key();
        const QRegExp &re = it.value();

680 681
        if ((defaultExCommandMap().contains(id) && defaultExCommandMap()[id] != re)
            || (!defaultExCommandMap().contains(id) && !re.pattern().isEmpty())) {
682
            settings->setArrayIndex(count);
hjk's avatar
hjk committed
683 684
            settings->setValue(_(idKey), id);
            settings->setValue(_(reKey), re.pattern());
685 686 687 688 689 690 691 692 693
            ++count;
        }
    }

    settings->endArray();
}

void FakeVimPluginPrivate::readSettings(QSettings *settings)
{
694
    exCommandMap() = defaultExCommandMap();
695

hjk's avatar
hjk committed
696
    int size = settings->beginReadArray(_(exCommandMapGroup));
697
    for (int i = 0; i < size; ++i) {
698
        settings->setArrayIndex(i);
hjk's avatar
hjk committed
699 700
        const QString id = settings->value(_(idKey)).toString();
        const QString re = settings->value(_(reKey)).toString();
701
        exCommandMap()[id] = QRegExp(re);
702 703 704 705
    }
    settings->endArray();
}

706 707
void FakeVimPluginPrivate::maybeReadVimRc()
{
hjk's avatar
hjk committed
708 709 710
    //qDebug() << theFakeVimSetting(ConfigReadVimRc)
    //    << theFakeVimSetting(ConfigReadVimRc)->value();
    //qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
711 712 713 714 715 716 717 718 719 720
    if (!theFakeVimSetting(ConfigReadVimRc)->value().toBool())
        return;
    QString fileName =
        QDesktopServices::storageLocation(QDesktopServices::HomeLocation)
            + "/.vimrc";
    //qDebug() << "READING VIMRC: " << fileName;
    // Read it into a temporary handler for effects modifying global state.
    QPlainTextEdit editor;
    FakeVimHandler handler(&editor);
    handler.handleCommand("source " + fileName);
hjk's avatar
hjk committed
721
    theFakeVimSettings()->writeSettings(core()->settings());
hjk's avatar
hjk committed
722
    //qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
723 724
}

hjk's avatar
hjk committed
725 726
void FakeVimPluginPrivate::showSettingsDialog()
{
hjk's avatar
hjk committed
727
    core()->showOptionsDialog(
hjk's avatar
hjk committed
728 729
        _(Constants::SETTINGS_CATEGORY),
        _(Constants::SETTINGS_ID));
hjk's avatar
hjk committed
730 731
}

732
void FakeVimPluginPrivate::triggerAction(const QString &code)
733
{
hjk's avatar
hjk committed
734
    Core::ActionManager *am = actionManager();
735 736
    QTC_ASSERT(am, return);
    Core::Command *cmd = am->command(code);
737
    QTC_ASSERT(cmd, qDebug() << "UNKNOWN CODE: " << code; return);
738 739 740 741 742
    QAction *action = cmd->action();
    QTC_ASSERT(action, return);
    action->trigger();
}

743
void FakeVimPluginPrivate::setActionChecked(const QString &code, bool check)
744
{
hjk's avatar
hjk committed
745
    Core::ActionManager *am = actionManager();
746 747 748 749 750 751
    QTC_ASSERT(am, return);
    Core::Command *cmd = am->command(code);
    QTC_ASSERT(cmd, return);
    QAction *action = cmd->action();
    QTC_ASSERT(action, return);
    QTC_ASSERT(action->isCheckable(), return);
752
    action->setChecked(!check); // trigger negates the action's state
753 754 755
    action->trigger();
}

756 757 758 759 760 761
static int moveRightWeight(const QRect &cursor, const QRect &other)
{
    int dx = other.left() - cursor.right();
    if (dx < 0)
        return -1;
    int w = 10000 * dx;
762 763
    int dy1 = cursor.top() - other.bottom();
    int dy2 = cursor.bottom() - other.top();
764 765 766 767 768 769 770 771 772 773 774 775
    w += dy1 * (dy1 > 0);
    w += dy2 * (dy2 > 0);
    qDebug() << "      DX: " << dx << dy1 << dy2 << w;
    return w;
}

static int moveLeftWeight(const QRect &cursor, const QRect &other)
{
    int dx = other.right() - cursor.left();
    if (dx < 0)
        return -1;
    int w = 10000 * dx;
776 777
    int dy1 = cursor.top() - other.bottom();
    int dy2 = cursor.bottom() - other.top();
778 779 780 781 782 783 784 785 786 787 788
    w += dy1 * (dy1 > 0);
    w += dy2 * (dy2 > 0);
    return w;
}

static int moveUpWeight(const QRect &cursor, const QRect &other)
{
    int dy = other.bottom() - cursor.top();
    if (dy < 0)
        return -1;
    int w = 10000 * dy;
789 790
    int dx1 = cursor.left() - other.right();
    int dx2 = cursor.right() - other.left();
791 792 793 794 795 796 797 798 799 800