diff --git a/addons/externaltools/externaltools.cpp b/addons/externaltools/externaltools.cpp index f9abd0b81..628f4b02a 100644 --- a/addons/externaltools/externaltools.cpp +++ b/addons/externaltools/externaltools.cpp @@ -1,643 +1,650 @@ /* 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 #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->edtInput->setText(tool->command); ui->edtMimeType->setText(tool->mimetypes.join(QStringLiteral("; "))); ui->cmbSave->setCurrentIndex(static_cast(tool->saveMode)); ui->edtCommand->setText(tool->cmdname); + ui->chkIncludeStderr->setChecked(tool->includeStderr); } } void KateExternalToolServiceEditor::slotOKClicked() { if (ui->edtName->text().isEmpty() || ui->edtInput->document()->isEmpty()) { QMessageBox::information(this, i18n("External Tool"), i18n("You must specify at least a name and a command")); return; } accept(); } void KateExternalToolServiceEditor::showMTDlg() { QString text = i18n("Select the MimeTypes for which to enable this tool."); - QStringList list = ui->edtMimeType->text().split(QRegExp(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts); + 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( - editor.ui->edtName->text(), editor.ui->edtInput->toPlainText(), editor.ui->btnIcon->icon(), editor.ui->edtExecutable->text(), - editor.ui->edtMimeType->text().split(QRegExp(QStringLiteral("\\s*;\\s*")), QString::SkipEmptyParts)); + KateExternalTool* t = new KateExternalTool(); + t->name = editor.ui->edtName->text(); + t->command = editor.ui->edtInput->toPlainText(); + t->icon = editor.ui->btnIcon->icon(); + t->executable = editor.ui->edtExecutable->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->cmdname = editor.ui->edtCommand->text(); t->command = editor.ui->edtInput->toPlainText(); t->icon = editor.ui->btnIcon->icon(); t->executable = editor.ui->edtExecutable->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/kateexternaltool.cpp b/addons/externaltools/kateexternaltool.cpp index 4b69f0777..e0c777e5f 100644 --- a/addons/externaltools/kateexternaltool.cpp +++ b/addons/externaltools/kateexternaltool.cpp @@ -1,79 +1,81 @@ /* 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) 2019 Dominik Haumann */ #include "kateexternaltool.h" #include #include KateExternalTool::KateExternalTool(const QString& name, const QString& command, const QString& icon, const QString& executable, const QStringList& mimetypes, const QString& actionName, const QString& cmdname, SaveMode saveMode) : name(name) , icon(icon) , executable(executable) , command(command) , mimetypes(mimetypes) , actionName(actionName) , cmdname(cmdname) , saveMode(saveMode) { // if ( ! executable.isEmpty() ) hasexec = checkExec(); } bool KateExternalTool::checkExec() { m_exec = QStandardPaths::findExecutable(executable); return !m_exec.isEmpty(); } bool KateExternalTool::valid(const QString& mt) const { return mimetypes.isEmpty() || mimetypes.contains(mt); } void KateExternalTool::load(const KConfigGroup & cg) { name = cg.readEntry("name", ""); command = cg.readEntry("command", ""); icon = cg.readEntry("icon", ""); executable = cg.readEntry("executable", ""); mimetypes = cg.readEntry("mimetypes", QStringList()); actionName = cg.readEntry("actionName"); cmdname = cg.readEntry("cmdname"); saveMode = static_cast(cg.readEntry("save", 0)); + includeStderr = cg.readEntry("includeStderr", false); hasexec = checkExec(); } void KateExternalTool::save(KConfigGroup & cg) { cg.writeEntry("name", name); cg.writeEntry("command", command); cg.writeEntry("icon", icon); cg.writeEntry("executable", executable); cg.writeEntry("mimetypes", mimetypes); cg.writeEntry("actionName", actionName); cg.writeEntry("cmdname", cmdname); cg.writeEntry("save", static_cast(saveMode)); + cg.writeEntry("includeStderr", includeStderr); } // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/externaltools/kateexternaltool.h b/addons/externaltools/kateexternaltool.h index c94fa4efe..5bb78ec17 100644 --- a/addons/externaltools/kateexternaltool.h +++ b/addons/externaltools/kateexternaltool.h @@ -1,128 +1,130 @@ /* 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_KATE_EXTERNALTOOL_H #define KTEXTEDITOR_KATE_EXTERNALTOOL_H #include #include #include class KConfigGroup; /** * This class defines a single external tool. */ class KateExternalTool { Q_GADGET public: /** * Defines whether any document should be saved before running the tool. */ enum class SaveMode { //! Do not save any document. None, //! Save current document. CurrentDocument, //! Save all documents AllDocuments }; Q_ENUM(SaveMode) /** * Defines where to redirect stdout from the tool. */ // enum class OutputMode { // Ignore, // InsertAtCursor, // ReplaceSelectedText, // AppendToCurrentDocument, // InsertInNewDocument, // DisplayInPane // } // Q_ENUM(OutputMode) public: explicit KateExternalTool(const QString& name = QString(), const QString& command = QString(), const QString& icon = QString(), const QString& executable = QString(), const QStringList& mimetypes = QStringList(), const QString& actionName = QString(), const QString& cmdname = QString(), SaveMode saveMode = SaveMode::None); ~KateExternalTool() = default; /// The name used in the menu. QString name; /// the icon to use in the menu. QString icon; /// The name or path of the executable. QString executable; /// The command line arguments. QString arguments; /// The command to execute. QString command; /// Optional list of mimetypes for which this action is valid. QStringList mimetypes; /// This is set by the constructor by calling checkExec(), if a /// value is present. bool hasexec; /// The name for the action. This is generated first time the /// action is is created. QString actionName; /// The name for the commandline. QString cmdname; /// Possibly save documents prior to activating the tool command. SaveMode saveMode = SaveMode::None; /// Possibly redirect the stdout output of the tool. //OutputMode outputMode; + /// Include stderr output when running the tool. + bool includeStderr = false; /** * @return true if mimetypes is empty, or the @p mimetype matches. */ bool valid(const QString& mimetype) const; /** * @return true if "executable" exists and has the executable bit set, or is * empty. * This is run at least once, and the tool is disabled if it fails. */ bool checkExec(); /** * Load tool data from the config group @p cg. */ void load(const KConfigGroup & cg); /** * Save tool data to the config group @p cg. */ void save(KConfigGroup & cg); private: QString m_exec; ///< The fully qualified path of the executable. }; #endif // KTEXTEDITOR_KATE_EXTERNALTOOL_H // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/externaltools/katetoolrunner.cpp b/addons/externaltools/katetoolrunner.cpp index c7421a63e..9c1782770 100644 --- a/addons/externaltools/katetoolrunner.cpp +++ b/addons/externaltools/katetoolrunner.cpp @@ -1,78 +1,80 @@ /* 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 "katetoolrunner.h" #include "kateexternaltool.h" KateToolRunner::KateToolRunner(KateExternalTool * tool) : m_tool(tool) , m_process(new QProcess()) { } KateToolRunner::~KateToolRunner() { delete m_process; m_process = nullptr; } void KateToolRunner::run() { - m_process->setProcessChannelMode(QProcess::MergedChannels); + if (m_tool->includeStderr) { + m_process->setProcessChannelMode(QProcess::MergedChannels); + } QObject::connect(m_process, &QProcess::readyRead, this, &KateToolRunner::slotReadyRead); QObject::connect(m_process, static_cast(&QProcess::finished), this, &KateToolRunner::toolFinished); m_process->start(m_tool->executable, { m_tool->arguments }); } void KateToolRunner::waitForFinished() { m_process->waitForFinished(); } QString KateToolRunner::outputData() const { return QString::fromLocal8Bit(m_output); } void KateToolRunner::slotReadyRead() { m_output += m_process->readAll(); } void KateToolRunner::toolFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode != 0) { // FIXME: somehow tell user return; } if (exitStatus != QProcess::NormalExit) { // FIXME: somehow tell user return; } // FIXME: process m_output depending on the tool's outputMode } // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/externaltools/tooldialog.ui b/addons/externaltools/tooldialog.ui index ab72e6883..389c05e8a 100644 --- a/addons/externaltools/tooldialog.ui +++ b/addons/externaltools/tooldialog.ui @@ -1,353 +1,360 @@ ToolDialog 0 0 470 491 Edit Tool Name: The name will be displayed in the 'Tools->External Tools' menu. Short name of the tool Executable: The executable used by the command. This is used to check if a tool should be displayed; if not set, the first word of <em>command</em> will be used. Application or interpreter ../../../../../../../../.designer/backup../../../../../../../../.designer/backup QToolButton::InstantPopup Arguments: Input: <p>The script to execute to invoke the tool. The script is passed to /bin/sh for execution. The following macros will be expanded:</p><ul><li><code>%URL</code> - the URL of the current document.</li><li><code>%URLs</code> - a list of the URLs of all open documents.</li><li><code>%directory</code> - the URL of the directory containing the current document.</li><li><code>%filename</code> - the filename of the current document.</li><li><code>%line</code> - the current line of the text cursor in the current view.</li><li><code>%column</code> - the column of the text cursor in the current view.</li><li><code>%selection</code> - the selected text in the current view.</li><li><code>%text</code> - the text of the current document.</li></ul> Optional standard input ../../../../../../../../.designer/backup../../../../../../../../.designer/backup QToolButton::InstantPopup Mime types: A semicolon-separated list of mime types for which this tool should be available; if this is left empty, the tool is always available. To choose from known mimetypes, press the button on the right. Show tool only for given mime types Click for a dialog that can help you create a list of mimetypes. ../../../../../../../../.designer/backup../../../../../../../../.designer/backup Save: You can choose to save the current or all [modified] documents prior to running the command. This is helpful if you want to pass URLs to an application like, for example, an FTP client. None Current Document All Documents Reload current document after execution Output: Ignore Insert at Cursor Position Replace Selected Text Replace Current Document Append to Current Document Insert in New Document Display in Pane Embedded Console - + Editor command: - + If you specify a name here, you can invoke the command from the view command line with exttool-the_name_you_specified_here. Please do not use spaces or tabs in the name. Optional command bar name - + Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok Working directory: Uses current document path if empty ../../../../../../../../.designer/backup../../../../../../../../.designer/backup QToolButton::InstantPopup Command line arguments ../../../../../../../../.designer/backup../../../../../../../../.designer/backup QToolButton::InstantPopup + + + + Include output from stderr + + + KIconButton QPushButton
kiconbutton.h
buttonBox accepted() ToolDialog accept() 248 254 157 274 buttonBox rejected() ToolDialog reject() 316 260 286 274