fakevimplugin.cpp 37.4 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
**
9
** Commercial Usage
hjk's avatar
hjk committed
10
**
11
12
13
14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
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
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
hjk's avatar
hjk committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29
30
31

#include "fakevimplugin.h"

32
#include "fakevimhandler.h"
hjk's avatar
hjk committed
33
34
#include "ui_fakevimoptions.h"

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

#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/session.h>

#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
hjk's avatar
hjk committed
56
#include <texteditor/completionsupport.h>
hjk's avatar
hjk committed
57
58
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>
59
60
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
61
#include <texteditor/textblockiterator.h>
hjk's avatar
hjk committed
62

63
#include <find/findplugin.h>
64
65
#include <find/textfindconstants.h>

hjk's avatar
hjk committed
66
#include <utils/qtcassert.h>
hjk's avatar
hjk committed
67
#include <utils/savedaction.h>
68
#include <utils/treewidgetcolumnstretcher.h>
hjk's avatar
hjk committed
69

70
71
#include <cppeditor/cppeditorconstants.h>

72
73
#include <cpptools/cpptoolsconstants.h>

74
75
#include <indenter.h>

hjk's avatar
hjk committed
76
#include <QtCore/QDebug>
77
#include <QtCore/QtPlugin>
hjk's avatar
hjk committed
78
79
80
#include <QtCore/QObject>
#include <QtCore/QPoint>
#include <QtCore/QSettings>
81
#include <QtCore/QTextStream>
hjk's avatar
hjk committed
82

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

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


namespace FakeVim {
namespace Constants {

100
101
const char * const INSTALL_HANDLER        = "TextEditor.FakeVimHandler";
const char * const MINI_BUFFER            = "TextEditor.FakeVimMiniBuffer";
hjk's avatar
hjk committed
102
const char * const INSTALL_KEY            = "Alt+V,Alt+V";
103
104
const char * const SETTINGS_CATEGORY      = "D.FakeVim";
const char * const SETTINGS_ID            = "General";
105
const char * const SETTINGS_EX_CMDS_ID    = "ExCommands";
106
107
const char * const CMD_FILE_NEXT          = "FakeVim.SwitchFileNext";
const char * const CMD_FILE_PREV          = "FakeVim.SwitchFilePrev";
hjk's avatar
hjk committed
108
109
110
111
112

} // namespace Constants
} // namespace FakeVim


hjk's avatar
hjk committed
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
///////////////////////////////////////////////////////////////////////
//
// FakeVimOptionPage
//
///////////////////////////////////////////////////////////////////////

namespace FakeVim {
namespace Internal {

class FakeVimOptionPage : public Core::IOptionsPage
{
    Q_OBJECT

public:
    FakeVimOptionPage() {}

    // IOptionsPage
130
    QString id() const { return QLatin1String(Constants::SETTINGS_ID); }
131
    QString displayName() const { return tr("General"); }
132
    QString category() const { return QLatin1String(Constants::SETTINGS_CATEGORY); }
133
    QString displayCategory() const { return tr("FakeVim"); }
hjk's avatar
hjk committed
134
135
136
137

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(ICore::instance()->settings()); }
    void finish() { m_group.finish(); }
138
    virtual bool matches(const QString &) const;
hjk's avatar
hjk committed
139
140
141
142
143
144
145
146
147

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

private:
    friend class DebuggerPlugin;
    Ui::FakeVimOptionPage m_ui;
148
    QString m_searchKeywords;
149
    Utils::SavedActionSet m_group;
hjk's avatar
hjk committed
150
151
152
153
154
155
156
157
};

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

    m_group.clear();
158
    m_group.insert(theFakeVimSetting(ConfigUseFakeVim),
159
        m_ui.groupBox);
hjk's avatar
hjk committed
160

161
    m_group.insert(theFakeVimSetting(ConfigExpandTab),
hjk's avatar
hjk committed
162
        m_ui.checkBoxExpandTab);
163
    m_group.insert(theFakeVimSetting(ConfigHlSearch),
hjk's avatar
hjk committed
164
        m_ui.checkBoxHlSearch);
165
    m_group.insert(theFakeVimSetting(ConfigShiftWidth),
hjk's avatar
hjk committed
166
167
        m_ui.lineEditShiftWidth);

168
    m_group.insert(theFakeVimSetting(ConfigSmartTab),
hjk's avatar
hjk committed
169
        m_ui.checkBoxSmartTab);
170
    m_group.insert(theFakeVimSetting(ConfigStartOfLine),
hjk's avatar
hjk committed
171
        m_ui.checkBoxStartOfLine);
172
    m_group.insert(theFakeVimSetting(ConfigTabStop),
hjk's avatar
hjk committed
173
        m_ui.lineEditTabStop);
174
    m_group.insert(theFakeVimSetting(ConfigBackspace),
hjk's avatar
hjk committed
175
176
        m_ui.lineEditBackspace);

177
    m_group.insert(theFakeVimSetting(ConfigAutoIndent),
hjk's avatar
hjk committed
178
        m_ui.checkBoxAutoIndent);
179
    m_group.insert(theFakeVimSetting(ConfigSmartIndent),
180
        m_ui.checkBoxSmartIndent);
181
    m_group.insert(theFakeVimSetting(ConfigIncSearch),
182
        m_ui.checkBoxIncSearch);
hjk's avatar
hjk committed
183
184

    connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
hjk's avatar
hjk committed
185
        this, SLOT(copyTextEditorSettings()));
hjk's avatar
hjk committed
186
187
188
189
    connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
        this, SLOT(setQtStyle()));
    connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
        this, SLOT(setPlainStyle()));
190
191
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
hjk's avatar
hjk committed
192
193
194
195
196
197
198
199
200
201
202
            << ' ' << m_ui.labelAutoIndent->text()
            << ' ' << m_ui.labelExpandTab->text()
            << ' ' << m_ui.labelSmartIndent->text()
            << ' ' << m_ui.labelExpandTab->text()
            << ' ' << m_ui.labelHlSearch->text()
            << ' ' << m_ui.labelIncSearch->text()
            << ' ' << m_ui.labelShiftWidth->text()
            << ' ' << m_ui.labelSmartTab->text()
            << ' ' << m_ui.labelStartOfLine->text()
            << ' ' << m_ui.tabulatorLabel->text()
            << ' ' << m_ui.labelBackspace->text();
203
204
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
205
206
207
208
209
    return w;
}

void FakeVimOptionPage::copyTextEditorSettings()
{
210
    TextEditor::TabSettings ts =
hjk's avatar
hjk committed
211
        TextEditor::TextEditorSettings::instance()->tabSettings();
212

hjk's avatar
hjk committed
213
214
215
216
    m_ui.checkBoxExpandTab->setChecked(ts.m_spacesForTabs);
    m_ui.lineEditTabStop->setText(QString::number(ts.m_tabSize));
    m_ui.lineEditShiftWidth->setText(QString::number(ts.m_indentSize));
    m_ui.checkBoxSmartTab->setChecked(ts.m_smartBackspace);
217
218
    m_ui.checkBoxAutoIndent->setChecked(true);
    m_ui.checkBoxSmartIndent->setChecked(ts.m_autoIndent);
219
220
    // FIXME: Not present in core
    //m_ui.checkBoxIncSearch->setChecked(ts.m_incSearch);
hjk's avatar
hjk committed
221
222
223
224
225
}

void FakeVimOptionPage::setQtStyle()
{
    m_ui.checkBoxExpandTab->setChecked(true);
226
227
228
    const QString four = QString(QLatin1Char('4'));
    m_ui.lineEditTabStop->setText(four);
    m_ui.lineEditShiftWidth->setText(four);
hjk's avatar
hjk committed
229
230
    m_ui.checkBoxSmartTab->setChecked(true);
    m_ui.checkBoxAutoIndent->setChecked(true);
231
    m_ui.checkBoxSmartIndent->setChecked(true);
232
    m_ui.checkBoxIncSearch->setChecked(true);
233
    m_ui.lineEditBackspace->setText(QLatin1String("indent,eol,start"));
hjk's avatar
hjk committed
234
235
236
237
238
}

void FakeVimOptionPage::setPlainStyle()
{
    m_ui.checkBoxExpandTab->setChecked(false);
239
240
241
    const QString eight = QString(QLatin1Char('4'));
    m_ui.lineEditTabStop->setText(eight);
    m_ui.lineEditShiftWidth->setText(eight);
hjk's avatar
hjk committed
242
243
    m_ui.checkBoxSmartTab->setChecked(false);
    m_ui.checkBoxAutoIndent->setChecked(false);
244
    m_ui.checkBoxSmartIndent->setChecked(false);
245
    m_ui.checkBoxIncSearch->setChecked(false);
hjk's avatar
hjk committed
246
    m_ui.lineEditBackspace->setText(QString());
hjk's avatar
hjk committed
247
248
}

249
250
251
252
253
bool FakeVimOptionPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
254
255
256
257
} // namespace Internal
} // namespace FakeVim


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
///////////////////////////////////////////////////////////////////////
//
// 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;


280
class FakeVimExCommandsPage : public Core::CommandMappings
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
{
    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();

public slots:
    void commandChanged(QTreeWidgetItem *current);
298
299
300
    void targetIdentifierChanged();
    void resetTargetIdentifier();
    void removeTargetIdentifier();
301
302
303
304
305
306
307
308
309
    void defaultAction();

private:
    void setRegex(const QString &regex);
    QList<CommandItem *> m_citems;
};

