File indexing completed on 2024-05-05 05:51:38
0001 /* Description : Kate CTags plugin 0002 * 0003 * SPDX-FileCopyrightText: 2008-2011 Kare Sars <kare.sars@iki.fi> 0004 * 0005 * This program is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2.1 of the License, or (at your option) version 3, or any 0009 * later version accepted by the membership of KDE e.V. (or its 0010 * successor approved by the membership of KDE e.V.), which shall 0011 * act as a proxy defined in Section 6 of version 3 of the license. 0012 * 0013 * This program is distributed in the hope that it will be useful, 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 * General Public License for more details. 0017 * 0018 * You should have received a copy of the GNU General Public 0019 * License along with this program. If not, see <http://www.gnu.org/licenses/>. 0020 */ 0021 0022 #include "kate_ctags_view.h" 0023 #include "kate_ctags_debug.h" 0024 #include "kate_ctags_plugin.h" 0025 0026 #include "hostprocess.h" 0027 0028 #include <QFileDialog> 0029 #include <QFileInfo> 0030 #include <QKeyEvent> 0031 0032 #include <KActionCollection> 0033 #include <KConfigGroup> 0034 #include <KXMLGUIFactory> 0035 #include <QMenu> 0036 0037 #include <KLocalizedString> 0038 #include <KStringHandler> 0039 #include <QDialogButtonBox> 0040 #include <QStandardPaths> 0041 0042 #include <ktexteditor_utils.h> 0043 0044 /******************************************************************/ 0045 KateCTagsView::KateCTagsView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin) 0046 : QObject(mainWin) 0047 , m_proc(nullptr) 0048 { 0049 KXMLGUIClient::setComponentName(QStringLiteral("katectags"), i18n("CTags")); 0050 setXMLFile(QStringLiteral("ui.rc")); 0051 0052 m_toolView = mainWin->createToolView(plugin, 0053 QStringLiteral("kate_plugin_katectagsplugin"), 0054 KTextEditor::MainWindow::Bottom, 0055 QIcon::fromTheme(QStringLiteral("application-x-ms-dos-executable")), 0056 i18n("CTags")); 0057 m_mWin = mainWin; 0058 0059 QAction *back = actionCollection()->addAction(QStringLiteral("ctags_return_step")); 0060 back->setText(i18n("Jump back one step")); 0061 connect(back, &QAction::triggered, this, &KateCTagsView::stepBack); 0062 0063 QAction *decl = actionCollection()->addAction(QStringLiteral("ctags_lookup_current_as_declaration")); 0064 decl->setText(i18n("Go to Declaration")); 0065 connect(decl, &QAction::triggered, this, &KateCTagsView::gotoDeclaration); 0066 0067 QAction *defin = actionCollection()->addAction(QStringLiteral("ctags_lookup_current_as_definition")); 0068 defin->setText(i18n("Go to Definition")); 0069 connect(defin, &QAction::triggered, this, &KateCTagsView::gotoDefinition); 0070 0071 QAction *lookup = actionCollection()->addAction(QStringLiteral("ctags_lookup_current")); 0072 lookup->setText(i18n("Lookup Current Text")); 0073 connect(lookup, &QAction::triggered, this, &KateCTagsView::lookupTag); 0074 0075 QAction *updateDB = actionCollection()->addAction(QStringLiteral("ctags_update_global_db")); 0076 updateDB->setText(i18n("Configure ...")); 0077 connect(updateDB, &QAction::triggered, this, [this, plugin](bool) { 0078 if (m_mWin) { 0079 KateCTagsPlugin *p = static_cast<KateCTagsPlugin *>(plugin); 0080 QDialog *confWin = new QDialog(m_mWin->window()); 0081 confWin->setAttribute(Qt::WA_DeleteOnClose); 0082 auto confPage = p->configPage(0, confWin); 0083 auto controls = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, confWin); 0084 connect(confWin, &QDialog::accepted, confPage, &KTextEditor::ConfigPage::apply); 0085 connect(controls, &QDialogButtonBox::accepted, confWin, &QDialog::accept); 0086 connect(controls, &QDialogButtonBox::rejected, confWin, &QDialog::reject); 0087 auto layout = new QVBoxLayout(confWin); 0088 layout->addWidget(confPage); 0089 layout->addWidget(controls); 0090 confWin->setLayout(layout); 0091 confWin->setWindowTitle(i18nc("@title:window", "Configure CTags Plugin")); 0092 confWin->setWindowIcon(confPage->icon()); 0093 confWin->show(); 0094 confWin->exec(); 0095 } 0096 }); 0097 0098 // popup menu 0099 m_menu = new KActionMenu(i18n("CTags"), this); 0100 actionCollection()->addAction(QStringLiteral("popup_ctags"), m_menu); 0101 0102 m_gotoDec = m_menu->menu()->addAction(i18n("Go to Declaration: %1", QString()), this, &KateCTagsView::gotoDeclaration); 0103 m_gotoDef = m_menu->menu()->addAction(i18n("Go to Definition: %1", QString()), this, &KateCTagsView::gotoDefinition); 0104 m_lookup = m_menu->menu()->addAction(i18n("Lookup: %1", QString()), this, &KateCTagsView::lookupTag); 0105 0106 connect(m_menu->menu(), &QMenu::aboutToShow, this, &KateCTagsView::aboutToShow); 0107 0108 QWidget *ctagsWidget = new QWidget(m_toolView.data()); 0109 m_ctagsUi.setupUi(ctagsWidget); 0110 m_ctagsUi.cmdEdit->setText(DEFAULT_CTAGS_CMD); 0111 0112 m_ctagsUi.addButton->setToolTip(i18n("Add a directory to index.")); 0113 m_ctagsUi.addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); 0114 0115 m_ctagsUi.delButton->setToolTip(i18n("Remove a directory.")); 0116 m_ctagsUi.delButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0117 0118 m_ctagsUi.updateButton->setToolTip(i18n("(Re-)generate the session specific CTags database.")); 0119 m_ctagsUi.updateButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 0120 0121 m_ctagsUi.updateButton2->setToolTip(i18n("(Re-)generate the session specific CTags database.")); 0122 m_ctagsUi.updateButton2->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 0123 0124 m_ctagsUi.resetCMD->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); 0125 0126 m_ctagsUi.tagsFile->setToolTip(i18n("Select new or existing database file.")); 0127 m_ctagsUi.tagsFile->setMode(KFile::File); 0128 0129 connect(m_ctagsUi.resetCMD, &QToolButton::clicked, this, &KateCTagsView::resetCMD); 0130 connect(m_ctagsUi.addButton, &QPushButton::clicked, this, &KateCTagsView::addTagTarget); 0131 connect(m_ctagsUi.delButton, &QPushButton::clicked, this, &KateCTagsView::delTagTarget); 0132 connect(m_ctagsUi.updateButton, &QPushButton::clicked, this, &KateCTagsView::updateSessionDB); 0133 connect(m_ctagsUi.updateButton2, &QPushButton::clicked, this, &KateCTagsView::updateSessionDB); 0134 connect(&m_proc, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &KateCTagsView::updateDone); 0135 connect(&m_proc, &QProcess::readyReadStandardError, this, [this]() { 0136 QString error = QString::fromLocal8Bit(m_proc.readAllStandardError()); 0137 Utils::showMessage(error, QIcon(), i18n("CTags"), MessageType::Error); 0138 }); 0139 0140 m_gotoSymbWidget.reset(new GotoSymbolWidget(mainWin, this)); 0141 auto openLocal = actionCollection()->addAction(QStringLiteral("open_local_gts")); 0142 openLocal->setText(i18n("Go To Local Symbol")); 0143 actionCollection()->setDefaultShortcut(openLocal, Qt::CTRL | Qt::ALT | Qt::Key_P); 0144 connect(openLocal, &QAction::triggered, this, &KateCTagsView::showSymbols); 0145 0146 auto openGlobal = actionCollection()->addAction(QStringLiteral("open_global_gts")); 0147 openGlobal->setText(i18n("Go To Global Symbol")); 0148 actionCollection()->setDefaultShortcut(openGlobal, Qt::CTRL | Qt::SHIFT | Qt::Key_P); 0149 connect(openGlobal, &QAction::triggered, this, &KateCTagsView::showGlobalSymbols); 0150 0151 connect(m_ctagsUi.inputEdit, &QLineEdit::textChanged, this, &KateCTagsView::startEditTmr); 0152 0153 m_editTimer.setSingleShot(true); 0154 connect(&m_editTimer, &QTimer::timeout, this, &KateCTagsView::editLookUp); 0155 0156 connect(m_ctagsUi.tagTreeWidget, &QTreeWidget::itemActivated, this, &KateCTagsView::tagHitClicked); 0157 0158 connect(m_mWin, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KateCTagsView::handleEsc); 0159 0160 m_toolView->layout()->addWidget(ctagsWidget); 0161 m_toolView->installEventFilter(this); 0162 0163 m_mWin->guiFactory()->addClient(this); 0164 0165 m_commonDB = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1String("/katectags/common_db"); 0166 } 0167 0168 /******************************************************************/ 0169 KateCTagsView::~KateCTagsView() 0170 { 0171 if (m_mWin && m_mWin->guiFactory()) { 0172 m_mWin->guiFactory()->removeClient(this); 0173 } 0174 0175 if (m_toolView) { 0176 delete m_toolView; 0177 } 0178 } 0179 0180 /******************************************************************/ 0181 void KateCTagsView::aboutToShow() 0182 { 0183 QString currWord = currentWord(); 0184 if (currWord.isEmpty()) { 0185 return; 0186 } 0187 0188 if (Tags::hasTag(m_commonDB, currWord) || Tags::hasTag(m_ctagsUi.tagsFile->text(), currWord)) { 0189 QString squeezed = KStringHandler::csqueeze(currWord, 30); 0190 0191 m_gotoDec->setText(i18n("Go to Declaration: %1", squeezed)); 0192 m_gotoDef->setText(i18n("Go to Definition: %1", squeezed)); 0193 m_lookup->setText(i18n("Lookup: %1", squeezed)); 0194 } 0195 } 0196 0197 /******************************************************************/ 0198 void KateCTagsView::readSessionConfig(const KConfigGroup &cg) 0199 { 0200 m_ctagsUi.cmdEdit->setText(cg.readEntry("TagsGenCMD", DEFAULT_CTAGS_CMD)); 0201 0202 int numEntries = cg.readEntry("SessionNumTargets", 0); 0203 QString nr; 0204 QString target; 0205 for (int i = 0; i < numEntries; i++) { 0206 nr = QStringLiteral("%1").arg(i, 3); 0207 target = cg.readEntry(QStringLiteral("SessionTarget_%1").arg(nr), QString()); 0208 if (!listContains(target)) { 0209 new QListWidgetItem(target, m_ctagsUi.targetList); 0210 } 0211 } 0212 0213 QString sessionDB = cg.readEntry("SessionDatabase", QString()); 0214 m_ctagsUi.tagsFile->setText(sessionDB); 0215 } 0216 0217 /******************************************************************/ 0218 void KateCTagsView::writeSessionConfig(KConfigGroup &cg) 0219 { 0220 cg.writeEntry("TagsGenCMD", m_ctagsUi.cmdEdit->text()); 0221 cg.writeEntry("SessionNumTargets", m_ctagsUi.targetList->count()); 0222 0223 QString nr; 0224 for (int i = 0; i < m_ctagsUi.targetList->count(); i++) { 0225 nr = QStringLiteral("%1").arg(i, 3); 0226 cg.writeEntry(QStringLiteral("SessionTarget_%1").arg(nr), m_ctagsUi.targetList->item(i)->text()); 0227 } 0228 0229 cg.writeEntry("SessionDatabase", m_ctagsUi.tagsFile->text()); 0230 0231 cg.sync(); 0232 } 0233 0234 /******************************************************************/ 0235 void KateCTagsView::stepBack() 0236 { 0237 if (m_jumpStack.isEmpty()) { 0238 return; 0239 } 0240 0241 TagJump back; 0242 back = m_jumpStack.pop(); 0243 0244 m_mWin->openUrl(back.url); 0245 if (m_mWin->activeView()) { 0246 m_mWin->activeView()->setCursorPosition(back.cursor); 0247 m_mWin->activeView()->setFocus(); 0248 } 0249 } 0250 0251 /******************************************************************/ 0252 void KateCTagsView::lookupTag() 0253 { 0254 QString currWord = currentWord(); 0255 if (currWord.isEmpty()) { 0256 return; 0257 } 0258 0259 setNewLookupText(currWord); 0260 Tags::TagList list = Tags::getExactMatches(m_ctagsUi.tagsFile->text(), currWord); 0261 if (list.empty()) { 0262 list = Tags::getExactMatches(m_commonDB, currWord); 0263 } 0264 displayHits(list); 0265 0266 // activate the hits tab 0267 m_ctagsUi.tabWidget->setCurrentIndex(0); 0268 m_mWin->showToolView(m_toolView); 0269 } 0270 0271 /******************************************************************/ 0272 void KateCTagsView::editLookUp() 0273 { 0274 Tags::TagList list = Tags::getPartialMatches(m_ctagsUi.tagsFile->text(), m_ctagsUi.inputEdit->text()); 0275 if (list.empty()) { 0276 list = Tags::getPartialMatches(m_commonDB, m_ctagsUi.inputEdit->text()); 0277 } 0278 displayHits(list); 0279 } 0280 0281 /******************************************************************/ 0282 void KateCTagsView::gotoDefinition() 0283 { 0284 QString currWord = currentWord(); 0285 if (currWord.isEmpty()) { 0286 return; 0287 } 0288 0289 QStringList types; 0290 types << QStringLiteral("S") << QStringLiteral("d") << QStringLiteral("f") << QStringLiteral("t") << QStringLiteral("v"); 0291 Tags::TagList list = Tags::getMatches(m_ctagsUi.tagsFile->text(), currWord, false, types); 0292 if (list.isEmpty()) { 0293 gotoDeclaration(); 0294 } else { 0295 gotoResults(currWord, list); 0296 } 0297 } 0298 0299 /******************************************************************/ 0300 void KateCTagsView::gotoDeclaration() 0301 { 0302 QString currWord = currentWord(); 0303 if (currWord.isEmpty()) { 0304 return; 0305 } 0306 0307 QStringList types; 0308 types << QStringLiteral("L") << QStringLiteral("c") << QStringLiteral("e") << QStringLiteral("g") << QStringLiteral("m") << QStringLiteral("n") 0309 << QStringLiteral("p") << QStringLiteral("s") << QStringLiteral("u") << QStringLiteral("x"); 0310 Tags::TagList list = Tags::getMatches(m_ctagsUi.tagsFile->text(), currWord, false, types); 0311 gotoResults(currWord, list); 0312 } 0313 0314 /******************************************************************/ 0315 void KateCTagsView::gotoResults(const QString &word, const Tags::TagList &list) 0316 { 0317 // qCDebug(KTECTAGS) << "found" << list.count() << word << types; 0318 setNewLookupText(word); 0319 0320 if (list.count() < 1) { 0321 m_ctagsUi.tagTreeWidget->clear(); 0322 new QTreeWidgetItem(m_ctagsUi.tagTreeWidget, QStringList(i18n("No hits found"))); 0323 m_ctagsUi.tabWidget->setCurrentIndex(0); 0324 m_mWin->showToolView(m_toolView); 0325 return; 0326 } 0327 0328 displayHits(list); 0329 0330 if (list.count() == 1) { 0331 Tags::TagEntry tag = list.first(); 0332 jumpToTag(tag.file, tag.pattern, word); 0333 } else { 0334 Tags::TagEntry tag = list.first(); 0335 jumpToTag(tag.file, tag.pattern, word); 0336 m_ctagsUi.tabWidget->setCurrentIndex(0); 0337 m_mWin->showToolView(m_toolView); 0338 } 0339 } 0340 0341 /******************************************************************/ 0342 void KateCTagsView::setNewLookupText(const QString &newString) 0343 { 0344 m_ctagsUi.inputEdit->blockSignals(true); 0345 m_ctagsUi.inputEdit->setText(newString); 0346 m_ctagsUi.inputEdit->blockSignals(false); 0347 } 0348 0349 /******************************************************************/ 0350 void KateCTagsView::displayHits(const Tags::TagList &list) 0351 { 0352 m_ctagsUi.tagTreeWidget->clear(); 0353 if (list.isEmpty()) { 0354 new QTreeWidgetItem(m_ctagsUi.tagTreeWidget, QStringList(i18n("No hits found"))); 0355 return; 0356 } 0357 m_ctagsUi.tagTreeWidget->setSortingEnabled(false); 0358 0359 for (const auto &tag : list) { 0360 QTreeWidgetItem *item = new QTreeWidgetItem(m_ctagsUi.tagTreeWidget); 0361 item->setText(0, tag.tag); 0362 item->setText(1, tag.type); 0363 item->setText(2, tag.file); 0364 item->setData(0, Qt::UserRole, tag.pattern); 0365 0366 QString pattern = tag.pattern; 0367 pattern.replace(QStringLiteral("\\/"), QStringLiteral("/")); 0368 pattern = pattern.mid(2, pattern.length() - 4); 0369 pattern = pattern.trimmed(); 0370 0371 item->setData(0, Qt::ToolTipRole, pattern); 0372 item->setData(1, Qt::ToolTipRole, pattern); 0373 item->setData(2, Qt::ToolTipRole, pattern); 0374 } 0375 m_ctagsUi.tagTreeWidget->setSortingEnabled(true); 0376 } 0377 0378 /******************************************************************/ 0379 void KateCTagsView::tagHitClicked(QTreeWidgetItem *item) 0380 { 0381 // get stuff 0382 const QString file = item->data(2, Qt::DisplayRole).toString(); 0383 const QString pattern = item->data(0, Qt::UserRole).toString(); 0384 const QString word = item->data(0, Qt::DisplayRole).toString(); 0385 0386 jumpToTag(file, pattern, word); 0387 } 0388 0389 /******************************************************************/ 0390 QString KateCTagsView::currentWord() 0391 { 0392 KTextEditor::View *kv = m_mWin->activeView(); 0393 if (!kv) { 0394 qCDebug(KTECTAGS) << "no KTextEditor::View"; 0395 return QString(); 0396 } 0397 0398 if (kv->selection() && kv->selectionRange().onSingleLine()) { 0399 return kv->selectionText(); 0400 } 0401 0402 if (!kv->cursorPosition().isValid()) { 0403 qCDebug(KTECTAGS) << "cursor not valid!"; 0404 return QString(); 0405 } 0406 0407 int line = kv->cursorPosition().line(); 0408 int col = kv->cursorPosition().column(); 0409 bool includeColon = m_ctagsUi.cmdEdit->text().contains(QLatin1String("--extra=+q")); 0410 0411 QString linestr = kv->document()->line(line); 0412 0413 int startPos = qMax(qMin(col, linestr.length() - 1), 0); 0414 int endPos = startPos; 0415 while (startPos >= 0 0416 && (linestr[startPos].isLetterOrNumber() || (linestr[startPos] == QLatin1Char(':') && includeColon) || linestr[startPos] == QLatin1Char('_') 0417 || linestr[startPos] == QLatin1Char('~'))) { 0418 startPos--; 0419 } 0420 while (endPos < linestr.length() 0421 && (linestr[endPos].isLetterOrNumber() || (linestr[endPos] == QLatin1Char(':') && includeColon) || linestr[endPos] == QLatin1Char('_'))) { 0422 endPos++; 0423 } 0424 if (startPos == endPos) { 0425 qCDebug(KTECTAGS) << "no word found!"; 0426 return QString(); 0427 } 0428 0429 linestr = linestr.mid(startPos + 1, endPos - startPos - 1); 0430 0431 while (linestr.endsWith(QLatin1Char(':'))) { 0432 linestr.remove(linestr.size() - 1, 1); 0433 } 0434 0435 while (linestr.startsWith(QLatin1Char(':'))) { 0436 linestr.remove(0, 1); 0437 } 0438 0439 // qCDebug(KTECTAGS) << linestr; 0440 return linestr; 0441 } 0442 0443 /******************************************************************/ 0444 void KateCTagsView::jumpToTag(const QString &file, const QString &pattern, const QString &word) 0445 { 0446 if (pattern.isEmpty()) { 0447 return; 0448 } 0449 0450 // generate a regexp from the pattern 0451 // ctags interestingly escapes "/", but apparently nothing else. lets revert that 0452 QString unescaped = pattern; 0453 unescaped.replace(QStringLiteral("\\/"), QStringLiteral("/")); 0454 0455 // most of the time, the ctags pattern has the form /^foo$/ 0456 // but this isn't true for some macro definitions 0457 // where the form is only /^foo/ 0458 // I have no idea if this is a ctags bug or not, but we have to deal with it 0459 0460 QString reduced; 0461 QString escaped; 0462 QString re_string; 0463 0464 if (unescaped.endsWith(QLatin1String("$/"))) { 0465 reduced = unescaped.mid(2, unescaped.length() - 4); 0466 escaped = QRegularExpression::escape(reduced); 0467 re_string = QStringLiteral("^%1$").arg(escaped); 0468 } else { 0469 reduced = unescaped.mid(2, unescaped.length() - 3); 0470 escaped = QRegularExpression::escape(reduced); 0471 re_string = QStringLiteral("^%1").arg(escaped); 0472 } 0473 0474 QRegularExpression re(re_string); 0475 0476 // save current location 0477 TagJump from; 0478 if (auto v = m_mWin->activeView()) { 0479 from.url = v->document()->url(); 0480 from.cursor = v->cursorPosition(); 0481 } 0482 m_jumpStack.push(from); 0483 0484 // open/activate the new file 0485 QFileInfo fInfo(file); 0486 // qCDebug(KTECTAGS) << pattern << file << fInfo.absoluteFilePath(); 0487 m_mWin->openUrl(QUrl::fromLocalFile(fInfo.absoluteFilePath())); 0488 0489 // any view active? 0490 if (!m_mWin->activeView()) { 0491 return; 0492 } 0493 0494 // look for the line 0495 QString linestr; 0496 int line; 0497 for (line = 0; line < m_mWin->activeView()->document()->lines(); line++) { 0498 linestr = m_mWin->activeView()->document()->line(line); 0499 if (linestr.indexOf(re) > -1) { 0500 break; 0501 } 0502 } 0503 0504 // activate the line 0505 if (line != m_mWin->activeView()->document()->lines()) { 0506 // line found now look for the column 0507 int column = linestr.indexOf(word) + (word.length() / 2); 0508 m_mWin->activeView()->setCursorPosition(KTextEditor::Cursor(line, column)); 0509 } 0510 m_mWin->activeView()->setFocus(); 0511 } 0512 0513 /******************************************************************/ 0514 void KateCTagsView::startEditTmr() 0515 { 0516 if (m_ctagsUi.inputEdit->text().size() > 3) { 0517 m_editTimer.start(500); 0518 } 0519 } 0520 0521 /******************************************************************/ 0522 void KateCTagsView::updateSessionDB() 0523 { 0524 if (m_proc.state() != QProcess::NotRunning) { 0525 return; 0526 } 0527 0528 QStringList targets; 0529 for (int i = 0; i < m_ctagsUi.targetList->count(); i++) { 0530 auto target = m_ctagsUi.targetList->item(i)->text(); 0531 if (target.endsWith(QLatin1Char('/')) || target.endsWith(QLatin1Char('\\'))) { 0532 target = target.left(target.size() - 1); 0533 } 0534 targets << target; 0535 } 0536 0537 QString pluginFolder = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1String("/katectags"); 0538 QDir().mkpath(pluginFolder); 0539 0540 if (m_ctagsUi.tagsFile->text().isEmpty()) { 0541 // FIXME we need a way to get the session name 0542 pluginFolder += QLatin1String("/session_db_"); 0543 pluginFolder += QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd_hhmmss")); 0544 m_ctagsUi.tagsFile->setText(pluginFolder); 0545 } 0546 0547 if (targets.isEmpty()) { 0548 Utils::showMessage(i18n("No folders or files to index"), QIcon(), i18n("CTags"), MessageType::Error); 0549 QFile::remove(m_ctagsUi.tagsFile->text()); 0550 return; 0551 } 0552 0553 QStringList arguments = m_proc.splitCommand(m_ctagsUi.cmdEdit->text()); 0554 const QString command = arguments.takeFirst(); 0555 arguments << QStringLiteral("-f") << m_ctagsUi.tagsFile->text() << targets; 0556 startHostProcess(m_proc, command, arguments); 0557 0558 if (!m_proc.waitForStarted(500)) { 0559 Utils::showMessage(i18n("Failed to run. Error: %1, exit code: %2", m_proc.errorString(), m_proc.exitCode()), 0560 QIcon(), 0561 i18n("CTags"), 0562 MessageType::Error); 0563 return; 0564 } 0565 QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); 0566 m_ctagsUi.updateButton->setDisabled(true); 0567 m_ctagsUi.updateButton2->setDisabled(true); 0568 } 0569 0570 /******************************************************************/ 0571 void KateCTagsView::updateDone(int exitCode, QProcess::ExitStatus status) 0572 { 0573 if (status == QProcess::CrashExit) { 0574 Utils::showMessage(i18n("The CTags executable crashed", m_proc.errorString(), m_proc.exitCode()), QIcon(), i18n("CTags"), MessageType::Error); 0575 } else if (exitCode != 0) { 0576 Utils::showMessage(i18n("The CTags program exited with code %2: %1", QString::fromLocal8Bit(m_proc.readAllStandardError()), exitCode), 0577 QIcon(), 0578 i18n("CTags"), 0579 MessageType::Error); 0580 } 0581 0582 m_ctagsUi.updateButton->setDisabled(false); 0583 m_ctagsUi.updateButton2->setDisabled(false); 0584 QApplication::restoreOverrideCursor(); 0585 } 0586 0587 /******************************************************************/ 0588 void KateCTagsView::addTagTarget() 0589 { 0590 QFileDialog dialog; 0591 dialog.setDirectory(QFileInfo(m_mWin->activeView()->document()->url().path()).path()); 0592 dialog.setFileMode(QFileDialog::Directory); 0593 0594 // i18n("CTags Database Location")); 0595 if (dialog.exec() != QDialog::Accepted) { 0596 return; 0597 } 0598 0599 QStringList urls = dialog.selectedFiles(); 0600 0601 for (int i = 0; i < urls.size(); i++) { 0602 if (!listContains(urls[i])) { 0603 new QListWidgetItem(urls[i], m_ctagsUi.targetList); 0604 } 0605 } 0606 } 0607 0608 /******************************************************************/ 0609 void KateCTagsView::delTagTarget() 0610 { 0611 delete m_ctagsUi.targetList->currentItem(); 0612 } 0613 0614 /******************************************************************/ 0615 bool KateCTagsView::listContains(const QString &target) 0616 { 0617 for (int i = 0; i < m_ctagsUi.targetList->count(); i++) { 0618 if (m_ctagsUi.targetList->item(i)->text() == target) { 0619 return true; 0620 } 0621 } 0622 return false; 0623 } 0624 0625 /******************************************************************/ 0626 bool KateCTagsView::eventFilter(QObject *obj, QEvent *event) 0627 { 0628 if (event->type() == QEvent::KeyPress) { 0629 QKeyEvent *ke = static_cast<QKeyEvent *>(event); 0630 if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { 0631 m_mWin->hideToolView(m_toolView); 0632 event->accept(); 0633 return true; 0634 } 0635 } 0636 return QObject::eventFilter(obj, event); 0637 } 0638 0639 /******************************************************************/ 0640 void KateCTagsView::resetCMD() 0641 { 0642 m_ctagsUi.cmdEdit->setText(DEFAULT_CTAGS_CMD); 0643 } 0644 0645 /******************************************************************/ 0646 void KateCTagsView::handleEsc(QEvent *e) 0647 { 0648 if (!m_mWin) { 0649 return; 0650 } 0651 0652 QKeyEvent *k = static_cast<QKeyEvent *>(e); 0653 if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { 0654 if (m_toolView->isVisible()) { 0655 m_mWin->hideToolView(m_toolView); 0656 } 0657 } 0658 } 0659 0660 void KateCTagsView::showSymbols() 0661 { 0662 m_gotoSymbWidget->showSymbols(m_mWin->activeView()->document()->url().toLocalFile()); 0663 m_gotoSymbWidget->show(); 0664 m_gotoSymbWidget->setFocus(); 0665 } 0666 0667 void KateCTagsView::showGlobalSymbols() 0668 { 0669 m_gotoSymbWidget->showGlobalSymbols(m_ctagsUi.tagsFile->text()); 0670 m_gotoSymbWidget->show(); 0671 m_gotoSymbWidget->setFocus(); 0672 } 0673 0674 #include "moc_kate_ctags_view.cpp"