fakevimplugin.cpp 37.6 KB
Newer Older
1
/**************************************************************************
hjk's avatar
hjk committed
2
3
4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 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
#include "ui_fakevimoptions.h"
34
#include "ui_fakevimexcommands.h"
hjk's avatar
hjk committed
35

hjk's avatar
hjk committed
36

37
#include <coreplugin/actionmanager/actionmanager.h>
hjk's avatar
hjk committed
38
39
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
40
#include <coreplugin/editormanager/openeditorsmodel.h>
41
#include <coreplugin/filemanager.h>
hjk's avatar
hjk committed
42
#include <coreplugin/icore.h>
43
#include <coreplugin/ifile.h>
hjk's avatar
hjk committed
44
#include <coreplugin/dialogs/ioptionspage.h>
hjk's avatar
hjk committed
45
46
47
48
49
50
51
52
53
#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
54
#include <texteditor/completionsupport.h>
hjk's avatar
hjk committed
55
56
#include <texteditor/itexteditor.h>
#include <texteditor/texteditorconstants.h>
57
58
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
59
#include <texteditor/textblockiterator.h>
hjk's avatar
hjk committed
60

61
#include <find/findplugin.h>
62
63
#include <find/textfindconstants.h>

hjk's avatar
hjk committed
64
#include <utils/qtcassert.h>
hjk's avatar
hjk committed
65
#include <utils/savedaction.h>
hjk's avatar
hjk committed
66

67
68
#include <cpptools/cpptoolsconstants.h>

69
70
#include <indenter.h>

hjk's avatar
hjk committed
71
#include <QtCore/QDebug>
72
#include <QtCore/QtPlugin>
hjk's avatar
hjk committed
73
74
75
#include <QtCore/QObject>
#include <QtCore/QPoint>
#include <QtCore/QSettings>
76
#include <QtCore/QTextStream>
hjk's avatar
hjk committed
77

78
#include <QtGui/QMessageBox>
hjk's avatar
hjk committed
79
#include <QtGui/QPlainTextEdit>
80
#include <QtGui/QShortcut>
hjk's avatar
hjk committed
81
82
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
83
#include <QtGui/QTextEdit>
hjk's avatar
hjk committed
84
85
86
87
88
89
90
91
92
93
94


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


namespace FakeVim {
namespace Constants {

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

} // namespace Constants
} // namespace FakeVim


hjk's avatar
hjk committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
///////////////////////////////////////////////////////////////////////
//
// FakeVimOptionPage
//
///////////////////////////////////////////////////////////////////////

namespace FakeVim {
namespace Internal {

class FakeVimOptionPage : public Core::IOptionsPage
{
    Q_OBJECT

public:
    FakeVimOptionPage() {}

    // IOptionsPage
125
    QString id() const { return QLatin1String(Constants::SETTINGS_ID); }
126
    QString displayName() const { return tr("General"); }
127
    QString category() const { return QLatin1String(Constants::SETTINGS_CATEGORY); }
128
    QString displayCategory() const { return tr("FakeVim"); }
hjk's avatar
hjk committed
129
130
131
132

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(ICore::instance()->settings()); }
    void finish() { m_group.finish(); }
133
    virtual bool matches(const QString &) const;
hjk's avatar
hjk committed
134
135
136
137
138
139
140
141
142

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

private:
    friend class DebuggerPlugin;
    Ui::FakeVimOptionPage m_ui;
143
    QString m_searchKeywords;
144
    Utils::SavedActionSet m_group;
hjk's avatar
hjk committed
145
146
147
148
149
150
151
152
153
};

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

    m_group.clear();
    m_group.insert(theFakeVimSetting(ConfigUseFakeVim), 
154
        m_ui.groupBox);
hjk's avatar
hjk committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

    m_group.insert(theFakeVimSetting(ConfigExpandTab), 
        m_ui.checkBoxExpandTab);
    m_group.insert(theFakeVimSetting(ConfigHlSearch), 
        m_ui.checkBoxHlSearch);
    m_group.insert(theFakeVimSetting(ConfigShiftWidth), 
        m_ui.lineEditShiftWidth);

    m_group.insert(theFakeVimSetting(ConfigSmartTab), 
        m_ui.checkBoxSmartTab);
    m_group.insert(theFakeVimSetting(ConfigStartOfLine), 
        m_ui.checkBoxStartOfLine);
    m_group.insert(theFakeVimSetting(ConfigTabStop), 
        m_ui.lineEditTabStop);
    m_group.insert(theFakeVimSetting(ConfigBackspace), 
        m_ui.lineEditBackspace);

    m_group.insert(theFakeVimSetting(ConfigAutoIndent), 
        m_ui.checkBoxAutoIndent);
174
175
    m_group.insert(theFakeVimSetting(ConfigSmartIndent), 
        m_ui.checkBoxSmartIndent);
176
177
    m_group.insert(theFakeVimSetting(ConfigIncSearch), 
        m_ui.checkBoxIncSearch);
hjk's avatar
hjk committed
178
179

    connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
hjk's avatar
hjk committed
180
        this, SLOT(copyTextEditorSettings()));
hjk's avatar
hjk committed
181
182
183
184
    connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
        this, SLOT(setQtStyle()));
    connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
        this, SLOT(setPlainStyle()));
185
186
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
hjk's avatar
hjk committed
187
188
189
190
191
192
193
194
195
196
197
            << ' ' << 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();
198
199
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
200
201
202
203
204
205
206
207
208
209
210
211
    return w;
}

void FakeVimOptionPage::copyTextEditorSettings()
{
    TextEditor::TabSettings ts = 
        TextEditor::TextEditorSettings::instance()->tabSettings();
    
    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);
212
213
    m_ui.checkBoxAutoIndent->setChecked(true);
    m_ui.checkBoxSmartIndent->setChecked(ts.m_autoIndent);
214
215
    // FIXME: Not present in core
    //m_ui.checkBoxIncSearch->setChecked(ts.m_incSearch);
hjk's avatar
hjk committed
216
217
218
219
220
}

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

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

244
245
246
247
248
bool FakeVimOptionPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
249
250
251
252
} // namespace Internal
} // namespace FakeVim


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
///////////////////////////////////////////////////////////////////////
//
// 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 {
hjk's avatar
hjk committed
370
            ci->m_regex.clear();
371
372
373
374
375
376
377
378
379
380
381
382
        }

        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()) {
hjk's avatar
hjk committed
383
        m_ui.regexEdit->setText(QString());
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
        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
hjk's avatar
hjk committed
452
            setRegex(QString());
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
    }
}

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 {
hjk's avatar
hjk committed
469
            item->m_regex.clear();
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
        }
        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


hjk's avatar
hjk committed
486
487
///////////////////////////////////////////////////////////////////////
//
488
// FakeVimPluginPrivate
hjk's avatar
hjk committed
489
490
491
//
///////////////////////////////////////////////////////////////////////

492
493
494
495
namespace FakeVim {
namespace Internal {

class FakeVimPluginPrivate : public QObject
hjk's avatar
hjk committed
496
{
497
498
499
500
501
502
503
    Q_OBJECT

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

504
    bool initialize();
505
506
507
508
509
    void shutdown();

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

511
    void setUseFakeVim(const QVariant &value);
512
    void quitFakeVim();
513
    void triggerCompletions();
hjk's avatar
hjk committed
514
    void windowCommand(int key);
515
    void find(bool reverse);
516
    void findNext(bool reverse);
hjk's avatar
hjk committed
517
    void showSettingsDialog();
518
519
520
521
522

    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);
523
    void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
524
    void checkForElectricCharacter(bool *result, QChar c);
hjk's avatar
hjk committed
525
    void indentRegion(int *amount, int beginLine, int endLine,  QChar typedChar);
526
    void handleExCommand(const QString &cmd);
527
    void handleSetCommand(bool *handled, QString cmd);
528
529
530
531

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

532
533
534
535
    void switchFile(bool previous);
    void switchFileNext();
    void switchFilePrev();

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

private:
    FakeVimPlugin *q;
hjk's avatar
hjk committed
542
    FakeVimOptionPage *m_fakeVimOptionsPage;
543
    FakeVimExCommandsPage *m_fakeVimExCommandsPage;
544
    QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
545
546

    void triggerAction(const QString& code);
547
    void setActionChecked(const QString& code, bool check);
548
549
550

    void readSettings(QSettings *settings);
    void writeSettings(QSettings *settings);
551
552
553
554
555
556
557
558
};

} // namespace Internal
} // namespace FakeVim

FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
{       
    q = plugin;
hjk's avatar
hjk committed
559
    m_fakeVimOptionsPage = 0;
560
561
    m_fakeVimExCommandsPage = 0;

562
563
    s_defaultExCommandMap[Constants::CMD_FILE_NEXT] = QRegExp("^n(ext)?!?( (.*))?$");
    s_defaultExCommandMap[Constants::CMD_FILE_PREV] = QRegExp("^(N(ext)?|prev(ious)?)!?( (.*))?$");
564
565
566
567
    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)?!?( (.*))?$");
hjk's avatar
hjk committed
568
569
}

570
571
572
FakeVimPluginPrivate::~FakeVimPluginPrivate()
{
}
hjk's avatar
hjk committed
573

574
void FakeVimPluginPrivate::shutdown()
hjk's avatar
hjk committed
575
{
hjk's avatar
hjk committed
576
577
578
579
    q->removeObject(m_fakeVimOptionsPage);
    delete m_fakeVimOptionsPage;
    m_fakeVimOptionsPage = 0;
    theFakeVimSettings()->writeSettings(Core::ICore::instance()->settings());
dt's avatar
dt committed
580
    delete theFakeVimSettings();
581
582
583
584
585

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

588
bool FakeVimPluginPrivate::initialize()
hjk's avatar
hjk committed
589
{
hjk's avatar
hjk committed
590
    Core::ActionManager *actionManager = Core::ICore::instance()->actionManager();
hjk's avatar
hjk committed
591
592
593
594
595
    QTC_ASSERT(actionManager, return false);

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

hjk's avatar
hjk committed
596
597
598
    m_fakeVimOptionsPage = new FakeVimOptionPage;
    q->addObject(m_fakeVimOptionsPage);
    theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
599
600
601
602

    m_fakeVimExCommandsPage = new FakeVimExCommandsPage;
    q->addObject(m_fakeVimExCommandsPage);
    readSettings(Core::ICore::instance()->settings());
hjk's avatar
hjk committed
603
    
con's avatar
con committed
604
    Core::Command *cmd = 0;
605
    cmd = actionManager->registerAction(theFakeVimSetting(ConfigUseFakeVim),
hjk's avatar
hjk committed
606
607
608
        Constants::INSTALL_HANDLER, globalcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::INSTALL_KEY));

609
    ActionContainer *advancedMenu =
hjk's avatar
hjk committed
610
        actionManager->actionContainer(Core::Constants::M_EDIT_ADVANCED);
611
    advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
612

613
    // EditorManager
hjk's avatar
hjk committed
614
    QObject *editorManager = Core::ICore::instance()->editorManager();
615
616
617
618
619
    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
620
621
    connect(theFakeVimSetting(SettingsDialog), SIGNAL(triggered()),
        this, SLOT(showSettingsDialog()));
622
623
    connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
        this, SLOT(setUseFakeVim(QVariant)));
hjk's avatar
hjk committed
624

625
626
627
628
629
630
631
632
633
634
    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()));

635
636
637
638
639
640
    // 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
641
642
643
    return true;
}

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
676
677
678
679
680
681
682
683
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
684
685
void FakeVimPluginPrivate::showSettingsDialog()
{
686
687
    Core::ICore::instance()->showOptionsDialog(QLatin1String(Constants::SETTINGS_CATEGORY),
                                               QLatin1String(Constants::SETTINGS_ID));
hjk's avatar
hjk committed
688
689
}

690
691
692
693
694
695
696
697
698
699
700
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();
}

701
702
703
704
705
706
707
708
709
710
711
712
713
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
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
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;
    }
745
746
747
748
749
    triggerAction(code);
}

void FakeVimPluginPrivate::find(bool reverse)
{
750
751
752
753
754
755
    if (Find::Internal::FindPlugin *plugin = Find::Internal::FindPlugin::instance()) {
        plugin->setUseFakeVim(true);
        plugin->openFindToolBar(reverse
                ? Find::Internal::FindPlugin::FindBackward
                : Find::Internal::FindPlugin::FindForward);
    }
hjk's avatar
hjk committed
756
757
}

758
759
760
761
762
763
764
765
void FakeVimPluginPrivate::findNext(bool reverse)
{
    if (reverse)
        triggerAction(Find::Constants::FIND_PREVIOUS);
    else
        triggerAction(Find::Constants::FIND_NEXT);
}

766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
// 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;
        }
    }
};

790
void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
791
{
792
793
794
    if (!editor)
        return;

795
    QWidget *widget = editor->widget();
796
797
    if (!widget)
        return;
798
799
800
801

    // we can only handle QTextEdit and QPlainTextEdit
    if (!qobject_cast<QTextEdit *>(widget) && !qobject_cast<QPlainTextEdit *>(widget))
        return;
802
    
803
804
805
    //qDebug() << "OPENING: " << editor << editor->widget()
    //    << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();

806
807
808
809
    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);
810
    m_editorToHandler[editor] = handler;
811
812
813
814

    connect(handler, SIGNAL(extraInformationChanged(QString)),
        this, SLOT(showExtraInformation(QString)));
    connect(handler, SIGNAL(commandBufferChanged(QString)),
hjk's avatar
hjk committed
815
        this, SLOT(showCommandBuffer(QString)));
816
817
818
819
    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>)));
820
821
    connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
        this, SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)));
hjk's avatar
hjk committed
822
823
    connect(handler, SIGNAL(indentRegion(int*,int,int,QChar)),
        this, SLOT(indentRegion(int*,int,int,QChar)));
824
825
    connect(handler, SIGNAL(checkForElectricCharacter(bool*,QChar)),
        this, SLOT(checkForElectricCharacter(bool*,QChar)));
826
827
    connect(handler, SIGNAL(completionRequested()),
        this, SLOT(triggerCompletions()));
hjk's avatar
hjk committed
828
829
    connect(handler, SIGNAL(windowCommandRequested(int)),
        this, SLOT(windowCommand(int)));
830
831
    connect(handler, SIGNAL(findRequested(bool)),
        this, SLOT(find(bool)));
832
833
    connect(handler, SIGNAL(findNextRequested(bool)),
        this, SLOT(findNext(bool)));
834

835
836
    connect(handler, SIGNAL(handleExCommandRequested(QString)),
        this, SLOT(handleExCommand(QString)));
837
838
    connect(handler, SIGNAL(handleSetCommandRequested(bool *,QString)),
        this, SLOT(handleSetCommand(bool *,QString)));
839

hjk's avatar
hjk committed
840
    handler->setCurrentFileName(editor->file()->fileName());
841
    handler->installEventFilter();
842
843
844
    
    // pop up the bar
    if (theFakeVimSetting(ConfigUseFakeVim)->value().toBool())
hjk's avatar
hjk committed
845
       showCommandBuffer(QString());
hjk's avatar
hjk committed
846
847
}

848
void FakeVimPluginPrivate::editorAboutToClose(Core::IEditor *editor)
hjk's avatar
hjk committed
849
{
850
851
852
853
854
855
    //qDebug() << "CLOSING: " << editor << editor->widget();
    m_editorToHandler.remove(editor);
}

void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
{
856
    //qDebug() << "SET USE FAKEVIM" << value;
857
    bool on = value.toBool();
858
859
    if (Find::Internal::FindPlugin::instance())
        Find::Internal::FindPlugin::instance()->setUseFakeVim(on);
860
861
862
863
    if (on) {
        Core::EditorManager::instance()->showEditorStatusBar( 
            QLatin1String(Constants::MINI_BUFFER), 
            "vi emulation mode. Type :q to leave. Use , Ctrl-R to trigger run.",
864
            tr("Quit FakeVim"), this, SLOT(quitFakeVim()));
865
866
867
868
869
870
871
872
        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
873
874
}

875
876
877
878
879
880
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
881
882
883
        TextEditor::Internal::CompletionSupport::instance()->
            autoComplete(bt->editableInterface(), false);
   //     bt->triggerCompletions();
884
885
}

886
887
888
889
890
891
892
893
894
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);
}

895
896
void FakeVimPluginPrivate::writeFile(bool *handled,
    const QString &fileName, const QString &contents)
897
{
898
    Q_UNUSED(contents)
899

900
901
902
903
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

904
    Core::IEditor *editor = m_editorToHandler.key(handler);
905
    if (editor && editor->file()->fileName() == fileName) {
hjk's avatar
hjk committed
906
        // Handle that as a special case for nicer interaction with core
907
        Core::IFile *file = editor->file();
hjk's avatar
hjk committed
908
        Core::ICore::instance()->fileManager()->blockFileChange(file);
909
        file->save(fileName);
hjk's avatar
hjk committed
910
        Core::ICore::instance()->fileManager()->unblockFileChange(file);
911
912
        *handled = true;
    } 
913
914
}

915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
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);

930
    if (reWriteAll.indexIn(cmd) != -1) {
931
932
933
934
935
936
937
        // :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
938
            handler->showRedMessage(tr("%n files not saved", 0, failed.size()));
939
940
941
942
943
944
945
946
947
    } 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 {
948
949
950
951
952
953
954
955
956
957
958
        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;
            }
        }

959
        handler->showRedMessage(tr("Not an editor command: %1").arg(cmd));
960
961
962
    }
}

963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
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;
    }
}

978
979
980
981
982
983
984
985
986
987
988
989
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);
}

990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
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;
1005
    } else {
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
        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
1026
void FakeVimPluginPrivate::indentRegion(int *amount, int beginLine, int endLine,
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
      QChar typedChar)
{
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

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

1037
1038
1039
1040
    TextEditor::TabSettings tabSettings;
    tabSettings.m_indentSize = theFakeVimSetting(ConfigShiftWidth)->value().toInt();
    tabSettings.m_tabSize = theFakeVimSetting(ConfigTabStop)->value().toInt();
    tabSettings.m_spacesForTabs = theFakeVimSetting(ConfigExpandTab)->value().toBool();
1041
1042
    typedef SharedTools::Indenter<TextEditor::TextBlockIterator> Indenter;
    Indenter &indenter = Indenter::instance();
hjk's avatar
hjk committed
1043
1044
    indenter.setIndentSize(tabSettings.m_indentSize);
    indenter.setTabSize(tabSettings.m_tabSize);
1045

hjk's avatar
hjk committed
1046
    const QTextDocument *doc = bt->document();
1047
    const TextEditor::TextBlockIterator docStart(doc->begin());
Martin Aumüller's avatar
Martin Aumüller committed
1048
1049
1050
    QTextBlock cur = doc->findBlockByNumber(beginLine);
    for(int i = beginLine; i<= endLine; ++i)
    {
1051
        if (typedChar == 0 && cur.text().simplified().isEmpty()) {
Martin Aumüller's avatar
Martin Aumüller committed
1052
            // clear empty lines
1053
            *amount = 0;
Martin Aumüller's avatar
Martin Aumüller committed
1054
1055
1056
            QTextCursor cursor(cur);
            while (!cursor.atBlockEnd())
                cursor.deleteChar();
1057
1058
1059
1060
        } 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
1061
            tabSettings.indentLine(cur, *amount);
1062
        }
Martin Aumüller's avatar
Martin Aumüller committed
1063
1064
        cur = cur.next();
    }
1065
1066
}

1067
void FakeVimPluginPrivate::quitFakeVim()
1068
{
hjk's avatar
hjk committed
1069
    theFakeVimSetting(ConfigUseFakeVim)->setValue(false);
1070
1071
}

1072
void FakeVimPluginPrivate::showCommandBuffer(const QString &contents)
hjk's avatar
hjk committed
1073
{
1074
1075
1076
    //qDebug() << "SHOW COMMAND BUFFER" << contents;
    Core::EditorManager::instance()->showEditorStatusBar( 
        QLatin1String(Constants::MINI_BUFFER), contents,
1077
        tr("Quit FakeVim"), this, SLOT(quitFakeVim()));
hjk's avatar
hjk committed
1078
1079
}

1080
void FakeVimPluginPrivate::showExtraInformation(const QString &text)
1081
{
1082
1083
1084
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (handler)
        QMessageBox::information(handler->widget(), tr("FakeVim Information"), text);
1085
1086
}

1087
1088
void FakeVimPluginPrivate::changeSelection
    (const QList<QTextEdit::ExtraSelection> &selection)
1089
{
1090
1091
1092
    if (FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender()))
        if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget()))
            bt->setExtraSelections(BaseTextEditor::FakeVimSelection, selection);
1093
1094
}

1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
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);
}
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129

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

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

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

1130
bool FakeVimPlugin::initialize(const QStringList &arguments, QString *errorMessage)
1131
{
1132
1133
    Q_UNUSED(arguments)
    Q_UNUSED(errorMessage)
1134
    return d->initialize();
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
}

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

void FakeVimPlugin::extensionsInitialized()
{
}

#include "fakevimplugin.moc"
hjk's avatar
hjk committed
1147
1148

Q_EXPORT_PLUGIN(FakeVimPlugin)