QWidget *FakeVimExCommandsPage::createPage(QWidget *parent)
{
310
311
312
313
314
    QWidget *w = CommandMappings::createPage(parent);
    setPageTitle(tr("Ex Command Mapping"));
    setTargetHeader(tr("Ex Trigger Expression"));
    setTargetLabelText(tr("Regular Expression:"));
    setTargetEditTitle(tr("Ex Command"));
315

316
    setImportExportEnabled(false);
317
318
319
320
321
322
323
324
325
326
327

    return w;
}

void FakeVimExCommandsPage::initialize()
{
    Core::ActionManager *am = Core::ICore::instance()->actionManager();
    QTC_ASSERT(am, return);
    UniqueIDManager *uidm = UniqueIDManager::instance();
    QTC_ASSERT(uidm, return);

328
329
    QMap<QString, QTreeWidgetItem *> sections;

330
331
332
333
334
    foreach (Command *c, am->commands()) {
        if (c->action() && c->action()->isSeparator())
            continue;

        CommandItem *ci = new CommandItem;
335
        QTreeWidgetItem *item = new QTreeWidgetItem;
336
337
338
339
340
        ci->m_cmd = c;
        ci->m_item = item;
        m_citems << ci;

        const QString name = uidm->stringForUniqueIdentifier(c->id());
341
342
343
344
345
        const int pos = name.indexOf(QLatin1Char('.'));
        const QString section = name.left(pos);
        const QString subId = name.mid(pos+1);

        if (!sections.contains(section)) {
346
            QTreeWidgetItem *categoryItem = new QTreeWidgetItem(commandList(), QStringList() << section);
347
348
349
350
            QFont f = categoryItem->font(0);
            f.setBold(true);
            categoryItem->setFont(0, f);
            sections.insert(section, categoryItem);
351
            commandList()->expandItem(categoryItem);
352
353
354
355
        }
        sections[section]->addChild(item);

        item->setText(0, subId);
356
357
358
359
360
361
362
363
364
365
366

        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 {
hjk's avatar
hjk committed
367
            ci->m_regex.clear();
368
369
370
371
        }

        item->setText(2, ci->m_regex);
        item->setData(0, Qt::UserRole, qVariantFromValue(ci));
372
373
374
375
376
377
378
379
380
381

        if (ci->m_regex != s_defaultExCommandMap[name].pattern()) {
            QFont f = item->font(0);
            f.setItalic(true);
            item->setFont(0, f);
            item->setFont(1, f);
            f.setBold(true);
            item->setFont(2, f);
        }

382
383
384
385
386
387
388
    }

    commandChanged(0);
}

void FakeVimExCommandsPage::commandChanged(QTreeWidgetItem *current)
{
389
390
391
    CommandMappings::commandChanged(current);

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

394
    CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
395
    targetEdit()->setText(citem->m_regex);
396
397
}

398
void FakeVimExCommandsPage::targetIdentifierChanged()
399
{
400
    QTreeWidgetItem *current = commandList()->currentItem();
401
402
403
404
405
406
407
408
    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()) {
409
        citem->m_regex = targetEdit()->text();
410
        current->setText(2, citem->m_regex);
411
        s_exCommandMap[name] = QRegExp(citem->m_regex);
412
    }
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

    if (citem->m_regex != s_defaultExCommandMap[name].pattern()) {
        QFont f = current->font(0);
        f.setItalic(true);
        current->setFont(0, f);
        current->setFont(1, f);
        f.setBold(true);
        current->setFont(2, f);
    } else {
        QFont f = current->font(0);
        f.setItalic(false);
        f.setBold(false);
        current->setFont(0, f);
        current->setFont(1, f);
        current->setFont(2, f);
    }

430
431
432
433
}

void FakeVimExCommandsPage::setRegex(const QString &regex)
{
434
    targetEdit()->setText(regex);
435
436
}

437
void FakeVimExCommandsPage::resetTargetIdentifier()
438
439
{
    UniqueIDManager *uidm = UniqueIDManager::instance();
440
    QTreeWidgetItem *current = commandList()->currentItem();
441
442
443
444
445
446
    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
hjk's avatar
hjk committed
447
            setRegex(QString());
448
449
450
    }
}

451
void FakeVimExCommandsPage::removeTargetIdentifier()
452
{
453
    targetEdit()->clear();
454
455
456
457
458
459
460
461
462
463
}

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 {
hjk's avatar
hjk committed
464
            item->m_regex.clear();
465
466
        }
        item->m_item->setText(2, item->m_regex);
467
        if (item->m_item == commandList()->currentItem())
468
469
470
471
472
473
474
475
            commandChanged(item->m_item);
    }
}

} // namespace Internal
} // namespace FakeVim


hjk's avatar
hjk committed
476
477
///////////////////////////////////////////////////////////////////////
//
478
// FakeVimPluginPrivate
hjk's avatar
hjk committed
479
480
481
//
///////////////////////////////////////////////////////////////////////

