Commit e86e3838 authored by Waqar Ahmed's avatar Waqar Ahmed
Browse files

Add Before/After save triggers

parent 9a599a94
......@@ -235,14 +235,14 @@ QVector<KateExternalTool> KateExternalToolsPlugin::defaultTools() const
return m_defaultTools;
}
void KateExternalToolsPlugin::runTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingOnSave)
KateToolRunner *KateExternalToolsPlugin::runnerForTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingSaveTrigger)
{
// expand the macros in command if any,
// and construct a command with an absolute path
auto mw = view->mainWindow();
// save documents if requested
if (!executingOnSave) {
if (!executingSaveTrigger) {
if (tool.saveMode == KateExternalTool::SaveMode::CurrentDocument) {
// only save if modified, to avoid unnecessary recompiles
if (view->document()->isModified()) {
......@@ -286,13 +286,25 @@ void KateExternalToolsPlugin::runTool(const KateExternalTool &tool, KTextEditor:
// Allocate runner on heap such that it lives as long as the child
// process is running and does not block the main thread.
auto runner = new KateToolRunner(std::move(copy), view, this);
return new KateToolRunner(std::move(copy), view, this);
}
void KateExternalToolsPlugin::runTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingSaveTrigger)
{
auto runner = runnerForTool(tool, view, executingSaveTrigger);
// use QueuedConnection, since handleToolFinished deletes the runner
connect(runner, &KateToolRunner::toolFinished, this, &KateExternalToolsPlugin::handleToolFinished, Qt::QueuedConnection);
runner->run();
}
void KateExternalToolsPlugin::blockingRunTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingSaveTrigger)
{
auto runner = runnerForTool(tool, view, executingSaveTrigger);
connect(runner, &KateToolRunner::toolFinished, this, &KateExternalToolsPlugin::handleToolFinished);
runner->run();
runner->waitForFinished();
}
void KateExternalToolsPlugin::handleToolFinished(KateToolRunner *runner, int exitCode, bool crashed)
{
auto view = runner->view();
......
......@@ -91,7 +91,13 @@ public:
/**
* Executes the tool based on the view as current document.
*/
void runTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingOnSave = false);
void runTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingSaveTrigger = false);
/**
* Executes the tool based on the view as current document.
* same as @ref runTool but waits for the tool to finish before returning
*/
void blockingRunTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingSaveTrigger = false);
Q_SIGNALS:
/**
......@@ -134,6 +140,7 @@ public:
private:
void migrateConfig();
KateToolRunner *runnerForTool(const KateExternalTool &tool, KTextEditor::View *view, bool executingSaveTrigger);
KSharedConfigPtr m_config;
QVector<KateExternalTool> m_defaultTools;
......
......@@ -92,6 +92,34 @@ KateExternalTool::OutputMode toOutputMode(const QString &mode)
}
return KateExternalTool::OutputMode::Ignore;
}
KateExternalTool::Trigger toTrigger(const QString &trigger)
{
if (trigger == QStringLiteral("None")) {
return KateExternalTool::Trigger::None;
}
if (trigger == QStringLiteral("BeforeSave")) {
return KateExternalTool::Trigger::BeforeSave;
}
if (trigger == QStringLiteral("AfterSave")) {
return KateExternalTool::Trigger::AfterSave;
}
return KateExternalTool::Trigger::None;
}
QString toString(KateExternalTool::Trigger trigger)
{
if (trigger == KateExternalTool::Trigger::None) {
return QStringLiteral("None");
}
if (trigger == KateExternalTool::Trigger::BeforeSave) {
return QStringLiteral("BeforeSave");
}
if (trigger == KateExternalTool::Trigger::AfterSave) {
return QStringLiteral("AfterSave");
}
return QStringLiteral("None");
}
}
bool KateExternalTool::checkExec() const
......@@ -119,7 +147,7 @@ void KateExternalTool::load(const KConfigGroup &cg)
saveMode = toSaveMode(cg.readEntry("save", "None"));
reload = cg.readEntry("reload", false);
outputMode = toOutputMode(cg.readEntry("output", "Ignore"));
execOnSave = cg.readEntry("execOnSave", false);
trigger = toTrigger(cg.readEntry("trigger", "None"));
hasexec = checkExec();
}
......@@ -149,10 +177,10 @@ void KateExternalTool::save(KConfigGroup &cg) const
writeEntryMaybe(cg, "cmdname", cmdname);
writeEntryMaybe(cg, "save", toString(saveMode));
writeEntryMaybe(cg, "output", toString(outputMode));
writeEntryMaybe(cg, "trigger", toString(trigger));
// a logical value is never empty
cg.writeEntry("reload", reload);
cg.writeEntry("execOnSave", execOnSave);
}
QString KateExternalTool::translatedName() const
......@@ -170,7 +198,7 @@ bool operator==(const KateExternalTool &lhs, const KateExternalTool &rhs)
return lhs.category == rhs.category && lhs.name == rhs.name && lhs.icon == rhs.icon && lhs.executable == rhs.executable && lhs.arguments == rhs.arguments
&& lhs.input == rhs.input && lhs.workingDir == rhs.workingDir && lhs.mimetypes == rhs.mimetypes && lhs.actionName == rhs.actionName
&& lhs.cmdname == rhs.cmdname && lhs.saveMode == rhs.saveMode && lhs.reload == rhs.reload && lhs.outputMode == rhs.outputMode
&& lhs.execOnSave == rhs.execOnSave;
&& lhs.trigger == rhs.trigger;
}
// kate: space-indent on; indent-width 4; replace-tabs on;
......@@ -45,6 +45,15 @@ public:
DisplayInPane
};
enum class Trigger {
//! No trigger
None,
//! Run the tool before saving
BeforeSave,
//! Run the tool after saving
AfterSave,
};
public:
/// The category used in the menu to categorize the tool.
QString category;
......@@ -73,8 +82,8 @@ public:
bool reload = false;
/// Defines where to redirect the tool's output
OutputMode outputMode = OutputMode::Ignore;
/// Whether to execute tool on document save
bool execOnSave = false;
/// Trigger to run tool
Trigger trigger = Trigger::None;
public:
/// This is set when loading the Tool from disk.
......
......@@ -13,6 +13,7 @@
#include <KTextEditor/Document>
#include <KTextEditor/Editor>
#include <KTextEditor/View>
#include <ktexteditor_version.h>
#include <KConfig>
#include <KConfigGroup>
......@@ -24,6 +25,7 @@
#include <KXmlGuiWindow>
#include <QBitmap>
#include <QComboBox>
#include <QListView>
#include <QMenu>
#include <QMessageBox>
#include <QRegularExpression>
......@@ -140,6 +142,13 @@ KateExternalToolServiceEditor::KateExternalToolServiceEditor(KateExternalTool *t
ui.setupUi(this);
ui.btnIcon->setIconSize(KIconLoader::SizeSmall);
#if KTEXTEDITOR_VERSION < QT_VERSION_CHECK(5, 90, 0)
{
auto v = qobject_cast<QListView *>(ui.cmbTrigger->view());
v->setRowHidden(1, true);
}
#endif
connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &KateExternalToolServiceEditor::slotOKClicked);
connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(ui.btnMimeType, &QToolButton::clicked, this, &KateExternalToolServiceEditor::showMTDlg);
......@@ -156,11 +165,11 @@ KateExternalToolServiceEditor::KateExternalToolServiceEditor(KateExternalTool *t
ui.edtWorkingDir->setText(m_tool->workingDir);
ui.edtWorkingDir->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly);
ui.edtMimeType->setText(m_tool->mimetypes.join(QStringLiteral("; ")));
ui.edtMimeType->setReadOnly(true);
ui.cmbSave->setCurrentIndex(static_cast<int>(m_tool->saveMode));
ui.chkReload->setChecked(m_tool->reload);
ui.cmbOutput->setCurrentIndex(static_cast<int>(m_tool->outputMode));
ui.edtCommand->setText(m_tool->cmdname);
ui.cmbTrigger->setCurrentIndex((int)m_tool->trigger);
static const QRegularExpressionValidator cmdLineValidator(QRegularExpression(QStringLiteral("[\\w-]*")));
ui.edtCommand->setValidator(&cmdLineValidator);
......@@ -181,7 +190,7 @@ KateExternalToolServiceEditor::KateExternalToolServiceEditor(KateExternalTool *t
ui.chkReload->setChecked(t.reload);
ui.cmbOutput->setCurrentIndex(static_cast<int>(t.outputMode));
ui.edtCommand->setText(t.cmdname);
ui.chkExecSave->setChecked(t.execOnSave);
ui.cmbTrigger->setCurrentIndex(static_cast<int>(t.trigger));
});
}
......@@ -196,9 +205,9 @@ void KateExternalToolServiceEditor::slotOKClicked()
return;
}
const bool execOnSave = ui.chkExecSave->isChecked();
if (execOnSave && ui.edtMimeType->text().isEmpty()) {
QMessageBox::information(this, i18n("External Tool"), i18n("With 'Execute On Save' enabled, at least one mimetype needs to be specified."));
const bool hasTrigger = ui.cmbTrigger->currentIndex() != (int)KateExternalTool::Trigger::None;
if (hasTrigger && ui.edtMimeType->text().isEmpty()) {
QMessageBox::information(this, i18n("External Tool"), i18n("With 'Trigger' enabled, at least one mimetype needs to be specified."));
return;
}
......@@ -355,7 +364,7 @@ bool KateExternalToolsConfigWidget::editTool(KateExternalTool *tool)
tool->reload = editor.ui.chkReload->isChecked();
tool->outputMode = static_cast<KateExternalTool::OutputMode>(editor.ui.cmbOutput->currentIndex());
tool->cmdname = editor.ui.edtCommand->text().trimmed();
tool->execOnSave = editor.ui.chkExecSave->isChecked();
tool->trigger = static_cast<KateExternalTool::Trigger>(editor.ui.cmbTrigger->currentIndex());
tool->executable = editor.ui.edtExecutable->text().trimmed();
tool->hasexec = tool->checkExec();
......
......@@ -9,7 +9,9 @@
#include "kateexternaltool.h"
#include "ui_toolview.h"
#include <KTextEditor/Application>
#include <KTextEditor/Document>
#include <KTextEditor/Editor>
#include <KTextEditor/MainWindow>
#include <KTextEditor/View>
......@@ -22,6 +24,7 @@
#include <KXMLGUIFactory>
#include <QMenu>
#include <QStandardPaths>
#include <ktexteditor_version.h>
#include <QFontDatabase>
#include <QKeyEvent>
......@@ -270,20 +273,54 @@ void KateExternalToolsPluginView::handleEsc(QEvent *event)
void KateExternalToolsPluginView::slotViewChanged(KTextEditor::View *v)
{
if (m_currentView) {
disconnect(m_currentView->document(), &KTextEditor::Document::documentSavedOrUploaded, this, &KateExternalToolsPluginView::documentSaved);
disconnect(m_currentView->document(), &KTextEditor::Document::documentSavedOrUploaded, this, &KateExternalToolsPluginView::onDocumentSaved);
#if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(5, 90, 0)
disconnect(m_currentView->document(), &KTextEditor::Document::aboutToSave, this, &KateExternalToolsPluginView::onDocumentAboutToSave);
#endif
}
m_currentView = v;
connect(v->document(), &KTextEditor::Document::documentSavedOrUploaded, this, &KateExternalToolsPluginView::documentSaved, Qt::UniqueConnection);
connect(v->document(), &KTextEditor::Document::documentSavedOrUploaded, this, &KateExternalToolsPluginView::onDocumentSaved, Qt::UniqueConnection);
#if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(5, 90, 0)
connect(v->document(), &KTextEditor::Document::aboutToSave, this, &KateExternalToolsPluginView::onDocumentAboutToSave, Qt::UniqueConnection);
#endif
}
void KateExternalToolsPluginView::documentSaved(KTextEditor::Document *doc)
void KateExternalToolsPluginView::onDocumentSaved(KTextEditor::Document *doc)
{
// We only want to run this in the current active mainwindow
if (KTextEditor::Editor::instance()->application()->activeMainWindow() != m_mainWindow) {
return;
}
const auto tools = m_plugin->tools();
for (KateExternalTool *tool : tools) {
const bool hasSaveTrigger = tool->trigger == KateExternalTool::Trigger::AfterSave;
if (hasSaveTrigger && tool->matchesMimetype(doc->mimeType())) {
m_plugin->runTool(*tool, m_currentView, /*exec save trigger=*/true);
}
}
}
void KateExternalToolsPluginView::onDocumentAboutToSave(KTextEditor::Document *doc)
{
// We only want to run this in the current active mainwindow
if (KTextEditor::Editor::instance()->application()->activeMainWindow() != m_mainWindow) {
return;
}
#if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(5, 90, 0)
const auto tools = m_plugin->tools();
for (KateExternalTool *tool : tools) {
if (tool->execOnSave && tool->matchesMimetype(doc->mimeType())) {
m_plugin->runTool(*tool, m_currentView, tool->execOnSave);
const bool hasSaveTrigger = tool->trigger == KateExternalTool::Trigger::BeforeSave;
if (hasSaveTrigger && tool->matchesMimetype(doc->mimeType())) {
m_plugin->blockingRunTool(*tool, m_currentView, /*exec save trigger=*/true);
}
}
#else
Q_UNUSED(doc)
#endif
}
// END KateExternalToolsPluginView
......
......@@ -140,7 +140,8 @@ public Q_SLOTS:
private Q_SLOTS:
void slotViewChanged(KTextEditor::View *v);
void documentSaved(KTextEditor::Document *doc);
void onDocumentSaved(KTextEditor::Document *doc);
void onDocumentAboutToSave(KTextEditor::Document *doc);
Q_SIGNALS:
/**
......
......@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>470</width>
<height>534</height>
<height>559</height>
</rect>
</property>
<property name="windowTitle">
......@@ -51,6 +51,13 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="KUrlRequester" name="edtExecutable">
<property name="placeholderText">
<string>Application or interpreter</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblArgs">
<property name="text">
......@@ -95,6 +102,13 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="KUrlRequester" name="edtWorkingDir">
<property name="placeholderText">
<string>Uses current document path if empty</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblMimeType">
<property name="text">
......@@ -162,7 +176,33 @@
</item>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Trigger</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="cmbTrigger">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Before Save</string>
</property>
</item>
<item>
<property name="text">
<string>After Save</string>
</property>
</item>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="chkReload">
<property name="text">
<string>Reload current document after execution</string>
......@@ -250,27 +290,6 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="KUrlRequester" name="edtExecutable">
<property name="placeholderText">
<string>Application or interpreter</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="KUrlRequester" name="edtWorkingDir">
<property name="placeholderText">
<string>Uses current document path if empty</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="chkExecSave">
<property name="text">
<string>Execute on save</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment