fakevimplugin.cpp 23.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
** 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"

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 56
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
57
#include <texteditor/textblockiterator.h>
hjk's avatar
hjk committed
58

59 60
#include <find/textfindconstants.h>

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

64 65
#include <indenter.h>

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

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


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


namespace FakeVim {
namespace Constants {

89 90
const char * const INSTALL_HANDLER        = "TextEditor.FakeVimHandler";
const char * const MINI_BUFFER            = "TextEditor.FakeVimMiniBuffer";
hjk's avatar
hjk committed
91
const char * const INSTALL_KEY            = "Alt+V,Alt+V";
92 93
const char * const SETTINGS_CATEGORY      = "D.FakeVim";
const char * const SETTINGS_ID            = "General";
hjk's avatar
hjk committed
94 95 96 97 98

} // namespace Constants
} // namespace FakeVim


hjk's avatar
hjk committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
///////////////////////////////////////////////////////////////////////
//
// FakeVimOptionPage
//
///////////////////////////////////////////////////////////////////////

namespace FakeVim {
namespace Internal {

class FakeVimOptionPage : public Core::IOptionsPage
{
    Q_OBJECT

public:
    FakeVimOptionPage() {}

    // IOptionsPage
116
    QString id() const { return QLatin1String(Constants::SETTINGS_ID); }
hjk's avatar
hjk committed
117
    QString trName() const { return tr("General"); }
118
    QString category() const { return QLatin1String(Constants::SETTINGS_CATEGORY); }
hjk's avatar
hjk committed
119 120 121 122 123
    QString trCategory() const { return tr("FakeVim"); }

    QWidget *createPage(QWidget *parent);
    void apply() { m_group.apply(ICore::instance()->settings()); }
    void finish() { m_group.finish(); }
124
    virtual bool matches(const QString &) const;
hjk's avatar
hjk committed
125 126 127 128 129 130 131 132 133

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

private:
    friend class DebuggerPlugin;
    Ui::FakeVimOptionPage m_ui;
134
    QString m_searchKeywords;
135
    Utils::SavedActionSet m_group;
hjk's avatar
hjk committed
136 137 138 139 140 141 142 143 144
};

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

    m_group.clear();
    m_group.insert(theFakeVimSetting(ConfigUseFakeVim), 
145
        m_ui.groupBox);
hjk's avatar
hjk committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

    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);
165 166
    m_group.insert(theFakeVimSetting(ConfigIncSearch), 
        m_ui.checkBoxIncSearch);
hjk's avatar
hjk committed
167 168

    connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
hjk's avatar
hjk committed
169
        this, SLOT(copyTextEditorSettings()));
hjk's avatar
hjk committed
170 171 172 173
    connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
        this, SLOT(setQtStyle()));
    connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
        this, SLOT(setPlainStyle()));
174 175 176 177 178 179 180 181 182
    if (m_searchKeywords.isEmpty()) {
        QTextStream(&m_searchKeywords)
           << ' ' << m_ui.labelAutoIndent->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();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
hjk's avatar
hjk committed
183 184 185 186 187 188 189 190 191 192 193 194 195
    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);
196 197
    // FIXME: Not present in core
    //m_ui.checkBoxIncSearch->setChecked(ts.m_incSearch);
hjk's avatar
hjk committed
198 199 200 201 202
}

void FakeVimOptionPage::setQtStyle()
{
    m_ui.checkBoxExpandTab->setChecked(true);
203 204 205
    const QString four = QString(QLatin1Char('4'));
    m_ui.lineEditTabStop->setText(four);
    m_ui.lineEditShiftWidth->setText(four);
hjk's avatar
hjk committed
206 207
    m_ui.checkBoxSmartTab->setChecked(true);
    m_ui.checkBoxAutoIndent->setChecked(true);
208
    m_ui.checkBoxIncSearch->setChecked(true);
209
    m_ui.lineEditBackspace->setText(QLatin1String("indent,eol,start"));
hjk's avatar
hjk committed
210 211 212 213 214
}

void FakeVimOptionPage::setPlainStyle()
{
    m_ui.checkBoxExpandTab->setChecked(false);
215 216 217
    const QString eight = QString(QLatin1Char('4'));
    m_ui.lineEditTabStop->setText(eight);
    m_ui.lineEditShiftWidth->setText(eight);
hjk's avatar
hjk committed
218 219
    m_ui.checkBoxSmartTab->setChecked(false);
    m_ui.checkBoxAutoIndent->setChecked(false);
220
    m_ui.checkBoxIncSearch->setChecked(false);
hjk's avatar
hjk committed
221
    m_ui.lineEditBackspace->setText(QString());
hjk's avatar
hjk committed
222 223
}