482
483
484
485
namespace FakeVim {
namespace Internal {

class FakeVimPluginPrivate : public QObject
hjk's avatar
hjk committed
486
{
487
488
489
490
491
492
493
    Q_OBJECT

public:
    FakeVimPluginPrivate(FakeVimPlugin *);
    ~FakeVimPluginPrivate();
    friend class FakeVimPlugin;

494
    bool initialize();
495
496
497
498
499
    void shutdown();

private slots:
    void editorOpened(Core::IEditor *);
    void editorAboutToClose(Core::IEditor *);
500

501
    void setUseFakeVim(const QVariant &value);
502
    void quitFakeVim();
503
    void triggerCompletions();
hjk's avatar
hjk committed
504
    void windowCommand(int key);
505
    void find(bool reverse);
506
    void findNext(bool reverse);
hjk's avatar
hjk committed
507
    void showSettingsDialog();
508
509
510
511
512

    void showCommandBuffer(const QString &contents);
    void showExtraInformation(const QString &msg);
    void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
    void writeFile(bool *handled, const QString &fileName, const QString &contents);
513
    void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
514
    void checkForElectricCharacter(bool *result, QChar c);
hjk's avatar
hjk committed
515
    void indentRegion(int *amount, int beginLine, int endLine,  QChar typedChar);
516
    void handleExCommand(const QString &cmd);
517
    void handleSetCommand(bool *handled, QString cmd);
518
519
520
521

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

522
523
524
525
    void switchFile(bool previous);
    void switchFileNext();
    void switchFilePrev();

526
527
528
signals:
    void delayedQuitRequested(bool forced, Core::IEditor *editor);
    void delayedQuitAllRequested(bool forced);
529
530
531

private:
    FakeVimPlugin *q;
hjk's avatar
hjk committed
532
    FakeVimOptionPage *m_fakeVimOptionsPage;
533
    FakeVimExCommandsPage *m_fakeVimExCommandsPage;
534
    QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
535
536

    void triggerAction(const QString& code);
537
    void setActionChecked(const QString& code, bool check);
538
539
540

    void readSettings(QSettings *settings);
    void writeSettings(QSettings *settings);
541
542
543
544
545
546
};

} // namespace Internal
} // namespace FakeVim

FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
547
{
548
    q = plugin;
hjk's avatar
hjk committed
549
    m_fakeVimOptionsPage = 0;
550
551
    m_fakeVimExCommandsPage = 0;

552
553
    s_defaultExCommandMap[Constants::CMD_FILE_NEXT] = QRegExp("^n(ext)?!?( (.*))?$");
    s_defaultExCommandMap[Constants::CMD_FILE_PREV] = QRegExp("^(N(ext)?|prev(ious)?)!?( (.*))?$");
554
555
556
557
    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)?!?( (.*))?$");
558
559
    s_defaultExCommandMap[CppEditor::Constants::JUMP_TO_DEFINITION] = QRegExp("^tag?$");
    s_defaultExCommandMap[Core::Constants::GO_BACK] = QRegExp("^pop?$");
hjk's avatar
hjk committed
560
561
}

562
563
564
FakeVimPluginPrivate::~FakeVimPluginPrivate()
{
}
hjk's avatar
hjk committed
565

566
void FakeVimPluginPrivate::shutdown()
hjk's avatar
hjk committed
567
{
hjk's avatar
hjk committed
568
569
570
571
    q->removeObject(m_fakeVimOptionsPage);
    delete m_fakeVimOptionsPage;
    m_fakeVimOptionsPage = 0;
    theFakeVimSettings()->writeSettings(Core::ICore::instance()->settings());
dt's avatar
dt committed
572
    delete theFakeVimSettings();
573
574
575
576
577

    q->removeObject(m_fakeVimExCommandsPage);
    delete m_fakeVimExCommandsPage;
    m_fakeVimExCommandsPage = 0;
    writeSettings(Core::ICore::instance()->settings());
hjk's avatar
hjk committed
578
579
}

580
bool FakeVimPluginPrivate::initialize()
hjk's avatar
hjk committed
581
{
hjk's avatar
hjk committed
582
    Core::ActionManager *actionManager = Core::ICore::instance()->actionManager();
hjk's avatar
hjk committed
583
584
585
586
587
    QTC_ASSERT(actionManager, return false);

    QList<int> globalcontext;
    globalcontext << Core::Constants::C_GLOBAL_ID;

hjk's avatar
hjk committed
588
589
590
    m_fakeVimOptionsPage = new FakeVimOptionPage;
    q->addObject(m_fakeVimOptionsPage);
    theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
591
592
593
594

    m_fakeVimExCommandsPage = new FakeVimExCommandsPage;
    q->addObject(m_fakeVimExCommandsPage);
    readSettings(Core::ICore::instance()->settings());
595

con's avatar
con committed
596
    Core::Command *cmd = 0;
597
    cmd = actionManager->registerAction(theFakeVimSetting(ConfigUseFakeVim),
hjk's avatar
hjk committed
598
599
600
        Constants::INSTALL_HANDLER, globalcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::INSTALL_KEY));

601
    ActionContainer *advancedMenu =
