- fix: Shouldn't auto indent lines starts with "\\".

- enhancement: When problem case's expected output is not too large (<= 5000 line), highlight text in the first different line in the expected output.
  - enhancement: Highlight text in the first different line using the error color.
  - enhancement: Add the option "redirect stderr to the Tools output panel" in the options dialog -> executor -> problem set page.
This commit is contained in:
Roy Qu 2023-07-12 12:08:26 +08:00
parent 45c191bae4
commit d629a496ff
20 changed files with 359 additions and 202 deletions

View File

@ -38,6 +38,10 @@ Red Panda C++ Version 2.23
- enhancement: Auto insert spaces between #include and "" when reformat
- fix: Click editor's gutter won't toggle breakpoint in KDE debian 12
- fix: "Toggle breakpoint " in the editor gutter's context menu doesn't work.
- fix: Shouldn't auto indent lines starts with "\\".
- enhancement: When problem case's expected output is not too large (<= 5000 line), highlight text in the first different line in the expected output.
- enhancement: Highlight text in the first different line using the error color.
- enhancement: Add the option "redirect stderr to the Tools output panel" in the options dialog -> executor -> problem set page.
Red Panda C++ Version 2.22

View File

@ -357,6 +357,9 @@ void CompilerManager::doRunProblem(const QString &filename, const QString &argum
connect(execRunner, &OJProblemCasesRunner::caseFinished, pMainWindow, &MainWindow::onOJProblemCaseFinished);
connect(execRunner, &OJProblemCasesRunner::newOutputGetted, pMainWindow, &MainWindow::onOJProblemCaseNewOutputGetted);
connect(execRunner, &OJProblemCasesRunner::resetOutput, pMainWindow, &MainWindow::onOJProblemCaseResetOutput);
if (pSettings->executor().redirectStderrToToolLog()) {
connect(execRunner, &OJProblemCasesRunner::logStderrOutput, pMainWindow, &MainWindow::logToolsOutput);
}
mRunner->start();
}

View File

