diff --git a/addons/externaltools/CMakeLists.txt b/addons/externaltools/CMakeLists.txt index 58611e053..cf82041d6 100644 --- a/addons/externaltools/CMakeLists.txt +++ b/addons/externaltools/CMakeLists.txt @@ -1,39 +1,40 @@ project(externaltoolsplugin) add_definitions(-DTRANSLATION_DOMAIN=\"externaltoolsplugin\") include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) set(externaltoolsplugin_PART_SRCS externaltoolsplugin.cpp externaltools.cpp katetoolrunner.cpp kateexternaltool.cpp + katemacroexpander.cpp ) # resource for ui file and stuff qt5_add_resources(externaltoolsplugin_PART_SRCS plugin.qrc) set(externaltoolsplugin_PART_UI configwidget.ui tooldialog.ui ) ki18n_wrap_ui(externaltoolsplugin_PART_SRCS ${externaltoolsplugin_PART_UI} ) add_library(externaltoolsplugin MODULE ${externaltoolsplugin_PART_SRCS}) # we compile in the .desktop file kcoreaddons_desktop_to_json (externaltoolsplugin externaltoolsplugin.desktop) target_link_libraries(externaltoolsplugin KF5::CoreAddons KF5::IconThemes KF5::TextEditor KF5::I18n ) ########### install files ############### install(TARGETS externaltoolsplugin DESTINATION ${PLUGIN_INSTALL_DIR}/ktexteditor ) ############# unit tests ################ if (BUILD_TESTING) add_subdirectory(autotests) endif() diff --git a/addons/externaltools/autotests/CMakeLists.txt b/addons/externaltools/autotests/CMakeLists.txt index d3fbc9966..1d6776d63 100644 --- a/addons/externaltools/autotests/CMakeLists.txt +++ b/addons/externaltools/autotests/CMakeLists.txt @@ -1,11 +1,12 @@ include(ECMMarkAsTest) # Project Plugin add_executable(externaltools_test externaltooltest.cpp ../kateexternaltool.cpp ../katetoolrunner.cpp + ../katemacroexpander.cpp ) add_test(plugin-externaltools_test externaltools_test) target_link_libraries(externaltools_test kdeinit_kate Qt5::Test) ecm_mark_as_test(externaltools_test) diff --git a/addons/externaltools/externaltools.cpp b/addons/externaltools/externaltools.cpp index 6dde5c6cf..20851e9df 100644 --- a/addons/externaltools/externaltools.cpp +++ b/addons/externaltools/externaltools.cpp @@ -1,656 +1,618 @@ /* This file is part of the Kate text editor of the KDE project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2004, Anders Lund Copyright (C) 2019 Dominik Haumann */ // TODO // Icons // Direct shortcut setting #include "externaltools.h" #include "kateexternaltool.h" #include "externaltoolsplugin.h" +#include "katemacroexpander.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // BEGIN KateExternalToolsCommand KateExternalToolsCommand::KateExternalToolsCommand(KateExternalToolsPlugin* plugin) : KTextEditor::Command({/* FIXME */}) , m_plugin(plugin) { reload(); } // FIXME // const QStringList& KateExternalToolsCommand::cmds() // { // return m_list; // } void KateExternalToolsCommand::reload() { m_list.clear(); m_map.clear(); m_name.clear(); KConfig _config(QStringLiteral("externaltools"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation); KConfigGroup config(&_config, "Global"); const QStringList tools = config.readEntry("tools", QStringList()); for (QStringList::const_iterator it = tools.begin(); it != tools.end(); ++it) { if (*it == QStringLiteral("---")) continue; config = KConfigGroup(&_config, *it); KateExternalTool t = KateExternalTool(config.readEntry(QStringLiteral("name"), ""), config.readEntry("command", ""), config.readEntry(QStringLiteral("icon"), ""), config.readEntry("executable", ""), config.readEntry(QStringLiteral("mimetypes"), QStringList()), config.readEntry(QStringLiteral("actionName"), ""), config.readEntry("cmdname", "")); // FIXME test for a command name first! if (t.hasexec && (!t.cmdname.isEmpty())) { m_list.append(QStringLiteral("exttool-") + t.cmdname); m_map.insert(QStringLiteral("exttool-") + t.cmdname, t.actionName); m_name.insert(QStringLiteral("exttool-") + t.cmdname, t.name); } } } bool KateExternalToolsCommand::exec(KTextEditor::View* view, const QString& cmd, QString& msg, const KTextEditor::Range& range) { Q_UNUSED(msg) Q_UNUSED(range) auto wv = dynamic_cast(view); if (!wv) { // qDebug()<<"KateExternalToolsCommand::exec: Could not get view widget"; return false; } // qDebug()<<"cmd="<(dmw->action("tools_external")); if (!a) return false;*/ KateExternalToolsPluginView* extview = m_plugin->extView(wv->window()); if (!extview) return false; if (!extview->externalTools) return false; // qDebug()<<"trying to find action"; QAction* a1 = extview->externalTools->actionCollection()->action(actionName); if (!a1) return false; // qDebug()<<"activating action"; a1->trigger(); return true; } bool KateExternalToolsCommand::help(KTextEditor::View*, const QString&, QString&) { return false; } // END KateExternalToolsCommand // BEGIN KateExternalToolAction KateExternalToolAction::KateExternalToolAction(QObject* parent, KateExternalTool* t) : QAction(QIcon::fromTheme(t->icon), t->name, parent) , tool(t) { setText(t->name); if (!t->icon.isEmpty()) setIcon(QIcon::fromTheme(t->icon)); connect(this, SIGNAL(triggered(bool)), SLOT(slotRun())); } -bool KateExternalToolAction::expandMacro(const QString& str, QStringList& ret) -{ - KTextEditor::MainWindow* mw = qobject_cast(parent()->parent()); - Q_ASSERT(mw); - - KTextEditor::View* view = mw->activeView(); - if (!view) - return false; - - KTextEditor::Document* doc = view->document(); - QUrl url = doc->url(); - - if (str == QStringLiteral("URL")) - ret += url.url(); - else if (str == QStringLiteral("directory")) // directory of current doc - ret += url.toString(QUrl::RemoveScheme | QUrl::RemoveFilename); - else if (str == QStringLiteral("filename")) - ret += url.fileName(); - else if (str == QStringLiteral("line")) // cursor line of current doc - ret += QString::number(view->cursorPosition().line()); - else if (str == QStringLiteral("col")) // cursor col of current doc - ret += QString::number(view->cursorPosition().column()); - else if (str == QStringLiteral("selection")) // selection of current doc if any - ret += view->selectionText(); - else if (str == QStringLiteral("text")) // text of current doc - ret += doc->text(); - else if (str == QStringLiteral("URLs")) { - foreach (KTextEditor::Document* it, KTextEditor::Editor::instance()->application()->documents()) - if (!it->url().isEmpty()) - ret += it->url().url(); - } else - return false; - - return true; } KateExternalToolAction::~KateExternalToolAction() { delete (tool); } void KateExternalToolAction::slotRun() { // expand the macros in command if any, // and construct a command with an absolute path QString cmd = tool->command; auto mw = qobject_cast(parent()->parent()); - if (!expandMacrosShellQuote(cmd)) { - KMessageBox::sorry(mw->window(), i18n("Failed to expand the command '%1'.", cmd), i18n("Kate External Tools")); - return; - } - qDebug() << "externaltools: Running command: " << cmd; // save documents if requested if (tool->saveMode == KateExternalTool::SaveMode::CurrentDocument) mw->activeView()->document()->save(); else if (tool->saveMode == KateExternalTool::SaveMode::AllDocuments) { foreach (KXMLGUIClient* client, mw->guiFactory()->clients()) { if (QAction* a = client->actionCollection()->action(QStringLiteral("file_save_all"))) { a->trigger(); break; } } } KRun::runCommand(cmd, tool->executable, tool->icon, mw->window()); } // END KateExternalToolAction // BEGIN KateExternalToolsMenuAction KateExternalToolsMenuAction::KateExternalToolsMenuAction(const QString& text, KActionCollection* collection, QObject* parent, KTextEditor::MainWindow* mw) : KActionMenu(text, parent) , mainwindow(mw) { m_actionCollection = collection; // connect to view changed... connect(mw, &KTextEditor::MainWindow::viewChanged, this, &KateExternalToolsMenuAction::slotViewChanged); reload(); } KateExternalToolsMenuAction::~KateExternalToolsMenuAction() { // kDebug() << "deleted KateExternalToolsMenuAction"; } void KateExternalToolsMenuAction::reload() { bool needs_readd = (m_actionCollection->takeAction(this) != nullptr); m_actionCollection->clear(); if (needs_readd) m_actionCollection->addAction(QStringLiteral("tools_external"), this); menu()->clear(); // load all the tools, and create a action for each of them KSharedConfig::Ptr pConfig = KSharedConfig::openConfig(QStringLiteral("externaltools"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation); KConfigGroup config(pConfig, "Global"); const QStringList tools = config.readEntry("tools", QStringList()); for (int i = 0; i < tools.size(); ++i) { const QString & toolSection = tools[i]; if (toolSection == QStringLiteral("---")) { menu()->addSeparator(); // a separator continue; } config = KConfigGroup(pConfig, toolSection); KateExternalTool* t = new KateExternalTool(); t->load(config); if (t->hasexec) { QAction* a = new KateExternalToolAction(this, t); m_actionCollection->addAction(t->actionName, a); addAction(a); } else delete t; } config = KConfigGroup(pConfig, "Shortcuts"); m_actionCollection->readSettings(&config); slotViewChanged(mainwindow->activeView()); } void KateExternalToolsMenuAction::slotViewChanged(KTextEditor::View* view) { // no active view, oh oh if (!view) { return; } // try to enable/disable to match current mime type KTextEditor::Document* doc = view->document(); if (doc) { const QString mimeType = doc->mimeType(); foreach (QAction* kaction, m_actionCollection->actions()) { KateExternalToolAction* action = dynamic_cast(kaction); if (action) { const QStringList l = action->tool->mimetypes; const bool b = (!l.count() || l.contains(mimeType)); action->setEnabled(b); } } } } // END KateExternalToolsMenuAction // BEGIN ToolItem /** * This is a QListBoxItem, that has a KateExternalTool. The text is the Name * of the tool. */ class ToolItem : public QListWidgetItem { public: ToolItem(QListWidget* lb, const QPixmap& icon, KateExternalTool* tool) : QListWidgetItem(icon, tool->name, lb) , tool(tool) { } ~ToolItem() {} KateExternalTool* tool; }; // END ToolItem // BEGIN KateExternalToolServiceEditor KateExternalToolServiceEditor::KateExternalToolServiceEditor(KateExternalTool* tool, QWidget* parent) : QDialog(parent) , tool(tool) { setWindowTitle(i18n("Edit External Tool")); ui = new Ui::ToolDialog(); ui->setupUi(this); ui->btnIcon->setIconSize(KIconLoader::SizeSmall); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &KateExternalToolServiceEditor::slotOKClicked); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(ui->btnMimeType, &QToolButton::clicked, this, &KateExternalToolServiceEditor::showMTDlg); if (tool) { ui->edtName->setText(tool->name); if (!tool->icon.isEmpty()) ui->btnIcon->setIcon(tool->icon); ui->edtExecutable->setText(tool->executable); ui->edtArgs->setText(tool->arguments); ui->edtInput->setText(tool->command); ui->edtCommand->setText(tool->cmdname); ui->edtWorkingDir->setText(tool->workingDir); ui->edtMimeType->setText(tool->mimetypes.join(QStringLiteral("; "))); ui->cmbSave->setCurrentIndex(static_cast(tool->saveMode)); ui->chkIncludeStderr->setChecked(tool->includeStderr); } } void KateExternalToolServiceEditor::slotOKClicked() { if (ui->edtName->text().isEmpty() || ui->edtExecutable->text().isEmpty()) { QMessageBox::information(this, i18n("External Tool"), i18n("You must specify at least a name and an executable")); return; } accept(); } void KateExternalToolServiceEditor::showMTDlg() { QString text = i18n("Select the MimeTypes for which to enable this tool."); QStringList list = ui->edtMimeType->text().split(QRegularExpression(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts); KMimeTypeChooserDialog d(i18n("Select Mime Types"), text, list, QStringLiteral("text"), this); if (d.exec() == QDialog::Accepted) { ui->edtMimeType->setText(d.chooser()->mimeTypes().join(QStringLiteral(";"))); } } // END KateExternalToolServiceEditor // BEGIN KateExternalToolsConfigWidget KateExternalToolsConfigWidget::KateExternalToolsConfigWidget(QWidget* parent, KateExternalToolsPlugin* plugin) : KTextEditor::ConfigPage(parent) , m_plugin(plugin) { setupUi(this); btnMoveUp->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); btnMoveDown->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); connect(lbTools, &QListWidget::itemSelectionChanged, this, &KateExternalToolsConfigWidget::slotSelectionChanged); connect(lbTools, &QListWidget::itemDoubleClicked, this, &KateExternalToolsConfigWidget::slotEdit); connect(btnNew, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotNew); connect(btnRemove, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotRemove); connect(btnEdit, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotEdit); connect(btnSeparator, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotInsertSeparator); connect(btnMoveUp, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotMoveUp); connect(btnMoveDown, &QPushButton::clicked, this, &KateExternalToolsConfigWidget::slotMoveDown); m_config = new KConfig(QStringLiteral("externaltools"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation); reset(); slotSelectionChanged(); } KateExternalToolsConfigWidget::~KateExternalToolsConfigWidget() { delete m_config; } QString KateExternalToolsConfigWidget::name() const { return i18n("External Tools"); } QString KateExternalToolsConfigWidget::fullName() const { return i18n("External Tools"); } QIcon KateExternalToolsConfigWidget::icon() const { return QIcon(); } void KateExternalToolsConfigWidget::reset() { // m_tools.clear(); lbTools->clear(); // load the files from a KConfig const QStringList tools = m_config->group("Global").readEntry("tools", QStringList()); for (int i = 0; i < tools.size(); ++i) { const QString & toolSection = tools[i]; if (toolSection == QStringLiteral("---")) { new QListWidgetItem(QStringLiteral("---"), lbTools); } else { KConfigGroup cg(m_config, toolSection); KateExternalTool* t = new KateExternalTool(); t->load(cg); if (t->hasexec) // we only show tools that are also in the menu. new ToolItem(lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t); else delete t; } } m_changed = false; } QPixmap KateExternalToolsConfigWidget::blankIcon() { QPixmap pm(KIconLoader::SizeSmall, KIconLoader::SizeSmall); pm.fill(); pm.setMask(pm.createHeuristicMask()); return pm; } void KateExternalToolsConfigWidget::apply() { if (!m_changed) return; m_changed = false; QStringList tools; for (int i = 0; i < lbTools->count(); i++) { if (lbTools->item(i)->text() == QStringLiteral("---")) { tools << QStringLiteral("---"); continue; } const QString toolSection = QStringLiteral("Tool ") + QString::number(i); tools << toolSection; KConfigGroup cg(m_config, toolSection); KateExternalTool* t = static_cast(lbTools->item(i))->tool; t->save(cg); } m_config->group("Global").writeEntry("tools", tools); m_config->sync(); m_plugin->reload(); } void KateExternalToolsConfigWidget::slotSelectionChanged() { // update button state bool hs = lbTools->currentItem() != nullptr; btnEdit->setEnabled(hs && dynamic_cast(lbTools->currentItem())); btnRemove->setEnabled(hs); btnMoveUp->setEnabled((lbTools->currentRow() > 0) && hs); btnMoveDown->setEnabled((lbTools->currentRow() < (int)lbTools->count() - 1) && hs); } void KateExternalToolsConfigWidget::slotNew() { // display a editor, and if it is OK'd, create a new tool and // create a listbox item for it KateExternalToolServiceEditor editor(nullptr, this); if (editor.exec() == QDialog::Accepted) { KateExternalTool* t = new KateExternalTool(); t->name = editor.ui->edtName->text(); t->icon = editor.ui->btnIcon->icon(); t->executable = editor.ui->edtExecutable->text(); t->arguments = editor.ui->edtArgs->text(); t->command = editor.ui->edtInput->toPlainText(); t->workingDir = editor.ui->edtWorkingDir->text(); t->mimetypes = editor.ui->edtMimeType->text().split(QRegularExpression(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts); t->saveMode = static_cast(editor.ui->cmbSave->currentIndex()); t->includeStderr = editor.ui->chkIncludeStderr->isChecked(); // This is sticky, it does not change again, so that shortcuts sticks // TODO check for dups t->actionName = QStringLiteral("externaltool_") + QString(t->name).remove(QRegExp(QStringLiteral("\\W+"))); new ToolItem(lbTools, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t); emit changed(); m_changed = true; } } void KateExternalToolsConfigWidget::slotRemove() { // add the tool action name to a list of removed items, // remove the current listbox item if (lbTools->currentRow() > -1) { ToolItem* i = dynamic_cast(lbTools->currentItem()); if (i) m_removed << i->tool->actionName; delete lbTools->takeItem(lbTools->currentRow()); emit changed(); m_changed = true; } } void KateExternalToolsConfigWidget::slotEdit() { if (!dynamic_cast(lbTools->currentItem())) return; // show the item in an editor KateExternalTool* t = static_cast(lbTools->currentItem())->tool; KateExternalToolServiceEditor editor(t, this); editor.resize(m_config->group("Editor").readEntry("Size", QSize())); if (editor.exec() /*== KDialog::Ok*/) { bool elementChanged = ((editor.ui->btnIcon->icon() != t->icon) || (editor.ui->edtName->text() != t->name)); t->name = editor.ui->edtName->text(); t->icon = editor.ui->btnIcon->icon(); t->executable = editor.ui->edtExecutable->text(); t->arguments = editor.ui->edtArgs->text(); t->cmdname = editor.ui->edtCommand->text(); t->command = editor.ui->edtInput->toPlainText(); t->workingDir = editor.ui->edtWorkingDir->text(); t->mimetypes = editor.ui->edtMimeType->text().split(QRegExp(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts); t->saveMode = static_cast(editor.ui->cmbSave->currentIndex()); t->includeStderr = editor.ui->chkIncludeStderr->isChecked(); // if the icon has changed or name changed, I have to renew the listbox item :S if (elementChanged) { int idx = lbTools->row(lbTools->currentItem()); delete lbTools->takeItem(idx); lbTools->insertItem(idx, new ToolItem(nullptr, t->icon.isEmpty() ? blankIcon() : SmallIcon(t->icon), t)); } emit changed(); m_changed = true; } m_config->group("Editor").writeEntry("Size", editor.size()); m_config->sync(); } void KateExternalToolsConfigWidget::slotInsertSeparator() { lbTools->insertItem(lbTools->currentRow() + 1, QStringLiteral("---")); emit changed(); m_changed = true; } void KateExternalToolsConfigWidget::slotMoveUp() { // move the current item in the listbox upwards if possible QListWidgetItem* item = lbTools->currentItem(); if (!item) return; int idx = lbTools->row(item); if (idx < 1) return; if (dynamic_cast(item)) { KateExternalTool* tool = static_cast(item)->tool; delete lbTools->takeItem(idx); lbTools->insertItem(idx - 1, new ToolItem(nullptr, tool->icon.isEmpty() ? blankIcon() : SmallIcon(tool->icon), tool)); } else // a separator! { delete lbTools->takeItem(idx); lbTools->insertItem(idx - 1, new QListWidgetItem(QStringLiteral("---"))); } lbTools->setCurrentRow(idx - 1); slotSelectionChanged(); emit changed(); m_changed = true; } void KateExternalToolsConfigWidget::slotMoveDown() { // move the current item in the listbox downwards if possible QListWidgetItem* item = lbTools->currentItem(); if (!item) return; int idx = lbTools->row(item); if (idx > lbTools->count() - 1) return; if (dynamic_cast(item)) { KateExternalTool* tool = static_cast(item)->tool; delete lbTools->takeItem(idx); lbTools->insertItem(idx + 1, new ToolItem(nullptr, tool->icon.isEmpty() ? blankIcon() : SmallIcon(tool->icon), tool)); } else // a separator! { delete lbTools->takeItem(idx); lbTools->insertItem(idx + 1, new QListWidgetItem(QStringLiteral("---"))); } lbTools->setCurrentRow(idx + 1); slotSelectionChanged(); emit changed(); m_changed = true; } // END KateExternalToolsConfigWidget ExternalToolRunner::ExternalToolRunner(KateExternalTool * tool) : m_tool(tool) { } ExternalToolRunner::~ExternalToolRunner() { } void ExternalToolRunner::run() { } // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/externaltools/externaltools.h b/addons/externaltools/externaltools.h index e1123524a..0dc0559e5 100644 --- a/addons/externaltools/externaltools.h +++ b/addons/externaltools/externaltools.h @@ -1,227 +1,224 @@ /* This file is part of the Kate text editor of the KDE project. It describes a "external tools" action for kate and provides a dialog page to configure that. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2004 Anders Lund Copyright (C) 2019 Dominik Haumann */ #ifndef KTEXTEDITOR_EXTERNALTOOLS_H #define KTEXTEDITOR_EXTERNALTOOLS_H #include "ui_configwidget.h" #include "ui_tooldialog.h" #include #include #include #include #include #include #include #include #include #include #include class KateExternalToolsPlugin; class KateExternalTool; /** * The external tools action * This action creates a menu, in which each item will launch a process * with the provided arguments, which may include the following macros: * - %URLS: the URLs of all open documents. * - %URL: The URL of the active document. * - %filedir: The directory of the current document, if that is a local file. * - %selection: The selection of the active document. * - %text: The text of the active document. * - %line: The line number of the cursor in the active view. * - %column: The column of the cursor in the active view. * * Each item has the following properties: * - Name: The friendly text for the menu * - Exec: The command to execute, including arguments. * - TryExec: the name of the executable, if not available, the * item will not be displayed. * - MimeTypes: An optional list of mimetypes. The item will be disabled or * hidden if the current file is not of one of the indicated types. * */ class KateExternalToolsMenuAction : public KActionMenu { friend class KateExternalToolAction; Q_OBJECT public: KateExternalToolsMenuAction(const QString& text, class KActionCollection* collection, QObject* parent, class KTextEditor::MainWindow* mw = nullptr); virtual ~KateExternalToolsMenuAction(); /** * This will load all the configured services. */ void reload(); class KActionCollection* actionCollection() { return m_actionCollection; } private Q_SLOTS: void slotViewChanged(KTextEditor::View* view); private: class KActionCollection* m_actionCollection; KTextEditor::MainWindow* mainwindow; // for the actions to access view/doc managers }; /** * This Action contains a KateExternalTool */ -class KateExternalToolAction : public QAction, public KWordMacroExpander +class KateExternalToolAction : public QAction { Q_OBJECT public: KateExternalToolAction(QObject* parent, class KateExternalTool* t); ~KateExternalToolAction(); -protected: - bool expandMacro(const QString& str, QStringList& ret) override; - private Q_SLOTS: void slotRun(); public: class KateExternalTool* tool; }; /** * The config widget. * The config widget allows the user to view a list of services of the type * "Kate/ExternalTool" and add, remove or edit them. */ class KateExternalToolsConfigWidget : public KTextEditor::ConfigPage, public Ui::ExternalToolsConfigWidget { Q_OBJECT public: KateExternalToolsConfigWidget(QWidget* parent, KateExternalToolsPlugin* plugin); virtual ~KateExternalToolsConfigWidget(); QString name() const override; QString fullName() const override; QIcon icon() const override; public Q_SLOTS: void apply() override; void reset() override; void defaults() override { reset(); } // double sigh private Q_SLOTS: void slotNew(); void slotEdit(); void slotRemove(); void slotInsertSeparator(); void slotMoveUp(); void slotMoveDown(); void slotSelectionChanged(); private: QPixmap blankIcon(); QStringList m_removed; class KConfig* m_config = nullptr; bool m_changed = false; KateExternalToolsPlugin* m_plugin; }; /** * A Singleton class for invoking external tools with the view command line */ class KateExternalToolsCommand : public KTextEditor::Command { public: KateExternalToolsCommand(KateExternalToolsPlugin* plugin); virtual ~KateExternalToolsCommand() {} void reload(); public: // const QStringList& cmds() override; // FIXME bool exec(KTextEditor::View* view, const QString& cmd, QString& msg, const KTextEditor::Range& range = KTextEditor::Range::invalid()) override; bool help(KTextEditor::View* view, const QString& cmd, QString& msg) override; private: QStringList m_list; QHash m_map; QHash m_name; KateExternalToolsPlugin* m_plugin; }; /** * A Dialog to edit a single KateExternalTool object */ class KateExternalToolServiceEditor : public QDialog { Q_OBJECT public: explicit KateExternalToolServiceEditor(KateExternalTool* tool = nullptr, QWidget* parent = nullptr); private Q_SLOTS: /** * Run when the OK button is clicked, to ensure critical values are provided. */ void slotOKClicked(); /** * show a mimetype chooser dialog */ void showMTDlg(); public: Ui::ToolDialog * ui; private: KateExternalTool* tool; }; /** * Helper class to run a KateExternalTool. */ class ExternalToolRunner { public: ExternalToolRunner(KateExternalTool * tool); ExternalToolRunner(const ExternalToolRunner &) = delete; void operator=(const ExternalToolRunner &) = delete; ~ExternalToolRunner(); void run(); private: KateExternalTool * m_tool; QProcess * m_process = nullptr; }; #endif // KTEXTEDITOR_EXTERNALTOOLS_H // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/externaltools/katemacroexpander.cpp b/addons/externaltools/katemacroexpander.cpp new file mode 100644 index 000000000..44f137cde --- /dev/null +++ b/addons/externaltools/katemacroexpander.cpp @@ -0,0 +1,66 @@ +/* This file is part of the KDE project + * + * Copyright 2019 Dominik Haumann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "katemacroexpander.h" + +#include +#include +#include +#include + +MacroExpander::MacroExpander(KTextEditor::View * view) + : KWordMacroExpander() + , m_view(view) +{ +} + +bool MacroExpander::expandMacro(const QString& str, QStringList& ret) +{ + KTextEditor::View* view = m_view; + if (!view) + return false; + + KTextEditor::Document* doc = view->document(); + QUrl url = doc->url(); + + if (str == QStringLiteral("URL")) + ret += url.url(); + else if (str == QStringLiteral("directory")) // directory of current doc + ret += url.toString(QUrl::RemoveScheme | QUrl::RemoveFilename); + else if (str == QStringLiteral("filename")) + ret += url.fileName(); + else if (str == QStringLiteral("line")) // cursor line of current doc + ret += QString::number(view->cursorPosition().line()); + else if (str == QStringLiteral("col")) // cursor col of current doc + ret += QString::number(view->cursorPosition().column()); + else if (str == QStringLiteral("selection")) // selection of current doc if any + ret += view->selectionText(); + else if (str == QStringLiteral("text")) // text of current doc + ret += doc->text(); + else if (str == QStringLiteral("URLs")) { + foreach (KTextEditor::Document* it, KTextEditor::Editor::instance()->application()->documents()) + if (!it->url().isEmpty()) + ret += it->url().url(); + } else + return false; + + return true; +} + +// kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/externaltools/katemacroexpander.h b/addons/externaltools/katemacroexpander.h new file mode 100644 index 000000000..aca207194 --- /dev/null +++ b/addons/externaltools/katemacroexpander.h @@ -0,0 +1,46 @@ +/* This file is part of the KDE project + * + * Copyright 2019 Dominik Haumann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KTEXTEDITOR_MACRO_EXPANDER_H +#define KTEXTEDITOR_MACRO_EXPANDER_H + +#include + +namespace KTextEditor { + class View; +} + +/** + * Helper class for macro expansion. + */ +class MacroExpander : public KWordMacroExpander +{ +public: + MacroExpander(KTextEditor::View * view); + +protected: + bool expandMacro(const QString& str, QStringList& ret) override; + +private: + KTextEditor::View * m_view; +}; + +#endif // KTEXTEDITOR_MACRO_EXPANDER_H + +// kate: space-indent on; indent-width 4; replace-tabs on;