hjk's avatar
hjk committed
602
        actionManager->actionContainer(Core::Constants::M_EDIT_ADVANCED);
603
    advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
604

605
    // EditorManager
hjk's avatar
hjk committed
606
    QObject *editorManager = Core::ICore::instance()->editorManager();
607
608
609
610
611
    connect(editorManager, SIGNAL(editorAboutToClose(Core::IEditor*)),
        this, SLOT(editorAboutToClose(Core::IEditor*)));
    connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)),
        this, SLOT(editorOpened(Core::IEditor*)));

hjk's avatar
hjk committed
612
613
    connect(theFakeVimSetting(SettingsDialog), SIGNAL(triggered()),
        this, SLOT(showSettingsDialog()));
614
615
    connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
        this, SLOT(setUseFakeVim(QVariant)));
hjk's avatar
hjk committed
616

617
618
619
620
621
622
623
624
625
626
    QAction *switchFileNextAction = new QAction(tr("Switch to next file"), this);
    cmd = actionManager->registerAction(switchFileNextAction, Constants::CMD_FILE_NEXT, globalcontext);
    cmd->setAttribute(Command::CA_Hide);
    connect(switchFileNextAction, SIGNAL(triggered()), this, SLOT(switchFileNext()));

    QAction *switchFilePrevAction = new QAction(tr("Switch to previous file"), this);
    cmd = actionManager->registerAction(switchFilePrevAction, Constants::CMD_FILE_PREV, globalcontext);
    cmd->setAttribute(Command::CA_Hide);
    connect(switchFilePrevAction, SIGNAL(triggered()), this, SLOT(switchFilePrev()));

627
628
629
630
631
632
    // Delayed operatiosn
    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);

hjk's avatar
hjk committed
633
634
635
    return true;
}

636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
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();
}

hjk's avatar
hjk committed
676
677
void FakeVimPluginPrivate::showSettingsDialog()
{
678
679
    Core::ICore::instance()->showOptionsDialog(QLatin1String(Constants::SETTINGS_CATEGORY),
                                               QLatin1String(Constants::SETTINGS_ID));
hjk's avatar
hjk committed
680
681
}

682
683
684
685
686
687
688
689
690
691
692
void FakeVimPluginPrivate::triggerAction(const QString& code)
{
    Core::ActionManager *am = Core::ICore::instance()->actionManager();
    QTC_ASSERT(am, return);
    Core::Command *cmd = am->command(code);
    QTC_ASSERT(cmd, return);
    QAction *action = cmd->action();
    QTC_ASSERT(action, return);
    action->trigger();
}

693
694
695
696
697
698
699
700
701
702
703
704
705
void FakeVimPluginPrivate::setActionChecked(const QString& code, bool check)
{
    Core::ActionManager *am = Core::ICore::instance()->actionManager();
    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);
    action->setChecked(check);
    action->trigger();
}

hjk's avatar
hjk committed
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
void FakeVimPluginPrivate::windowCommand(int key)
{
    #define control(n) (256 + n)
    QString code;
    switch (key) {
        case 'c': case 'C': case control('c'):
            code = Core::Constants::CLOSE;
            break;
        case 'n': case 'N': case control('n'):
            code = Core::Constants::GOTONEXT;
            break;
        case 'o': case 'O': case control('o'):
            code = Core::Constants::REMOVE_ALL_SPLITS;
            code = Core::Constants::REMOVE_CURRENT_SPLIT;
            break;
        case 'p': case 'P': case control('p'):
            code = Core::Constants::GOTOPREV;
            break;
        case 's': case 'S': case control('s'):
            code = Core::Constants::SPLIT;
            break;
        case 'w': case 'W': case control('w'):
            code = Core::Constants::GOTO_OTHER_SPLIT;
            break;
    }
    #undef control
    qDebug() << "RUNNING WINDOW COMMAND: " << key << code;
    if (code.isEmpty()) {
        qDebug() << "UNKNOWN WINDOWS COMMAND: " << key;
        return;
    }
737
738
739
740
741
    triggerAction(code);
}

void FakeVimPluginPrivate::find(bool reverse)
{
742
    if (Find::FindPlugin *plugin = Find::FindPlugin::instance()) {
743
744
        plugin->setUseFakeVim(true);
        plugin->openFindToolBar(reverse
745
746
                ? Find::FindPlugin::FindBackward
                : Find::FindPlugin::FindForward);
747
    }
hjk's avatar
hjk committed
748
749
}

750
751
752
753
754
755
756
757
void FakeVimPluginPrivate::findNext(bool reverse)
{
    if (reverse)
        triggerAction(Find::Constants::FIND_PREVIOUS);
    else
        triggerAction(Find::Constants::FIND_NEXT);
}

758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
// this class defers deletion of a child FakeVimHandler using 'deleteLater'
// - direct children QObject's would be 'delete'ed immediately before their parents
class DeferredDeleter : public QObject
{
    Q_OBJECT

    FakeVimHandler *m_handler;

public:
    DeferredDeleter(QObject *parent, FakeVimHandler *handler)
        : QObject(parent)
          , m_handler(handler)
    {}

    virtual ~DeferredDeleter()
    {
        if (m_handler) {
            m_handler->disconnectFromEditor();
            m_handler->deleteLater();
            m_handler = 0;
        }
    }
};

782
void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
783
{
784
785
786
    if (!editor)
        return;

787
    QWidget *widget = editor->widget();
788
789
    if (!widget)
        return;
790
791
792
793

    // we can only handle QTextEdit and QPlainTextEdit
    if (!qobject_cast<QTextEdit *>(widget) && !qobject_cast<QPlainTextEdit *>(widget))
        return;
794

795
796
797
    //qDebug() << "OPENING: " << editor << editor->widget()
    //    << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();

798
799
800
801
    FakeVimHandler *handler = new FakeVimHandler(widget, 0);
    // the handler might have triggered the deletion of the editor:
    // make sure that it can return before being deleted itself
    new DeferredDeleter(widget, handler);
802
    m_editorToHandler[editor] = handler;
803
804
805
806

    connect(handler, SIGNAL(extraInformationChanged(QString)),
        this, SLOT(showExtraInformation(QString)));
    connect(handler, SIGNAL(commandBufferChanged(QString)),
hjk's avatar
hjk committed
807
        this, SLOT(showCommandBuffer(QString)));
808
809
810
811
    connect(handler, SIGNAL(writeFileRequested(bool*,QString,QString)),
        this, SLOT(writeFile(bool*,QString,QString)));
    connect(handler, SIGNAL(selectionChanged(QList<QTextEdit::ExtraSelection>)),
        this, SLOT(changeSelection(QList<QTextEdit::ExtraSelection>)));
812
813
    connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
        this, SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)));
hjk's avatar
hjk committed
814
815
    connect(handler, SIGNAL(indentRegion(int*,int,int,QChar)),
        this, SLOT(indentRegion(int*,int,int,QChar)));
816
817
    connect(handler, SIGNAL(checkForElectricCharacter(bool*,QChar)),
        this, SLOT(checkForElectricCharacter(bool*,QChar)));
818
819
    connect(handler, SIGNAL(completionRequested()),
        this, SLOT(triggerCompletions()));
hjk's avatar
hjk committed
820
821
    connect(handler, SIGNAL(windowCommandRequested(int)),
        this, SLOT(windowCommand(int)));
822
823
    connect(handler, SIGNAL(findRequested(bool)),
        this, SLOT(find(bool)));
824
825
    connect(handler, SIGNAL(findNextRequested(bool)),
        this, SLOT(findNext(bool)));
826

827
828
    connect(handler, SIGNAL(handleExCommandRequested(QString)),
        this, SLOT(handleExCommand(QString)));
829
830
    connect(handler, SIGNAL(handleSetCommandRequested(bool *,QString)),
        this, SLOT(handleSetCommand(bool *,QString)));
831

hjk's avatar
hjk committed
832
    handler->setCurrentFileName(editor->file()->fileName());
833
    handler->installEventFilter();
834

835
836
    // pop up the bar
    if (theFakeVimSetting(ConfigUseFakeVim)->value().toBool())
hjk's avatar
hjk committed
837
       showCommandBuffer(QString());
hjk's avatar
hjk committed
838
839
}

840
void FakeVimPluginPrivate::editorAboutToClose(Core::IEditor *editor)
hjk's avatar
hjk committed
841
{
842
843
844
845
846
847
    //qDebug() << "CLOSING: " << editor << editor->widget();
    m_editorToHandler.remove(editor);
}

void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
{
848
    //qDebug() << "SET USE FAKEVIM" << value;
849
    bool on = value.toBool();
850
851
    if (Find::FindPlugin::instance())
        Find::FindPlugin::instance()->setUseFakeVim(on);
852
    if (on) {
853
854
        Core::EditorManager::instance()->showEditorStatusBar(
            QLatin1String(Constants::MINI_BUFFER),
855
            "vi emulation mode. Type :q to leave. Use , Ctrl-R to trigger run.",
856
            tr("Quit FakeVim"), this, SLOT(quitFakeVim()));
857
858
859
860
861
862
863
864
        foreach (Core::IEditor *editor, m_editorToHandler.keys())
            m_editorToHandler[editor]->setupWidget();
    } else {
        Core::EditorManager::instance()->hideEditorStatusBar(
            QLatin1String(Constants::MINI_BUFFER));
        foreach (Core::IEditor *editor, m_editorToHandler.keys())
            m_editorToHandler[editor]->restoreWidget();
    }
hjk's avatar
hjk committed
865
866
}

867
868
869
870
871
872
void FakeVimPluginPrivate::triggerCompletions()
{
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;
    if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget()))
