File indexing completed on 2024-04-28 12:23:19

0001 /*
0002 * This file is part of KDevelop
0003 *
0004 * Copyright 2007-2010 Alexander Dymo <adymo@kdevelop.org>
0005 * Copyright (C) 2014-2015 Miquel Sabaté Solà <mikisabate@gmail.com>
0006 *
0007 * This program is free software; you can redistribute it and/or modify
0008 * it under the terms of the GNU Library General Public License as
0009 * published by the Free Software Foundation; either version 2 of the
0010 * License, or (at your option) any later version.
0011 *
0012 * This program is distributed in the hope that it will be useful,
0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015 * GNU General Public License for more details.
0016 *
0017 * You should have received a copy of the GNU General Public
0018 * License along with this program; if not, write to the
0019 * Free Software Foundation, Inc.,
0020 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include <QtCore/QDir>
0024 #include <QtCore/QFileInfo>
0025 
0026 #include <KLocalizedString>
0027 
0028 #include <interfaces/icore.h>
0029 #include <interfaces/idocumentcontroller.h>
0030 #include <interfaces/iplugincontroller.h>
0031 #include <language/interfaces/iquickopen.h>
0032 
0033 #include <languagesupport.h>
0034 #include <rails/switchers.h>
0035 #include <rails/helpers.h>
0036 
0037 using namespace KDevelop;
0038 using namespace ruby::rails;
0039 
0040 namespace {
0041 
0042 bool isViewExtension(const QString &extension)
0043 {
0044     return (extension == QStringLiteral("rjs") ||
0045             extension == QStringLiteral("rxml") ||
0046             extension == QStringLiteral("rhtml") ||
0047             extension == QStringLiteral("js.rjs") ||
0048             extension == QStringLiteral("xml.builder") ||
0049             extension == QStringLiteral("html.erb") ||
0050             extension == QStringLiteral("erb") ||
0051             extension == QStringLiteral("haml"));
0052 }
0053 
0054 }
0055 
0056 Switchers::Switchers(ruby::LanguageSupport *language)
0057     : QObject(language)
0058 {
0059 }
0060 
0061 QVector<Path> Switchers::viewsToSwitch()
0062 {
0063     QVector<Path> urls;
0064 
0065     auto doc = ICore::self()->documentController()->activeDocument();
0066     if (!doc) {
0067         return urls;
0068     }
0069 
0070     const QUrl &url = doc->url();
0071     QFileInfo file(url.toLocalFile());
0072     if (!file.exists()) {
0073         return urls;
0074     }
0075 
0076     const QString &ext = file.completeSuffix();
0077     QString name = file.baseName();
0078     QString switchTo = "";
0079 
0080     if (isViewExtension(ext)) {
0081         switchTo = file.dir().dirName();
0082     } else if (ext == "rb") {
0083         switchTo = name.remove(QRegExp("_controller$"));
0084         switchTo = switchTo.remove(QRegExp("_controller_test$"));
0085         switchTo = switchTo.remove(QRegExp("_test$"));
0086     }
0087 
0088     if (switchTo.isEmpty()) {
0089         return urls;
0090     }
0091     if (switchTo.endsWith("s")) {
0092         switchTo = switchTo.mid(0, switchTo.length() - 1);
0093     }
0094 
0095     Path root = Helpers::findRailsRoot(url);
0096     if (!root.isValid()) {
0097         return urls;
0098     }
0099 
0100     Path viewsUrl(root, QStringLiteral("app/views"));
0101     Path viewsUrlS(viewsUrl, switchTo);
0102     Path viewsUrlP(viewsUrl, switchTo + "s");
0103 
0104     if (QFile::exists(viewsUrlS.toLocalFile())) {
0105         viewsUrl = viewsUrlS;
0106     } else if (QFile::exists(viewsUrlP.toLocalFile())) {
0107         viewsUrl = viewsUrlP;
0108     } else {
0109         return urls;
0110     }
0111 
0112     QDir viewsDir(viewsUrl.toLocalFile());
0113     const QStringList &views = viewsDir.entryList();
0114     const Path base(viewsDir.absolutePath());
0115 
0116     foreach (const QString &name, views) {
0117         if (!(name.endsWith("~") || name == "." || name == "..")) {
0118             urls << KDevelop::Path(base, name);
0119         }
0120     }
0121     return urls;
0122 }
0123 
0124 QVector<Path> Switchers::testsToSwitch()
0125 {
0126     QVector<KDevelop::Path> urls;
0127 
0128     auto doc = KDevelop::ICore::self()->documentController()->activeDocument();
0129     if (!doc) {
0130         return urls;
0131     }
0132 
0133     QFileInfo file(doc->url().toLocalFile());
0134     if (!file.exists()) {
0135         return urls;
0136     }
0137 
0138     const QString &ext = file.completeSuffix();
0139     QString name = file.baseName();
0140     QString switchTo = "";
0141 
0142     if (isViewExtension(ext)) {
0143         switchTo = file.dir().dirName();
0144     } else if (ext == "rb") {
0145         switchTo = name.remove(QRegExp("_controller$")).
0146             remove(QRegExp("_controller_test$")).remove(QRegExp("_test$"));
0147     }
0148     if (switchTo.isEmpty()) {
0149         return urls;
0150     }
0151     if (switchTo.endsWith("s")) {
0152         switchTo = switchTo.mid(0, switchTo.length() - 1);
0153     }
0154 
0155     Path testsUrl(Helpers::findRailsRoot(doc->url()), "test");
0156     Path functionalTestsUrlS(testsUrl, "functional/" + switchTo +
0157         "_controller_test.rb");
0158     if (QFile::exists(functionalTestsUrlS.toLocalFile())) {
0159         urls << functionalTestsUrlS;
0160     }
0161 
0162     Path functionalTestsUrlP(testsUrl, "functional/" + switchTo +
0163         "s_controller_test.rb");
0164     if (QFile::exists(functionalTestsUrlP.toLocalFile())) {
0165         urls << functionalTestsUrlP;
0166     }
0167 
0168     Path integrationTestsUrlS(testsUrl, "integration/" + switchTo + "_test.rb");
0169     if (QFile::exists(integrationTestsUrlS.toLocalFile())) {
0170         urls << integrationTestsUrlS;
0171     }
0172 
0173     Path integrationTestsUrlP(testsUrl, "integration/" + switchTo + "s_test.rb");
0174     if (QFile::exists(integrationTestsUrlP.toLocalFile())) {
0175         urls << integrationTestsUrlP;
0176     }
0177 
0178     Path unitTestsUrlS(testsUrl, "unit/" + switchTo + "_test.rb");
0179     if (QFile::exists(unitTestsUrlS.toLocalFile())) {
0180         urls << unitTestsUrlS;
0181     }
0182 
0183     Path unitTestsUrlP(testsUrl, "unit/" + switchTo + "s_test.rb");
0184     if (QFile::exists(unitTestsUrlP.toLocalFile())) {
0185         urls << unitTestsUrlP;
0186     }
0187 
0188     return urls;
0189 }
0190 
0191 void Switchers::switchToController()
0192 {
0193     auto doc = KDevelop::ICore::self()->documentController()->activeDocument();
0194     if (!doc) {
0195         return;
0196     }
0197 
0198     QFileInfo file(doc->url().toLocalFile());
0199     if (!file.exists()) {
0200         return;
0201     }
0202 
0203     const QString &ext = file.completeSuffix();
0204     QString name = file.baseName();
0205     QString switchTo = "";
0206     Path root = Helpers::findRailsRoot(doc->url());
0207     if (!root.isValid()) {
0208         return;
0209     }
0210 
0211     if (ext == QStringLiteral("rb") &&
0212         !name.endsWith(QStringLiteral("_controller"))) {
0213 
0214         if (name.endsWith("_test")) {
0215             switchTo = name.remove(QRegExp("_test$"));
0216             switchTo = name.remove(QRegExp("_controller$"));
0217         } else {
0218             switchTo = name;
0219         }
0220     } else if (isViewExtension(ext)) {
0221         switchTo = file.dir().dirName();
0222     }
0223 
0224     if (!switchTo.isEmpty()) {
0225         Path url(root, "app/controllers");
0226 
0227         if (switchTo.endsWith("s")) {
0228             switchTo = switchTo.mid(0, switchTo.length() - 1);
0229         }
0230         Path singular(url, switchTo + "_controller.rb");
0231         Path plural(url, switchTo + "s_controller.rb");
0232 
0233         QUrl docUrl;
0234         if (QFile::exists(singular.toLocalFile())) {
0235             docUrl = singular.toUrl();
0236         } else {
0237             docUrl = plural.toUrl();
0238         }
0239         ICore::self()->documentController()->openDocument(docUrl);
0240     }
0241 }
0242 
0243 void Switchers::switchToModel()
0244 {
0245     auto doc = ICore::self()->documentController()->activeDocument();
0246     if (!doc) {
0247         return;
0248     }
0249 
0250     QFileInfo file(doc->url().toLocalFile());
0251     if (!file.exists()) {
0252         return;
0253     }
0254 
0255     const QString &ext = file.completeSuffix();
0256     QString name = file.baseName();
0257     QString switchTo = "";
0258 
0259     Path root = Helpers::findRailsRoot(doc->url());
0260     if (!root.isValid()) {
0261         return;
0262     }
0263 
0264     if (isViewExtension(ext)) {
0265         switchTo = file.dir().dirName();
0266     } else if (ext == QStringLiteral("rb") &&
0267                 (name.endsWith(QStringLiteral("_controller")) ||
0268                  name.endsWith(QStringLiteral("_test")))) {
0269 
0270         switchTo = name.remove(QRegExp("_controller$"));
0271         switchTo = switchTo.remove(QRegExp("_controller_test$"));
0272         switchTo = switchTo.remove(QRegExp("_test$"));
0273     }
0274     if (switchTo.isEmpty()) {
0275         return;
0276     }
0277 
0278     Path url(root, QStringLiteral("app/models"));
0279     if (switchTo.endsWith("s")) {
0280         switchTo = switchTo.mid(0, switchTo.length() - 1);
0281     }
0282     url.addPath(switchTo + ".rb");
0283     ICore::self()->documentController()->openDocument(url.toUrl());
0284 }
0285 
0286 void Switchers::switchToView()
0287 {
0288     if (viewsToSwitch().isEmpty()) {
0289         return;
0290     }
0291 
0292     auto quickOpen = ICore::self()->pluginController()->
0293         extensionForPlugin<IQuickOpen>("org.kdevelop.IQuickOpen");
0294 
0295     Q_ASSERT(quickOpen);
0296     quickOpen->showQuickOpen(QStringList{ i18n("Rails Views") });
0297 }
0298 
0299 void Switchers::switchToTest()
0300 {
0301     if (testsToSwitch().isEmpty()) {
0302         return;
0303     }
0304 
0305     auto quickOpen = ICore::self()->pluginController()->
0306         extensionForPlugin<IQuickOpen>("org.kdevelop.IQuickOpen");
0307 
0308     Q_ASSERT(quickOpen);
0309     quickOpen->showQuickOpen(QStringList{ i18n("Rails Tests") });
0310 }
0311