PageRenderTime 63ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/plugins/fakevim/fakevimplugin.cpp

https://bitbucket.org/kpozn/qt-creator-py-reborn
C++ | 1772 lines | 1385 code | 243 blank | 144 comment | 192 complexity | 6f3a37e1ab3424668f9d2df4add34de3 MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /**************************************************************************
  2. **
  3. ** This file is part of Qt Creator
  4. **
  5. ** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Nokia Corporation (qt-info@nokia.com)
  8. **
  9. **
  10. ** GNU Lesser General Public License Usage
  11. **
  12. ** This file may be used under the terms of the GNU Lesser General Public
  13. ** License version 2.1 as published by the Free Software Foundation and
  14. ** appearing in the file LICENSE.LGPL included in the packaging of this file.
  15. ** Please review the following information to ensure the GNU Lesser General
  16. ** Public License version 2.1 requirements will be met:
  17. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  18. **
  19. ** In addition, as a special exception, Nokia gives you certain additional
  20. ** rights. These rights are described in the Nokia Qt LGPL Exception
  21. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  22. **
  23. ** Other Usage
  24. **
  25. ** Alternatively, this file may be used in accordance with the terms and
  26. ** conditions contained in a signed written agreement between you and Nokia.
  27. **
  28. ** If you have questions regarding the use of this file, please contact
  29. ** Nokia at qt-info@nokia.com.
  30. **
  31. **************************************************************************/
  32. #include "fakevimplugin.h"
  33. #include "fakevimhandler.h"
  34. #include "ui_fakevimoptions.h"
  35. #include <coreplugin/actionmanager/actioncontainer.h>
  36. #include <coreplugin/actionmanager/actionmanager.h>
  37. #include <coreplugin/actionmanager/command.h>
  38. #include <coreplugin/actionmanager/command.h>
  39. #include <coreplugin/actionmanager/commandmappings.h>
  40. #include <coreplugin/coreconstants.h>
  41. #include <coreplugin/dialogs/ioptionspage.h>
  42. #include <coreplugin/editormanager/editormanager.h>
  43. #include <coreplugin/editormanager/openeditorsmodel.h>
  44. #include <coreplugin/documentmanager.h>
  45. #include <coreplugin/icore.h>
  46. #include <coreplugin/idocument.h>
  47. #include <coreplugin/messagemanager.h>
  48. #include <coreplugin/id.h>
  49. #include <coreplugin/statusbarwidget.h>
  50. #include <coreplugin/statusbarmanager.h>
  51. #include <projectexplorer/projectexplorerconstants.h>
  52. #include <texteditor/basetextdocumentlayout.h>
  53. #include <texteditor/basetexteditor.h>
  54. #include <texteditor/basetextmark.h>
  55. #include <texteditor/texteditorconstants.h>
  56. #include <texteditor/typingsettings.h>
  57. #include <texteditor/tabsettings.h>
  58. #include <texteditor/icodestylepreferences.h>
  59. #include <texteditor/texteditorsettings.h>
  60. #include <texteditor/indenter.h>
  61. #include <texteditor/codeassist/basicproposalitem.h>
  62. #include <texteditor/codeassist/basicproposalitemlistmodel.h>
  63. #include <texteditor/codeassist/completionassistprovider.h>
  64. #include <texteditor/codeassist/iassistprocessor.h>
  65. #include <texteditor/codeassist/iassistinterface.h>
  66. #include <texteditor/codeassist/genericproposal.h>
  67. #include <find/findplugin.h>
  68. #include <find/textfindconstants.h>
  69. #include <utils/qtcassert.h>
  70. #include <utils/savedaction.h>
  71. #include <utils/treewidgetcolumnstretcher.h>
  72. #include <utils/stylehelper.h>
  73. #include <cpptools/cpptoolsconstants.h>
  74. #include <QAbstractTableModel>
  75. #include <QDebug>
  76. #include <QFile>
  77. #include <QtPlugin>
  78. #include <QObject>
  79. #include <QSettings>
  80. #include <QTextStream>
  81. #include <QDesktopServices>
  82. #include <QItemDelegate>
  83. #include <QMessageBox>
  84. #include <QPlainTextEdit>
  85. #include <QShortcut>
  86. #include <QTextBlock>
  87. #include <QTextCursor>
  88. #include <QTextEdit>
  89. #include <QTreeWidgetItem>
  90. using namespace FakeVim::Internal;
  91. using namespace TextEditor;
  92. using namespace Core;
  93. namespace FakeVim {
  94. namespace Constants {
  95. const char INSTALL_HANDLER[] = "TextEditor.FakeVimHandler";
  96. const char MINI_BUFFER[] = "TextEditor.FakeVimMiniBuffer";
  97. const char SETTINGS_CATEGORY[] = "D.FakeVim";
  98. const char SETTINGS_CATEGORY_FAKEVIM_ICON[] = ":/core/images/category_fakevim.png";
  99. const char SETTINGS_ID[] = "A.General";
  100. const char SETTINGS_EX_CMDS_ID[] = "B.ExCommands";
  101. const char SETTINGS_USER_CMDS_ID[] = "C.UserCommands";
  102. } // namespace Constants
  103. } // namespace FakeVim
  104. namespace FakeVim {
  105. namespace Internal {
  106. class MiniBuffer : public QLabel
  107. {
  108. Q_OBJECT
  109. public:
  110. void setContents(const QString &contents, int cursorPos)
  111. {
  112. QString msg = contents;
  113. if (cursorPos != -1)
  114. msg = contents.left(cursorPos) + QChar(10073) + contents.mid(cursorPos);
  115. setText(" " + msg);
  116. }
  117. };
  118. class MiniBuffer1 : public QLineEdit
  119. {
  120. Q_OBJECT
  121. public:
  122. MiniBuffer1()
  123. {
  124. setFrame(false);
  125. }
  126. void showEvent(QShowEvent *ev)
  127. {
  128. QLineEdit::showEvent(ev);
  129. QColor color = Qt::black;
  130. QPalette pal = parentWidget()->palette();
  131. pal.setBrush(QPalette::All, QPalette::WindowText, color);
  132. pal.setBrush(QPalette::All, QPalette::ButtonText, color);
  133. pal.setBrush(QPalette::All, QPalette::Foreground, color);
  134. pal.setBrush(QPalette::All, QPalette::Background, color);
  135. //color.setAlpha(100);
  136. //pal.setBrush(QPalette::Disabled, QPalette::WindowText, color);
  137. //pal.setBrush(QPalette::Disabled, QPalette::ButtonText, color);
  138. //pal.setBrush(QPalette::Disabled, QPalette::Foreground, color);
  139. setPalette(pal);
  140. }
  141. void setContents(const QString &contents, int cursorPos)
  142. {
  143. setText(contents);
  144. setCursorPosition(cursorPos);
  145. }
  146. };
  147. ///////////////////////////////////////////////////////////////////////
  148. //
  149. // FakeVimOptionPage
  150. //
  151. ///////////////////////////////////////////////////////////////////////
  152. typedef QMap<QString, QRegExp> ExCommandMap;
  153. typedef QMap<int, QString> UserCommandMap;
  154. typedef QLatin1String _;
  155. class FakeVimOptionPage : public Core::IOptionsPage
  156. {
  157. Q_OBJECT
  158. public:
  159. FakeVimOptionPage()
  160. {
  161. setId(_(Constants::SETTINGS_ID));
  162. setDisplayName(tr("General"));
  163. setCategory(_(Constants::SETTINGS_CATEGORY));
  164. setDisplayCategory(tr("FakeVim"));
  165. setCategoryIcon(_(Constants::SETTINGS_CATEGORY_FAKEVIM_ICON));
  166. }
  167. QWidget *createPage(QWidget *parent);
  168. void apply() { m_group.apply(ICore::settings()); }
  169. void finish() { m_group.finish(); }
  170. virtual bool matches(const QString &) const;
  171. private slots:
  172. void copyTextEditorSettings();
  173. void setQtStyle();
  174. void setPlainStyle();
  175. private:
  176. friend class DebuggerPlugin;
  177. Ui::FakeVimOptionPage m_ui;
  178. QString m_searchKeywords;
  179. Utils::SavedActionSet m_group;
  180. };
  181. QWidget *FakeVimOptionPage::createPage(QWidget *parent)
  182. {
  183. QWidget *w = new QWidget(parent);
  184. m_ui.setupUi(w);
  185. m_group.clear();
  186. m_group.insert(theFakeVimSetting(ConfigUseFakeVim),
  187. m_ui.checkBoxUseFakeVim);
  188. m_group.insert(theFakeVimSetting(ConfigReadVimRc),
  189. m_ui.checkBoxReadVimRc);
  190. m_group.insert(theFakeVimSetting(ConfigExpandTab),
  191. m_ui.checkBoxExpandTab);
  192. m_group.insert(theFakeVimSetting(ConfigHlSearch),
  193. m_ui.checkBoxHlSearch);
  194. m_group.insert(theFakeVimSetting(ConfigShiftWidth),
  195. m_ui.spinBoxShiftWidth);
  196. m_group.insert(theFakeVimSetting(ConfigShowMarks),
  197. m_ui.checkBoxShowMarks);
  198. m_group.insert(theFakeVimSetting(ConfigSmartTab),
  199. m_ui.checkBoxSmartTab);
  200. m_group.insert(theFakeVimSetting(ConfigStartOfLine),
  201. m_ui.checkBoxStartOfLine);
  202. m_group.insert(theFakeVimSetting(ConfigTabStop),
  203. m_ui.spinBoxTabStop);
  204. m_group.insert(theFakeVimSetting(ConfigBackspace),
  205. m_ui.lineEditBackspace);
  206. m_group.insert(theFakeVimSetting(ConfigIsKeyword),
  207. m_ui.lineEditIsKeyword);
  208. m_group.insert(theFakeVimSetting(ConfigPassControlKey),
  209. m_ui.checkBoxPassControlKey);
  210. m_group.insert(theFakeVimSetting(ConfigAutoIndent),
  211. m_ui.checkBoxAutoIndent);
  212. m_group.insert(theFakeVimSetting(ConfigSmartIndent),
  213. m_ui.checkBoxSmartIndent);
  214. m_group.insert(theFakeVimSetting(ConfigIncSearch),
  215. m_ui.checkBoxIncSearch);
  216. m_group.insert(theFakeVimSetting(ConfigUseCoreSearch),
  217. m_ui.checkBoxUseCoreSearch);
  218. connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()),
  219. SLOT(copyTextEditorSettings()));
  220. connect(m_ui.pushButtonSetQtStyle, SIGNAL(clicked()),
  221. SLOT(setQtStyle()));
  222. connect(m_ui.pushButtonSetPlainStyle, SIGNAL(clicked()),
  223. SLOT(setPlainStyle()));
  224. if (m_searchKeywords.isEmpty()) {
  225. QLatin1Char sep(' ');
  226. QTextStream(&m_searchKeywords)
  227. << sep << m_ui.checkBoxUseFakeVim->text()
  228. << sep << m_ui.checkBoxReadVimRc->text()
  229. << sep << m_ui.checkBoxAutoIndent->text()
  230. << sep << m_ui.checkBoxSmartIndent->text()
  231. << sep << m_ui.checkBoxExpandTab->text()
  232. << sep << m_ui.checkBoxSmartTab->text()
  233. << sep << m_ui.checkBoxHlSearch->text()
  234. << sep << m_ui.checkBoxIncSearch->text()
  235. << sep << m_ui.checkBoxStartOfLine->text()
  236. << sep << m_ui.checkBoxUseCoreSearch->text()
  237. << sep << m_ui.checkBoxShowMarks->text()
  238. << sep << m_ui.checkBoxPassControlKey->text()
  239. << sep << m_ui.labelShiftWidth->text()
  240. << sep << m_ui.labelTabulator->text()
  241. << sep << m_ui.labelBackspace->text()
  242. << sep << m_ui.labelIsKeyword->text();
  243. m_searchKeywords.remove(QLatin1Char('&'));
  244. }
  245. return w;
  246. }
  247. void FakeVimOptionPage::copyTextEditorSettings()
  248. {
  249. TabSettings ts = TextEditorSettings::instance()->codeStyle()->tabSettings();
  250. TypingSettings tps = TextEditorSettings::instance()->typingSettings();
  251. m_ui.checkBoxExpandTab->setChecked(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy);
  252. m_ui.spinBoxTabStop->setValue(ts.m_tabSize);
  253. m_ui.spinBoxShiftWidth->setValue(ts.m_indentSize);
  254. m_ui.checkBoxSmartTab->setChecked(
  255. tps.m_smartBackspaceBehavior == TypingSettings::BackspaceFollowsPreviousIndents);
  256. m_ui.checkBoxAutoIndent->setChecked(true);
  257. m_ui.checkBoxSmartIndent->setChecked(tps.m_autoIndent);
  258. m_ui.checkBoxIncSearch->setChecked(true);
  259. }
  260. void FakeVimOptionPage::setQtStyle()
  261. {
  262. m_ui.checkBoxExpandTab->setChecked(true);
  263. m_ui.spinBoxTabStop->setValue(4);
  264. m_ui.spinBoxShiftWidth->setValue(4);
  265. m_ui.checkBoxSmartTab->setChecked(true);
  266. m_ui.checkBoxAutoIndent->setChecked(true);
  267. m_ui.checkBoxSmartIndent->setChecked(true);
  268. m_ui.checkBoxIncSearch->setChecked(true);
  269. m_ui.lineEditBackspace->setText(_("indent,eol,start"));
  270. }
  271. void FakeVimOptionPage::setPlainStyle()
  272. {
  273. m_ui.checkBoxExpandTab->setChecked(false);
  274. m_ui.spinBoxTabStop->setValue(8);
  275. m_ui.spinBoxShiftWidth->setValue(8);
  276. m_ui.checkBoxSmartTab->setChecked(false);
  277. m_ui.checkBoxAutoIndent->setChecked(false);
  278. m_ui.checkBoxSmartIndent->setChecked(false);
  279. m_ui.checkBoxIncSearch->setChecked(false);
  280. m_ui.lineEditBackspace->setText(QString());
  281. }
  282. bool FakeVimOptionPage::matches(const QString &s) const
  283. {
  284. return m_searchKeywords.contains(s, Qt::CaseInsensitive);
  285. }
  286. //const char *FAKEVIM_CONTEXT = "FakeVim";
  287. ///////////////////////////////////////////////////////////////////////
  288. //
  289. // FakeVimExCommandsPage
  290. //
  291. ///////////////////////////////////////////////////////////////////////
  292. enum { CommandRole = Qt::UserRole };
  293. class FakeVimExCommandsPage : public Core::CommandMappings
  294. {
  295. Q_OBJECT
  296. public:
  297. FakeVimExCommandsPage(FakeVimPluginPrivate *q)
  298. : m_q(q)
  299. {
  300. setId(_(Constants::SETTINGS_EX_CMDS_ID));
  301. setDisplayName(tr("Ex Command Mapping"));
  302. setCategory(_(Constants::SETTINGS_CATEGORY));
  303. setDisplayCategory(tr("FakeVim"));
  304. setCategoryIcon(_(Constants::SETTINGS_CATEGORY_FAKEVIM_ICON));
  305. }
  306. QWidget *createPage(QWidget *parent);
  307. void initialize();
  308. ExCommandMap &exCommandMap();
  309. ExCommandMap &defaultExCommandMap();
  310. public slots:
  311. void commandChanged(QTreeWidgetItem *current);
  312. void targetIdentifierChanged();
  313. void resetTargetIdentifier();
  314. void removeTargetIdentifier();
  315. void defaultAction();
  316. private:
  317. FakeVimPluginPrivate *m_q;
  318. };
  319. QWidget *FakeVimExCommandsPage::createPage(QWidget *parent)
  320. {
  321. QWidget *w = CommandMappings::createPage(parent);
  322. setPageTitle(tr("Ex Command Mapping"));
  323. setTargetHeader(tr("Ex Trigger Expression"));
  324. setTargetLabelText(tr("Regular expression:"));
  325. setTargetEditTitle(tr("Ex Command"));
  326. setImportExportEnabled(false);
  327. return w;
  328. }
  329. void FakeVimExCommandsPage::initialize()
  330. {
  331. QMap<QString, QTreeWidgetItem *> sections;
  332. foreach (Command *c, Core::ActionManager::commands()) {
  333. if (c->action() && c->action()->isSeparator())
  334. continue;
  335. QTreeWidgetItem *item = new QTreeWidgetItem;
  336. const QString name = c->id().toString();
  337. const int pos = name.indexOf(QLatin1Char('.'));
  338. const QString section = name.left(pos);
  339. const QString subId = name.mid(pos + 1);
  340. item->setData(0, CommandRole, name);
  341. if (!sections.contains(section)) {
  342. QTreeWidgetItem *categoryItem =
  343. new QTreeWidgetItem(commandList(), QStringList() << section);
  344. QFont f = categoryItem->font(0);
  345. f.setBold(true);
  346. categoryItem->setFont(0, f);
  347. sections.insert(section, categoryItem);
  348. commandList()->expandItem(categoryItem);
  349. }
  350. sections[section]->addChild(item);
  351. item->setText(0, subId);
  352. item->setText(1, c->description());
  353. QString regex;
  354. if (exCommandMap().contains(name))
  355. regex = exCommandMap()[name].pattern();
  356. item->setText(2, regex);
  357. if (regex != defaultExCommandMap()[name].pattern())
  358. setModified(item, true);
  359. }
  360. commandChanged(0);
  361. }
  362. void FakeVimExCommandsPage::commandChanged(QTreeWidgetItem *current)
  363. {
  364. CommandMappings::commandChanged(current);
  365. if (current)
  366. targetEdit()->setText(current->text(2));
  367. }
  368. void FakeVimExCommandsPage::targetIdentifierChanged()
  369. {
  370. QTreeWidgetItem *current = commandList()->currentItem();
  371. if (!current)
  372. return;
  373. const QString name = current->data(0, CommandRole).toString();
  374. const QString regex = targetEdit()->text();
  375. if (current->data(0, Qt::UserRole).isValid()) {
  376. current->setText(2, regex);
  377. exCommandMap()[name] = QRegExp(regex);
  378. }
  379. setModified(current, regex != defaultExCommandMap()[name].pattern());
  380. }
  381. void FakeVimExCommandsPage::resetTargetIdentifier()
  382. {
  383. QTreeWidgetItem *current = commandList()->currentItem();
  384. if (!current)
  385. return;
  386. const QString name = current->data(0, CommandRole).toString();
  387. QString regex;
  388. if (defaultExCommandMap().contains(name))
  389. regex = defaultExCommandMap()[name].pattern();
  390. targetEdit()->setText(regex);
  391. }
  392. void FakeVimExCommandsPage::removeTargetIdentifier()
  393. {
  394. targetEdit()->clear();
  395. }
  396. void FakeVimExCommandsPage::defaultAction()
  397. {
  398. int n = commandList()->topLevelItemCount();
  399. for (int i = 0; i != n; ++i) {
  400. QTreeWidgetItem *section = commandList()->topLevelItem(i);
  401. int m = section->childCount();
  402. for (int j = 0; j != m; ++j) {
  403. QTreeWidgetItem *item = section->child(j);
  404. const QString name = item->data(0, CommandRole).toString();
  405. QString regex;
  406. if (defaultExCommandMap().contains(name))
  407. regex = defaultExCommandMap()[name].pattern();
  408. setModified(item, false);
  409. item->setText(2, regex);
  410. if (item == commandList()->currentItem())
  411. commandChanged(item);
  412. }
  413. }
  414. }
  415. ///////////////////////////////////////////////////////////////////////
  416. //
  417. // FakeVimUserCommandsPage
  418. //
  419. ///////////////////////////////////////////////////////////////////////
  420. class FakeVimUserCommandsModel : public QAbstractTableModel
  421. {
  422. Q_OBJECT
  423. public:
  424. FakeVimUserCommandsModel(FakeVimPluginPrivate *q) : m_q(q) {}
  425. ~FakeVimUserCommandsModel() {}
  426. int rowCount(const QModelIndex &parent) const;
  427. int columnCount(const QModelIndex &parent) const;
  428. QVariant data(const QModelIndex &index, int role) const;
  429. bool setData(const QModelIndex &index, const QVariant &data, int role);
  430. QVariant headerData(int section, Qt::Orientation orientation, int role) const;
  431. Qt::ItemFlags flags(const QModelIndex &index) const;
  432. private:
  433. FakeVimPluginPrivate *m_q;
  434. };
  435. int FakeVimUserCommandsModel::rowCount(const QModelIndex &parent) const
  436. {
  437. return parent.isValid() ? 0 : 9;
  438. }
  439. int FakeVimUserCommandsModel::columnCount(const QModelIndex &parent) const
  440. {
  441. return parent.isValid() ? 0 : 2;
  442. }
  443. QVariant FakeVimUserCommandsModel::headerData(int section,
  444. Qt::Orientation orient, int role) const
  445. {
  446. if (orient == Qt::Horizontal && role == Qt::DisplayRole) {
  447. switch (section) {
  448. case 0: return tr("Action");
  449. case 1: return tr("Command");
  450. };
  451. }
  452. return QVariant();
  453. }
  454. Qt::ItemFlags FakeVimUserCommandsModel::flags(const QModelIndex &index) const
  455. {
  456. if (index.column() == 1)
  457. return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
  458. return QAbstractTableModel::flags(index);
  459. }
  460. class FakeVimUserCommandsDelegate : public QItemDelegate
  461. {
  462. public:
  463. explicit FakeVimUserCommandsDelegate(QObject *parent)
  464. : QItemDelegate(parent)
  465. {}
  466. QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &,
  467. const QModelIndex &) const
  468. {
  469. QLineEdit *lineEdit = new QLineEdit(parent);
  470. lineEdit->setFrame(false);
  471. return lineEdit;
  472. }
  473. void setModelData(QWidget *editor, QAbstractItemModel *model,
  474. const QModelIndex &index) const
  475. {
  476. QLineEdit *lineEdit = qobject_cast<QLineEdit *>(editor);
  477. QTC_ASSERT(lineEdit, return);
  478. model->setData(index, lineEdit->text(), Qt::EditRole);
  479. }
  480. };
  481. class FakeVimUserCommandsPage : public Core::IOptionsPage
  482. {
  483. Q_OBJECT
  484. public:
  485. FakeVimUserCommandsPage(FakeVimPluginPrivate *q)
  486. : m_q(q)
  487. {
  488. setId(_(Constants::SETTINGS_USER_CMDS_ID));
  489. setDisplayName(tr("User Command Mapping"));
  490. setCategory(_(Constants::SETTINGS_CATEGORY));
  491. setDisplayCategory(tr("FakeVim"));
  492. setCategoryIcon(_(Constants::SETTINGS_CATEGORY_FAKEVIM_ICON));
  493. }
  494. void apply();
  495. void finish() {}
  496. QWidget *createPage(QWidget *parent);
  497. void initialize() {}
  498. UserCommandMap &userCommandMap();
  499. UserCommandMap &defaultUserCommandMap();
  500. private:
  501. FakeVimPluginPrivate *m_q;
  502. };
  503. QWidget *FakeVimUserCommandsPage::createPage(QWidget *parent)
  504. {
  505. QGroupBox *box = new QGroupBox(parent);
  506. FakeVimUserCommandsModel *model = new FakeVimUserCommandsModel(m_q);
  507. QTreeView *widget = new QTreeView;
  508. widget->setModel(model);
  509. widget->resizeColumnToContents(0);
  510. FakeVimUserCommandsDelegate *delegate = new FakeVimUserCommandsDelegate(widget);
  511. widget->setItemDelegateForColumn(1, delegate);
  512. QGridLayout *layout = new QGridLayout(box);
  513. layout->addWidget(widget, 0, 0);
  514. box->setLayout(layout);
  515. return box;
  516. }
  517. void FakeVimUserCommandsPage::apply()
  518. {
  519. //m_q->writeSettings();
  520. }
  521. ///////////////////////////////////////////////////////////////////////
  522. //
  523. // WordCompletion
  524. //
  525. ///////////////////////////////////////////////////////////////////////
  526. class FakeVimCompletionAssistProvider : public TextEditor::CompletionAssistProvider
  527. {
  528. public:
  529. bool supportsEditor(const Core::Id &) const
  530. {
  531. return false;
  532. }
  533. TextEditor::IAssistProcessor *createProcessor() const;
  534. void setActive(const QString &needle, bool forward, FakeVimHandler *handler)
  535. {
  536. Q_UNUSED(forward);
  537. m_handler = handler;
  538. if (!m_handler)
  539. return;
  540. BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget());
  541. if (!editor)
  542. return;
  543. //qDebug() << "ACTIVATE: " << needle << forward;
  544. m_needle = needle;
  545. editor->invokeAssist(Completion, this);
  546. }
  547. void setInactive()
  548. {
  549. m_needle.clear();
  550. m_handler = 0;
  551. }
  552. const QString &needle() const
  553. {
  554. return m_needle;
  555. }
  556. void appendNeedle(const QChar &c)
  557. {
  558. m_needle.append(c);
  559. }
  560. FakeVimHandler *handler() const
  561. {
  562. return m_handler;
  563. }
  564. private:
  565. FakeVimHandler *m_handler;
  566. QString m_needle;
  567. };
  568. class FakeVimAssistProposalItem : public BasicProposalItem
  569. {
  570. public:
  571. FakeVimAssistProposalItem(const FakeVimCompletionAssistProvider *provider)
  572. : m_provider(const_cast<FakeVimCompletionAssistProvider *>(provider))
  573. {}
  574. virtual bool implicitlyApplies() const
  575. {
  576. return false;
  577. }
  578. virtual bool prematurelyApplies(const QChar &c) const
  579. {
  580. m_provider->appendNeedle(c);
  581. return text() == m_provider->needle();
  582. }
  583. virtual void applyContextualContent(BaseTextEditor *, int) const
  584. {
  585. QTC_ASSERT(m_provider->handler(), return);
  586. m_provider->handler()->handleReplay(text().mid(m_provider->needle().size()));
  587. const_cast<FakeVimCompletionAssistProvider *>(m_provider)->setInactive();
  588. }
  589. private:
  590. FakeVimCompletionAssistProvider *m_provider;
  591. };
  592. class FakeVimAssistProposalModel : public BasicProposalItemListModel
  593. {
  594. public:
  595. FakeVimAssistProposalModel(const QList<BasicProposalItem *> &items)
  596. : BasicProposalItemListModel(items)
  597. {}
  598. virtual bool supportsPrefixExpansion() const
  599. {
  600. return false;
  601. }
  602. };
  603. class FakeVimCompletionAssistProcessor : public IAssistProcessor
  604. {
  605. public:
  606. FakeVimCompletionAssistProcessor(const TextEditor::IAssistProvider *provider)
  607. : m_provider(static_cast<const FakeVimCompletionAssistProvider *>(provider))
  608. {}
  609. virtual TextEditor::IAssistProposal *perform(const IAssistInterface *interface)
  610. {
  611. const QString &needle = m_provider->needle();
  612. const int basePosition = interface->position() - needle.size();
  613. QTextCursor tc(interface->textDocument());
  614. tc.setPosition(interface->position());
  615. tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
  616. QList<BasicProposalItem *> items;
  617. QSet<QString> seen;
  618. QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
  619. while (1) {
  620. tc = tc.document()->find(needle, tc.position(), flags);
  621. if (tc.isNull())
  622. break;
  623. QTextCursor sel = tc;
  624. sel.select(QTextCursor::WordUnderCursor);
  625. QString found = sel.selectedText();
  626. // Only add "real" completions.
  627. if (found.startsWith(needle)
  628. && !seen.contains(found)
  629. && sel.anchor() != basePosition) {
  630. seen.insert(found);
  631. BasicProposalItem *item = new FakeVimAssistProposalItem(m_provider);
  632. item->setText(found);
  633. items.append(item);
  634. }
  635. tc.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor);
  636. }
  637. //qDebug() << "COMPLETIONS" << completions->size();
  638. delete interface;
  639. return new GenericProposal(basePosition, new FakeVimAssistProposalModel(items));
  640. }
  641. private:
  642. const FakeVimCompletionAssistProvider *m_provider;
  643. };
  644. IAssistProcessor *FakeVimCompletionAssistProvider::createProcessor() const
  645. {
  646. return new FakeVimCompletionAssistProcessor(this);
  647. }
  648. ///////////////////////////////////////////////////////////////////////
  649. //
  650. // FakeVimPluginPrivate
  651. //
  652. ///////////////////////////////////////////////////////////////////////
  653. class FakeVimPluginPrivate : public QObject
  654. {
  655. Q_OBJECT
  656. public:
  657. FakeVimPluginPrivate(FakeVimPlugin *);
  658. ~FakeVimPluginPrivate();
  659. friend class FakeVimPlugin;
  660. friend class FakeVimExCommandsPage;
  661. friend class FakeVimUserCommandsPage;
  662. friend class FakeVimUserCommandsModel;
  663. bool initialize();
  664. void aboutToShutdown();
  665. private slots:
  666. void onCoreAboutToClose();
  667. void editorOpened(Core::IEditor *);
  668. void editorAboutToClose(Core::IEditor *);
  669. void setUseFakeVim(const QVariant &value);
  670. void setUseFakeVimInternal(bool on);
  671. void quitFakeVim();
  672. void triggerCompletions();
  673. void triggerSimpleCompletions(const QString &needle, bool forward);
  674. void windowCommand(int key);
  675. void find(bool reverse);
  676. void findNext(bool reverse);
  677. void showSettingsDialog();
  678. void maybeReadVimRc();
  679. void setBlockSelection(bool);
  680. void hasBlockSelection(bool*);
  681. void showCommandBuffer(const QString &contents, int cursorPos);
  682. void showExtraInformation(const QString &msg);
  683. void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
  684. void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
  685. void checkForElectricCharacter(bool *result, QChar c);
  686. void indentRegion(int beginLine, int endLine, QChar typedChar);
  687. void handleExCommand(bool *handled, const ExCommand &cmd);
  688. void writeSettings();
  689. void readSettings();
  690. void handleDelayedQuitAll(bool forced);
  691. void handleDelayedQuit(bool forced, Core::IEditor *editor);
  692. void userActionTriggered();
  693. void switchToFile(int n);
  694. int currentFile() const;
  695. signals:
  696. void delayedQuitRequested(bool forced, Core::IEditor *editor);
  697. void delayedQuitAllRequested(bool forced);
  698. private:
  699. FakeVimPlugin *q;
  700. FakeVimOptionPage *m_fakeVimOptionsPage;
  701. FakeVimExCommandsPage *m_fakeVimExCommandsPage;
  702. FakeVimUserCommandsPage *m_fakeVimUserCommandsPage;
  703. QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
  704. void triggerAction(const Core::Id &id);
  705. void setActionChecked(const Core::Id &id, bool check);
  706. typedef int (*DistFunction)(const QRect &cursor, const QRect &other);
  707. void moveSomewhere(DistFunction f);
  708. ExCommandMap &exCommandMap() { return m_exCommandMap; }
  709. ExCommandMap &defaultExCommandMap() { return m_defaultExCommandMap; }
  710. ExCommandMap m_exCommandMap;
  711. ExCommandMap m_defaultExCommandMap;
  712. UserCommandMap &userCommandMap() { return m_userCommandMap; }
  713. UserCommandMap &defaultUserCommandMap() { return m_defaultUserCommandMap; }
  714. UserCommandMap m_userCommandMap;
  715. UserCommandMap m_defaultUserCommandMap;
  716. Core::StatusBarWidget *m_statusBar;
  717. // @TODO: Delete
  718. //WordCompletion *m_wordCompletion;
  719. FakeVimCompletionAssistProvider *m_wordProvider;
  720. };
  721. QVariant FakeVimUserCommandsModel::data(const QModelIndex &index, int role) const
  722. {
  723. if (!index.isValid())
  724. return QVariant();
  725. if (role == Qt::DisplayRole || role == Qt::EditRole) {
  726. switch (index.column()) {
  727. case 0: // Action
  728. return tr("User command #%1").arg(index.row() + 1);
  729. case 1: // Command
  730. return m_q->userCommandMap().value(index.row() + 1);
  731. }
  732. }
  733. return QVariant();
  734. }
  735. bool FakeVimUserCommandsModel::setData(const QModelIndex &index,
  736. const QVariant &data, int role)
  737. {
  738. if (role == Qt::DisplayRole || role == Qt::EditRole)
  739. if (index.column() == 1)
  740. m_q->userCommandMap()[index.row() + 1] = data.toString();
  741. return true;
  742. }
  743. FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
  744. {
  745. q = plugin;
  746. m_fakeVimOptionsPage = 0;
  747. m_fakeVimExCommandsPage = 0;
  748. m_fakeVimUserCommandsPage = 0;
  749. defaultExCommandMap()[CppTools::Constants::SWITCH_HEADER_SOURCE] =
  750. QRegExp("^A$");
  751. defaultExCommandMap()["Coreplugin.OutputPane.previtem"] =
  752. QRegExp("^(cN(ext)?|cp(revious)?)!?( (.*))?$");
  753. defaultExCommandMap()["Coreplugin.OutputPane.nextitem"] =
  754. QRegExp("^cn(ext)?!?( (.*))?$");
  755. defaultExCommandMap()[TextEditor::Constants::FOLLOW_SYMBOL_UNDER_CURSOR] =
  756. QRegExp("^tag?$");
  757. defaultExCommandMap()[Core::Constants::GO_BACK] =
  758. QRegExp("^pop?$");
  759. defaultExCommandMap()[_("QtCreator.Locate")] =
  760. QRegExp("^e$");
  761. for (int i = 1; i < 10; ++i) {
  762. QString cmd = QString::fromLatin1(":echo User command %1 executed.<CR>");
  763. defaultUserCommandMap().insert(i, cmd.arg(i));
  764. }
  765. m_statusBar = 0;
  766. }
  767. FakeVimPluginPrivate::~FakeVimPluginPrivate()
  768. {
  769. q->removeObject(m_fakeVimOptionsPage);
  770. delete m_fakeVimOptionsPage;
  771. m_fakeVimOptionsPage = 0;
  772. delete theFakeVimSettings();
  773. q->removeObject(m_fakeVimExCommandsPage);
  774. delete m_fakeVimExCommandsPage;
  775. m_fakeVimExCommandsPage = 0;
  776. q->removeObject(m_fakeVimUserCommandsPage);
  777. delete m_fakeVimUserCommandsPage;
  778. m_fakeVimUserCommandsPage = 0;
  779. }
  780. void FakeVimPluginPrivate::onCoreAboutToClose()
  781. {
  782. // Don't attach to editors anymore.
  783. disconnect(ICore::editorManager(), SIGNAL(editorOpened(Core::IEditor*)),
  784. this, SLOT(editorOpened(Core::IEditor*)));
  785. }
  786. void FakeVimPluginPrivate::aboutToShutdown()
  787. {
  788. }
  789. bool FakeVimPluginPrivate::initialize()
  790. {
  791. EditorManager *editorManager = ICore::editorManager();
  792. //m_wordCompletion = new WordCompletion;
  793. //q->addAutoReleasedObject(m_wordCompletion);
  794. m_wordProvider = new FakeVimCompletionAssistProvider;
  795. /*
  796. // Set completion settings and keep them up to date.
  797. TextEditorSettings *textEditorSettings = TextEditorSettings::instance();
  798. completion->setCompletionSettings(textEditorSettings->completionSettings());
  799. connect(textEditorSettings,
  800. SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)),
  801. completion,
  802. SLOT(setCompletionSettings(TextEditor::CompletionSettings)));
  803. */
  804. Context globalcontext(Core::Constants::C_GLOBAL);
  805. m_fakeVimOptionsPage = new FakeVimOptionPage;
  806. q->addObject(m_fakeVimOptionsPage);
  807. m_fakeVimExCommandsPage = new FakeVimExCommandsPage(this);
  808. q->addObject(m_fakeVimExCommandsPage);
  809. m_fakeVimUserCommandsPage = new FakeVimUserCommandsPage(this);
  810. q->addObject(m_fakeVimUserCommandsPage);
  811. readSettings();
  812. Core::Command *cmd = 0;
  813. cmd = Core::ActionManager::registerAction(theFakeVimSetting(ConfigUseFakeVim),
  814. Constants::INSTALL_HANDLER, globalcontext, true);
  815. cmd->setDefaultKeySequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+V,Meta+V") : tr("Alt+V,Alt+V")));
  816. ActionContainer *advancedMenu =
  817. Core::ActionManager::actionContainer(Core::Constants::M_EDIT_ADVANCED);
  818. advancedMenu->addAction(cmd, Core::Constants::G_EDIT_EDITOR);
  819. for (int i = 1; i < 10; ++i) {
  820. QAction *act = new QAction(this);
  821. act->setText(tr("Execute User Action #%1").arg(i));
  822. act->setData(i);
  823. QString id = QString("FakeVim.UserAction%1").arg(i);
  824. cmd = Core::ActionManager::registerAction(act, Core::Id(id), globalcontext);
  825. cmd->setDefaultKeySequence(QKeySequence((Core::UseMacShortcuts ? tr("Meta+V,%1") : tr("Alt+V,%1")).arg(i)));
  826. connect(act, SIGNAL(triggered()), SLOT(userActionTriggered()));
  827. }
  828. connect(ICore::instance(), SIGNAL(coreAboutToClose()), this, SLOT(onCoreAboutToClose()));
  829. // EditorManager
  830. connect(editorManager, SIGNAL(editorAboutToClose(Core::IEditor*)),
  831. this, SLOT(editorAboutToClose(Core::IEditor*)));
  832. connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)),
  833. this, SLOT(editorOpened(Core::IEditor*)));
  834. connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
  835. this, SLOT(setUseFakeVim(QVariant)));
  836. connect(theFakeVimSetting(ConfigReadVimRc), SIGNAL(valueChanged(QVariant)),
  837. this, SLOT(maybeReadVimRc()));
  838. // Delayed operations.
  839. connect(this, SIGNAL(delayedQuitRequested(bool,Core::IEditor*)),
  840. this, SLOT(handleDelayedQuit(bool,Core::IEditor*)), Qt::QueuedConnection);
  841. connect(this, SIGNAL(delayedQuitAllRequested(bool)),
  842. this, SLOT(handleDelayedQuitAll(bool)), Qt::QueuedConnection);
  843. maybeReadVimRc();
  844. // << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
  845. return true;
  846. }
  847. void FakeVimPluginPrivate::userActionTriggered()
  848. {
  849. QAction *act = qobject_cast<QAction *>(sender());
  850. if (!act)
  851. return;
  852. const int key = act->data().toInt();
  853. if (!key)
  854. return;
  855. QString cmd = userCommandMap().value(key);
  856. IEditor *editor = EditorManager::currentEditor();
  857. FakeVimHandler *handler = m_editorToHandler[editor];
  858. if (handler)
  859. handler->handleInput(cmd);
  860. }
  861. static const char exCommandMapGroup[] = "FakeVimExCommand";
  862. static const char userCommandMapGroup[] = "FakeVimUserCommand";
  863. static const char reKey[] = "RegEx";
  864. static const char cmdKey[] = "Cmd";
  865. static const char idKey[] = "Command";
  866. void FakeVimPluginPrivate::writeSettings()
  867. {
  868. QSettings *settings = ICore::settings();
  869. theFakeVimSettings()->writeSettings(settings);
  870. { // block
  871. settings->beginWriteArray(_(exCommandMapGroup));
  872. int count = 0;
  873. typedef ExCommandMap::const_iterator Iterator;
  874. const Iterator end = exCommandMap().constEnd();
  875. for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
  876. const QString id = it.key();
  877. const QRegExp re = it.value();
  878. if ((defaultExCommandMap().contains(id) && defaultExCommandMap()[id] != re)
  879. || (!defaultExCommandMap().contains(id) && !re.pattern().isEmpty())) {
  880. settings->setArrayIndex(count);
  881. settings->setValue(_(idKey), id);
  882. settings->setValue(_(reKey), re.pattern());
  883. ++count;
  884. }
  885. }
  886. settings->endArray();
  887. } // block
  888. { // block
  889. settings->beginWriteArray(_(userCommandMapGroup));
  890. int count = 0;
  891. typedef UserCommandMap::const_iterator Iterator;
  892. const Iterator end = userCommandMap().constEnd();
  893. for (Iterator it = userCommandMap().constBegin(); it != end; ++it) {
  894. const int key = it.key();
  895. const QString cmd = it.value();
  896. if ((defaultUserCommandMap().contains(key)
  897. && defaultUserCommandMap()[key] != cmd)
  898. || (!defaultUserCommandMap().contains(key) && !cmd.isEmpty())) {
  899. settings->setArrayIndex(count);
  900. settings->setValue(_(idKey), key);
  901. settings->setValue(_(cmdKey), cmd);
  902. ++count;
  903. }
  904. }
  905. settings->endArray();
  906. } // block
  907. }
  908. void FakeVimPluginPrivate::readSettings()
  909. {
  910. QSettings *settings = ICore::settings();
  911. theFakeVimSettings()->readSettings(settings);
  912. exCommandMap() = defaultExCommandMap();
  913. int size = settings->beginReadArray(_(exCommandMapGroup));
  914. for (int i = 0; i < size; ++i) {
  915. settings->setArrayIndex(i);
  916. const QString id = settings->value(_(idKey)).toString();
  917. const QString re = settings->value(_(reKey)).toString();
  918. exCommandMap()[id] = QRegExp(re);
  919. }
  920. settings->endArray();
  921. userCommandMap() = defaultUserCommandMap();
  922. size = settings->beginReadArray(_(userCommandMapGroup));
  923. for (int i = 0; i < size; ++i) {
  924. settings->setArrayIndex(i);
  925. const int id = settings->value(_(idKey)).toInt();
  926. const QString cmd = settings->value(_(cmdKey)).toString();
  927. userCommandMap()[id] = cmd;
  928. }
  929. settings->endArray();
  930. }
  931. void FakeVimPluginPrivate::maybeReadVimRc()
  932. {
  933. //qDebug() << theFakeVimSetting(ConfigReadVimRc)
  934. // << theFakeVimSetting(ConfigReadVimRc)->value();
  935. //qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
  936. if (!theFakeVimSetting(ConfigReadVimRc)->value().toBool())
  937. return;
  938. QString fileName =
  939. QDesktopServices::storageLocation(QDesktopServices::HomeLocation)
  940. + "/.vimrc";
  941. //qDebug() << "READING VIMRC: " << fileName;
  942. // Read it into a temporary handler for effects modifying global state.
  943. QPlainTextEdit editor;
  944. FakeVimHandler handler(&editor);
  945. handler.handleCommand("source " + fileName);
  946. //writeSettings();
  947. //qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
  948. }
  949. void FakeVimPluginPrivate::showSettingsDialog()
  950. {
  951. ICore::showOptionsDialog(
  952. _(Constants::SETTINGS_CATEGORY),
  953. _(Constants::SETTINGS_ID));
  954. }
  955. void FakeVimPluginPrivate::triggerAction(const Id &id)
  956. {
  957. Core::Command *cmd = Core::ActionManager::command(id);
  958. QTC_ASSERT(cmd, qDebug() << "UNKNOWN CODE: " << id.name(); return);
  959. QAction *action = cmd->action();
  960. QTC_ASSERT(action, return);
  961. action->trigger();
  962. }
  963. void FakeVimPluginPrivate::setActionChecked(const Id &id, bool check)
  964. {
  965. Core::Command *cmd = Core::ActionManager::command(id);
  966. QTC_ASSERT(cmd, return);
  967. QAction *action = cmd->action();
  968. QTC_ASSERT(action, return);
  969. QTC_ASSERT(action->isCheckable(), return);
  970. action->setChecked(!check); // trigger negates the action's state
  971. action->trigger();
  972. }
  973. static int moveRightWeight(const QRect &cursor, const QRect &other)
  974. {
  975. int dx = other.left() - cursor.right();
  976. if (dx < 0)
  977. return -1;
  978. int w = 10000 * dx;
  979. int dy1 = cursor.top() - other.bottom();
  980. int dy2 = cursor.bottom() - other.top();
  981. w += dy1 * (dy1 > 0);
  982. w += dy2 * (dy2 > 0);
  983. qDebug() << " DX: " << dx << dy1 << dy2 << w;
  984. return w;
  985. }
  986. static int moveLeftWeight(const QRect &cursor, const QRect &other)
  987. {
  988. int dx = other.right() - cursor.left();
  989. if (dx < 0)
  990. return -1;
  991. int w = 10000 * dx;
  992. int dy1 = cursor.top() - other.bottom();
  993. int dy2 = cursor.bottom() - other.top();
  994. w += dy1 * (dy1 > 0);
  995. w += dy2 * (dy2 > 0);
  996. return w;
  997. }
  998. static int moveUpWeight(const QRect &cursor, const QRect &other)
  999. {
  1000. int dy = other.bottom() - cursor.top();
  1001. if (dy < 0)
  1002. return -1;
  1003. int w = 10000 * dy;
  1004. int dx1 = cursor.left() - other.right();
  1005. int dx2 = cursor.right() - other.left();
  1006. w += dx1 * (dx1 > 0);
  1007. w += dx2 * (dx2 > 0);
  1008. return w;
  1009. }
  1010. static int moveDownWeight(const QRect &cursor, const QRect &other)
  1011. {
  1012. int dy = other.top() - cursor.bottom();
  1013. if (dy < 0)
  1014. return -1;
  1015. int w = 10000 * dy;
  1016. int dx1 = cursor.left() - other.right();
  1017. int dx2 = cursor.right() - other.left();
  1018. w += dx1 * (dx1 > 0);
  1019. w += dx2 * (dx2 > 0);
  1020. return w;
  1021. }
  1022. void FakeVimPluginPrivate::windowCommand(int key)
  1023. {
  1024. # define control(n) (256 + n)
  1025. switch (key) {
  1026. case 'c': case 'C': case control('c'):
  1027. triggerAction(Core::Constants::CLOSE);
  1028. break;
  1029. case 'n': case 'N': case control('n'):
  1030. triggerAction(Core::Constants::GOTONEXT);
  1031. break;
  1032. case 'o': case 'O': case control('o'):
  1033. //triggerAction(Core::Constants::REMOVE_ALL_SPLITS);
  1034. triggerAction(Core::Constants::REMOVE_CURRENT_SPLIT);
  1035. break;
  1036. case 'p': case 'P': case control('p'):
  1037. triggerAction(Core::Constants::GOTOPREV);
  1038. break;
  1039. case 's': case 'S': case control('s'):
  1040. triggerAction(Core::Constants::SPLIT);
  1041. break;
  1042. case 'w': case 'W': case control('w'):
  1043. triggerAction(Core::Constants::GOTO_OTHER_SPLIT);
  1044. break;
  1045. case Qt::Key_Right:
  1046. moveSomewhere(&moveRightWeight);
  1047. break;
  1048. case Qt::Key_Left:
  1049. moveSomewhere(&moveLeftWeight);
  1050. break;
  1051. case Qt::Key_Up:
  1052. moveSomewhere(&moveUpWeight);
  1053. break;
  1054. case Qt::Key_Down:
  1055. moveSomewhere(&moveDownWeight);
  1056. break;
  1057. default:
  1058. qDebug() << "UNKNOWN WINDOWS COMMAND: " << key;
  1059. break;
  1060. }
  1061. # undef control
  1062. }
  1063. void FakeVimPluginPrivate::moveSomewhere(DistFunction f)
  1064. {
  1065. IEditor *editor = EditorManager::currentEditor();
  1066. QWidget *w = editor->widget();
  1067. QPlainTextEdit *pe = qobject_cast<QPlainTextEdit *>(w);
  1068. QTC_ASSERT(pe, return);
  1069. QRect rc = pe->cursorRect();
  1070. QRect cursorRect(w->mapToGlobal(rc.topLeft()),
  1071. w->mapToGlobal(rc.bottomRight()));
  1072. //qDebug() << "\nCURSOR: " << cursorRect;
  1073. IEditor *bestEditor = 0;
  1074. int bestValue = 1 << 30;
  1075. foreach (IEditor *editor, EditorManager::instance()->visibleEditors()) {
  1076. QWidget *w = editor->widget();
  1077. QRect editorRect(w->mapToGlobal(w->geometry().topLeft()),
  1078. w->mapToGlobal(w->geometry().bottomRight()));
  1079. //qDebug() << " EDITOR: " << editorRect << editor;
  1080. int value = f(cursorRect, editorRect);
  1081. if (value != -1 && value < bestValue) {
  1082. bestValue = value;
  1083. bestEditor = editor;
  1084. //qDebug() << " BEST SO FAR: " << bestValue << bestEditor;
  1085. }
  1086. }
  1087. //qDebug() << " BEST: " << bestValue << bestEditor;
  1088. // FIME: This is know to fail as the EditorManager will fall back to
  1089. // the current editor's view. Needs additional public API there.
  1090. if (bestEditor)
  1091. EditorManager::activateEditor(bestEditor);
  1092. }
  1093. void FakeVimPluginPrivate::find(bool reverse)
  1094. {
  1095. if (Find::FindPlugin *plugin = Find::FindPlugin::instance()) {
  1096. plugin->setUseFakeVim(true);
  1097. plugin->openFindToolBar(reverse
  1098. ? Find::FindPlugin::FindBackward
  1099. : Find::FindPlugin::FindForward);
  1100. }
  1101. }
  1102. void FakeVimPluginPrivate::findNext(bool reverse)
  1103. {
  1104. if (reverse)
  1105. triggerAction(Find::Constants::FIND_PREVIOUS);
  1106. else
  1107. triggerAction(Find::Constants::FIND_NEXT);
  1108. }
  1109. // This class defers deletion of a child FakeVimHandler using deleteLater().
  1110. class DeferredDeleter : public QObject
  1111. {
  1112. Q_OBJECT
  1113. FakeVimHandler *m_handler;
  1114. public:
  1115. DeferredDeleter(QObject *parent, FakeVimHandler *handler)
  1116. : QObject(parent), m_handler(handler)
  1117. {}
  1118. virtual ~DeferredDeleter()
  1119. {
  1120. if (m_handler) {
  1121. m_handler->disconnectFromEditor();
  1122. m_handler->deleteLater();
  1123. m_handler = 0;
  1124. }
  1125. }
  1126. };
  1127. void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
  1128. {
  1129. if (!editor)
  1130. return;
  1131. QWidget *widget = editor->widget();
  1132. if (!widget)
  1133. return;
  1134. // we can only handle QTextEdit and QPlainTextEdit
  1135. if (!qobject_cast<QTextEdit *>(widget) && !qobject_cast<QPlainTextEdit *>(widget))
  1136. return;
  1137. //qDebug() << "OPENING: " << editor << editor->widget()
  1138. // << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
  1139. FakeVimHandler *handler = new FakeVimHandler(widget, 0);
  1140. // the handler might have triggered the deletion of the editor:
  1141. // make sure that it can return before being deleted itself
  1142. new DeferredDeleter(widget, handler);
  1143. m_editorToHandler[editor] = handler;
  1144. connect(handler, SIGNAL(extraInformationChanged(QString)),
  1145. SLOT(showExtraInformation(QString)));
  1146. connect(handler, SIGNAL(commandBufferChanged(QString,int)),
  1147. SLOT(showCommandBuffer(QString,int)));
  1148. connect(handler, SIGNAL(selectionChanged(QList<QTextEdit::ExtraSelection>)),
  1149. SLOT(changeSelection(QList<QTextEdit::ExtraSelection>)));
  1150. connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
  1151. SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)));
  1152. connect(handler, SIGNAL(indentRegion(int,int,QChar)),
  1153. SLOT(indentRegion(int,int,QChar)));
  1154. connect(handler, SIGNAL(checkForElectricCharacter(bool*,QChar)),
  1155. SLOT(checkForElectricCharacter(bool*,QChar)));
  1156. connect(handler, SIGNAL(requestSetBlockSelection(bool)),
  1157. SLOT(setBlockSelection(bool)));
  1158. connect(handler, SIGNAL(requestHasBlockSelection(bool*)),
  1159. SLOT(hasBlockSelection(bool*)));
  1160. connect(handler, SIGNAL(completionRequested()),
  1161. SLOT(triggerCompletions()));
  1162. connect(handler, SIGNAL(simpleCompletionRequested(QString,bool)),
  1163. SLOT(triggerSimpleCompletions(QString,bool)));
  1164. connect(handler, SIGNAL(windowCommandRequested(int)),
  1165. SLOT(windowCommand(int)));
  1166. connect(handler, SIGNAL(findRequested(bool)),
  1167. SLOT(find(bool)));
  1168. connect(handler, SIGNAL(findNextRequested(bool)),
  1169. SLOT(findNext(bool)));
  1170. connect(handler, SIGNAL(handleExCommandRequested(bool*,ExCommand)),
  1171. SLOT(handleExCommand(bool*,ExCommand)));
  1172. connect(ICore::instance(), SIGNAL(saveSettingsRequested()),
  1173. SLOT(writeSettings()));
  1174. handler->setCurrentFileName(editor->document()->fileName());
  1175. handler->installEventFilter();
  1176. // pop up the bar
  1177. if (theFakeVimSetting(ConfigUseFakeVim)->value().toBool()) {
  1178. showCommandBuffer(QString(), -1);
  1179. handler->setupWidget();
  1180. }
  1181. }
  1182. void FakeVimPluginPrivate::editorAboutToClose(Core::IEditor *editor)
  1183. {
  1184. //qDebug() << "CLOSING: " << editor << editor->widget();
  1185. m_editorToHandler.remove(editor);
  1186. }
  1187. void FakeVimPluginPrivate::setUseFakeVim(const QVariant &value)
  1188. {
  1189. //qDebug() << "SET USE FAKEVIM" << value;
  1190. bool on = value.toBool();
  1191. if (Find::FindPlugin::instance())
  1192. Find::FindPlugin::instance()->setUseFakeVim(on);
  1193. setUseFakeVimInternal(on);
  1194. }
  1195. void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
  1196. {
  1197. if (on) {
  1198. //ICore *core = ICore::instance();
  1199. //core->updateAdditionalContexts(Core::Context(FAKEVIM_CONTEXT),
  1200. // Core::Context());
  1201. foreach (Core::IEditor *editor, m_editorToHandler.keys())
  1202. m_editorToHandler[editor]->setupWidget();
  1203. } else {
  1204. //ICore *core = ICore::instance();
  1205. //core->updateAdditionalContexts(Core::Context(),
  1206. // Core::Context(FAKEVIM_CONTEXT));
  1207. showCommandBuffer(QString(), -1);
  1208. foreach (Core::IEditor *editor, m_editorToHandler.keys()) {
  1209. if (TextEditor::BaseTextEditorWidget *textEditor =
  1210. qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget())) {
  1211. m_editorToHandler[editor]->restoreWidget(textEditor->tabSettings().m_tabSize);
  1212. }
  1213. }
  1214. }
  1215. }
  1216. void FakeVimPluginPrivate::triggerCompletions()
  1217. {
  1218. FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
  1219. if (!handler)
  1220. return;
  1221. if (BaseTextEditorWidget *editor = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
  1222. editor->invokeAssist(Completion, m_wordProvider);
  1223. // CompletionSupport::instance()->complete(editor->editor(), TextCompletion, false);
  1224. }
  1225. void FakeVimPluginPrivate::triggerSimpleCompletions(const QString &needle,
  1226. bool forward)
  1227. {
  1228. // m_wordCompletion->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
  1229. m_wordProvider->setActive(needle, forward, qobject_cast<FakeVimHandler *>(sender()));
  1230. }
  1231. void FakeVimPluginPrivate::setBlockSelection(bool on)
  1232. {
  1233. FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
  1234. if (!handler)
  1235. return;
  1236. if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
  1237. bt->setBlockSelection(on);
  1238. }
  1239. void FakeVimPluginPrivate::hasBlockSelection(bool *on)
  1240. {
  1241. FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
  1242. if (!handler)
  1243. return;
  1244. if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
  1245. *on = bt->hasBlockSelection();
  1246. }
  1247. void FakeVimPluginPrivate::checkForElectricCharacter(bool *result, QChar c)
  1248. {
  1249. FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
  1250. if (!handler)
  1251. return;
  1252. if (BaseTextEditorWidget *bt = qobject_cast<BaseTextEditorWidget *>(handler->widget()))
  1253. *result = bt->indenter()->isElectricCharacter(c);
  1254. }
  1255. void FakeVimPluginPrivate::handleExCommand(bool *handled, const ExCommand &cmd)
  1256. {
  1257. using namespace Core;
  1258. //qDebug() << "PLUGIN HANDLE: " << cmd.cmd << cmd.count;
  1259. *handled = false;
  1260. FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
  1261. if (!handler)
  1262. return;
  1263. *handled = true;
  1264. if (cmd.matches("w", "write") || cmd.cmd == "wq") {
  1265. // :w[rite]
  1266. Core::IEditor *editor = m_editorToHandler.key(handler);
  1267. const QString fileName = handler->currentFileName();
  1268. if (editor && editor->document()->fileName() == fileName) {
  1269. // Handle that as a special case for nicer interaction with core
  1270. DocumentManager::saveDocument(editor->document());
  1271. // Check result by reading back.
  1272. QFile file3(fileName);
  1273. file3.open(QIODevice::ReadOnly);
  1274. QByteArray ba = file3.readAll();
  1275. handler->showBlackMessage(FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
  1276. .arg(fileName).arg(" ")
  1277. .arg(ba.count('\n')).arg(ba.size()));
  1278. if (cmd.cmd == "wq")
  1279. delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
  1280. } else {
  1281. handler->showRedMessage(tr("File not saved"));
  1282. }
  1283. } else if (cmd.matches("wa", "wall")) {
  1284. // :w[all]
  1285. QList<IDocument *> toSave = DocumentManager::modifiedDocuments();
  1286. QList<IDocument *> failed = DocumentManager::saveModifiedDocumentsSilently(toSave);
  1287. if (failed.isEmpty())
  1288. handler->showBlackMessage(tr("Saving succeeded"));
  1289. else
  1290. handler->showRedMessage(tr("%n files not saved", 0, failed.size()));
  1291. } else if (cmd.matches("q", "quit")) {
  1292. // :q[uit]
  1293. emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
  1294. } else if (cmd.matches("qa", "qall")) {
  1295. // :qa[ll]
  1296. emit delayedQuitAllRequested(cmd.hasBang);
  1297. } else if (cmd.matches("sp", "split")) {
  1298. // :sp[lit]
  1299. triggerAction(Core::Constants::SPLIT);
  1300. } else if (cmd.matches("vs", "vsplit")) {
  1301. // :vs[plit]
  1302. triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE);
  1303. } else if (cmd.matches("mak", "make")) {
  1304. // :mak[e][!] [arguments]
  1305. triggerAction(ProjectExplorer::Constants::BUILD);
  1306. } else if (cmd.matches("se", "set")) {
  1307. if (cmd.args.isEmpty()) {
  1308. // :se[t]
  1309. showSettingsDialog();
  1310. } else if (cmd.args == "ic" || cmd.args == "ignorecase") {
  1311. // :set nc
  1312. setActionChecked(Find::Con

Large files files are truncated, but you can click here to view the full file