hjk's avatar
hjk committed
873
874
875
        TextEditor::Internal::CompletionSupport::instance()->
            autoComplete(bt->editableInterface(), false);
   //     bt->triggerCompletions();
876
877
}

878
879
880
881
882
883
884
885
886
void FakeVimPluginPrivate::checkForElectricCharacter(bool *result, QChar c)
{
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;
    if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget()))
        *result = bt->isElectricCharacter(c);
}

887
888
void FakeVimPluginPrivate::writeFile(bool *handled,
    const QString &fileName, const QString &contents)
889
{
890
    Q_UNUSED(contents)
891

892
893
894
895
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

896
    Core::IEditor *editor = m_editorToHandler.key(handler);
897
    if (editor && editor->file()->fileName() == fileName) {
hjk's avatar
hjk committed
898
        // Handle that as a special case for nicer interaction with core
899
        Core::IFile *file = editor->file();
hjk's avatar
hjk committed
900
        Core::ICore::instance()->fileManager()->blockFileChange(file);
901
        file->save(fileName);
hjk's avatar
hjk committed
902
        Core::ICore::instance()->fileManager()->unblockFileChange(file);
903
        *handled = true;
904
    }
905
906
}

907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
{
    static QRegExp reWriteAll("^wa(ll)?!?$");
    static QRegExp reQuit("^q!?$");
    static QRegExp reQuitAll("^qa!?$");

    using namespace Core;

    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

    EditorManager *editorManager = EditorManager::instance();
    QTC_ASSERT(editorManager, return);

922
    if (reWriteAll.indexIn(cmd) != -1) {
923
924
925
926
927
928
929
        // :wa
        FileManager *fm = ICore::instance()->fileManager();
        QList<IFile *> toSave = fm->modifiedFiles();
        QList<IFile *> failed = fm->saveModifiedFilesSilently(toSave);
        if (failed.isEmpty())
            handler->showBlackMessage(tr("Saving succeeded"));
        else
930
            handler->showRedMessage(tr("%n files not saved", 0, failed.size()));
931
932
933
934
935
936
937
938
939
    } else if (reQuit.indexIn(cmd) != -1) {
        // :q
        bool forced = cmd.contains(QChar('!'));
        emit delayedQuitRequested(forced, m_editorToHandler.key(handler));
    } else if (reQuitAll.indexIn(cmd) != -1) {
        // :qa
        bool forced = cmd.contains(QChar('!'));
        emit delayedQuitAllRequested(forced);
    } else {
940
941
942
943
944
        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();

945
            if (!re.pattern().isEmpty() && re.indexIn(cmd) != -1) {
946
947
948
949
950
                triggerAction(id);
                return;
            }
        }

951
        handler->showRedMessage(tr("Not an editor command: %1").arg(cmd));
952
953
954
    }
}

955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
void FakeVimPluginPrivate::handleSetCommand(bool *handled, QString cmd)
{
    *handled = false;
    bool value = true;
    if (cmd.startsWith("no")) {
        value = false;
        cmd = cmd.mid(2);
    }

    if (cmd == "ic" || cmd == "ignorecase") {
        setActionChecked(Find::Constants::CASE_SENSITIVE, value);
        *handled = true;
    }
}

970
971
972
973
974
975
976
977
978
979
980
981
void FakeVimPluginPrivate::handleDelayedQuit(bool forced, Core::IEditor *editor)
{
    QList<Core::IEditor *> editors;
    editors.append(editor);
    Core::EditorManager::instance()->closeEditors(editors, !forced);
}

void FakeVimPluginPrivate::handleDelayedQuitAll(bool forced)
{
    Core::EditorManager::instance()->closeAllEditors(!forced);
}

982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
void FakeVimPluginPrivate::moveToMatchingParenthesis(bool *moved, bool *forward,
        QTextCursor *cursor)
{
    *moved = false;

    bool undoFakeEOL = false;
    if (cursor->atBlockEnd() && cursor->block().length() > 1) {
        cursor->movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
        undoFakeEOL = true;
    }
    TextEditor::TextBlockUserData::MatchType match
        = TextEditor::TextBlockUserData::matchCursorForward(cursor);
    if (match == TextEditor::TextBlockUserData::Match) {
        *moved = true;
        *forward = true;
997
    } else {
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
        if (undoFakeEOL)
            cursor->movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
        if (match == TextEditor::TextBlockUserData::NoMatch) {
            // backward matching is according to the character before the cursor
            bool undoMove = false;
            if (!cursor->atBlockEnd()) {
                cursor->movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
                undoMove = true;
            }
            match = TextEditor::TextBlockUserData::matchCursorBackward(cursor);
            if (match == TextEditor::TextBlockUserData::Match) {
                *moved = true;
                *forward = false;
            } else if (undoMove) {
                cursor->movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
            }
        }
    }
}

hjk's avatar
hjk committed
1018
void FakeVimPluginPrivate::indentRegion(int *amount, int beginLine, int endLine,
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
      QChar typedChar)
{
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

    BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget());
    if (!bt)
        return;

