File indexing completed on 2024-05-05 05:51:23

0001 /* This file is part of the KDE project
0002  *
0003  *  SPDX-FileCopyrightText: 2019 Dominik Haumann <dhaumann@kde.org>
0004  *
0005  *  SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "katetoolrunner.h"
0009 
0010 #include "hostprocess.h"
0011 #include "kateexternaltool.h"
0012 
0013 #include <KLocalizedString>
0014 #include <KShell>
0015 #include <KTextEditor/Document>
0016 #include <KTextEditor/View>
0017 #include <QFileInfo>
0018 #include <QRegularExpression>
0019 #include <QStandardPaths>
0020 
0021 KateToolRunner::KateToolRunner(std::unique_ptr<KateExternalTool> tool, KTextEditor::View *view, QObject *parent)
0022     : QObject(parent)
0023     , m_view(view)
0024     , m_tool(std::move(tool))
0025     , m_process(new QProcess())
0026 {
0027     m_process->setProcessChannelMode(QProcess::SeparateChannels);
0028 }
0029 
0030 KateToolRunner::~KateToolRunner()
0031 {
0032 }
0033 
0034 KTextEditor::View *KateToolRunner::view() const
0035 {
0036     return m_view;
0037 }
0038 
0039 KateExternalTool *KateToolRunner::tool() const
0040 {
0041     return m_tool.get();
0042 }
0043 
0044 void KateToolRunner::run()
0045 {
0046     // always only execute the tool from PATH
0047     const auto fullExecutable = safeExecutableName(m_tool->executable);
0048     if (fullExecutable.isEmpty()) {
0049         return;
0050     }
0051 
0052     if (!m_tool->workingDir.isEmpty()) {
0053         m_process->setWorkingDirectory(m_tool->workingDir);
0054     } else if (m_view) {
0055         // if nothing is set, use the current document's directory
0056         const auto url = m_view->document()->url();
0057         if (url.isLocalFile()) {
0058             const QString localFilePath = url.toLocalFile();
0059             m_process->setWorkingDirectory(QFileInfo(localFilePath).absolutePath());
0060         }
0061     }
0062 
0063     QObject::connect(m_process.get(), &QProcess::readyReadStandardOutput, [this]() {
0064         m_stdout += m_process->readAllStandardOutput();
0065     });
0066     QObject::connect(m_process.get(), &QProcess::readyReadStandardError, [this]() {
0067         m_stderr += m_process->readAllStandardError();
0068     });
0069     QObject::connect(m_process.get(),
0070                      static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
0071                      [this](int exitCode, QProcess::ExitStatus exitStatus) {
0072                          Q_EMIT toolFinished(this, exitCode, exitStatus == QProcess::CrashExit);
0073                      });
0074 
0075     // Write stdin to process, if applicable, then close write channel
0076     QObject::connect(m_process.get(), &QProcess::started, [this]() {
0077         if (!m_tool->input.isEmpty()) {
0078             m_process->write(m_tool->input.toLocal8Bit());
0079         }
0080         m_process->closeWriteChannel();
0081     });
0082 
0083     const QStringList args = KShell::splitArgs(m_tool->arguments);
0084     startHostProcess(*m_process, fullExecutable, args);
0085 }
0086 
0087 void KateToolRunner::waitForFinished()
0088 {
0089     m_process->waitForFinished();
0090 }
0091 
0092 /**
0093  * Convert input from local encoding to text with only \n line endings
0094  * @param localOutput local output from tool to convert
0095  * @return string with proper \n line endings
0096  */
0097 static QString textFromLocal(const QByteArray &localOutput)
0098 {
0099     // normalize line endings, to e.g. catch issues with \r\n
0100     // see bug 436753
0101     QString s = QString::fromLocal8Bit(localOutput);
0102     static const QRegularExpression lineEndings(QStringLiteral("\r\n?"));
0103     s.replace(lineEndings, QStringLiteral("\n"));
0104     return s;
0105 }
0106 
0107 QString KateToolRunner::outputData() const
0108 {
0109     return textFromLocal(m_stdout);
0110 }
0111 
0112 QString KateToolRunner::errorData() const
0113 {
0114     return textFromLocal(m_stderr);
0115 }
0116 
0117 #include "moc_katetoolrunner.cpp"
0118 
0119 // kate: space-indent on; indent-width 4; replace-tabs on;