| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- #include "vvimindicator.h"
- #include <QLabel>
- #include <QHBoxLayout>
- #include <QTreeWidget>
- #include <QStringList>
- #include <QFontMetrics>
- #include <QFont>
- #include <QHeaderView>
- #include "vconfigmanager.h"
- #include "vbuttonwithwidget.h"
- #include "vedittab.h"
- extern VConfigManager vconfig;
- VVimIndicator::VVimIndicator(QWidget *p_parent)
- : QWidget(p_parent), m_vim(NULL)
- {
- setupUI();
- }
- void VVimIndicator::setupUI()
- {
- m_cmdLineEdit = new VVimCmdLineEdit(this);
- m_cmdLineEdit->setProperty("VimCommandLine", true);
- connect(m_cmdLineEdit, &VVimCmdLineEdit::commandCancelled,
- this, [this](){
- if (m_vim) {
- m_vim->processCommandLineCancelled();
- }
- if (m_editTab) {
- m_editTab->focusTab();
- }
- // NOTICE: m_cmdLineEdit should not hide itself before setting
- // focus to edit tab.
- m_cmdLineEdit->hide();
- });
- connect(m_cmdLineEdit, &VVimCmdLineEdit::commandFinished,
- this, [this](VVim::CommandLineType p_type, const QString &p_cmd){
- if (m_vim) {
- m_vim->processCommandLine(p_type, p_cmd);
- }
- if (m_editTab) {
- m_editTab->focusTab();
- }
- m_cmdLineEdit->hide();
- });
- connect(m_cmdLineEdit, &VVimCmdLineEdit::commandChanged,
- this, [this](VVim::CommandLineType p_type, const QString &p_cmd){
- if (m_vim) {
- m_vim->processCommandLineChanged(p_type, p_cmd);
- }
- });
- connect(m_cmdLineEdit, &VVimCmdLineEdit::requestNextCommand,
- this, [this](VVim::CommandLineType p_type, const QString &p_cmd){
- if (m_vim) {
- QString cmd = m_vim->getNextCommandHistory(p_type, p_cmd);
- if (!cmd.isNull()) {
- m_cmdLineEdit->setCommand(cmd);
- } else {
- m_cmdLineEdit->restoreUserLastInput();
- }
- }
- });
- connect(m_cmdLineEdit, &VVimCmdLineEdit::requestPreviousCommand,
- this, [this](VVim::CommandLineType p_type, const QString &p_cmd){
- if (m_vim) {
- QString cmd = m_vim->getPreviousCommandHistory(p_type, p_cmd);
- if (!cmd.isNull()) {
- m_cmdLineEdit->setCommand(cmd);
- }
- }
- });
- connect(m_cmdLineEdit, &VVimCmdLineEdit::requestRegister,
- this, [this](int p_key, int p_modifiers){
- if (m_vim) {
- QString val = m_vim->readRegister(p_key, p_modifiers);
- if (!val.isEmpty()) {
- m_cmdLineEdit->setText(m_cmdLineEdit->text() + val);
- }
- }
- });
- m_cmdLineEdit->hide();
- m_modeLabel = new QLabel(this);
- m_regBtn = new VButtonWithWidget(QIcon(":/resources/icons/arrow_dropup.svg"),
- "\"",
- this);
- m_regBtn->setToolTip(tr("Registers"));
- m_regBtn->setProperty("StatusBtn", true);
- m_regBtn->setFocusPolicy(Qt::NoFocus);
- QTreeWidget *regTree = new QTreeWidget(this);
- regTree->setColumnCount(2);
- regTree->header()->setStretchLastSection(true);
- QStringList headers;
- headers << tr("Register") << tr("Value");
- regTree->setHeaderLabels(headers);
- m_regBtn->setPopupWidget(regTree);
- connect(m_regBtn, &VButtonWithWidget::popupWidgetAboutToShow,
- this, &VVimIndicator::updateRegistersTree);
- m_markBtn = new VButtonWithWidget(QIcon(":/resources/icons/arrow_dropup.svg"),
- "[]",
- this);
- m_markBtn->setToolTip(tr("Marks"));
- m_markBtn->setProperty("StatusBtn", true);
- m_markBtn->setFocusPolicy(Qt::NoFocus);
- QTreeWidget *markTree = new QTreeWidget(this);
- markTree->setColumnCount(4);
- markTree->header()->setStretchLastSection(true);
- headers.clear();
- headers << tr("Mark") << tr("Line") << tr("Column") << tr("Text");
- markTree->setHeaderLabels(headers);
- m_markBtn->setPopupWidget(markTree);
- connect(m_markBtn, &VButtonWithWidget::popupWidgetAboutToShow,
- this, &VVimIndicator::updateMarksTree);
- m_keyLabel = new QLabel(this);
- QFontMetrics metric(font());
- m_keyLabel->setMinimumWidth(metric.width('A') * 5);
- QHBoxLayout *mainLayout = new QHBoxLayout(this);
- mainLayout->addStretch();
- mainLayout->addWidget(m_cmdLineEdit);
- mainLayout->addWidget(m_modeLabel);
- mainLayout->addWidget(m_regBtn);
- mainLayout->addWidget(m_markBtn);
- mainLayout->addWidget(m_keyLabel);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- setLayout(mainLayout);
- }
- QString VVimIndicator::modeToString(VimMode p_mode) const
- {
- QString str;
- switch (p_mode) {
- case VimMode::Normal:
- str = tr("Normal");
- break;
- case VimMode::Insert:
- str = tr("Insert");
- break;
- case VimMode::Visual:
- str = tr("Visual");
- break;
- case VimMode::VisualLine:
- str = tr("VisualLine");
- break;
- case VimMode::Replace:
- str = tr("Replace");
- break;
- default:
- str = tr("Unknown");
- break;
- }
- return str;
- }
- static QString modeBackgroundColor(VimMode p_mode)
- {
- QString color;
- switch (p_mode) {
- case VimMode::Normal:
- color = vconfig.getEditorVimNormalBg();
- break;
- case VimMode::Insert:
- color = vconfig.getEditorVimInsertBg();
- break;
- case VimMode::Visual:
- color = vconfig.getEditorVimVisualBg();
- break;
- case VimMode::VisualLine:
- color = vconfig.getEditorVimVisualBg();
- break;
- case VimMode::Replace:
- color = vconfig.getEditorVimReplaceBg();
- break;
- default:
- color = "red";
- break;
- }
- return color;
- }
- static void fillTreeItemsWithRegisters(QTreeWidget *p_tree,
- const QMap<QChar, VVim::Register> &p_regs)
- {
- p_tree->clear();
- for (auto const ® : p_regs) {
- if (reg.m_value.isEmpty()) {
- continue;
- }
- QStringList itemStr;
- itemStr << reg.m_name << reg.m_value;
- QTreeWidgetItem *item = new QTreeWidgetItem(p_tree, itemStr);
- item->setFlags(item->flags() | Qt::ItemIsSelectable | Qt::ItemIsEditable);
- }
- p_tree->resizeColumnToContents(0);
- p_tree->resizeColumnToContents(1);
- }
- void VVimIndicator::update(const VVim *p_vim, const VEditTab *p_editTab)
- {
- m_editTab = const_cast<VEditTab *>(p_editTab);
- if (m_vim != p_vim) {
- // Disconnect from previous Vim.
- if (m_vim) {
- disconnect(m_vim.data(), 0, this, 0);
- }
- m_vim = const_cast<VVim *>(p_vim);
- if (m_vim) {
- // Connect signal.
- connect(m_vim.data(), &VVim::commandLineTriggered,
- this, &VVimIndicator::triggerCommandLine);
- m_cmdLineEdit->hide();
- }
- }
- if (!m_vim) {
- m_cmdLineEdit->hide();
- return;
- }
- VimMode mode = VimMode::Normal;
- QChar curRegName(' ');
- QChar lastUsedMark;
- QString pendingKeys;
- if (p_vim) {
- mode = p_vim->getMode();
- curRegName = p_vim->getCurrentRegisterName();
- lastUsedMark = p_vim->getMarks().getLastUsedMark();
- pendingKeys = p_vim->getPendingKeys();
- }
- QString style = QString("QLabel { padding: 0px 2px 0px 2px; font: bold; background-color: %1; }")
- .arg(modeBackgroundColor(mode));
- m_modeLabel->setStyleSheet(style);
- m_modeLabel->setText(modeToString(mode));
- m_regBtn->setText(curRegName);
- QString markText = QString("[%1]")
- .arg(lastUsedMark.isNull() ? QChar(' ') : lastUsedMark);
- m_markBtn->setText(markText);
- QString keyText = QString("<span style=\"font-weight:bold; color: %1;\">%2</span>")
- .arg("#15AE67").arg(pendingKeys);
- m_keyLabel->setText(keyText);
- }
- void VVimIndicator::updateRegistersTree(QWidget *p_widget)
- {
- QTreeWidget *regTree = dynamic_cast<QTreeWidget *>(p_widget);
- if (!m_vim) {
- regTree->clear();
- return;
- }
- const QMap<QChar, VVim::Register> ®s = m_vim->getRegisters();
- fillTreeItemsWithRegisters(regTree, regs);
- }
- static void fillTreeItemsWithMarks(QTreeWidget *p_tree,
- const QMap<QChar, VVim::Mark> &p_marks)
- {
- p_tree->clear();
- for (auto const &mark : p_marks) {
- if (!mark.m_location.isValid()) {
- continue;
- }
- QStringList itemStr;
- itemStr << mark.m_name << QString::number(mark.m_location.m_blockNumber + 1)
- << QString::number(mark.m_location.m_positionInBlock) << mark.m_text;
- QTreeWidgetItem *item = new QTreeWidgetItem(p_tree, itemStr);
- item->setFlags(item->flags() | Qt::ItemIsSelectable | Qt::ItemIsEditable);
- }
- p_tree->resizeColumnToContents(0);
- p_tree->resizeColumnToContents(1);
- p_tree->resizeColumnToContents(2);
- p_tree->resizeColumnToContents(3);
- }
- void VVimIndicator::updateMarksTree(QWidget *p_widget)
- {
- QTreeWidget *markTree = dynamic_cast<QTreeWidget *>(p_widget);
- if (!m_vim) {
- markTree->clear();
- return;
- }
- const QMap<QChar, VVim::Mark> &marks = m_vim->getMarks().getMarks();
- fillTreeItemsWithMarks(markTree, marks);
- }
- void VVimIndicator::triggerCommandLine(VVim::CommandLineType p_type)
- {
- m_cmdLineEdit->reset(p_type);
- }
- VVimCmdLineEdit::VVimCmdLineEdit(QWidget *p_parent)
- : QLineEdit(p_parent), m_type(VVim::CommandLineType::Invalid),
- m_registerPending(false)
- {
- // When user delete all the text, cancel command input.
- connect(this, &VVimCmdLineEdit::textChanged,
- this, [this](const QString &p_text){
- if (p_text.isEmpty()) {
- emit commandCancelled();
- } else {
- emit commandChanged(m_type, p_text.right(p_text.size() - 1));
- }
- });
- connect(this, &VVimCmdLineEdit::textEdited,
- this, [this](const QString &p_text){
- if (p_text.size() < 2) {
- m_userLastInput.clear();
- } else {
- m_userLastInput = p_text.right(p_text.size() - 1);
- }
- });
- m_originStyleSheet = styleSheet();
- }
- QString VVimCmdLineEdit::getCommand() const
- {
- QString tx = text();
- if (tx.size() < 2) {
- return "";
- } else {
- return tx.right(tx.size() - 1);
- }
- }
- QString VVimCmdLineEdit::commandLineTypeLeader(VVim::CommandLineType p_type)
- {
- QString leader;
- switch (p_type) {
- case VVim::CommandLineType::Command:
- leader = ":";
- break;
- case VVim::CommandLineType::SearchForward:
- leader = "/";
- break;
- case VVim::CommandLineType::SearchBackward:
- leader = "?";
- break;
- case VVim::CommandLineType::Invalid:
- leader.clear();
- break;
- default:
- Q_ASSERT(false);
- break;
- }
- return leader;
- }
- void VVimCmdLineEdit::reset(VVim::CommandLineType p_type)
- {
- m_type = p_type;
- m_userLastInput.clear();
- setCommand("");
- show();
- setFocus();
- }
- // See if @p_modifiers is Control which is different on macOs and Windows.
- static bool isControlModifier(int p_modifiers)
- {
- #if defined(Q_OS_MACOS) || defined(Q_OS_MAC)
- return p_modifiers == Qt::MetaModifier;
- #else
- return p_modifiers == Qt::ControlModifier;
- #endif
- }
- void VVimCmdLineEdit::keyPressEvent(QKeyEvent *p_event)
- {
- int key = p_event->key();
- int modifiers = p_event->modifiers();
- if (m_registerPending) {
- // Ctrl and Shift may be sent out first.
- if (key == Qt::Key_Control || key == Qt::Key_Shift || key == Qt::Key_Meta) {
- goto exit;
- }
- // Expecting a register name.
- emit requestRegister(key, modifiers);
- p_event->accept();
- setRegisterPending(false);
- return;
- }
- if ((key == Qt::Key_Return && modifiers == Qt::NoModifier)
- || (key == Qt::Key_Enter && modifiers == Qt::KeypadModifier)) {
- // Enter, complete the command line input.
- p_event->accept();
- emit commandFinished(m_type, getCommand());
- return;
- } else if (key == Qt::Key_Escape
- || (key == Qt::Key_BracketLeft && isControlModifier(modifiers))) {
- // Exit command line input.
- setText(commandLineTypeLeader(m_type));
- p_event->accept();
- emit commandCancelled();
- return;
- }
- switch (key) {
- case Qt::Key_U:
- if (isControlModifier(modifiers)) {
- // Ctrl+U, delete all user input.
- setText(commandLineTypeLeader(m_type));
- p_event->accept();
- return;
- }
- break;
- case Qt::Key_N:
- if (!isControlModifier(modifiers)) {
- break;
- }
- // Ctrl+N, request next command.
- // Fall through.
- case Qt::Key_Down:
- {
- emit requestNextCommand(m_type, getCommand());
- p_event->accept();
- return;
- }
- case Qt::Key_P:
- if (!isControlModifier(modifiers)) {
- break;
- }
- // Ctrl+P, request previous command.
- // Fall through.
- case Qt::Key_Up:
- {
- emit requestPreviousCommand(m_type, getCommand());
- p_event->accept();
- return;
- }
- case Qt::Key_R:
- {
- if (isControlModifier(modifiers)) {
- // Ctrl+R, insert the content of a register.
- setRegisterPending(true);
- p_event->accept();
- return;
- }
- }
- default:
- break;
- }
- exit:
- QLineEdit::keyPressEvent(p_event);
- }
- void VVimCmdLineEdit::focusOutEvent(QFocusEvent *p_event)
- {
- if (p_event->reason() != Qt::ActiveWindowFocusReason) {
- emit commandCancelled();
- }
- }
- void VVimCmdLineEdit::setCommand(const QString &p_cmd)
- {
- setText(commandLineTypeLeader(m_type) + p_cmd);
- }
- void VVimCmdLineEdit::restoreUserLastInput()
- {
- setCommand(m_userLastInput);
- }
- void VVimCmdLineEdit::setRegisterPending(bool p_pending)
- {
- if (p_pending && !m_registerPending) {
- // Going to pending.
- setStyleSheet("QLineEdit { background: #D6EACE }");
- } else if (!p_pending && m_registerPending) {
- // Leaving pending.
- setStyleSheet(m_originStyleSheet);
- }
- m_registerPending = p_pending;
- }
|