1029
1030
1031
1032
    TextEditor::TabSettings tabSettings;
    tabSettings.m_indentSize = theFakeVimSetting(ConfigShiftWidth)->value().toInt();
    tabSettings.m_tabSize = theFakeVimSetting(ConfigTabStop)->value().toInt();
    tabSettings.m_spacesForTabs = theFakeVimSetting(ConfigExpandTab)->value().toBool();
1033
1034
    typedef SharedTools::Indenter<TextEditor::TextBlockIterator> Indenter;
    Indenter &indenter = Indenter::instance();
hjk's avatar
hjk committed
1035
1036
    indenter.setIndentSize(tabSettings.m_indentSize);
    indenter.setTabSize(tabSettings.m_tabSize);
1037

hjk's avatar
hjk committed
1038
    const QTextDocument *doc = bt->document();
1039
    const TextEditor::TextBlockIterator docStart(doc->begin());
Martin Aumüller's avatar
Martin Aumüller committed
1040
1041
1042
    QTextBlock cur = doc->findBlockByNumber(beginLine);
    for(int i = beginLine; i<= endLine; ++i)
    {
1043
        if (typedChar == 0 && cur.text().simplified().isEmpty()) {
Martin Aumüller's avatar
Martin Aumüller committed
1044
            // clear empty lines
1045
            *amount = 0;
Martin Aumüller's avatar
Martin Aumüller committed
1046
1047
1048
            QTextCursor cursor(cur);
            while (!cursor.atBlockEnd())
                cursor.deleteChar();
1049
1050
1051
1052
        } else {
            const TextEditor::TextBlockIterator current(cur);
            const TextEditor::TextBlockIterator next(cur.next());
            *amount = indenter.indentForBottomLine(current, docStart, next, typedChar);
Martin Aumüller's avatar
Martin Aumüller committed
1053
            tabSettings.indentLine(cur, *amount);
1054
        }
Martin Aumüller's avatar
Martin Aumüller committed
1055
1056
        cur = cur.next();
    }
1057
1058
}

1059
void FakeVimPluginPrivate::quitFakeVim()
1060
{
hjk's avatar
hjk committed
1061
    theFakeVimSetting(ConfigUseFakeVim)->setValue(false);
1062
1063
}

1064
void FakeVimPluginPrivate::showCommandBuffer(const QString &contents)
hjk's avatar
hjk committed
1065
{
1066
    //qDebug() << "SHOW COMMAND BUFFER" << contents;
1067
    Core::EditorManager::instance()->showEditorStatusBar(
1068
        QLatin1String(Constants::MINI_BUFFER), contents,
1069
        tr("Quit FakeVim"), this, SLOT(quitFakeVim()));
hjk's avatar
hjk committed
1070
1071
}

1072
void FakeVimPluginPrivate::showExtraInformation(const QString &text)
1073
{
1074
1075
1076
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (handler)
        QMessageBox::information(handler->widget(), tr("FakeVim Information"), text);
1077
1078
}

1079
1080
void FakeVimPluginPrivate::changeSelection
    (const QList<QTextEdit::ExtraSelection> &selection)
1081
{
1082
1083
1084
    if (FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender()))
        if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget()))
            bt->setExtraSelections(BaseTextEditor::FakeVimSelection, selection);
1085
1086
}

1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
void FakeVimPluginPrivate::switchFile(bool previous)
{
    Core::EditorManager *em = Core::EditorManager::instance();
    Core::OpenEditorsModel *model = em->openedEditorsModel();
    IEditor *cur = Core::EditorManager::instance()->currentEditor();
    int curIdx = model->indexOf(cur).row();
    int nIdx = (curIdx + model->rowCount() + (previous ? -1 : 1)) % model->rowCount();
    em->activateEditor(model->index(nIdx, 0), 0);
}

void FakeVimPluginPrivate::switchFileNext()
{
    switchFile(false);
}

void FakeVimPluginPrivate::switchFilePrev()
{
    switchFile(true);
}
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121

///////////////////////////////////////////////////////////////////////
//
// FakeVimPlugin
//
///////////////////////////////////////////////////////////////////////

FakeVimPlugin::FakeVimPlugin()
    : d(new FakeVimPluginPrivate(this))
{}

FakeVimPlugin::~FakeVimPlugin()
{
    delete d;
}

1122
bool FakeVimPlugin::initialize(const QStringList &arguments, QString *errorMessage)
1123
{
1124
1125
    Q_UNUSED(arguments)
    Q_UNUSED(errorMessage)
1126
    return d->initialize();
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
}

void FakeVimPlugin::shutdown()
{
    d->shutdown();
}

void FakeVimPlugin::extensionsInitialized()
{
}

#include "fakevimplugin.moc"
hjk's avatar
hjk committed
1139
1140

Q_EXPORT_PLUGIN(FakeVimPlugin)