fakevimplugin.cpp 17.5 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
8
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
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
26
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
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"

hjk's avatar
hjk committed
35

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

#include <utils/qtcassert.h>
hjk's avatar
hjk committed
61
#include <utils/savedaction.h>
hjk's avatar
hjk committed
62

63
64
#include <indenter.h>

hjk's avatar
hjk committed
65
#include <QtCore/QDebug>
66
#include <QtCore/QtPlugin>
hjk's avatar
hjk committed
67
68
69
70
#include <QtCore/QObject>
#include <QtCore/QPoint>
#include <QtCore/QSettings>

71
#include <QtGui/QMessageBox>
hjk's avatar
hjk committed
72
73
74
#include <QtGui/QPlainTextEdit>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
75
#include <QtGui/QTextEdit>
hjk's avatar
hjk committed
76
77
78
79
80
81
82
83
84
85
86


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


namespace FakeVim {
namespace Constants {

87
88
const char * const INSTALL_HANDLER        = "TextEditor.FakeVimHandler";
const char * const MINI_BUFFER            = "TextEditor.FakeVimMiniBuffer";
hjk's avatar
hjk committed
89
90
91
92
93
94
const char * const INSTALL_KEY            = "Alt+V,Alt+V";

} // namespace Constants
} // namespace FakeVim


hjk's avatar
hjk committed
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
///////////////////////////////////////////////////////////////////////
//
// FakeVimOptionPage
//
///////////////////////////////////////////////////////////////////////

namespace FakeVim {
namespace Internal {

class FakeVimOptionPage : public Core::IOptionsPage
{
    Q_OBJECT

public:
    FakeVimOptionPage() {}

    // IOptionsPage
    QString id() const { return QLatin1String("General"); }
    QString trName() const { return tr("General"); }
    QString category() const { return QLatin1String("FakeVim"); }
    QString trCategory() const { return tr("FakeVim"); }

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(ICore::instance()->settings()); }
    void finish() { m_group.finish(); }

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

private:
    friend class DebuggerPlugin;
    Ui::FakeVimOptionPage m_ui;

    Core::Utils::SavedActionSet m_group;
};

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

    m_group.clear();
    m_group.insert(theFakeVimSetting(ConfigUseFakeVim), 
        m_ui.checkBoxUseFakeVim);

    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);

    connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
hjk's avatar
hjk committed
162
        this, SLOT(copyTextEditorSettings()));
hjk's avatar
hjk committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
        this, SLOT(setQtStyle()));
    connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
        this, SLOT(setPlainStyle()));

    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);
    m_ui.checkBoxAutoIndent->setChecked(ts.m_autoIndent);
}

void FakeVimOptionPage::setQtStyle()
{
    m_ui.checkBoxExpandTab->setChecked(true);
    m_ui.lineEditTabStop->setText("4");
    m_ui.lineEditShiftWidth->setText("4");
    m_ui.checkBoxSmartTab->setChecked(true);
    m_ui.checkBoxAutoIndent->setChecked(true);
hjk's avatar
hjk committed
190
    m_ui.lineEditBackspace->setText("indent,eol,start");
hjk's avatar
hjk committed
191
192
193
194
195
196
197
198
199
}

void FakeVimOptionPage::setPlainStyle()
{
    m_ui.checkBoxExpandTab->setChecked(false);
    m_ui.lineEditTabStop->setText("8");
    m_ui.lineEditShiftWidth->setText("8");
    m_ui.checkBoxSmartTab->setChecked(false);
    m_ui.checkBoxAutoIndent->setChecked(false);
hjk's avatar
hjk committed
200
    m_ui.lineEditBackspace->setText(QString());
hjk's avatar
hjk committed
201
202
203
204
205
206
}

} // namespace Internal
} // namespace FakeVim


hjk's avatar
hjk committed
207
208
///////////////////////////////////////////////////////////////////////
//
209
// FakeVimPluginPrivate
hjk's avatar
hjk committed
210
211
212
//
///////////////////////////////////////////////////////////////////////

213
214
215
216
namespace FakeVim {
namespace Internal {

class FakeVimPluginPrivate : public QObject
hjk's avatar
hjk committed
217
{
218
219
220
221
222
223
224
    Q_OBJECT

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

225
    bool initialize();
226
227
228
229
230
    void shutdown();

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

hjk's avatar
hjk committed
232
    void installHandlerOnCurrentEditor();
233
234
    void installHandler(Core::IEditor *editor);
    void removeHandler();
235
    void triggerCompletions();
hjk's avatar
hjk committed
236
    void showSettingsDialog();
237
238
239
240
241

    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);
242
    void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
hjk's avatar
hjk committed
243
    void indentRegion(int *amount, int beginLine, int endLine,  QChar typedChar);
244
245
246
247

private:
    FakeVimPlugin *q;
    QAction *m_installHandlerAction; 
hjk's avatar
hjk committed
248
    FakeVimOptionPage *m_fakeVimOptionsPage;
249
250
251
252
253
254
255
256
257
};

} // namespace Internal
} // namespace FakeVim

FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
{       
    q = plugin;
    m_installHandlerAction = 0;
hjk's avatar
hjk committed
258
    m_fakeVimOptionsPage = 0;
hjk's avatar
hjk committed
259
260
}

261
262
263
FakeVimPluginPrivate::~FakeVimPluginPrivate()
{
}
hjk's avatar
hjk committed
264

265
void FakeVimPluginPrivate::shutdown()
hjk's avatar
hjk committed
266
{
hjk's avatar
hjk committed
267
268
269
270
    q->removeObject(m_fakeVimOptionsPage);
    delete m_fakeVimOptionsPage;
    m_fakeVimOptionsPage = 0;
    theFakeVimSettings()->writeSettings(Core::ICore::instance()->settings());
hjk's avatar
hjk committed
271
272
}

273
bool FakeVimPluginPrivate::initialize()
hjk's avatar
hjk committed
274
{
hjk's avatar
hjk committed
275
    Core::ActionManager *actionManager = Core::ICore::instance()->actionManager();
hjk's avatar
hjk committed
276
277
278
279
280
281
282
    QTC_ASSERT(actionManager, return false);

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

    m_installHandlerAction = new QAction(this);
    m_installHandlerAction->setText(tr("Set vi-Style Keyboard Action Handler"));
hjk's avatar
hjk committed
283
284
285
286

    m_fakeVimOptionsPage = new FakeVimOptionPage;
    q->addObject(m_fakeVimOptionsPage);
    theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
hjk's avatar
hjk committed
287
    
con's avatar
con committed
288
    Core::Command *cmd = 0;
hjk's avatar
hjk committed
289
290
291
292
    cmd = actionManager->registerAction(m_installHandlerAction,
        Constants::INSTALL_HANDLER, globalcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::INSTALL_KEY));

293
    ActionContainer *advancedMenu =
hjk's avatar
hjk committed
294
        actionManager->actionContainer(Core::Constants::M_EDIT_ADVANCED);
295
    advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
296
297

    connect(m_installHandlerAction, SIGNAL(triggered()),
hjk's avatar
hjk committed
298
        this, SLOT(installHandlerOnCurrentEditor()));
299
300

    // EditorManager
hjk's avatar
hjk committed
301
    QObject *editorManager = Core::ICore::instance()->editorManager();
302
303
304
305
306
    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
307
308
309
    connect(theFakeVimSetting(SettingsDialog), SIGNAL(triggered()),
        this, SLOT(showSettingsDialog()));

hjk's avatar
hjk committed
310
311
312
    return true;
}

hjk's avatar
hjk committed
313
314
315
316
317
void FakeVimPluginPrivate::showSettingsDialog()
{
    Core::ICore::instance()->showOptionsDialog("FakeVim", "General");
}

318
void FakeVimPluginPrivate::installHandler(Core::IEditor *editor)
319
{
320
321
322
    if (!editor)
        return;

323
    QWidget *widget = editor->widget();
324
325
    if (!widget)
        return;
326
327
328
329

    // we can only handle QTextEdit and QPlainTextEdit
    if (!qobject_cast<QTextEdit *>(widget) && !qobject_cast<QPlainTextEdit *>(widget))
        return;
330
    
331
    FakeVimHandler *handler = new FakeVimHandler(widget, widget);
332
333
334
335

    connect(handler, SIGNAL(extraInformationChanged(QString)),
        this, SLOT(showExtraInformation(QString)));
    connect(handler, SIGNAL(commandBufferChanged(QString)),
hjk's avatar
hjk committed
336
        this, SLOT(showCommandBuffer(QString)));
337
338
339
340
341
342
    connect(handler, SIGNAL(quitRequested()),
        this, SLOT(removeHandler()), Qt::QueuedConnection);
    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>)));
343
344
    connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
        this, SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)));
hjk's avatar
hjk committed
345
346
    connect(handler, SIGNAL(indentRegion(int*,int,int,QChar)),
        this, SLOT(indentRegion(int*,int,int,QChar)));
347
348
    connect(handler, SIGNAL(completionRequested()),
        this, SLOT(triggerCompletions()));
349
350
351

    handler->setupWidget();
    handler->setExtraData(editor);
hjk's avatar
hjk committed
352
    handler->setCurrentFileName(editor->file()->fileName());
hjk's avatar
hjk committed
353
354
}

hjk's avatar
hjk committed
355
356
357
358
359
void FakeVimPluginPrivate::installHandlerOnCurrentEditor()
{
    installHandler(EditorManager::instance()->currentEditor());
}

360
361
362
363
364
365
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
366
367
368
        TextEditor::Internal::CompletionSupport::instance()->
            autoComplete(bt->editableInterface(), false);
   //     bt->triggerCompletions();
369
370
}

371
372
void FakeVimPluginPrivate::writeFile(bool *handled,
    const QString &fileName, const QString &contents)
