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;