224 225 226 227 228
bool FakeVimOptionPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}

hjk's avatar
hjk committed
229 230 231 232
} // namespace Internal
} // namespace FakeVim


hjk's avatar
hjk committed
233 234
///////////////////////////////////////////////////////////////////////
//
235
// FakeVimPluginPrivate
hjk's avatar
hjk committed
236 237 238
//
///////////////////////////////////////////////////////////////////////

239 240 241 242
namespace FakeVim {
namespace Internal {

class FakeVimPluginPrivate : public QObject
hjk's avatar
hjk committed
243
{
244 245 246 247 248 249 250
    Q_OBJECT

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

251
    bool initialize();
252 253 254 255 256
    void shutdown();

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

258
    void setUseFakeVim(const QVariant &value);
259
    void quitFakeVim();
260
    void triggerCompletions();
hjk's avatar
hjk committed
261
    void windowCommand(int key);
262
    void find(bool reverse);
263
    void findNext(bool reverse);
hjk's avatar
hjk committed
264
    void showSettingsDialog();
265 266 267 268 269

    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);
270
    void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
hjk's avatar
hjk committed
271
    void indentRegion(int *amount, int beginLine, int endLine,  QChar typedChar);
272 273 274 275 276 277 278 279
    void handleExCommand(const QString &cmd);

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

signals:
    void delayedQuitRequested(bool forced, Core::IEditor *editor);
    void delayedQuitAllRequested(bool forced);
280 281 282

private:
    FakeVimPlugin *q;
hjk's avatar
hjk committed
283
    FakeVimOptionPage *m_fakeVimOptionsPage;
284
    QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
285 286

    void triggerAction(const QString& code);
287 288 289 290 291 292 293 294
};

} // namespace Internal
} // namespace FakeVim

FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
{       
    q = plugin;
hjk's avatar
hjk committed
295
    m_fakeVimOptionsPage = 0;
hjk's avatar
hjk committed
296 297
}

298 299 300
FakeVimPluginPrivate::~FakeVimPluginPrivate()
{
}
hjk's avatar
hjk committed
301

302
void FakeVimPluginPrivate::shutdown()
hjk's avatar
hjk committed
303
{
hjk's avatar
hjk committed
304 305 306 307
    q->removeObject(m_fakeVimOptionsPage);
    delete m_fakeVimOptionsPage;
    m_fakeVimOptionsPage = 0;
    theFakeVimSettings()->writeSettings(Core::ICore::instance()->settings());
dt's avatar
dt committed
308
    delete theFakeVimSettings();
hjk's avatar
hjk committed
309 310
}

311
bool FakeVimPluginPrivate::initialize()
hjk's avatar
hjk committed
312
{
hjk's avatar
hjk committed
313
    Core::ActionManager *actionManager = Core::ICore::instance()->actionManager();
hjk's avatar
hjk committed
314 315 316 317 318
    QTC_ASSERT(actionManager, return false);

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

hjk's avatar
hjk committed
319 320 321
    m_fakeVimOptionsPage = new FakeVimOptionPage;
    q->addObject(m_fakeVimOptionsPage);
    theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
hjk's avatar
hjk committed
322
    
con's avatar
con committed
323
    Core::Command *cmd = 0;
324
    cmd = actionManager->registerAction(theFakeVimSetting(ConfigUseFakeVim),
hjk's avatar
hjk committed
325 326 327
        Constants::INSTALL_HANDLER, globalcontext);
    cmd->setDefaultKeySequence(QKeySequence(Constants::INSTALL_KEY));

328
    ActionContainer *advancedMenu =
hjk's avatar
hjk committed
329
        actionManager->actionContainer(Core::Constants::M_EDIT_ADVANCED);
330
    advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
hjk's avatar
hjk committed
331

332
    // EditorManager
hjk's avatar
hjk committed
333
    QObject *editorManager = Core::ICore::instance()->editorManager();
334 335 336 337 338
    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
339 340
    connect(theFakeVimSetting(SettingsDialog), SIGNAL(triggered()),
        this, SLOT(showSettingsDialog()));
341 342
    connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
        this, SLOT(setUseFakeVim(QVariant)));
hjk's avatar
hjk committed
343

344 345 346 347 348 349
    // 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
350 351 352
    return true;
}

