forked from qt-creator/qt-creator
Currently we pass in some places by value, elsewhere by const ref and for some weird reason also by const value in a lot of places. The latter is particularly annoying, as it is also used in interfaces and therefore forces all implementors to do the same, since leaving the "const" off is causing compiler warnings with MSVC. Change-Id: I65b87dc3cce0986b8a55ff6119cb752361027803 Reviewed-by: hjk <hjk121@nokiamail.com>
2294 lines
77 KiB
C++
2294 lines
77 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
|
** Contact: http://www.qt-project.org/legal
|
|
**
|
|
** This file is part of Qt Creator.
|
|
**
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** 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.
|
|
**
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "fakevimplugin.h"
|
|
|
|
#include "fakevimactions.h"
|
|
#include "fakevimhandler.h"
|
|
#include "ui_fakevimoptions.h"
|
|
|
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
|
#include <coreplugin/actionmanager/command.h>
|
|
#include <coreplugin/actionmanager/command.h>
|
|
#include <coreplugin/actionmanager/commandmappings.h>
|
|
#include <coreplugin/coreconstants.h>
|
|
#include <coreplugin/dialogs/ioptionspage.h>
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
#include <coreplugin/editormanager/documentmodel.h>
|
|
#include <coreplugin/find/findplugin.h>
|
|
#include <coreplugin/find/textfindconstants.h>
|
|
#include <coreplugin/find/ifindsupport.h>
|
|
#include <coreplugin/documentmanager.h>
|
|
#include <coreplugin/icore.h>
|
|
#include <coreplugin/idocument.h>
|
|
#include <coreplugin/messagemanager.h>
|
|
#include <coreplugin/id.h>
|
|
#include <coreplugin/statusbarwidget.h>
|
|
#include <coreplugin/statusbarmanager.h>
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
#include <texteditor/basetextdocumentlayout.h>
|
|
#include <texteditor/basetexteditor.h>
|
|
#include <texteditor/basetextmark.h>
|
|
#include <texteditor/texteditorconstants.h>
|
|
#include <texteditor/typingsettings.h>
|
|
#include <texteditor/tabsettings.h>
|
|
#include <texteditor/icodestylepreferences.h>
|
|
#include <texteditor/texteditorsettings.h>
|
|
#include <texteditor/indenter.h>
|
|
#include <texteditor/codeassist/basicproposalitem.h>
|
|
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
|
|
#include <texteditor/codeassist/completionassistprovider.h>
|
|
#include <texteditor/codeassist/iassistprocessor.h>
|
|
#include <texteditor/codeassist/iassistinterface.h>
|
|
#include <texteditor/codeassist/genericproposal.h>
|
|
|
|
#include <utils/fancylineedit.h>
|
|
#include <utils/hostosinfo.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/pathchooser.h>
|
|
#include <utils/qtcoverride.h>
|
|
#include <utils/savedaction.h>
|
|
#include <utils/stylehelper.h>
|
|
|
|
#include <cpptools/cpptoolsconstants.h>
|
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
#include <QAbstractTableModel>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QFileDialog>
|
|
#include <QtPlugin>
|
|
#include <QObject>
|
|
#include <QPainter>
|
|
#include <QPointer>
|
|
#include <QSettings>
|
|
#include <QScrollBar>
|
|
#include <QStackedWidget>
|
|
#include <QTextStream>
|
|
|
|
#include <QDesktopServices>
|
|
#include <QItemDelegate>
|
|
#include <QPlainTextEdit>
|
|
#include <QShortcut>
|
|
#include <QTextBlock>
|
|
#include <QTextCursor>
|
|
#include <QTextEdit>
|
|
#include <QTimer>
|
|
#include <QTreeWidgetItem>
|
|
|
|
using namespace TextEditor;
|
|
using namespace Core;
|
|
|
|
namespace FakeVim {
|
|
namespace Internal {
|
|
|
|
const char INSTALL_HANDLER[] = "TextEditor.FakeVimHandler";
|
|
const char SETTINGS_CATEGORY[] = "D.FakeVim";
|
|
const char SETTINGS_CATEGORY_FAKEVIM_ICON[] = ":/fakevim/images/category_fakevim.png";
|
|
const char SETTINGS_ID[] = "A.General";
|
|
const char SETTINGS_EX_CMDS_ID[] = "B.ExCommands";
|
|
const char SETTINGS_USER_CMDS_ID[] = "C.UserCommands";
|
|
typedef QLatin1String _;
|
|
|
|
class MiniBuffer : public QStackedWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
MiniBuffer()
|
|
: m_label(new QLabel(this))
|
|
, m_edit(new QLineEdit(this))
|
|
, m_eventFilter(0)
|
|
, m_lastMessageLevel(MessageMode)
|
|
{
|
|
connect(m_edit, SIGNAL(textEdited(QString)), SLOT(changed()));
|
|
connect(m_edit, SIGNAL(cursorPositionChanged(int,int)), SLOT(changed()));
|
|
connect(m_edit, SIGNAL(selectionChanged()), SLOT(changed()));
|
|
m_label->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
|
|
|
addWidget(m_label);
|
|
addWidget(m_edit);
|
|
|
|
m_hideTimer.setSingleShot(true);
|
|
m_hideTimer.setInterval(8000);
|
|
connect(&m_hideTimer, SIGNAL(timeout()), SLOT(hide()));
|
|
}
|
|
|
|
void setContents(const QString &contents, int cursorPos, int anchorPos,
|
|
int messageLevel, QObject *eventFilter)
|
|
{
|
|
if (cursorPos != -1) {
|
|
m_edit->blockSignals(true);
|
|
m_label->clear();
|
|
m_edit->setText(contents);
|
|
if (anchorPos != -1 && anchorPos != cursorPos)
|
|
m_edit->setSelection(anchorPos, cursorPos - anchorPos);
|
|
else
|
|
m_edit->setCursorPosition(cursorPos);
|
|
m_edit->blockSignals(false);
|
|
setCurrentWidget(m_edit);
|
|
m_edit->setFocus();
|
|
} else {
|
|
if (contents.isEmpty()) {
|
|
if (m_lastMessageLevel == MessageMode)
|
|
hide();
|
|
else
|
|
m_hideTimer.start();
|
|
} else {
|
|
m_hideTimer.stop();
|
|
show();
|
|
|
|
m_label->setText(contents);
|
|
|
|
QString css;
|
|
if (messageLevel == MessageError) {
|
|
css = _("border:1px solid rgba(255,255,255,150);"
|
|
"background-color:rgba(255,0,0,100);");
|
|
} else if (messageLevel == MessageWarning) {
|
|
css = _("border:1px solid rgba(255,255,255,120);"
|
|
"background-color:rgba(255,255,0,20);");
|
|
} else if (messageLevel == MessageShowCmd) {
|
|
css = _("border:1px solid rgba(255,255,255,120);"
|
|
"background-color:rgba(100,255,100,30);");
|
|
}
|
|
m_label->setStyleSheet(QString::fromLatin1(
|
|
"*{border-radius:2px;padding-left:4px;padding-right:4px;%1}").arg(css));
|
|
}
|
|
|
|
if (m_edit->hasFocus())
|
|
emit edited(QString(), -1, -1);
|
|
|
|
setCurrentWidget(m_label);
|
|
}
|
|
|
|
if (m_eventFilter != eventFilter) {
|
|
if (m_eventFilter != 0) {
|
|
m_edit->removeEventFilter(m_eventFilter);
|
|
disconnect(SIGNAL(edited(QString,int,int)));
|
|
}
|
|
if (eventFilter != 0) {
|
|
m_edit->installEventFilter(eventFilter);
|
|
connect(this, SIGNAL(edited(QString,int,int)),
|
|
eventFilter, SLOT(miniBufferTextEdited(QString,int,int)));
|
|
}
|
|
m_eventFilter = eventFilter;
|
|
}
|
|
|
|
m_lastMessageLevel = messageLevel;
|
|
}
|
|
|
|
QSize sizeHint() const
|
|
{
|
|
QSize size = QWidget::sizeHint();
|
|
// reserve maximal width for line edit widget
|
|
return currentWidget() == m_edit ? QSize(maximumWidth(), size.height()) : size;
|
|
}
|
|
|
|
signals:
|
|
void edited(const QString &text, int cursorPos, int anchorPos);
|
|
|
|
private slots:
|
|
void changed()
|
|
{
|
|
const int cursorPos = m_edit->cursorPosition();
|
|
int anchorPos = m_edit->selectionStart();
|
|
if (anchorPos == cursorPos)
|
|
anchorPos = cursorPos + m_edit->selectedText().length();
|
|
emit edited(m_edit->text(), cursorPos, anchorPos);
|
|
}
|
|
|
|
private:
|
|
QLabel *m_label;
|
|
QLineEdit *m_edit;
|
|
QObject *m_eventFilter;
|
|
QTimer m_hideTimer;
|
|
int m_lastMessageLevel;
|
|
};
|
|
|
|
class RelativeNumbersColumn : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
RelativeNumbersColumn(BaseTextEditorWidget *baseTextEditor)
|
|
: QWidget(baseTextEditor)
|
|
, m_currentPos(0)
|
|
, m_lineSpacing(0)
|
|
, m_editor(baseTextEditor)
|
|
{
|
|
setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
|
|
|
m_timerUpdate.setSingleShot(true);
|
|
m_timerUpdate.setInterval(0);
|
|
connect(&m_timerUpdate, SIGNAL(timeout()), SLOT(followEditorLayout()));
|
|
updateOnSignal(m_editor, SIGNAL(cursorPositionChanged()));
|
|
updateOnSignal(m_editor->verticalScrollBar(), SIGNAL(valueChanged(int)));
|
|
updateOnSignal(m_editor->document(), SIGNAL(contentsChanged()));
|
|
updateOnSignal(TextEditorSettings::instance(),
|
|
SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)));
|
|
|
|
m_editor->installEventFilter(this);
|
|
|
|
followEditorLayout();
|
|
}
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent *event)
|
|
{
|
|
QTextCursor firstVisibleCursor = m_editor->cursorForPosition(QPoint(0, 0));
|
|
QTextBlock firstVisibleBlock = firstVisibleCursor.block();
|
|
if (firstVisibleCursor.positionInBlock() > 0) {
|
|
firstVisibleBlock = firstVisibleBlock.next();
|
|
firstVisibleCursor.setPosition(firstVisibleBlock.position());
|
|
}
|
|
|
|
// Find relative number for the first visible line.
|
|
QTextBlock block = m_editor->textCursor().block();
|
|
bool forward = firstVisibleBlock.blockNumber() > block.blockNumber();
|
|
int n = 0;
|
|
while (block.isValid() && block != firstVisibleBlock) {
|
|
block = forward ? block.next() : block.previous();
|
|
if (block.isVisible())
|
|
n += forward ? 1 : -1;
|
|
}
|
|
|
|
// Copy colors from extra area palette.
|
|
QPainter p(this);
|
|
QPalette pal = m_editor->extraArea()->palette();
|
|
const QColor fg = pal.color(QPalette::Dark);
|
|
const QColor bg = pal.color(QPalette::Background);
|
|
p.setPen(fg);
|
|
|
|
// Draw relative line numbers.
|
|
QRect rect(0, m_editor->cursorRect(firstVisibleCursor).y(), width(), m_lineSpacing);
|
|
bool hideLineNumbers = m_editor->lineNumbersVisible();
|
|
while (block.isValid()) {
|
|
if (block.isVisible()) {
|
|
if (n != 0 && rect.intersects(event->rect())) {
|
|
const int line = qAbs(n);
|
|
const QString number = QString::number(line);
|
|
if (hideLineNumbers)
|
|
p.fillRect(rect, bg);
|
|
if (hideLineNumbers || line < 100)
|
|
p.drawText(rect, Qt::AlignRight | Qt::AlignVCenter, number);
|
|
}
|
|
|
|
rect.translate(0, m_lineSpacing * block.lineCount());
|
|
if (rect.y() > height())
|
|
break;
|
|
|
|
++n;
|
|
}
|
|
|
|
block = block.next();
|
|
}
|
|
}
|
|
|
|
bool eventFilter(QObject *, QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::Resize || event->type() == QEvent::Move)
|
|
m_timerUpdate.start();
|
|
return false;
|
|
}
|
|
|
|
private slots:
|
|
void followEditorLayout()
|
|
{
|
|
QTextCursor tc = m_editor->textCursor();
|
|
m_currentPos = tc.position();
|
|
m_lineSpacing = m_editor->cursorRect(tc).height();
|
|
setFont(m_editor->extraArea()->font());
|
|
|
|
// Follow geometry of normal line numbers if visible,
|
|
// otherwise follow geometry of marks (breakpoints etc.).
|
|
QRect rect = m_editor->extraArea()->geometry().adjusted(0, 0, -3, 0);
|
|
bool marksVisible = m_editor->marksVisible();
|
|
bool lineNumbersVisible = m_editor->lineNumbersVisible();
|
|
bool foldMarksVisible = m_editor->codeFoldingVisible();
|
|
if (marksVisible && lineNumbersVisible)
|
|
rect.setLeft(m_lineSpacing);
|
|
if (foldMarksVisible && (marksVisible || lineNumbersVisible))
|
|
rect.setRight(rect.right() - (m_lineSpacing + m_lineSpacing % 2));
|
|
setGeometry(rect);
|
|
|
|
update();
|
|
}
|
|
|
|
void updateOnSignal(QObject *object, const char *signal)
|
|
{
|
|
connect(object, signal, &m_timerUpdate, SLOT(start()));
|
|
}
|
|
|
|
private:
|
|
int m_currentPos;
|
|
int m_lineSpacing;
|
|
BaseTextEditorWidget *m_editor;
|
|
QTimer m_timerUpdate;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FakeVimOptionPage
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
typedef QMap<QString, QRegExp> ExCommandMap;
|
|
typedef QMap<int, QString> UserCommandMap;
|
|
|
|
class FakeVimOptionPage : public IOptionsPage
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
FakeVimOptionPage()
|
|
{
|
|
setId(SETTINGS_ID);
|
|
setDisplayName(tr("General"));
|
|
setCategory(SETTINGS_CATEGORY);
|
|
setDisplayCategory(tr("FakeVim"));
|
|
setCategoryIcon(_(SETTINGS_CATEGORY_FAKEVIM_ICON));
|
|
}
|
|
|
|
QWidget *widget();
|
|
void apply();
|
|
void finish();
|
|
|
|
private slots:
|
|
void copyTextEditorSettings();
|
|
void setQtStyle();
|
|
void setPlainStyle();
|
|
void updateVimRcWidgets();
|
|
|
|
private:
|
|
friend class DebuggerPlugin;
|
|
QPointer<QWidget> m_widget;
|
|
Ui::FakeVimOptionPage m_ui;
|
|
Utils::SavedActionSet m_group;
|
|
};
|
|
|
|
QWidget *FakeVimOptionPage::widget()
|
|
{
|
|
if (!m_widget) {
|
|
m_widget = new QWidget;
|
|
m_ui.setupUi(m_widget);
|
|
const QString vimrcDefault = Utils::HostOsInfo::isAnyUnixHost() ?
|
|
QLatin1String("$HOME/.vimrc") : QLatin1String("%USERPROFILE%\\_vimrc");
|
|
m_ui.pathChooserVimRcPath->setExpectedKind(Utils::PathChooser::File);
|
|
m_ui.pathChooserVimRcPath->lineEdit()->setToolTip(tr("Keep empty to use the default path, i.e. "
|
|
"%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise."));
|
|
m_ui.pathChooserVimRcPath->lineEdit()->setPlaceholderText(tr("Default: %1").arg(vimrcDefault));
|
|
|
|
m_group.clear();
|
|
m_group.insert(theFakeVimSetting(ConfigUseFakeVim),
|
|
m_ui.checkBoxUseFakeVim);
|
|
m_group.insert(theFakeVimSetting(ConfigReadVimRc),
|
|
m_ui.checkBoxReadVimRc);
|
|
m_group.insert(theFakeVimSetting(ConfigVimRcPath),
|
|
m_ui.pathChooserVimRcPath);
|
|
|
|
m_group.insert(theFakeVimSetting(ConfigExpandTab),
|
|
m_ui.checkBoxExpandTab);
|
|
m_group.insert(theFakeVimSetting(ConfigHlSearch),
|
|
m_ui.checkBoxHlSearch);
|
|
m_group.insert(theFakeVimSetting(ConfigShiftWidth),
|
|
m_ui.spinBoxShiftWidth);
|
|
m_group.insert(theFakeVimSetting(ConfigShowMarks),
|
|
m_ui.checkBoxShowMarks);
|
|
|
|
m_group.insert(theFakeVimSetting(ConfigSmartTab),
|
|
m_ui.checkBoxSmartTab);
|
|
m_group.insert(theFakeVimSetting(ConfigStartOfLine),
|
|
m_ui.checkBoxStartOfLine);
|
|
m_group.insert(theFakeVimSetting(ConfigPassKeys),
|
|
m_ui.checkBoxPassKeys);
|
|
m_group.insert(theFakeVimSetting(ConfigTabStop),
|
|
m_ui.spinBoxTabStop);
|
|
m_group.insert(theFakeVimSetting(ConfigScrollOff),
|
|
m_ui.spinBoxScrollOff);
|
|
m_group.insert(theFakeVimSetting(ConfigBackspace),
|
|
m_ui.lineEditBackspace);
|
|
m_group.insert(theFakeVimSetting(ConfigIsKeyword),
|
|
m_ui.lineEditIsKeyword);
|
|
|
|
m_group.insert(theFakeVimSetting(ConfigPassControlKey),
|
|
m_ui.checkBoxPassControlKey);
|
|
m_group.insert(theFakeVimSetting(ConfigAutoIndent),
|
|
m_ui.checkBoxAutoIndent);
|
|
m_group.insert(theFakeVimSetting(ConfigSmartIndent),
|
|
m_ui.checkBoxSmartIndent);
|
|
|
|
m_group.insert(theFakeVimSetting(ConfigIncSearch),
|
|
m_ui.checkBoxIncSearch);
|
|
m_group.insert(theFakeVimSetting(ConfigUseCoreSearch),
|
|
m_ui.checkBoxUseCoreSearch);
|
|
m_group.insert(theFakeVimSetting(ConfigSmartCase),
|
|
m_ui.checkBoxSmartCase);
|
|
m_group.insert(theFakeVimSetting(ConfigIgnoreCase),
|
|
m_ui.checkBoxIgnoreCase);
|
|
m_group.insert(theFakeVimSetting(ConfigWrapScan),
|
|
m_ui.checkBoxWrapScan);
|
|
|
|
m_group.insert(theFakeVimSetting(ConfigShowCmd),
|
|
m_ui.checkBoxShowCmd);
|
|
|
|
m_group.insert(theFakeVimSetting(ConfigRelativeNumber),
|
|
m_ui.checkBoxRelativeNumber);
|
|
|
|
connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
|
|
SLOT(copyTextEditorSettings()));
|
|
connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
|
|
SLOT(setQtStyle()));
|
|
connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
|
|
SLOT(setPlainStyle()));
|
|
connect(m_ui.checkBoxReadVimRc, SIGNAL(stateChanged(int)),
|
|
SLOT(updateVimRcWidgets()));
|
|
updateVimRcWidgets();
|
|
|
|
}
|
|
return m_widget;
|
|
}
|
|
|
|
void FakeVimOptionPage::apply()
|
|
{
|
|
m_group.apply(ICore::settings());
|
|
}
|
|
|
|
void FakeVimOptionPage::finish()
|
|
{
|
|
m_group.finish();
|
|
delete m_widget;
|
|
}
|
|
|
|
void FakeVimOptionPage::copyTextEditorSettings()
|
|
{
|
|
TabSettings ts = TextEditorSettings::codeStyle()->tabSettings();
|
|
TypingSettings tps = TextEditorSettings::typingSettings();
|
|
m_ui.checkBoxExpandTab->setChecked(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy);
|
|
m_ui.spinBoxTabStop->setValue(ts.m_tabSize);
|
|
m_ui.spinBoxShiftWidth->setValue(ts.m_indentSize);
|
|
m_ui.checkBoxSmartTab->setChecked(
|
|
tps.m_smartBackspaceBehavior == TypingSettings::BackspaceFollowsPreviousIndents);
|
|
m_ui.checkBoxAutoIndent->setChecked(true);
|
|
m_ui.checkBoxSmartIndent->setChecked(tps.m_autoIndent);
|
|
m_ui.checkBoxIncSearch->setChecked(true);
|
|
}
|
|
|
|
void FakeVimOptionPage::setQtStyle()
|
|
{
|
|
m_ui.checkBoxExpandTab->setChecked(true);
|
|
m_ui.spinBoxTabStop->setValue(4);
|
|
m_ui.spinBoxShiftWidth->setValue(4);
|
|
m_ui.checkBoxSmartTab->setChecked(true);
|
|
m_ui.checkBoxAutoIndent->setChecked(true);
|
|
m_ui.checkBoxSmartIndent->setChecked(true);
|
|
m_ui.checkBoxIncSearch->setChecked(true);
|
|
m_ui.lineEditBackspace->setText(_("indent,eol,start"));
|
|
m_ui.checkBoxPassKeys->setChecked(true);
|
|
}
|
|
|
|
void FakeVimOptionPage::setPlainStyle()
|
|
{
|
|
m_ui.checkBoxExpandTab->setChecked(false);
|
|
m_ui.spinBoxTabStop->setValue(8);
|
|
m_ui.spinBoxShiftWidth->setValue(8);
|
|
m_ui.checkBoxSmartTab->setChecked(false);
|
|
m_ui.checkBoxAutoIndent->setChecked(false);
|
|
m_ui.checkBoxSmartIndent->setChecked(false);
|
|
m_ui.checkBoxIncSearch->setChecked(false);
|
|
m_ui.lineEditBackspace->setText(QString());
|
|
m_ui.checkBoxPassKeys->setChecked(false);
|
|
}
|
|
|
|
void FakeVimOptionPage::updateVimRcWidgets()
|
|
{
|
|
m_ui.pathChooserVimRcPath->setEnabled(m_ui.checkBoxReadVimRc->isChecked());
|
|
}
|
|
|
|
//const char *FAKEVIM_CONTEXT = "FakeVim";
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FakeVimExCommandsPage
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
enum { CommandRole = Qt::UserRole };
|
|
|
|
class FakeVimExCommandsPage : public CommandMappings
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
FakeVimExCommandsPage(FakeVimPluginPrivate *q)
|
|
: m_q(q)
|
|
{
|
|
setId(SETTINGS_EX_CMDS_ID);
|
|
setDisplayName(tr("Ex Command Mapping"));
|
|
setCategory(SETTINGS_CATEGORY);
|
|
setDisplayCategory(tr("FakeVim"));
|
|
setCategoryIcon(_(SETTINGS_CATEGORY_FAKEVIM_ICON));
|
|
}
|
|
|
|
QWidget *widget();
|
|
void initialize();
|
|
ExCommandMap &exCommandMap();
|
|
ExCommandMap &defaultExCommandMap();
|
|
|
|
public slots:
|
|
void commandChanged(QTreeWidgetItem *current);
|
|
void targetIdentifierChanged();
|
|
void resetTargetIdentifier();
|
|
void removeTargetIdentifier();
|
|
void defaultAction();
|
|
|
|
private:
|
|
FakeVimPluginPrivate *m_q;
|
|
};
|
|
|
|
QWidget *FakeVimExCommandsPage::widget()
|
|
{
|
|
QWidget *w = CommandMappings::widget();
|
|
setPageTitle(tr("Ex Command Mapping"));
|
|
setTargetHeader(tr("Ex Trigger Expression"));
|
|
setTargetLabelText(tr("Regular expression:"));
|
|
setTargetEditTitle(tr("Ex Command"));
|
|
setImportExportEnabled(false);
|
|
return w;
|
|
}
|
|
|
|
void FakeVimExCommandsPage::initialize()
|
|
{
|
|
QMap<QString, QTreeWidgetItem *> sections;
|
|
|
|
foreach (Command *c, ActionManager::commands()) {
|
|
if (c->action() && c->action()->isSeparator())
|
|
continue;
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem;
|
|
const QString name = c->id().toString();
|
|
const int pos = name.indexOf(QLatin1Char('.'));
|
|
const QString section = name.left(pos);
|
|
const QString subId = name.mid(pos + 1);
|
|
item->setData(0, CommandRole, name);
|
|
|
|
if (!sections.contains(section)) {
|
|
QTreeWidgetItem *categoryItem =
|
|
new QTreeWidgetItem(commandList(), QStringList() << section);
|
|
QFont f = categoryItem->font(0);
|
|
f.setBold(true);
|
|
categoryItem->setFont(0, f);
|
|
sections.insert(section, categoryItem);
|
|
commandList()->expandItem(categoryItem);
|
|
}
|
|
sections[section]->addChild(item);
|
|
|
|
item->setText(0, subId);
|
|
item->setText(1, c->description());
|
|
|
|
QString regex;
|
|
if (exCommandMap().contains(name))
|
|
regex = exCommandMap()[name].pattern();
|
|
item->setText(2, regex);
|
|
|
|
if (regex != defaultExCommandMap()[name].pattern())
|
|
setModified(item, true);
|
|
}
|
|
|
|
commandChanged(0);
|
|
}
|
|
|
|
void FakeVimExCommandsPage::commandChanged(QTreeWidgetItem *current)
|
|
{
|
|
CommandMappings::commandChanged(current);
|
|
if (current)
|
|
targetEdit()->setText(current->text(2));
|
|
}
|
|
|
|
void FakeVimExCommandsPage::targetIdentifierChanged()
|
|
{
|
|
QTreeWidgetItem *current = commandList()->currentItem();
|
|
if (!current)
|
|
return;
|
|
|
|
const QString name = current->data(0, CommandRole).toString();
|
|
const QString regex = targetEdit()->text();
|
|
|
|
if (current->data(0, Qt::UserRole).isValid()) {
|
|
current->setText(2, regex);
|
|
exCommandMap()[name] = QRegExp(regex);
|
|
}
|
|
|
|
setModified(current, regex != defaultExCommandMap()[name].pattern());
|
|
}
|
|
|
|
void FakeVimExCommandsPage::resetTargetIdentifier()
|
|
{
|
|
QTreeWidgetItem *current = commandList()->currentItem();
|
|
if (!current)
|
|
return;
|
|
const QString name = current->data(0, CommandRole).toString();
|
|
QString regex;
|
|
if (defaultExCommandMap().contains(name))
|
|
regex = defaultExCommandMap()[name].pattern();
|
|
targetEdit()->setText(regex);
|
|
}
|
|
|
|
void FakeVimExCommandsPage::removeTargetIdentifier()
|
|
{
|
|
targetEdit()->clear();
|
|
}
|
|
|
|
void FakeVimExCommandsPage::defaultAction()
|
|
{
|
|
int n = commandList()->topLevelItemCount();
|
|
for (int i = 0; i != n; ++i) {
|
|
QTreeWidgetItem *section = commandList()->topLevelItem(i);
|
|
int m = section->childCount();
|
|
for (int j = 0; j != m; ++j) {
|
|
QTreeWidgetItem *item = section->child(j);
|
|
const QString name = item->data(0, CommandRole).toString();
|
|
QString regex;
|
|
if (defaultExCommandMap().contains(name))
|
|
regex = defaultExCommandMap()[name].pattern();
|
|
setModified(item, false);
|
|
item->setText(2, regex);
|
|
if (item == commandList()->currentItem())
|
|
commandChanged(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FakeVimUserCommandsPage
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
class FakeVimUserCommandsModel : public QAbstractTableModel
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
FakeVimUserCommandsModel(FakeVimPluginPrivate *q) : m_q(q) {}
|
|
~FakeVimUserCommandsModel() {}
|
|
|
|
int rowCount(const QModelIndex &parent) const;
|
|
int columnCount(const QModelIndex &parent) const;
|
|
QVariant data(const QModelIndex &index, int role) const;
|
|
bool setData(const QModelIndex &index, const QVariant &data, int role);
|
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
|
|
|
private:
|
|
FakeVimPluginPrivate *m_q;
|
|
};
|
|
|
|
int FakeVimUserCommandsModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
return parent.isValid() ? 0 : 9;
|
|
}
|
|
|
|
int FakeVimUserCommandsModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
return parent.isValid() ? 0 : 2;
|
|
}
|
|
|
|
|
|
QVariant FakeVimUserCommandsModel::headerData(int section,
|
|
Qt::Orientation orient, int role) const
|
|
{
|
|
if (orient == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
switch (section) {
|
|
case 0: return tr("Action");
|
|
case 1: return tr("Command");
|
|
};
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
Qt::ItemFlags FakeVimUserCommandsModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (index.column() == 1)
|
|
return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
|
|
return QAbstractTableModel::flags(index);
|
|
}
|
|
|
|
class FakeVimUserCommandsDelegate : public QItemDelegate
|
|
{
|
|
public:
|
|
explicit FakeVimUserCommandsDelegate(QObject *parent)
|
|
: QItemDelegate(parent)
|
|
{}
|
|
|
|
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
|
|
const QModelIndex &) const
|
|
{
|
|
QLineEdit *lineEdit = new QLineEdit(parent);
|
|
lineEdit->setFrame(false);
|
|
return lineEdit;
|
|
}
|
|
|
|
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
|
const QModelIndex &index) const
|
|
{
|
|
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor);
|
|
QTC_ASSERT(lineEdit, return);
|
|
model->setData(index, lineEdit->text(), Qt::EditRole);
|
|
}
|
|
};
|
|
|
|
class FakeVimUserCommandsPage : public IOptionsPage
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
FakeVimUserCommandsPage(FakeVimPluginPrivate *q)
|
|
: m_q(q)
|
|
{
|
|
setId(SETTINGS_USER_CMDS_ID);
|
|
setDisplayName(tr("User Command Mapping"));
|
|
setCategory(SETTINGS_CATEGORY);
|
|
setDisplayCategory(tr("FakeVim"));
|
|
setCategoryIcon(_(SETTINGS_CATEGORY_FAKEVIM_ICON));
|
|
}
|
|
|
|
void apply();
|
|
void finish() {}
|
|
|
|
QWidget *widget();
|
|
void initialize() {}
|
|
UserCommandMap &userCommandMap();
|
|
UserCommandMap &defaultUserCommandMap();
|
|
|
|
private:
|
|
FakeVimPluginPrivate *m_q;
|
|
QPointer<QGroupBox> m_widget;
|
|
};
|
|
|
|
QWidget *FakeVimUserCommandsPage::widget()
|
|
{
|
|
if (!m_widget) {
|
|
m_widget = new QGroupBox;
|
|
|
|
FakeVimUserCommandsModel *model = new FakeVimUserCommandsModel(m_q);
|
|
QTreeView *widget = new QTreeView;
|
|
model->setParent(widget);
|
|
widget->setModel(model);
|
|
widget->resizeColumnToContents(0);
|
|
|
|
FakeVimUserCommandsDelegate *delegate = new FakeVimUserCommandsDelegate(widget);
|
|
widget->setItemDelegateForColumn(1, delegate);
|
|
|
|
QGridLayout *layout = new QGridLayout(m_widget);
|
|
layout->addWidget(widget, 0, 0);
|
|
m_widget->setLayout(layout);
|
|
}
|
|
return m_widget;
|
|
}
|
|
|
|
void FakeVimUserCommandsPage::apply()
|
|
{
|
|
//m_q->writeSettings();
|
|
delete m_widget;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WordCompletion
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
class FakeVimCompletionAssistProvider : public CompletionAssistProvider
|
|
{
|
|
public:
|
|
bool supportsEditor(Id ) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IAssistProcessor *createProcessor() const;
|
|
|
|
void setActive(const QString &needle, bool forward, FakeVimHandler *handler)
|
|
{
|
|
Q_UNUSED(forward);
|
|
m_handler = handler;
|
|
if (!m_handler)
|
|
return;
|
|
|
|
BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget());
|
|
if (!editor)
|
|
return;
|
|
|
|
//qDebug() << "ACTIVATE: " << needle << forward;
|
|
m_needle = needle;
|
|
editor->invokeAssist(Completion, this);
|
|
}
|
|
|
|
void setInactive()
|
|
{
|
|
m_needle.clear();
|
|
m_handler = 0;
|
|
}
|
|
|
|
const QString &needle() const
|
|
{
|
|
return m_needle;
|
|
}
|
|
|
|
void appendNeedle(const QChar &c)
|
|
{
|
|
m_needle.append(c);
|
|
}
|
|
|
|
FakeVimHandler *handler() const
|
|
{
|
|
return m_handler;
|
|
}
|
|
|
|
private:
|
|
FakeVimHandler *m_handler;
|
|
QString m_needle;
|
|
};
|
|
|
|
class FakeVimAssistProposalItem : public BasicProposalItem
|
|
{
|
|
public:
|
|
FakeVimAssistProposalItem(const FakeVimCompletionAssistProvider *provider)
|
|
: m_provider(const_cast<FakeVimCompletionAssistProvider *>(provider))
|
|
{}
|
|
|
|
bool implicitlyApplies() const QTC_OVERRIDE
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool prematurelyApplies(const QChar &c) const QTC_OVERRIDE
|
|
{
|
|
m_provider->appendNeedle(c);
|
|
return text() == m_provider->needle();
|
|
}
|
|
|
|
void applyContextualContent(BaseTextEditor *, int) const QTC_OVERRIDE
|
|
{
|
|
QTC_ASSERT(m_provider->handler(), return);
|
|
m_provider->handler()->handleReplay(text().mid(m_provider->needle().size()));
|
|
const_cast<FakeVimCompletionAssistProvider *>(m_provider)->setInactive();
|
|
}
|
|
|
|
private:
|
|
FakeVimCompletionAssistProvider *m_provider;
|
|
};
|
|
|
|
|
|
class FakeVimAssistProposalModel : public BasicProposalItemListModel
|
|
{
|
|
public:
|
|
FakeVimAssistProposalModel(const QList<BasicProposalItem *> &items)
|
|
: BasicProposalItemListModel(items)
|
|
{}
|
|
|
|
bool supportsPrefixExpansion() const QTC_OVERRIDE
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class FakeVimCompletionAssistProcessor : public IAssistProcessor
|
|
{
|
|
public:
|
|
FakeVimCompletionAssistProcessor(const IAssistProvider *provider)
|
|
: m_provider(static_cast<const FakeVimCompletionAssistProvider *>(provider))
|
|
{}
|
|
|
|
IAssistProposal *perform(const IAssistInterface *interface) QTC_OVERRIDE
|
|
{
|
|
const QString &needle = m_provider->needle();
|
|
|
|
const int basePosition = interface->position() - needle.size();
|
|
|
|
QTextCursor tc(interface->textDocument());
|
|
tc.setPosition(interface->position());
|
|
tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
|
|
|
QList<BasicProposalItem *> items;
|
|
QSet<QString> seen;
|
|
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
|
|
while (1) {
|
|
tc = tc.document()->find(needle, tc.position(), flags);
|
|
if (tc.isNull())
|
|
break;
|
|
QTextCursor sel = tc;
|
|
sel.select(QTextCursor::WordUnderCursor);
|
|
QString found = sel.selectedText();
|
|
// Only add "real" completions.
|
|
if (found.startsWith(needle)
|
|
&& !seen.contains(found)
|
|
&& sel.anchor() != basePosition) {
|
|
seen.insert(found);
|
|
BasicProposalItem *item = new FakeVimAssistProposalItem(m_provider);
|
|
item->setText(found);
|
|
items.append(item);
|
|
}
|
|
tc.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor);
|
|
}
|
|
//qDebug() << "COMPLETIONS" << completions->size();
|
|
|
|
delete interface;
|
|
return new GenericProposal(basePosition, new FakeVimAssistProposalModel(items));
|
|
}
|
|
|
|
private:
|
|
const FakeVimCompletionAssistProvider *m_provider;
|
|
};
|
|
|
|
IAssistProcessor *FakeVimCompletionAssistProvider::createProcessor() const
|
|
{
|
|
return new FakeVimCompletionAssistProcessor(this);
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FakeVimPluginPrivate
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
class FakeVimPluginPrivate : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
FakeVimPluginPrivate(FakeVimPlugin *);
|
|
~FakeVimPluginPrivate();
|
|
friend class FakeVimPlugin;
|
|
friend class FakeVimExCommandsPage;
|
|
friend class FakeVimUserCommandsPage;
|
|
friend class FakeVimUserCommandsModel;
|
|
|
|
bool initialize();
|
|
void aboutToShutdown();
|
|
|
|
private slots:
|
|
void onCoreAboutToClose();
|
|
void editorOpened(Core::IEditor *);
|
|
void editorAboutToClose(Core::IEditor *);
|
|
|
|
void setUseFakeVim(const QVariant &value);
|
|
void setUseFakeVimInternal(bool on);
|
|
void quitFakeVim();
|
|
void triggerCompletions();
|
|
void triggerSimpleCompletions(const QString &needle, bool forward);
|
|
void windowCommand(const QString &key, int count);
|
|
void find(bool reverse);
|
|
void findNext(bool reverse);
|
|
void foldToggle(int depth);
|
|
void foldAll(bool fold);
|
|
void fold(int depth, bool fold);
|
|
void foldGoTo(int count, bool current);
|
|
void jumpToGlobalMark(QChar mark, bool backTickMode, const QString &fileName);
|
|
void showSettingsDialog();
|
|
void maybeReadVimRc();
|
|
void disableBlockSelection();
|
|
void setBlockSelection(const QTextCursor&);
|
|
void blockSelection(QTextCursor *);
|
|
void hasBlockSelection(bool*);
|
|
void setShowRelativeLineNumbers(const QVariant &value);
|
|
|
|
void resetCommandBuffer();
|
|
void showCommandBuffer(const QString &contents, int cursorPos, int anchorPos,
|
|
int messageLevel, QObject *eventFilter);
|
|
void showExtraInformation(const QString &msg);
|
|
void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
|
|
void highlightMatches(const QString &needle);
|
|
void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
|
|
void checkForElectricCharacter(bool *result, QChar c);
|
|
void indentRegion(int beginBlock, int endBlock, QChar typedChar);
|
|
void handleExCommand(bool *handled, const ExCommand &cmd);
|
|
|
|
void writeSettings();
|
|
void readSettings();
|
|
|
|
void handleDelayedQuitAll(bool forced);
|
|
void handleDelayedQuit(bool forced, Core::IEditor *editor);
|
|
void userActionTriggered();
|
|
|
|
void switchToFile(int n);
|
|
int currentFile() const;
|
|
|
|
void createRelativeNumberWidget(IEditor *editor);
|
|
|
|
signals:
|
|
void delayedQuitRequested(bool forced, Core::IEditor *editor);
|
|
void delayedQuitAllRequested(bool forced);
|
|
|
|
private:
|
|
FakeVimPlugin *q;
|
|
FakeVimOptionPage *m_fakeVimOptionsPage;
|
|
FakeVimExCommandsPage *m_fakeVimExCommandsPage;
|
|
FakeVimUserCommandsPage *m_fakeVimUserCommandsPage;
|
|
QHash<IEditor *, FakeVimHandler *> m_editorToHandler;
|
|
|
|
void triggerAction(Id id);
|
|
void setActionChecked(Id id, bool check);
|
|
|
|
typedef int (*DistFunction)(const QRect &cursor, const QRect &other);
|
|
void moveSomewhere(DistFunction f, int count);
|
|
|
|
void keepOnlyWindow(); // :only
|
|
|
|
ExCommandMap &exCommandMap() { return m_exCommandMap; }
|
|
ExCommandMap &defaultExCommandMap() { return m_defaultExCommandMap; }
|
|
ExCommandMap m_exCommandMap;
|
|
ExCommandMap m_defaultExCommandMap;
|
|
|
|
UserCommandMap &userCommandMap() { return m_userCommandMap; }
|
|
UserCommandMap &defaultUserCommandMap() { return m_defaultUserCommandMap; }
|
|
UserCommandMap m_userCommandMap;
|
|
UserCommandMap m_defaultUserCommandMap;
|
|
|
|
StatusBarWidget *m_statusBar;
|
|
// @TODO: Delete
|
|
//WordCompletion *m_wordCompletion;
|
|
FakeVimCompletionAssistProvider *m_wordProvider;
|
|
};
|
|
|
|
QVariant FakeVimUserCommandsModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
|
switch (index.column()) {
|
|
case 0: // Action
|
|
return tr("User command #%1").arg(index.row() + 1);
|
|
case 1: // Command
|
|
return m_q->userCommandMap().value(index.row() + 1);
|
|
}
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
bool FakeVimUserCommandsModel::setData(const QModelIndex &index,
|
|
const QVariant &data, int role)
|
|
{
|
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
|
if (index.column() == 1)
|
|
m_q->userCommandMap()[index.row() + 1] = data.toString();
|
|
return true;
|
|
}
|
|
|
|
FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
|
|
{
|
|
q = plugin;
|
|
m_fakeVimOptionsPage = 0;
|
|
m_fakeVimExCommandsPage = 0;
|
|
m_fakeVimUserCommandsPage = 0;
|
|
defaultExCommandMap()[_(CppTools::Constants::SWITCH_HEADER_SOURCE)] =
|
|
QRegExp(_("^A$"));
|
|
defaultExCommandMap()[_("Coreplugin.OutputPane.previtem")] =
|
|
QRegExp(_("^(cN(ext)?|cp(revious)?)!?( (.*))?$"));
|
|
defaultExCommandMap()[_("Coreplugin.OutputPane.nextitem")] =
|
|
QRegExp(_("^cn(ext)?!?( (.*))?$"));
|
|
defaultExCommandMap()[_(TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR)] =
|
|
QRegExp(_("^tag?$"));
|
|
defaultExCommandMap()[_(Core::Constants::GO_BACK)] =
|
|
QRegExp(_("^pop?$"));
|
|
defaultExCommandMap()[_("QtCreator.Locate")] =
|
|
QRegExp(_("^e$"));
|
|
|
|
for (int i = 1; i < 10; ++i) {
|
|
QString cmd = QString::fromLatin1(":echo User command %1 executed.<CR>");
|
|
defaultUserCommandMap().insert(i, cmd.arg(i));
|
|
}
|
|
|
|
m_statusBar = 0;
|
|
}
|
|
|
|
FakeVimPluginPrivate::~FakeVimPluginPrivate()
|
|
{
|
|
q->removeObject(m_fakeVimOptionsPage);
|
|
delete m_fakeVimOptionsPage;
|
|
m_fakeVimOptionsPage = 0;
|
|
|
|
q->removeObject(m_fakeVimExCommandsPage);
|
|
delete m_fakeVimExCommandsPage;
|
|
m_fakeVimExCommandsPage = 0;
|
|
|
|
q->removeObject(m_fakeVimUserCommandsPage);
|
|
delete m_fakeVimUserCommandsPage;
|
|
m_fakeVimUserCommandsPage = 0;
|
|
|
|
delete m_wordProvider;
|
|
m_wordProvider = 0;
|
|
|
|
theFakeVimSettings()->deleteLater();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::onCoreAboutToClose()
|
|
{
|
|
// Don't attach to editors anymore.
|
|
disconnect(EditorManager::instance(), SIGNAL(editorOpened(Core::IEditor*)),
|
|
this, SLOT(editorOpened(Core::IEditor*)));
|
|
}
|
|
|
|
void FakeVimPluginPrivate::aboutToShutdown()
|
|
{
|
|
}
|
|
|
|
bool FakeVimPluginPrivate::initialize()
|
|
{
|
|
//m_wordCompletion = new WordCompletion;
|
|
//q->addAutoReleasedObject(m_wordCompletion);
|
|
m_wordProvider = new FakeVimCompletionAssistProvider;
|
|
|
|
/*
|
|
// Set completion settings and keep them up to date.
|
|
TextEditorSettings *textEditorSettings = TextEditorSettings::instance();
|
|
completion->setCompletionSettings(textEditorSettings->completionSettings());
|
|
connect(textEditorSettings,
|
|
SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)),
|
|
completion,
|
|
SLOT(setCompletionSettings(TextEditor::CompletionSettings)));
|
|
*/
|
|
|
|
Context globalcontext(Core::Constants::C_GLOBAL);
|
|
|
|
m_fakeVimOptionsPage = new FakeVimOptionPage;
|
|
q->addObject(m_fakeVimOptionsPage);
|
|
|
|
m_fakeVimExCommandsPage = new FakeVimExCommandsPage(this);
|
|
q->addObject(m_fakeVimExCommandsPage);
|
|
|
|
m_fakeVimUserCommandsPage = new FakeVimUserCommandsPage(this);
|
|
q->addObject(m_fakeVimUserCommandsPage);
|
|
|
|
readSettings();
|
|
|
|
Command *cmd = 0;
|
|
cmd = ActionManager::registerAction(theFakeVimSetting(ConfigUseFakeVim),
|
|
INSTALL_HANDLER, globalcontext, true);
|
|
cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Meta+V,Meta+V") : tr("Alt+V,Alt+V")));
|
|
|
|
ActionContainer *advancedMenu =
|
|
ActionManager::actionContainer(Core::Constants::M_EDIT_ADVANCED);
|
|
advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
|
|
|
|
const Id base = "FakeVim.UserAction";
|
|
for (int i = 1; i < 10; ++i) {
|
|
QAction *act = new QAction(this);
|
|
act->setText(tr("Execute User Action #%1").arg(i));
|
|
act->setData(i);
|
|
cmd = ActionManager::registerAction(act, base.withSuffix(i), globalcontext);
|
|
cmd->setDefaultKeySequence(QKeySequence((UseMacShortcuts ? tr("Meta+V,%1") : tr("Alt+V,%1")).arg(i)));
|
|
connect(act, SIGNAL(triggered()), SLOT(userActionTriggered()));
|
|
}
|
|
|
|
connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(onCoreAboutToClose()));
|
|
|
|
// EditorManager
|
|
connect(EditorManager::instance(), SIGNAL(editorAboutToClose(Core::IEditor*)),
|
|
this, SLOT(editorAboutToClose(Core::IEditor*)));
|
|
connect(EditorManager::instance(), SIGNAL(editorOpened(Core::IEditor*)),
|
|
this, SLOT(editorOpened(Core::IEditor*)));
|
|
|
|
connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
|
|
this, SLOT(setUseFakeVim(QVariant)));
|
|
connect(theFakeVimSetting(ConfigReadVimRc), SIGNAL(valueChanged(QVariant)),
|
|
this, SLOT(maybeReadVimRc()));
|
|
connect(theFakeVimSetting(ConfigVimRcPath), SIGNAL(valueChanged(QVariant)),
|
|
this, SLOT(maybeReadVimRc()));
|
|
connect(theFakeVimSetting(ConfigRelativeNumber), SIGNAL(valueChanged(QVariant)),
|
|
this, SLOT(setShowRelativeLineNumbers(QVariant)));
|
|
|
|
// Delayed operations.
|
|
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);
|
|
|
|
// Vimrc can break test so don't source it if running tests.
|
|
if (!ExtensionSystem::PluginManager::testRunRequested())
|
|
maybeReadVimRc();
|
|
// << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
|
|
|
|
return true;
|
|
}
|
|
|
|
void FakeVimPluginPrivate::userActionTriggered()
|
|
{
|
|
QAction *act = qobject_cast<QAction *>(sender());
|
|
if (!act)
|
|
return;
|
|
const int key = act->data().toInt();
|
|
if (!key)
|
|
return;
|
|
IEditor *editor = EditorManager::currentEditor();
|
|
FakeVimHandler *handler = m_editorToHandler[editor];
|
|
if (handler) {
|
|
// If disabled, enable FakeVim mode just for single user command.
|
|
bool enableFakeVim = !theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
|
|
if (enableFakeVim)
|
|
setUseFakeVimInternal(true);
|
|
|
|
const QString cmd = userCommandMap().value(key);
|
|
handler->handleInput(cmd);
|
|
|
|
if (enableFakeVim)
|
|
setUseFakeVimInternal(false);
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor)
|
|
{
|
|
if (BaseTextEditorWidget *textEditor = qobject_cast<BaseTextEditorWidget *>(editor->widget())) {
|
|
RelativeNumbersColumn *relativeNumbers = new RelativeNumbersColumn(textEditor);
|
|
connect(theFakeVimSetting(ConfigRelativeNumber), SIGNAL(valueChanged(QVariant)),
|
|
relativeNumbers, SLOT(deleteLater()));
|
|
relativeNumbers->show();
|
|
}
|
|
}
|
|
|
|
const char exCommandMapGroup[] = "FakeVimExCommand";
|
|
const char userCommandMapGroup[] = "FakeVimUserCommand";
|
|
const char reKey[] = "RegEx";
|
|
const char cmdKey[] = "Cmd";
|
|
const char idKey[] = "Command";
|
|
|
|
void FakeVimPluginPrivate::writeSettings()
|
|
{
|
|
QSettings *settings = ICore::settings();
|
|
|
|
theFakeVimSettings()->writeSettings(settings);
|
|
|
|
{ // block
|
|
settings->beginWriteArray(_(exCommandMapGroup));
|
|
int count = 0;
|
|
typedef ExCommandMap::const_iterator Iterator;
|
|
const Iterator end = exCommandMap().constEnd();
|
|
for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
|
|
const QString id = it.key();
|
|
const QRegExp re = it.value();
|
|
|
|
if ((defaultExCommandMap().contains(id) && defaultExCommandMap()[id] != re)
|
|
|| (!defaultExCommandMap().contains(id) && !re.pattern().isEmpty())) {
|
|
settings->setArrayIndex(count);
|
|
settings->setValue(_(idKey), id);
|
|
settings->setValue(_(reKey), re.pattern());
|
|
++count;
|
|
}
|
|
}
|
|
settings->endArray();
|
|
} // block
|
|
|
|
{ // block
|
|
settings->beginWriteArray(_(userCommandMapGroup));
|
|
int count = 0;
|
|
typedef UserCommandMap::const_iterator Iterator;
|
|
const Iterator end = userCommandMap().constEnd();
|
|
for (Iterator it = userCommandMap().constBegin(); it != end; ++it) {
|
|
const int key = it.key();
|
|
const QString cmd = it.value();
|
|
|
|
if ((defaultUserCommandMap().contains(key)
|
|
&& defaultUserCommandMap()[key] != cmd)
|
|
|| (!defaultUserCommandMap().contains(key) && !cmd.isEmpty())) {
|
|
settings->setArrayIndex(count);
|
|
settings->setValue(_(idKey), key);
|
|
settings->setValue(_(cmdKey), cmd);
|
|
++count;
|
|
}
|
|
}
|
|
settings->endArray();
|
|
} // block
|
|
}
|
|
|
|
void FakeVimPluginPrivate::readSettings()
|
|
{
|
|
QSettings *settings = ICore::settings();
|
|
|
|
theFakeVimSettings()->readSettings(settings);
|
|
|
|
exCommandMap() = defaultExCommandMap();
|
|
int size = settings->beginReadArray(_(exCommandMapGroup));
|
|
for (int i = 0; i < size; ++i) {
|
|
settings->setArrayIndex(i);
|
|
const QString id = settings->value(_(idKey)).toString();
|
|
const QString re = settings->value(_(reKey)).toString();
|
|
exCommandMap()[id] = QRegExp(re);
|
|
}
|
|
settings->endArray();
|
|
|
|
userCommandMap() = defaultUserCommandMap();
|
|
size = settings->beginReadArray(_(userCommandMapGroup));
|
|
for (int i = 0; i < size; ++i) {
|
|
settings->setArrayIndex(i);
|
|
const int id = settings->value(_(idKey)).toInt();
|
|
const QString cmd = settings->value(_(cmdKey)).toString();
|
|
userCommandMap()[id] = cmd;
|
|
}
|
|
settings->endArray();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::maybeReadVimRc()
|
|
{
|
|
//qDebug() << theFakeVimSetting(ConfigReadVimRc)
|
|
// << theFakeVimSetting(ConfigReadVimRc)->value();
|
|
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
|
|
if (!theFakeVimSetting(ConfigReadVimRc)->value().toBool())
|
|
return;
|
|
QString fileName = theFakeVimSetting(ConfigVimRcPath)->value().toString();
|
|
if (fileName.isEmpty()) {
|
|
fileName = QDesktopServices::storageLocation(QDesktopServices::HomeLocation)
|
|
+ (Utils::HostOsInfo::isWindowsHost() ? _("/_vimrc") : _("/.vimrc"));
|
|
}
|
|
//qDebug() << "READING VIMRC: " << fileName;
|
|
// Read it into a temporary handler for effects modifying global state.
|
|
QPlainTextEdit editor;
|
|
FakeVimHandler handler(&editor);
|
|
handler.handleCommand(_("source ") + fileName);
|
|
//writeSettings();
|
|
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::showSettingsDialog()
|
|
{
|
|
ICore::showOptionsDialog(SETTINGS_CATEGORY, SETTINGS_ID);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::triggerAction(Id id)
|
|
{
|
|
Core::Command *cmd = ActionManager::command(id);
|
|
QTC_ASSERT(cmd, qDebug() << "UNKNOWN CODE: " << id.name(); return);
|
|
QAction *action = cmd->action();
|
|
QTC_ASSERT(action, return);
|
|
action->trigger();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::setActionChecked(Id id, bool check)
|
|
{
|
|
Core::Command *cmd = ActionManager::command(id);
|
|
QTC_ASSERT(cmd, return);
|
|
QAction *action = cmd->action();
|
|
QTC_ASSERT(action, return);
|
|
QTC_ASSERT(action->isCheckable(), return);
|
|
action->setChecked(!check); // trigger negates the action's state
|
|
action->trigger();
|
|
}
|
|
|
|
static int moveRightWeight(const QRect &cursor, const QRect &other)
|
|
{
|
|
if (!cursor.adjusted(999999, 0, 0, 0).intersects(other))
|
|
return -1;
|
|
const int dx = other.left() - cursor.right();
|
|
const int dy = qAbs(cursor.center().y() - other.center().y());
|
|
const int w = 10000 * dx + dy;
|
|
return w;
|
|
}
|
|
|
|
static int moveLeftWeight(const QRect &cursor, const QRect &other)
|
|
{
|
|
if (!cursor.adjusted(-999999, 0, 0, 0).intersects(other))
|
|
return -1;
|
|
const int dx = cursor.left() - other.right();
|
|
const int dy = qAbs(cursor.center().y() -other.center().y());
|
|
const int w = 10000 * dx + dy;
|
|
return w;
|
|
}
|
|
|
|
static int moveUpWeight(const QRect &cursor, const QRect &other)
|
|
{
|
|
if (!cursor.adjusted(0, 0, 0, -999999).intersects(other))
|
|
return -1;
|
|
const int dy = cursor.top() - other.bottom();
|
|
const int dx = qAbs(cursor.center().x() - other.center().x());
|
|
const int w = 10000 * dy + dx;
|
|
return w;
|
|
}
|
|
|
|
static int moveDownWeight(const QRect &cursor, const QRect &other)
|
|
{
|
|
if (!cursor.adjusted(0, 0, 0, 999999).intersects(other))
|
|
return -1;
|
|
const int dy = other.top() - cursor.bottom();
|
|
const int dx = qAbs(cursor.center().x() - other.center().x());
|
|
const int w = 10000 * dy + dx;
|
|
return w;
|
|
}
|
|
|
|
void FakeVimPluginPrivate::windowCommand(const QString &map, int count)
|
|
{
|
|
// normalize mapping
|
|
const QString key = map.toUpper();
|
|
|
|
if (key == _("C") || key == _("<C-C>"))
|
|
triggerAction(Core::Constants::REMOVE_CURRENT_SPLIT);
|
|
else if (key == _("N") || key == _("<C-N>"))
|
|
triggerAction(Core::Constants::GOTONEXT);
|
|
else if (key == _("O") || key == _("<C-O>"))
|
|
keepOnlyWindow();
|
|
else if (key == _("P") || key == _("<C-P>"))
|
|
triggerAction(Core::Constants::GOTOPREV);
|
|
else if (key == _("S") || key == _("<C-S>"))
|
|
triggerAction(Core::Constants::SPLIT);
|
|
else if (key == _("V") || key == _("<C-V>"))
|
|
triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE);
|
|
else if (key == _("W") || key == _("<C-W>"))
|
|
triggerAction(Core::Constants::GOTO_NEXT_SPLIT);
|
|
else if (key.contains(_("RIGHT")) || key == _("L") || key == _("<S-L>"))
|
|
moveSomewhere(&moveRightWeight, key == _("<S-L>") ? -1 : count);
|
|
else if (key.contains(_("LEFT")) || key == _("H") || key == _("<S-H>"))
|
|
moveSomewhere(&moveLeftWeight, key == _("<S-H>") ? -1 : count);
|
|
else if (key.contains(_("UP")) || key == _("K") || key == _("<S-K>"))
|
|
moveSomewhere(&moveUpWeight, key == _("<S-K>") ? -1 : count);
|
|
else if (key.contains(_("DOWN")) || key == _("J") || key == _("<S-J>"))
|
|
moveSomewhere(&moveDownWeight, key == _("<S-J>") ? -1 : count);
|
|
else
|
|
qDebug() << "UNKNOWN WINDOW COMMAND: <C-W>" << map;
|
|
}
|
|
|
|
void FakeVimPluginPrivate::moveSomewhere(DistFunction f, int count)
|
|
{
|
|
IEditor *currentEditor = EditorManager::currentEditor();
|
|
QWidget *w = currentEditor->widget();
|
|
QPlainTextEdit *pe = qobject_cast<QPlainTextEdit *>(w);
|
|
QTC_ASSERT(pe, return);
|
|
QRect rc = pe->cursorRect();
|
|
QRect cursorRect(w->mapToGlobal(rc.topLeft()),
|
|
w->mapToGlobal(rc.bottomRight()));
|
|
//qDebug() << "\nCURSOR: " << cursorRect;
|
|
|
|
IEditor *bestEditor = 0;
|
|
int repeat = count;
|
|
|
|
QList<IEditor *> editors = EditorManager::visibleEditors();
|
|
while (repeat < 0 || repeat-- > 0) {
|
|
editors.removeOne(currentEditor);
|
|
int bestValue = -1;
|
|
foreach (IEditor *editor, editors) {
|
|
QWidget *w = editor->widget();
|
|
QRect editorRect(w->mapToGlobal(w->geometry().topLeft()),
|
|
w->mapToGlobal(w->geometry().bottomRight()));
|
|
//qDebug() << " EDITOR: " << editorRect << editor;
|
|
|
|
int value = f(cursorRect, editorRect);
|
|
if (value != -1 && (bestValue == -1 || value < bestValue)) {
|
|
bestValue = value;
|
|
bestEditor = editor;
|
|
//qDebug() << " BEST SO FAR: " << bestValue << bestEditor;
|
|
}
|
|
}
|
|
if (bestValue == -1)
|
|
break;
|
|
|
|
currentEditor = bestEditor;
|
|
//qDebug() << " BEST: " << bestValue << bestEditor;
|
|
}
|
|
|
|
// FIME: This is know to fail as the EditorManager will fall back to
|
|
// the current editor's view. Needs additional public API there.
|
|
if (bestEditor)
|
|
EditorManager::activateEditor(bestEditor);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::keepOnlyWindow()
|
|
{
|
|
IEditor *currentEditor = EditorManager::currentEditor();
|
|
QList<IEditor *> editors = EditorManager::visibleEditors();
|
|
editors.removeOne(currentEditor);
|
|
|
|
foreach (IEditor *editor, editors) {
|
|
EditorManager::activateEditor(editor);
|
|
triggerAction(Core::Constants::REMOVE_CURRENT_SPLIT);
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::find(bool reverse)
|
|
{
|
|
if (FindPlugin *plugin = FindPlugin::instance()) {
|
|
plugin->setUseFakeVim(true);
|
|
plugin->openFindToolBar(reverse
|
|
? FindPlugin::FindBackwardDirection
|
|
: FindPlugin::FindForwardDirection);
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::findNext(bool reverse)
|
|
{
|
|
if (reverse)
|
|
triggerAction(Core::Constants::FIND_PREVIOUS);
|
|
else
|
|
triggerAction(Core::Constants::FIND_NEXT);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::foldToggle(int depth)
|
|
{
|
|
IEditor *ieditor = EditorManager::currentEditor();
|
|
FakeVimHandler *handler = m_editorToHandler.value(ieditor, 0);
|
|
QTC_ASSERT(handler != 0, return);
|
|
|
|
QTextBlock block = handler->textCursor().block();
|
|
fold(depth, !BaseTextDocumentLayout::isFolded(block));
|
|
}
|
|
|
|
void FakeVimPluginPrivate::foldAll(bool fold)
|
|
{
|
|
IEditor *ieditor = EditorManager::currentEditor();
|
|
BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(ieditor->widget());
|
|
QTC_ASSERT(editor != 0, return);
|
|
|
|
QTextDocument *doc = editor->document();
|
|
BaseTextDocumentLayout *documentLayout =
|
|
qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
|
|
QTC_ASSERT(documentLayout != 0, return);
|
|
|
|
QTextBlock block = editor->document()->firstBlock();
|
|
while (block.isValid()) {
|
|
BaseTextDocumentLayout::doFoldOrUnfold(block, !fold);
|
|
block = block.next();
|
|
}
|
|
|
|
documentLayout->requestUpdate();
|
|
documentLayout->emitDocumentSizeChanged();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::fold(int depth, bool fold)
|
|
{
|
|
IEditor *ieditor = EditorManager::currentEditor();
|
|
FakeVimHandler *handler = m_editorToHandler.value(ieditor, 0);
|
|
QTC_ASSERT(handler != 0, return);
|
|
BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(ieditor->widget());
|
|
QTC_ASSERT(editor != 0, return);
|
|
|
|
QTextDocument *doc = editor->document();
|
|
BaseTextDocumentLayout *documentLayout =
|
|
qobject_cast<BaseTextDocumentLayout*>(doc->documentLayout());
|
|
QTC_ASSERT(documentLayout != 0, return);
|
|
|
|
QTextBlock block = handler->textCursor().block();
|
|
int indent = BaseTextDocumentLayout::foldingIndent(block);
|
|
if (fold) {
|
|
if (BaseTextDocumentLayout::isFolded(block)) {
|
|
while (block.isValid() && (BaseTextDocumentLayout::foldingIndent(block) >= indent
|
|
|| !block.isVisible())) {
|
|
block = block.previous();
|
|
}
|
|
}
|
|
if (BaseTextDocumentLayout::canFold(block))
|
|
++indent;
|
|
while (depth != 0 && block.isValid()) {
|
|
const int indent2 = BaseTextDocumentLayout::foldingIndent(block);
|
|
if (BaseTextDocumentLayout::canFold(block) && indent2 < indent) {
|
|
BaseTextDocumentLayout::doFoldOrUnfold(block, false);
|
|
if (depth > 0)
|
|
--depth;
|
|
indent = indent2;
|
|
}
|
|
block = block.previous();
|
|
}
|
|
} else {
|
|
if (BaseTextDocumentLayout::isFolded(block)) {
|
|
if (depth < 0) {
|
|
// recursively open fold
|
|
while (depth < 0 && block.isValid()
|
|
&& BaseTextDocumentLayout::foldingIndent(block) >= indent) {
|
|
if (BaseTextDocumentLayout::canFold(block)) {
|
|
BaseTextDocumentLayout::doFoldOrUnfold(block, true);
|
|
if (depth > 0)
|
|
--depth;
|
|
}
|
|
block = block.next();
|
|
}
|
|
} else {
|
|
if (BaseTextDocumentLayout::canFold(block)) {
|
|
BaseTextDocumentLayout::doFoldOrUnfold(block, true);
|
|
if (depth > 0)
|
|
--depth;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
documentLayout->requestUpdate();
|
|
documentLayout->emitDocumentSizeChanged();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::foldGoTo(int count, bool current)
|
|
{
|
|
IEditor *ieditor = EditorManager::currentEditor();
|
|
FakeVimHandler *handler = m_editorToHandler.value(ieditor, 0);
|
|
QTC_ASSERT(handler != 0, return);
|
|
|
|
QTextCursor tc = handler->textCursor();
|
|
QTextBlock block = tc.block();
|
|
|
|
int pos = -1;
|
|
if (count > 0) {
|
|
int repeat = count;
|
|
block = block.next();
|
|
QTextBlock prevBlock = block;
|
|
int indent = BaseTextDocumentLayout::foldingIndent(block);
|
|
block = block.next();
|
|
while (block.isValid()) {
|
|
int newIndent = BaseTextDocumentLayout::foldingIndent(block);
|
|
if (current ? indent > newIndent : indent < newIndent) {
|
|
if (prevBlock.isVisible()) {
|
|
pos = prevBlock.position();
|
|
if (--repeat <= 0)
|
|
break;
|
|
} else if (current) {
|
|
indent = newIndent;
|
|
}
|
|
}
|
|
if (!current)
|
|
indent = newIndent;
|
|
prevBlock = block;
|
|
block = block.next();
|
|
}
|
|
} else if (count < 0) {
|
|
int repeat = -count;
|
|
int indent = BaseTextDocumentLayout::foldingIndent(block);
|
|
block = block.previous();
|
|
while (block.isValid()) {
|
|
int newIndent = BaseTextDocumentLayout::foldingIndent(block);
|
|
if (current ? indent > newIndent : indent < newIndent) {
|
|
while (block.isValid() && !block.isVisible())
|
|
block = block.previous();
|
|
pos = block.position();
|
|
if (--repeat <= 0)
|
|
break;
|
|
}
|
|
if (!current)
|
|
indent = newIndent;
|
|
block = block.previous();
|
|
}
|
|
}
|
|
|
|
if (pos != -1) {
|
|
tc.setPosition(pos, QTextCursor::KeepAnchor);
|
|
handler->setTextCursor(tc);
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::jumpToGlobalMark(QChar mark, bool backTickMode,
|
|
const QString &fileName)
|
|
{
|
|
Core::IEditor *iedit = Core::EditorManager::openEditor(fileName);
|
|
if (!iedit)
|
|
return;
|
|
FakeVimHandler *handler = m_editorToHandler.value(iedit, 0);
|
|
if (handler)
|
|
handler->jumpToLocalMark(mark, backTickMode);
|
|
}
|
|
|
|
// This class defers deletion of a child FakeVimHandler using deleteLater().
|
|
class DeferredDeleter : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
FakeVimHandler *m_handler;
|
|
|
|
public:
|
|
DeferredDeleter(QObject *parent, FakeVimHandler *handler)
|
|
: QObject(parent), m_handler(handler)
|
|
{}
|
|
|
|
~DeferredDeleter()
|
|
{
|
|
if (m_handler) {
|
|
m_handler->disconnectFromEditor();
|
|
m_handler->deleteLater();
|
|
m_handler = 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
void FakeVimPluginPrivate::editorOpened(IEditor *editor)
|
|
{
|
|
if (!editor)
|
|
return;
|
|
|
|
QWidget *widget = editor->widget();
|
|
if (!widget)
|
|
return;
|
|
|
|
// we can only handle QTextEdit and QPlainTextEdit
|
|
if (!qobject_cast<QTextEdit *>(widget) && !qobject_cast<QPlainTextEdit *>(widget))
|
|
return;
|
|
|
|
//qDebug() << "OPENING: " << editor << editor->widget()
|
|
// << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
|
|
|
|
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);
|
|
m_editorToHandler[editor] = handler;
|
|
|
|
connect(handler, SIGNAL(extraInformationChanged(QString)),
|
|
SLOT(showExtraInformation(QString)));
|
|
connect(handler, SIGNAL(commandBufferChanged(QString,int,int,int,QObject*)),
|
|
SLOT(showCommandBuffer(QString,int,int,int,QObject*)));
|
|
connect(handler, SIGNAL(selectionChanged(QList<QTextEdit::ExtraSelection>)),
|
|
SLOT(changeSelection(QList<QTextEdit::ExtraSelection>)));
|
|
connect(handler, SIGNAL(highlightMatches(QString)),
|
|
SLOT(highlightMatches(QString)));
|
|
connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
|
|
SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)), Qt::DirectConnection);
|
|
connect(handler, SIGNAL(indentRegion(int,int,QChar)),
|
|
SLOT(indentRegion(int,int,QChar)));
|
|
connect(handler, SIGNAL(checkForElectricCharacter(bool*,QChar)),
|
|
SLOT(checkForElectricCharacter(bool*,QChar)), Qt::DirectConnection);
|
|
connect(handler, SIGNAL(requestDisableBlockSelection()),
|
|
SLOT(disableBlockSelection()));
|
|
connect(handler, SIGNAL(requestSetBlockSelection(QTextCursor)),
|
|
SLOT(setBlockSelection(QTextCursor)));
|
|
connect(handler, SIGNAL(requestBlockSelection(QTextCursor*)),
|
|
SLOT(blockSelection(QTextCursor*)), Qt::DirectConnection);
|
|
connect(handler, SIGNAL(requestHasBlockSelection(bool*)),
|
|
SLOT(hasBlockSelection(bool*)), Qt::DirectConnection);
|
|
connect(handler, SIGNAL(completionRequested()),
|
|
SLOT(triggerCompletions()));
|
|
connect(handler, SIGNAL(simpleCompletionRequested(QString,bool)),
|
|
SLOT(triggerSimpleCompletions(QString,bool)));
|
|
connect(handler, SIGNAL(windowCommandRequested(QString,int)),
|
|
SLOT(windowCommand(QString,int)));
|
|
connect(handler, SIGNAL(findRequested(bool)),
|
|
SLOT(find(bool)));
|
|
connect(handler, SIGNAL(findNextRequested(bool)),
|
|
SLOT(findNext(bool)));
|
|
connect(handler, SIGNAL(foldToggle(int)),
|
|
SLOT(foldToggle(int)));
|
|
connect(handler, SIGNAL(foldAll(bool)),
|
|
SLOT(foldAll(bool)));
|
|
connect(handler, SIGNAL(fold(int,bool)),
|
|
SLOT(fold(int,bool)));
|
|
connect(handler, SIGNAL(foldGoTo(int,bool)),
|
|
SLOT(foldGoTo(int,bool)));
|
|
connect(handler, SIGNAL(jumpToGlobalMark(QChar,bool,QString)),
|
|
SLOT(jumpToGlobalMark(QChar,bool,QString)));
|
|
|
|
connect(handler, SIGNAL(handleExCommandRequested(bool*,ExCommand)),
|
|
SLOT(handleExCommand(bool*,ExCommand)), Qt::DirectConnection);
|
|
|
|
connect(ICore::instance(), SIGNAL(saveSettingsRequested()),
|
|
SLOT(writeSettings()));
|
|
|
|
handler->setCurrentFileName(editor->document()->filePath());
|
|
handler->installEventFilter();
|
|
|
|
// pop up the bar
|
|
if (theFakeVimSetting(ConfigUseFakeVim)->value().toBool()) {
|
|
resetCommandBuffer();
|
|
handler->setupWidget();
|
|
}
|
|
|
|
if (theFakeVimSetting(ConfigRelativeNumber)->value().toBool())
|
|
createRelativeNumberWidget(editor);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::editorAboutToClose(IEditor *editor)
|
|
{
|
|
//qDebug() << "CLOSING: " << editor << editor->widget();
|
|
m_editorToHandler.remove(editor);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
|
|
{
|
|
//qDebug() << "SET USE FAKEVIM" << value;
|
|
bool on = value.toBool();
|
|
if (Core::FindPlugin::instance())
|
|
Core::FindPlugin::instance()->setUseFakeVim(on);
|
|
setUseFakeVimInternal(on);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
|
|
{
|
|
if (on) {
|
|
//ICore *core = ICore::instance();
|
|
//core->updateAdditionalContexts(Context(FAKEVIM_CONTEXT),
|
|
// Context());
|
|
foreach (IEditor *editor, m_editorToHandler.keys())
|
|
m_editorToHandler[editor]->setupWidget();
|
|
} else {
|
|
//ICore *core = ICore::instance();
|
|
//core->updateAdditionalContexts(Context(),
|
|
// Context(FAKEVIM_CONTEXT));
|
|
resetCommandBuffer();
|
|
foreach (IEditor *editor, m_editorToHandler.keys()) {
|
|
if (BaseTextDocument *textDocument =
|
|
qobject_cast<BaseTextDocument *>(editor->document())) {
|
|
m_editorToHandler[editor]->restoreWidget(textDocument->tabSettings().m_tabSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::triggerCompletions()
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
if (BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
editor->invokeAssist(Completion, m_wordProvider);
|
|
// CompletionSupport::instance()->complete(editor->editor(), TextCompletion, false);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::triggerSimpleCompletions(const QString &needle, bool forward)
|
|
{
|
|
// m_wordCompletion->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
|
|
m_wordProvider->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
|
|
}
|
|
|
|
void FakeVimPluginPrivate::disableBlockSelection()
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
bt->setBlockSelection(false);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::setBlockSelection(const QTextCursor &cursor)
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
bt->setBlockSelection(cursor);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::blockSelection(QTextCursor *cursor)
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
if (cursor)
|
|
*cursor = bt->blockSelection();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::hasBlockSelection(bool *on)
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
*on = bt->hasBlockSelection();
|
|
}
|
|
|
|
void FakeVimPluginPrivate::setShowRelativeLineNumbers(const QVariant &value)
|
|
{
|
|
if (value.toBool()) {
|
|
foreach (IEditor *editor, m_editorToHandler.keys())
|
|
createRelativeNumberWidget(editor);
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::checkForElectricCharacter(bool *result, QChar c)
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
*result = bt->baseTextDocument()->indenter()->isElectricCharacter(c);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::handleExCommand(bool *handled, const ExCommand &cmd)
|
|
{
|
|
using namespace Core;
|
|
//qDebug() << "PLUGIN HANDLE: " << cmd.cmd << cmd.count;
|
|
|
|
*handled = false;
|
|
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
|
|
// Focus editor first so actions can be executed in correct context.
|
|
QWidget *editor = handler->widget();
|
|
if (editor)
|
|
editor->setFocus();
|
|
|
|
*handled = true;
|
|
if (cmd.matches(_("w"), _("write")) || cmd.cmd == _("wq")) {
|
|
// :w[rite]
|
|
IEditor *editor = m_editorToHandler.key(handler);
|
|
const QString fileName = handler->currentFileName();
|
|
if (editor && editor->document()->filePath() == fileName) {
|
|
// Handle that as a special case for nicer interaction with core
|
|
DocumentManager::saveDocument(editor->document());
|
|
// Check result by reading back.
|
|
QFile file3(fileName);
|
|
file3.open(QIODevice::ReadOnly);
|
|
QByteArray ba = file3.readAll();
|
|
handler->showMessage(MessageInfo, FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
|
|
.arg(fileName).arg(QLatin1Char(' '))
|
|
.arg(ba.count('\n')).arg(ba.size()));
|
|
if (cmd.cmd == _("wq"))
|
|
delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
|
|
} else {
|
|
handler->showMessage(MessageError, tr("File not saved"));
|
|
}
|
|
} else if (cmd.matches(_("wa"), _("wall"))) {
|
|
// :w[all]
|
|
QList<IDocument *> toSave = DocumentManager::modifiedDocuments();
|
|
QList<IDocument *> failed;
|
|
bool success = DocumentManager::saveModifiedDocuments(toSave, QString(), 0, QString(), 0, &failed);
|
|
if (!success)
|
|
handler->showMessage(MessageInfo, tr("Saving succeeded"));
|
|
else
|
|
handler->showMessage(MessageError, tr("%n files not saved", 0, failed.size()));
|
|
} else if (cmd.matches(_("q"), _("quit"))) {
|
|
// :q[uit]
|
|
emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
|
|
} else if (cmd.matches(_("qa"), _("qall"))) {
|
|
// :qa[ll]
|
|
emit delayedQuitAllRequested(cmd.hasBang);
|
|
} else if (cmd.matches(_("sp"), _("split"))) {
|
|
// :sp[lit]
|
|
triggerAction(Core::Constants::SPLIT);
|
|
} else if (cmd.matches(_("vs"), _("vsplit"))) {
|
|
// :vs[plit]
|
|
triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE);
|
|
} else if (cmd.matches(_("mak"), _("make"))) {
|
|
// :mak[e][!] [arguments]
|
|
triggerAction(ProjectExplorer::Constants::BUILD);
|
|
} else if (cmd.matches(_("se"), _("set"))) {
|
|
if (cmd.args.isEmpty()) {
|
|
// :se[t]
|
|
showSettingsDialog();
|
|
} else if (cmd.args == _("ic") || cmd.args == _("ignorecase")) {
|
|
// :set nc
|
|
setActionChecked(Core::Constants::CASE_SENSITIVE, false);
|
|
} else if (cmd.args == _("noic") || cmd.args == _("noignorecase")) {
|
|
// :set noic
|
|
setActionChecked(Core::Constants::CASE_SENSITIVE, true);
|
|
}
|
|
*handled = false; // Let the handler see it as well.
|
|
} else if (cmd.matches(_("n"), _("next"))) {
|
|
// :n[ext]
|
|
switchToFile(currentFile() + cmd.count);
|
|
} else if (cmd.matches(_("prev"), _("previous")) || cmd.matches(_("N"), _("Next"))) {
|
|
// :prev[ious], :N[ext]
|
|
switchToFile(currentFile() - cmd.count);
|
|
} else if (cmd.matches(_("bn"), _("bnext"))) {
|
|
// :bn[ext]
|
|
switchToFile(currentFile() + cmd.count);
|
|
} else if (cmd.matches(_("bp"), _("bprevious")) || cmd.matches(_("bN"), _("bNext"))) {
|
|
// :bp[revious], :bN[ext]
|
|
switchToFile(currentFile() - cmd.count);
|
|
} else if (cmd.matches(_("on"), _("only"))) {
|
|
// :on[ly]
|
|
keepOnlyWindow();
|
|
} else if (cmd.cmd == _("AS")) {
|
|
triggerAction(Core::Constants::SPLIT);
|
|
triggerAction(CppTools::Constants::SWITCH_HEADER_SOURCE);
|
|
} else if (cmd.cmd == _("AV")) {
|
|
triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE);
|
|
triggerAction(CppTools::Constants::SWITCH_HEADER_SOURCE);
|
|
} else {
|
|
// Check whether one of the configure commands matches.
|
|
typedef ExCommandMap::const_iterator Iterator;
|
|
const Iterator end = exCommandMap().constEnd();
|
|
for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
|
|
const QString &id = it.key();
|
|
QRegExp re = it.value();
|
|
if (!re.pattern().isEmpty() && re.indexIn(cmd.cmd) != -1) {
|
|
triggerAction(Core::Id::fromString(id));
|
|
return;
|
|
}
|
|
}
|
|
*handled = false;
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::handleDelayedQuit(bool forced, IEditor *editor)
|
|
{
|
|
// This tries to simulate vim behaviour. But the models of vim and
|
|
// Qt Creator core do not match well...
|
|
if (EditorManager::hasSplitter())
|
|
triggerAction(Core::Constants::REMOVE_CURRENT_SPLIT);
|
|
else
|
|
EditorManager::closeEditor(editor, !forced);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::handleDelayedQuitAll(bool forced)
|
|
{
|
|
triggerAction(Core::Constants::REMOVE_ALL_SPLITS);
|
|
EditorManager::closeAllEditors(!forced);
|
|
}
|
|
|
|
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;
|
|
}
|
|
TextBlockUserData::MatchType match
|
|
= TextBlockUserData::matchCursorForward(cursor);
|
|
if (match == TextBlockUserData::Match) {
|
|
*moved = true;
|
|
*forward = true;
|
|
} else {
|
|
if (undoFakeEOL)
|
|
cursor->movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 1);
|
|
if (match == 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 = TextBlockUserData::matchCursorBackward(cursor);
|
|
if (match == TextBlockUserData::Match) {
|
|
*moved = true;
|
|
*forward = false;
|
|
} else if (undoMove) {
|
|
cursor->movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::indentRegion(int beginBlock, int endBlock,
|
|
QChar typedChar)
|
|
{
|
|
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
|
|
if (!handler)
|
|
return;
|
|
|
|
BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget());
|
|
if (!bt)
|
|
return;
|
|
|
|
TabSettings tabSettings;
|
|
tabSettings.m_indentSize = theFakeVimSetting(ConfigShiftWidth)->value().toInt();
|
|
tabSettings.m_tabSize = theFakeVimSetting(ConfigTabStop)->value().toInt();
|
|
tabSettings.m_tabPolicy = theFakeVimSetting(ConfigExpandTab)->value().toBool()
|
|
? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy;
|
|
|
|
QTextDocument *doc = bt->document();
|
|
QTextBlock startBlock = doc->findBlockByNumber(beginBlock);
|
|
|
|
// Record line lenghts for mark adjustments
|
|
QVector<int> lineLengths(endBlock - beginBlock + 1);
|
|
QTextBlock block = startBlock;
|
|
|
|
for (int i = beginBlock; i <= endBlock; ++i) {
|
|
lineLengths[i - beginBlock] = block.text().length();
|
|
if (typedChar == 0 && block.text().simplified().isEmpty()) {
|
|
// clear empty lines
|
|
QTextCursor cursor(block);
|
|
while (!cursor.atBlockEnd())
|
|
cursor.deleteChar();
|
|
} else {
|
|
bt->baseTextDocument()->indenter()->indentBlock(doc, block, typedChar, tabSettings);
|
|
}
|
|
block = block.next();
|
|
}
|
|
}
|
|
|
|
void FakeVimPluginPrivate::quitFakeVim()
|
|
{
|
|
theFakeVimSetting(ConfigUseFakeVim)->setValue(false);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::resetCommandBuffer()
|
|
{
|
|
showCommandBuffer(QString(), -1, -1, 0, 0);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::showCommandBuffer(const QString &contents,
|
|
int cursorPos, int anchorPos, int messageLevel, QObject *eventFilter)
|
|
{
|
|
//qDebug() << "SHOW COMMAND BUFFER" << contents;
|
|
if (MiniBuffer *w = qobject_cast<MiniBuffer *>(m_statusBar->widget()))
|
|
w->setContents(contents, cursorPos, anchorPos, messageLevel, eventFilter);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::showExtraInformation(const QString &text)
|
|
{
|
|
EditorManager::splitSideBySide();
|
|
QString title = _("stdout.txt");
|
|
IEditor *iedit = EditorManager::openEditorWithContents(Id(), &title, text.toUtf8());
|
|
EditorManager::activateEditor(iedit);
|
|
FakeVimHandler *handler = m_editorToHandler.value(iedit, 0);
|
|
QTC_ASSERT(handler, return);
|
|
handler->handleCommand(_("0"));
|
|
}
|
|
|
|
void FakeVimPluginPrivate::changeSelection(const QList<QTextEdit::ExtraSelection> &selection)
|
|
{
|
|
if (FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender()))
|
|
if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
|
|
bt->setExtraSelections(BaseTextEditorWidget::FakeVimSelection, selection);
|
|
}
|
|
|
|
void FakeVimPluginPrivate::highlightMatches(const QString &needle)
|
|
{
|
|
foreach (IEditor *editor, EditorManager::visibleEditors()) {
|
|
QWidget *w = editor->widget();
|
|
Core::IFindSupport *find = Aggregation::query<Core::IFindSupport>(w);
|
|
if (find != 0)
|
|
find->highlightAll(needle, FindRegularExpression | FindCaseSensitively);
|
|
}
|
|
}
|
|
|
|
int FakeVimPluginPrivate::currentFile() const
|
|
{
|
|
IEditor *editor = EditorManager::currentEditor();
|
|
if (!editor)
|
|
return -1;
|
|
return DocumentModel::indexOfDocument(editor->document());
|
|
}
|
|
|
|
void FakeVimPluginPrivate::switchToFile(int n)
|
|
{
|
|
int size = DocumentModel::entryCount();
|
|
QTC_ASSERT(size, return);
|
|
n = n % size;
|
|
if (n < 0)
|
|
n += size;
|
|
EditorManager::activateEditorForEntry(DocumentModel::entries().at(n));
|
|
}
|
|
|
|
ExCommandMap &FakeVimExCommandsPage::exCommandMap()
|
|
{
|
|
return m_q->exCommandMap();
|
|
}
|
|
|
|
ExCommandMap &FakeVimExCommandsPage::defaultExCommandMap()
|
|
{
|
|
return m_q->defaultExCommandMap();
|
|
}
|
|
|
|
UserCommandMap &FakeVimUserCommandsPage::userCommandMap()
|
|
{
|
|
return m_q->userCommandMap();
|
|
}
|
|
|
|
UserCommandMap &FakeVimUserCommandsPage::defaultUserCommandMap()
|
|
{
|
|
return m_q->defaultUserCommandMap();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FakeVimPlugin
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
FakeVimPlugin::FakeVimPlugin()
|
|
: d(new FakeVimPluginPrivate(this))
|
|
{}
|
|
|
|
FakeVimPlugin::~FakeVimPlugin()
|
|
{
|
|
delete d;
|
|
}
|
|
|
|
bool FakeVimPlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
|
{
|
|
Q_UNUSED(arguments)
|
|
Q_UNUSED(errorMessage)
|
|
return d->initialize();
|
|
}
|
|
|
|
ExtensionSystem::IPlugin::ShutdownFlag FakeVimPlugin::aboutToShutdown()
|
|
{
|
|
d->aboutToShutdown();
|
|
return SynchronousShutdown;
|
|
}
|
|
|
|
void FakeVimPlugin::extensionsInitialized()
|
|
{
|
|
d->m_statusBar = new StatusBarWidget;
|
|
d->m_statusBar->setWidget(new MiniBuffer);
|
|
d->m_statusBar->setPosition(StatusBarWidget::LastLeftAligned);
|
|
addAutoReleasedObject(d->m_statusBar);
|
|
}
|
|
|
|
#ifdef WITH_TESTS
|
|
void FakeVimPlugin::setupTest(QString *title, FakeVimHandler **handler, QWidget **edit)
|
|
{
|
|
*title = QString::fromLatin1("test.cpp");
|
|
Core::IEditor *iedit = Core::EditorManager::openEditorWithContents(Core::Id(), title);
|
|
Core::EditorManager::activateEditor(iedit);
|
|
*edit = iedit->widget();
|
|
*handler = d->m_editorToHandler.value(iedit, 0);
|
|
(*handler)->handleCommand(_("set startofline"));
|
|
|
|
// *handler = 0;
|
|
// m_statusMessage.clear();
|
|
// m_statusData.clear();
|
|
// m_infoMessage.clear();
|
|
// if (m_textedit) {
|
|
// m_textedit->setPlainText(lines);
|
|
// QTextCursor tc = m_textedit->textCursor();
|
|
// tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
|
// m_textedit->setTextCursor(tc);
|
|
// m_textedit->setPlainText(lines);
|
|
// *handler = new FakeVimHandler(m_textedit);
|
|
// } else {
|
|
// m_plaintextedit->setPlainText(lines);
|
|
// QTextCursor tc = m_plaintextedit->textCursor();
|
|
// tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
|
// m_plaintextedit->setTextCursor(tc);
|
|
// m_plaintextedit->setPlainText(lines);
|
|
// *handler = new FakeVimHandler(m_plaintextedit);
|
|
// }
|
|
|
|
// QObject::connect(*handler, SIGNAL(commandBufferChanged(QString,int)),
|
|
// this, SLOT(changeStatusMessage(QString,int)));
|
|
// QObject::connect(*handler, SIGNAL(extraInformationChanged(QString)),
|
|
// this, SLOT(changeExtraInformation(QString)));
|
|
// QObject::connect(*handler, SIGNAL(statusDataChanged(QString)),
|
|
// this, SLOT(changeStatusData(QString)));
|
|
|
|
// QCOMPARE(EDITOR(toPlainText()), lines);
|
|
(*handler)->handleCommand(_("set iskeyword=@,48-57,_,192-255,a-z,A-Z"));
|
|
}
|
|
#endif
|
|
|
|
} // namespace Internal
|
|
} // namespace FakeVim
|
|
|
|
#include "fakevimplugin.moc"
|
|
|
|
Q_EXPORT_PLUGIN(FakeVim::Internal::FakeVimPlugin)
|