Skip to content

Commit

Permalink
reworking code that takes data from sub-processes so that it avoids u…
Browse files Browse the repository at this point in the history
…sing a QString as much as possible. (#355)

this is necessary because, at least in Qt5, there is a hard upper limit to the length of a QString
addesses issue #354
  • Loading branch information
eteran authored Jun 25, 2024
1 parent 992a70e commit c51fcc0
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 17 deletions.
28 changes: 13 additions & 15 deletions src/DocumentWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4725,7 +4725,7 @@ void DocumentWidget::processFinished(int exitCode, QProcess::ExitStatus exitStat
});

QString errText;
QString outText;
std::string outText;

// If the process was killed or became inaccessible, give up
if (exitStatus != QProcess::NormalExit) {
Expand All @@ -4745,14 +4745,15 @@ void DocumentWidget::processFinished(int exitCode, QProcess::ExitStatus exitStat

QByteArray dataOut = shellCmdData_->process->readAllStandardOutput();
shellCmdData_->standardOutput.append(dataOut);
outText = QString::fromLocal8Bit(shellCmdData_->standardOutput);
outText = std::string(shellCmdData_->standardOutput.data(), shellCmdData_->standardOutput.size());
} else {

QByteArray dataAll = shellCmdData_->process->readAll();
shellCmdData_->standardOutput.append(dataAll);
outText = QString::fromLocal8Bit(shellCmdData_->standardOutput);
outText = std::string(shellCmdData_->standardOutput.data(), shellCmdData_->standardOutput.size());
}

static constexpr int MaxMessageLength = 4096;
static const QRegularExpression trailingNewlines(QLatin1String("\\n+$"));

/* Present error and stderr-information dialogs. If a command returned
Expand All @@ -4764,8 +4765,6 @@ void DocumentWidget::processFinished(int exitCode, QProcess::ExitStatus exitStat
bool failure = exitCode != 0;
bool errorReport = !errText.isEmpty();

static constexpr int MaxMessageLength = 4096;

if (failure && errorReport) {
errText.remove(trailingNewlines);
errText.truncate(MaxMessageLength);
Expand All @@ -4781,11 +4780,11 @@ void DocumentWidget::processFinished(int exitCode, QProcess::ExitStatus exitStat
cancel = (msgBox.exec() == QMessageBox::Cancel);

} else if (failure) {
outText.truncate(MaxMessageLength);
QString dialogOutText = QString::fromLocal8Bit(outText.data(), std::min<size_t>(MaxMessageLength, outText.size()));

QMessageBox msgBox;
msgBox.setWindowTitle(tr("Command Failure"));
msgBox.setText(tr("Command reported failed exit status.\nOutput from command:\n%1").arg(outText));
msgBox.setText(tr("Command reported failed exit status.\nOutput from command:\n%1").arg(dialogOutText));
msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Cancel);
auto accept = new QPushButton(tr("Proceed"));
Expand Down Expand Up @@ -4819,33 +4818,32 @@ void DocumentWidget::processFinished(int exitCode, QProcess::ExitStatus exitStat
(remaining) output in the text widget as requested, and move the
insert point to the end */
if (shellCmdData_->flags & OUTPUT_TO_DIALOG) {
outText.remove(trailingNewlines);
QString dialogOutText = QString::fromLocal8Bit(outText.data(), std::min<size_t>(MaxMessageLength, outText.size()));
dialogOutText.remove(trailingNewlines);

if (!outText.isEmpty()) {
if (!dialogOutText.isEmpty()) {
auto dialog = new DialogOutput(this);
dialog->setText(outText);
dialog->setText(dialogOutText);
dialog->show();
}
} else if (shellCmdData_->flags & OUTPUT_TO_STRING) {
returnShellCommandOutput(this, outText, exitCode);
} else {

std::string output_string = outText.toStdString();

auto area = shellCmdData_->area;
TextBuffer *buf = area->buffer();

if (shellCmdData_->flags & REPLACE_SELECTION) {
TextCursor reselectStart = buf->primary.isRectangular() ? TextCursor(-1) : buf->primary.start();
buf->BufReplaceSelected(output_string);
buf->BufReplaceSelected(outText);

area->TextSetCursorPos(buf->BufCursorPosHint());

if (reselectStart != -1) {
buf->BufSelect(reselectStart, reselectStart + static_cast<int64_t>(output_string.size()));
buf->BufSelect(reselectStart, reselectStart + static_cast<int64_t>(outText.size()));
}
} else {
safeBufReplace(buf, &shellCmdData_->leftPos, &shellCmdData_->rightPos, output_string);
safeBufReplace(buf, &shellCmdData_->leftPos, &shellCmdData_->rightPos, outText);
area->TextSetCursorPos(shellCmdData_->leftPos + outText.size());
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/macro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5212,7 +5212,7 @@ void RegisterMacroSubroutines() {
** teaching other modules about macro return globals, since other than this,
** they're not used outside of macro.c)
*/
void returnShellCommandOutput(DocumentWidget *document, const QString &outText, int status) {
void returnShellCommandOutput(DocumentWidget *document, view::string_view outText, int status) {

if (const std::shared_ptr<MacroCommandData> cmdData = document->macroCmdData_) {

Expand Down
3 changes: 2 additions & 1 deletion src/macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <QTimer>
#include <memory>
#include "Util/string_view.h"

class DocumentWidget;
class MainWindow;
Expand All @@ -22,7 +23,7 @@ bool CheckMacroString(QWidget *dialogParent, const QString &string, const QStrin
bool readCheckMacroString(QWidget *dialogParent, const QString &string, DocumentWidget *runDocument, const QString &errIn, int *errPos);

void RegisterMacroSubroutines();
void returnShellCommandOutput(DocumentWidget *document, const QString &outText, int status);
void returnShellCommandOutput(DocumentWidget *document, view::string_view outText, int status);

/* Data attached to window during shell command execution with
information for controlling and communicating with the process */
Expand Down

0 comments on commit c51fcc0

Please sign in to comment.