hjk's avatar
hjk committed
353 354
void FakeVimPluginPrivate::showSettingsDialog()
{
355 356
    Core::ICore::instance()->showOptionsDialog(QLatin1String(Constants::SETTINGS_CATEGORY),
                                               QLatin1String(Constants::SETTINGS_ID));
hjk's avatar
hjk committed
357 358
}

359 360 361 362 363 364 365 366 367 368 369
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();
}

hjk's avatar
hjk committed
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
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;
    }
401 402 403 404 405
    triggerAction(code);
}

void FakeVimPluginPrivate::find(bool reverse)
{
406
    Q_UNUSED(reverse)  // TODO: Creator needs an action for find in reverse.
407
    triggerAction(Find::Constants::FIND_IN_DOCUMENT);
hjk's avatar
hjk committed
408 409
}

410 411 412 413 414 415 416 417
void FakeVimPluginPrivate::findNext(bool reverse)
{
    if (reverse)
        triggerAction(Find::Constants::FIND_PREVIOUS);
    else
        triggerAction(Find::Constants::FIND_NEXT);
}

418
void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
419
{
420 421 422
    if (!editor)
        return;

423
    QWidget *widget = editor->widget();
424 425
    if (!widget)
        return;
426 427 428 429

    // we can only handle QTextEdit and QPlainTextEdit
    if (!qobject_cast<QTextEdit *>(widget) && !qobject_cast<QPlainTextEdit *>(widget))
        return;
430
    
431 432 433
    //qDebug() << "OPENING: " << editor << editor->widget()
    //    << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();

434
    FakeVimHandler *handler = new FakeVimHandler(widget, widget);
435
    m_editorToHandler[editor] = handler;
436 437 438 439

    connect(handler, SIGNAL(extraInformationChanged(QString)),
        this, SLOT(showExtraInformation(QString)));
    connect(handler, SIGNAL(commandBufferChanged(QString)),
hjk's avatar
hjk committed
440
        this, SLOT(showCommandBuffer(QString)));
441 442 443 444
    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>)));
445 446
    connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
        this, SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)));
hjk's avatar
hjk committed
447 448
    connect(handler, SIGNAL(indentRegion(int*,int,int,QChar)),
        this, SLOT(indentRegion(int*,int,int,QChar)));
449 450
    connect(handler, SIGNAL(completionRequested()),
        this, SLOT(triggerCompletions()));
hjk's avatar
hjk committed
451 452
    connect(handler, SIGNAL(windowCommandRequested(int)),
        this, SLOT(windowCommand(int)));
453 454
    connect(handler, SIGNAL(findRequested(bool)),
        this, SLOT(find(bool)));
455 456
    connect(handler, SIGNAL(findNextRequested(bool)),
        this, SLOT(findNext(bool)));
457

458 459 460
    connect(handler, SIGNAL(handleExCommandRequested(QString)),
        this, SLOT(handleExCommand(QString)));

hjk's avatar
hjk committed
461
    handler->setCurrentFileName(editor->file()->fileName());
462
    handler->installEventFilter();
463 464 465 466
    
    // pop up the bar
    if (theFakeVimSetting(ConfigUseFakeVim)->value().toBool())
       showCommandBuffer("");
hjk's avatar
hjk committed
467 468
}

469
void FakeVimPluginPrivate::editorAboutToClose(Core::IEditor *editor)
hjk's avatar
hjk committed
470
{
471 472 473 474 475 476
    //qDebug() << "CLOSING: " << editor << editor->widget();
    m_editorToHandler.remove(editor);
}

void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
{
477
    //qDebug() << "SET USE FAKEVIM" << value;
478 479 480 481 482
    bool on = value.toBool();
    if (on) {
        Core::EditorManager::instance()->showEditorStatusBar( 
            QLatin1String(Constants::MINI_BUFFER), 
            "vi emulation mode. Type :q to leave. Use , Ctrl-R to trigger run.",
483
            tr("Quit FakeVim"), this, SLOT(quitFakeVim()));
484 485 486 487 488 489 490 491
        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
492 493
}

494 495 496 497 498 499
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
500 501 502
        TextEditor::Internal::CompletionSupport::instance()->
            autoComplete(bt->editableInterface(), false);
   //     bt->triggerCompletions();
503 504
}

505 506
void FakeVimPluginPrivate::writeFile(bool *handled,
    const QString &fileName, const QString &contents)