@ -83,7 +83,12 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
}
env.insert("PATH",path);
process.setProcessEnvironment(env);
if (pSettings->executor().redirectStderrToToolLog()) {
emit logStderrOutput("\n");
} else {
process.setProcessChannelMode(QProcess::MergedChannels);
process.setReadChannel(QProcess::StandardOutput);
}
process.connect(
&process, &QProcess::errorOccurred,
[&](){
@ -129,6 +134,11 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
}
if (errorOccurred)
break;
if (pSettings->executor().redirectStderrToToolLog()) {
QString s = QString::fromLocal8Bit(process.readAllStandardError());
if (!s.isEmpty())
emit logStderrOutput(s);
}
readed = process.read(mBufferSize);
buffer += readed;
if (buffer.length()>=mBufferSize || noOutputTime > mOutputRefreshTime) {
@ -171,6 +181,11 @@ void OJProblemCasesRunner::runCase(int index,POJProblemCase problemCase)
problemCase->output = tr("Memory limit exceeded!");
emit resetOutput(problemCase->getId(), problemCase->output);
} else {
if (pSettings->executor().redirectStderrToToolLog()) {
QString s = QString::fromLocal8Bit(process.readAllStandardError());
if (!s.isEmpty())
emit logStderrOutput(s);
}
if (process.state() == QProcess::ProcessState::NotRunning)
buffer += process.readAll();
emit newOutputGetted(problemCase->getId(),QString::fromLocal8Bit(buffer));

View File

@ -54,6 +54,7 @@ signals:
void caseFinished(const QString &caseId, int current, int total);
void newOutputGetted(const QString &caseId, const QString &newOutputLine);
void resetOutput(const QString &caseId, const QString &newOutputLine);
void logStderrOutput(const QString& msg);
private:
void runCase(int index, POJProblemCase problemCase);
private:

View File

@ -4044,9 +4044,9 @@ void MainWindow::onProblemSetIndexChanged(const QModelIndex &current, const QMod
if (!idx.isValid()) {
mProblemSet_RemoveProblem->setEnabled(false);
mOJProblemModel.setProblem(nullptr);
ui->txtProblemCaseExpected->clear();
ui->txtProblemCaseInput->clear();
ui->txtProblemCaseOutput->clear();
ui->txtProblemCaseExpected->clearAll();
ui->txtProblemCaseInput->clearAll();
ui->txtProblemCaseOutput->clearAll();
ui->tabProblem->setEnabled(false);
ui->lblProblem->clear();
ui->lblProblem->setToolTip("");
@ -4087,7 +4087,7 @@ void MainWindow::onProblemCaseIndexChanged(const QModelIndex &current, const QMo
mProblem_RemoveCases->setEnabled(true);
mProblem_RunAllCases->setEnabled(ui->actionRun->isEnabled());
fillProblemCaseInputAndExpected(problemCase);
ui->txtProblemCaseOutput->clear();
ui->txtProblemCaseOutput->clearAll();
ui->txtProblemCaseOutput->setPlainText(problemCase->output);
updateProblemCaseOutput(problemCase);
return;
@ -4107,11 +4107,11 @@ void MainWindow::onProblemCaseIndexChanged(const QModelIndex &current, const QMo
mProblem_RunAllCases->setEnabled(false);
ui->txtProblemCaseInputFileName->clear();
ui->btnProblemCaseInputFileName->setEnabled(false);
ui->txtProblemCaseInput->clear();
ui->txtProblemCaseInput->clearAll();
ui->txtProblemCaseInput->setReadOnly(true);
ui->txtProblemCaseExpected->clear();
ui->txtProblemCaseExpected->clearAll();
ui->txtProblemCaseExpected->setReadOnly(true);
ui->txtProblemCaseOutput->clear();
ui->txtProblemCaseOutput->clearAll();
ui->lblProblemCaseExpected->clear();
ui->lblProblemCaseOutput->clear();
@ -5961,7 +5961,10 @@ void MainWindow::onOJProblemCaseStarted(const QString& id,int current, int total
if (!idx.isValid() || row != idx.row()) {
ui->tblProblemCases->setCurrentIndex(mOJProblemModel.index(row,0));
}
ui->txtProblemCaseOutput->clear();
ui->txtProblemCaseOutput->clearAll();
if (ui->txtProblemCaseExpected->document()->blockCount()<=5000) {
ui->txtProblemCaseExpected->clearFormat();
}
}
}
@ -5989,6 +5992,7 @@ void MainWindow::onOJProblemCaseNewOutputGetted(const QString &/* id */, const Q
void MainWindow::onOJProblemCaseResetOutput(const QString &/* id */, const QString &line)
{
ui->txtProblemCaseOutput->clearAll();
ui->txtProblemCaseOutput->setPlainText(line);
}
@ -7439,12 +7443,14 @@ void MainWindow::fillProblemCaseInputAndExpected(const POJProblemCase &problemCa
ui->btnProblemCaseExpectedOutputFileName->setEnabled(true);
if (fileExists(problemCase->expectedOutputFileName)) {
ui->txtProblemCaseExpected->setReadOnly(true);
ui->txtProblemCaseExpected->clearAll();
ui->txtProblemCaseExpected->setPlainText(readFileToByteArray(problemCase->expectedOutputFileName));
ui->btnProblemCaseClearExpectedOutputFileName->setVisible(true);
ui->txtProblemCaseExpectedOutputFileName->setText(extractFileName(problemCase->expectedOutputFileName));
ui->txtProblemCaseExpectedOutputFileName->setToolTip(problemCase->inputFileName);
} else {
ui->txtProblemCaseExpected->setReadOnly(false);
ui->txtProblemCaseExpected->clearAll();
ui->txtProblemCaseExpected->setPlainText(problemCase->expected);
ui->btnProblemCaseClearExpectedOutputFileName->setVisible(false);
ui->txtProblemCaseExpectedOutputFileName->clear();
@ -8003,14 +8009,11 @@ void MainWindow::doGenerateAssembly()
void MainWindow::updateProblemCaseOutput(POJProblemCase problemCase)
{
if (problemCase->testState == ProblemCaseTestState::Failed) {
int diffLine;
if (problemCase->outputLineCounts > problemCase->expectedLineCounts) {
diffLine = problemCase->expectedLineCounts;
} else if (problemCase->outputLineCounts < problemCase->expectedLineCounts) {
diffLine = problemCase->outputLineCounts;
} else {
int diffLine=-1;
if (problemCase->firstDiffLine!=-1) {
diffLine = problemCase->firstDiffLine;
}
} else
return;
if (diffLine < problemCase->outputLineCounts) {
QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(diffLine);
if (!block.isValid())
@ -8020,17 +8023,48 @@ void MainWindow::updateProblemCaseOutput(POJProblemCase problemCase)
return;
cur = QTextCursor(block);
QTextCharFormat oldFormat = cur.charFormat();
QTextCharFormat format = cur.charFormat();
QTextCharFormat format = QTextCharFormat(cur.charFormat());
cur.select(QTextCursor::LineUnderCursor);
format.setUnderlineColor(mErrorColor);
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
format.setTextOutline(mErrorColor);
cur.setCharFormat(format);
cur.clearSelection();
cur.setCharFormat(oldFormat);
ui->txtProblemCaseOutput->setTextCursor(cur);
} else if (diffLine < problemCase->expectedLineCounts) {
ui->txtProblemCaseOutput->moveCursor(QTextCursor::MoveOperation::StartOfLine);
} else {
ui->txtProblemCaseOutput->moveCursor(QTextCursor::MoveOperation::End);
ui->txtProblemCaseOutput->moveCursor(QTextCursor::MoveOperation::StartOfLine);
}
if (diffLine < problemCase->expectedLineCounts) {
QTextBlock block = ui->txtProblemCaseExpected->document()->findBlockByLineNumber(diffLine);
if (!block.isValid())
return;
QTextCursor cur(block);
if (cur.isNull())
return;
cur = QTextCursor(block);
if (ui->txtProblemCaseExpected->document()->blockCount()<=5000) {
QTextCharFormat oldFormat = cur.charFormat();
QTextCharFormat format = QTextCharFormat(cur.charFormat());
cur.select(QTextCursor::LineUnderCursor);
format.setUnderlineColor(mErrorColor);
format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
format.setTextOutline(mErrorColor);
cur.setCharFormat(format);
cur.clearSelection();
cur.setCharFormat(oldFormat);
}
ui->txtProblemCaseExpected->setTextCursor(cur);
ui->txtProblemCaseExpected->moveCursor(QTextCursor::MoveOperation::StartOfLine);
} else {
ui->txtProblemCaseExpected->moveCursor(QTextCursor::MoveOperation::End);
ui->txtProblemCaseExpected->moveCursor(QTextCursor::MoveOperation::StartOfLine);
}
} else {
ui->txtProblemCaseOutput->moveCursor(QTextCursor::MoveOperation::Start);
ui->txtProblemCaseExpected->moveCursor(QTextCursor::MoveOperation::Start);
}
}

View File

@ -34,9 +34,17 @@ bool ProblemCaseValidator::validate(POJProblemCase problemCase, bool ignoreSpace
expected = textToLines(problemCase->expected);
problemCase->outputLineCounts = output.count();
problemCase->expectedLineCounts = expected.count();
if (output.count()!=expected.count())
if (problemCase->expectedLineCounts>5000) {
if (output.count()<expected.count()) {
problemCase->firstDiffLine=output.count();
return false;
for (int i=0;i<output.count();i++) {
} else if (output.count()>expected.count()) {
problemCase->firstDiffLine=expected.count();
return false;
}
}
int count=std::min(output.count(), expected.count());
for (int i=0;i<count;i++) {
if (ignoreSpaces) {
if (!equalIgnoringSpaces(output[i],expected[i])) {
problemCase->firstDiffLine = i;
@ -49,6 +57,13 @@ bool ProblemCaseValidator::validate(POJProblemCase problemCase, bool ignoreSpace
}
}
}
if (output.count()<expected.count()) {
problemCase->firstDiffLine=output.count();
return false;
} else if (output.count()>expected.count()) {
problemCase->firstDiffLine=expected.count();
return false;
}
return true;
}

View File

@ -3719,6 +3719,16 @@ void Settings::Executor::setConvertHTMLToTextForExpected(bool newConvertHTMLToTe
mConvertHTMLToTextForExpected = newConvertHTMLToTextForExpected;
}
bool Settings::Executor::redirectStderrToToolLog() const
{
return mRedirectStderrToToolLog;
}
void Settings::Executor::setRedirectStderrToToolLog(bool newRedirectStderrToToolLog)
{
mRedirectStderrToToolLog = newRedirectStderrToToolLog;
}
bool Settings::Executor::convertHTMLToTextForInput() const
{
return mConvertHTMLToTextForInput;
@ -3794,6 +3804,7 @@ void Settings::Executor::doSave()
saveValue("input_convert_html", mConvertHTMLToTextForInput);
saveValue("expected_convert_html", mConvertHTMLToTextForExpected);
saveValue("ignore_spaces_when_validating_cases", mIgnoreSpacesWhenValidatingCases);
saveValue("redirect_stderr_to_toollog", mRedirectStderrToToolLog);
saveValue("case_editor_font_name",mCaseEditorFontName);
saveValue("case_editor_font_size",mCaseEditorFontSize);
saveValue("case_editor_font_only_monospaced",mCaseEditorFontOnlyMonospaced);
@ -3828,6 +3839,8 @@ void Settings::Executor::doLoad()
mConvertHTMLToTextForInput = boolValue("input_convert_html", false);
mConvertHTMLToTextForExpected = boolValue("expected_convert_html", false);
mIgnoreSpacesWhenValidatingCases = boolValue("ignore_spaces_when_validating_cases",false);
mRedirectStderrToToolLog = boolValue("redirect_stderr_to_toollog", false);
#ifdef Q_OS_WIN
mCaseEditorFontName = stringValue("case_editor_font_name","consolas");
#elif defined(Q_OS_MACOS)

View File

@ -931,6 +931,9 @@ public:
bool convertHTMLToTextForExpected() const;
void setConvertHTMLToTextForExpected(bool newConvertHTMLToTextForExpected);
bool redirectStderrToToolLog() const;
void setRedirectStderrToToolLog(bool newRedirectStderrToToolLog);
private:
// general
bool mPauseConsole;
@ -947,6 +950,7 @@ public:
bool mConvertHTMLToTextForInput;
bool mConvertHTMLToTextForExpected;
bool mIgnoreSpacesWhenValidatingCases;
bool mRedirectStderrToToolLog;
QString mCaseEditorFontName;
int mCaseEditorFontSize;
bool mCaseEditorFontOnlyMonospaced;

View File

@ -40,6 +40,7 @@ void ExecutorProblemSetWidget::doLoad()
ui->chkConvertExpectedHTML->setChecked(pSettings->executor().convertHTMLToTextForExpected());
ui->chkIgnoreSpacesWhenValidatingCases->setChecked(pSettings->executor().ignoreSpacesWhenValidatingCases());
ui->chkRedirectStderr->setChecked(pSettings->executor().redirectStderrToToolLog());
ui->cbFont->setCurrentFont(QFont(pSettings->executor().caseEditorFontName()));
ui->spinFontSize->setValue(pSettings->executor().caseEditorFontSize());
@ -58,6 +59,7 @@ void ExecutorProblemSetWidget::doSave()
pSettings->executor().setConvertHTMLToTextForInput(ui->chkConvertInputHTML->isChecked());
pSettings->executor().setConvertHTMLToTextForExpected(ui->chkConvertExpectedHTML->isChecked());
pSettings->executor().setIgnoreSpacesWhenValidatingCases(ui->chkIgnoreSpacesWhenValidatingCases->isChecked());
pSettings->executor().setRedirectStderrToToolLog(ui->chkRedirectStderr->isChecked());
pSettings->executor().setCaseEditorFontName(ui->cbFont->currentFont().family());
pSettings->executor().setCaseEditorFontOnlyMonospaced(ui->chkOnlyMonospaced->isChecked());
pSettings->executor().setCaseEditorFontSize(ui->spinFontSize->value());

View File

@ -117,6 +117,13 @@
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkRedirectStderr">
<property name="text">
<string>Redirect STDERR to Tools output panel</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkIgnoreSpacesWhenValidatingCases">
<property name="text">

View File

@ -2105,6 +2105,10 @@
<source>Expected Output</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Redirect STDERR to Tools output panel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FileAssociationModel</name>

File diff suppressed because it is too large Load Diff

View File

@ -1930,6 +1930,10 @@
<source>Expected Output</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Redirect STDERR to Tools output panel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FileAssociationModel</name>

View File

@ -61,6 +61,13 @@ void LineNumberTextEditor::updateLineNumberArea(const QRect &rect, int dy)
updateLineNumberAreaWidth(0);
}
void LineNumberTextEditor::clearStartFormat()
{
moveCursor(QTextCursor::Start);
QTextCursor cursor = textCursor();
cursor.setCharFormat(QTextCharFormat());
}
const QColor &LineNumberTextEditor::lineNumberAreaCurrentLine() const
{
return mLineNumberAreaCurrentLine;
@ -74,6 +81,20 @@ void LineNumberTextEditor::setLineNumberAreaCurrentLine(const QColor &newLineNum
emit lineNumberAreaCurrentLineChanged();
}
void LineNumberTextEditor::clearFormat()
{
QTextCursor cursor = textCursor();
cursor.select(QTextCursor::Document);
cursor.setCharFormat(QTextCharFormat());
cursor.clearSelection();
}
void LineNumberTextEditor::clearAll()
{
clear();
clearStartFormat();
}
const QColor &LineNumberTextEditor::lineNumberAreaBackground() const
{
return mLineNumberAreaBackground;

View File

@ -37,6 +37,10 @@ public:
const QColor &lineNumberAreaCurrentLine() const;
void setLineNumberAreaCurrentLine(const QColor &newLineNumberAreaCurrentLine);
void clearFormat();
void clearAll();
signals:
void lineNumberAreaCurrentLineChanged();
@ -47,6 +51,8 @@ private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void highlightCurrentLine();
void updateLineNumberArea(const QRect &rect, int dy);
private:
void clearStartFormat();
private:
QWidget *lineNumberArea;

View File

@ -1538,6 +1538,8 @@ int QSynEdit::calcIndentSpaces(int line, const QString& lineText, bool addIndent
line = std::min(line, mDocument->count()+1);
if (line<=1)
return 0;
if (lineText.startsWith("//"))
return 0;
if (mFormatter) {
return mFormatter->calcIndentSpaces(line,lineText,addIndent,this);
}

View File

@ -4294,17 +4294,22 @@
</message>
<message>
<location filename="qsynedit/document.cpp" line="630"/>
<location filename="qsynedit/document.cpp" line="751"/>
<location filename="qsynedit/document.cpp" line="753"/>
<source>Can&apos;t load codec &apos;%1&apos;!</source>
<translation>&quot;%1&quot;!</translation>
</message>
<message>
<location filename="qsynedit/document.cpp" line="754"/>
<location filename="qsynedit/document.cpp" line="649"/>
<source>This is a binaray File!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qsynedit/document.cpp" line="756"/>
<source>Can&apos;t open file &apos;%1&apos; for save!</source>
<translation>&quot;%1&quot;!</translation>
</message>
<message>
<location filename="qsynedit/document.cpp" line="777"/>
<location filename="qsynedit/document.cpp" line="779"/>
<source>Data not correctly writed to file &apos;%1&apos;.</source>
<translation>&quot;%1&quot;</translation>
</message>

View File

@ -32,6 +32,7 @@
#include <QWindow>
#include <QScreen>
#include <QDirIterator>
#include <QTextEdit>
#ifdef Q_OS_WIN
#include <QDirIterator>
#include <QFont>
@ -734,3 +735,11 @@ bool isBinaryContent(const QByteArray &text)
}
return false;
}
void clearQPlainTextEditFormat(QTextEdit *editor)
{
QTextCursor cursor = editor->textCursor();
cursor.select(QTextCursor::Document);
cursor.setCharFormat(QTextCharFormat());
cursor.clearSelection();
}

View File

@ -86,6 +86,9 @@ QList<QByteArray> splitByteArrayToLines(const QByteArray& content);
QString trimRight(const QString& s);
QString trimLeft(const QString& s);
class QTextEdit;
void clearQPlainTextEditFormat(QTextEdit* editor);
int countLeadingWhitespaceChars(const QString& line);
bool stringIsBlank(const QString& s);

View File

@ -125,7 +125,7 @@
<context>
<name>QObject</name>
<message>
<location filename="qt_utils/utils.cpp" line="56"/>
<location filename="qt_utils/utils.cpp" line="57"/>
<source>Index %1 out of range</source>
<translation>%1</translation>
</message>