373
{
374
375
    Q_UNUSED(contents);

376
377
378
379
380
381
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

    Core::IEditor *editor = qobject_cast<Core::IEditor *>(handler->extraData());
    if (editor && editor->file()->fileName() == fileName) {
hjk's avatar
hjk committed
382
        // Handle that as a special case for nicer interaction with core
383
        Core::IFile *file = editor->file();
hjk's avatar
hjk committed
384
        Core::ICore::instance()->fileManager()->blockFileChange(file);
385
        file->save(fileName);
hjk's avatar
hjk committed
386
        Core::ICore::instance()->fileManager()->unblockFileChange(file);
387
388
        *handled = true;
    } 
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
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;
   } else {
        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
427
void FakeVimPluginPrivate::indentRegion(int *amount, int beginLine, int endLine,
428
429
430
431
432
433
434
435
436
437
      QChar typedChar)
{
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

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

hjk's avatar
hjk committed
438
439
    TextEditor::TabSettings tabSettings = 
        TextEditor::TextEditorSettings::instance()->tabSettings();
440
441
    typedef SharedTools::Indenter<TextEditor::TextBlockIterator> Indenter;
    Indenter &indenter = Indenter::instance();
hjk's avatar
hjk committed
442
443
    indenter.setIndentSize(tabSettings.m_indentSize);
    indenter.setTabSize(tabSettings.m_tabSize);
444

hjk's avatar
hjk committed
445
446
447
    const QTextDocument *doc = bt->document();
    QTextBlock begin = doc->findBlockByNumber(beginLine);
    QTextBlock end = doc->findBlockByNumber(endLine);
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
    const TextEditor::TextBlockIterator docStart(doc->begin());
    QTextBlock cur = begin;
    do {
        if (typedChar == 0 && cur.text().simplified().isEmpty()) {
            *amount = 0;
            if (cur != end) {
                QTextCursor cursor(cur);
                while (!cursor.atBlockEnd())
                    cursor.deleteChar();
            }
        } else {
            const TextEditor::TextBlockIterator current(cur);
            const TextEditor::TextBlockIterator next(cur.next());
            *amount = indenter.indentForBottomLine(current, docStart, next, typedChar);
            if (cur != end)
hjk's avatar
hjk committed
463
                tabSettings.indentLine(cur, *amount);
464
465
466
467
468
469
        }
        if (cur != end)
           cur = cur.next();
    } while (cur != end);
}

470
void FakeVimPluginPrivate::removeHandler()
hjk's avatar
hjk committed
471
{
472
473
474
475
    if (FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender())) {
        handler->restoreWidget();
        handler->deleteLater();
    }
hjk's avatar
hjk committed
476
    Core::EditorManager::instance()->hideEditorStatusBar(
hjk's avatar
hjk committed
477
        QLatin1String(Constants::MINI_BUFFER));
hjk's avatar
hjk committed
478
479
}

480
void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
481
482
{
    //qDebug() << "OPENING: " << editor << editor->widget();
483
484
485
486
    QSettings *s = ICore::instance()->settings();
    bool automatic = s->value("textInteractionSettings/UseVim").toBool();
    if (automatic)
       installHandler(editor);
487
488
}

489
void FakeVimPluginPrivate::editorAboutToClose(Core::IEditor *editor)
490
{
hjk's avatar
hjk committed
491
    //qDebug() << "CLOSING: " << editor << editor->widget();
492
    Q_UNUSED(editor);
493
494
}

495
void FakeVimPluginPrivate::showCommandBuffer(const QString &contents)
hjk's avatar
hjk committed
496
{
497
498
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (handler) {
499
500
        //qDebug() << "SHOW COMMAND BUFFER" << contents;
        Core::EditorManager::instance()->showEditorStatusBar( 
501
502
            QLatin1String(Constants::MINI_BUFFER), contents,
            tr("Quit FakeVim"), handler, SLOT(quit()));
503
504
    } else {
        qDebug() << "\nNO HANDLER\n";
505
    }
hjk's avatar
hjk committed
506
507
}

508
void FakeVimPluginPrivate::showExtraInformation(const QString &text)
509
{
510
511
512
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (handler)
        QMessageBox::information(handler->widget(), tr("FakeVim Information"), text);
513
514
}

515
516
void FakeVimPluginPrivate::changeSelection
    (const QList<QTextEdit::ExtraSelection> &selection)
517
{
518
519
520
    if (FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender()))
        if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget()))
            bt->setExtraSelections(BaseTextEditor::FakeVimSelection, selection);
521
522
}

523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538

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

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

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

539
bool FakeVimPlugin::initialize(const QStringList &arguments, QString *errorMessage)
540
{
541
542
543
    Q_UNUSED(arguments);
    Q_UNUSED(errorMessage);
    return d->initialize();
544
545
546
547
548
549
550
551
552
553
554
555
}

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

void FakeVimPlugin::extensionsInitialized()
{
}

#include "fakevimplugin.moc"
hjk's avatar
hjk committed
556
557

Q_EXPORT_PLUGIN(FakeVimPlugin)