507
{
508
    Q_UNUSED(contents)
509

510 511 512 513
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (!handler)
        return;

514
    Core::IEditor *editor = m_editorToHandler.key(handler);
515
    if (editor && editor->file()->fileName() == fileName) {
hjk's avatar
hjk committed
516
        // Handle that as a special case for nicer interaction with core
517
        Core::IFile *file = editor->file();
hjk's avatar
hjk committed
518
        Core::ICore::instance()->fileManager()->blockFileChange(file);
519
        file->save(fileName);
hjk's avatar
hjk committed
520
        Core::ICore::instance()->fileManager()->unblockFileChange(file);
521 522
        *handled = true;
    } 
523 524
}

525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
{
    static QRegExp reNextFile("^n(ext)?!?( (.*))?$");
    static QRegExp rePreviousFile("^(N(ext)?|prev(ious)?)!?( (.*))?$");
    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);

    if (reNextFile.indexIn(cmd) != -1) {
        // :n
        editorManager->goForwardInNavigationHistory();
    } else if (rePreviousFile.indexIn(cmd) != -1) {
        // :N, :prev
        editorManager->goBackInNavigationHistory();
    } else if (reWriteAll.indexIn(cmd) != -1) {
        // :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
556
            handler->showRedMessage(tr("%n files not saved", 0, failed.size()));
557 558 559 560 561 562 563 564 565
    } 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 {
566
        handler->showRedMessage(tr("Not an editor command: %1").arg(cmd));
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
    }
}

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

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
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;
597
    } else {
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
        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
618
void FakeVimPluginPrivate::indentRegion(int *amount, int beginLine, int endLine,
619 620 621 622 623 624 625 626 627 628
      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
629 630
    TextEditor::TabSettings tabSettings = 
        TextEditor::TextEditorSettings::instance()->tabSettings();
631 632
    typedef SharedTools::Indenter<TextEditor::TextBlockIterator> Indenter;
    Indenter &indenter = Indenter::instance();
hjk's avatar
hjk committed
633 634
    indenter.setIndentSize(tabSettings.m_indentSize);
    indenter.setTabSize(tabSettings.m_tabSize);
635

hjk's avatar
hjk committed
636
    const QTextDocument *doc = bt->document();
637
    const TextEditor::TextBlockIterator docStart(doc->begin());
Martin Aumüller's avatar
Martin Aumüller committed
638 639 640
    QTextBlock cur = doc->findBlockByNumber(beginLine);
    for(int i = beginLine; i<= endLine; ++i)
    {
641
        if (typedChar == 0 && cur.text().simplified().isEmpty()) {
Martin Aumüller's avatar
Martin Aumüller committed
642
            // clear empty lines
643
            *amount = 0;
Martin Aumüller's avatar
Martin Aumüller committed
644 645 646
            QTextCursor cursor(cur);
            while (!cursor.atBlockEnd())
                cursor.deleteChar();
647 648 649 650
        } 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
651
            tabSettings.indentLine(cur, *amount);
652
        }
Martin Aumüller's avatar
Martin Aumüller committed
653 654
        cur = cur.next();
    }
655 656
}

657
void FakeVimPluginPrivate::quitFakeVim()
658
{
hjk's avatar
hjk committed
659
    theFakeVimSetting(ConfigUseFakeVim)->setValue(false);
660 661
}

662
void FakeVimPluginPrivate::showCommandBuffer(const QString &contents)
hjk's avatar
hjk committed
663
{
664 665 666
    //qDebug() << "SHOW COMMAND BUFFER" << contents;
    Core::EditorManager::instance()->showEditorStatusBar( 
        QLatin1String(Constants::MINI_BUFFER), contents,
667
        tr("Quit FakeVim"), this, SLOT(quitFakeVim()));
hjk's avatar
hjk committed
668 669
}

670
void FakeVimPluginPrivate::showExtraInformation(const QString &text)
671
{
672 673 674
    FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
    if (handler)
        QMessageBox::information(handler->widget(), tr("FakeVim Information"), text);
675 676
}

677 678
void FakeVimPluginPrivate::changeSelection
    (const QList<QTextEdit::ExtraSelection> &selection)
679
{
680 681 682
    if (FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender()))
        if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget()))
            bt->setExtraSelections(BaseTextEditor::FakeVimSelection, selection);
683 684
}

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700

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

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

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

701
bool FakeVimPlugin::initialize(const QStringList &arguments, QString *errorMessage)
702
{
703 704
    Q_UNUSED(arguments)
    Q_UNUSED(errorMessage)
705
    return d->initialize();
706 707 708 709 710 711 712 713 714 715 716 717
}

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

void FakeVimPlugin::extensionsInitialized()
{
}

#include "fakevimplugin.moc"
hjk's avatar
hjk committed
718 719

Q_EXPORT_PLUGIN(FakeVimPlugin)