Commit ca4ece68 authored by Leander Schulten's avatar Leander Schulten
Browse files

ModuleEditor: Show warnings and errors direct in the code so that the user can...

ModuleEditor: Show warnings and errors direct in the code so that the user can understand them better.
Compiler: Add -Wall and -Wextra to the default flags to produce more warnings
parent b63bb590
Pipeline #173170 passed with stage
in 1 minute and 53 seconds
......@@ -740,6 +740,37 @@ int CodeEditorHelper::countTabs(int startPos){
void CodeEditorHelper::contentsChange(int from, int charsRemoved, int charsAdded){
qDebug() << "pos " << from << " removed : " << charsRemoved << " added : " << charsAdded;
// remove all markups thats gets modified and move the others
const int lineDiff = document->lineCount() - lastLineCount;
for(auto i = codeMarkups.cbegin(); i != codeMarkups.cend();++i){
const auto & m = *i;
const auto block = document->findBlockByLineNumber(m->row);
const auto pos = block.position() + m->column;
if(pos >= from && pos <= from + std::max(charsAdded, charsRemoved)){
i = codeMarkups.erase(i);
--i;
continue;
}
const auto line = document->findBlock(from).firstLineNumber();
if(line == m->row){
if(from < pos){
// chars added/removed in same line before markup
m->column += charsAdded-charsRemoved - lineDiff;
emit m->columnChanged();
}
}
if(from < pos){
// check if lines gets added before position
if(lineDiff){
m->row += lineDiff;
emit m->rowChanged();
}
}
}
lastLineCount = document->lineCount();
if(charsAdded == 1 && document->characterAt(from) == QChar::ParagraphSeparator){
qDebug() << "Enter pressed : " << document->characterAt(from-1);
/*if(document->characterAt(from-1) == '{'){
......@@ -967,6 +998,7 @@ void CodeEditorHelper::compile(){
file.remove();
if ( file.open(QIODevice::ReadWrite) )
{
int lineCounter = 0;
QString typeName = toName(module->getType());
QString inputType = toName(module->getInputType());
QString outputType = toName(module->getOutputType());
......@@ -997,26 +1029,33 @@ void CodeEditorHelper::compile(){
stream << "using namespace Modules;" << endl;
stream << "using namespace std;" << endl;
stream << "" << endl;
lineCounter += 15;
stream << externCode << endl;
lineCounter += externCode.count("\n") + 1;
stream << "" << endl;
if(module->getType() == Modules::Module::Filter){
stream << "class Impl : public Typed" << typeName << "<"<<inputType<<","<<outputType<<">{"<< endl;
}else{
stream << "class Impl : public Typed" << typeName << "<"<<outputType<<">{"<< endl;
}
lineCounter += 2;
for(const auto &p : module->getProperties()){
writeDeclaration(stream,p);
++lineCounter;
}
stream << "public:" << endl;
stream << "Impl()" << getPropertiesNumericContructors(module->getProperties()) <<"{" << endl;
lineCounter += 2;
for(const auto &p : module->getProperties()){
writeConstructor(stream,p);
lineCounter += 3;
}
stream << "}" << endl;
stream << "const char* getName()const final override{" << endl;
stream << "return \"" << module->getName()<< "\";" << endl;
stream << "}" << endl;
stream << "" << endl;
lineCounter += 5;
stream << userCode << endl; // write Code from document
stream << "" << endl;
stream << "};" << endl; // class end
......@@ -1072,8 +1111,9 @@ void CodeEditorHelper::compile(){
auto result = Modules::Compiler::compileAndLoadModule(file,module->getName(),module->getCompiledName(),[&](auto){return module->getCompiledName().toStdString();});
QFileInfo finfo = file;
extractErrors(result.second, finfo.absoluteFilePath(), lineCounter);
if(result.first){
QFileInfo finfo = file;
emit information(result.second.replace(finfo.absoluteFilePath(),""));
}else{
emit information("Compilieren erfolgreich.");
......@@ -1083,3 +1123,41 @@ void CodeEditorHelper::compile(){
emit information("Cant open file : " + s.getModuleDirPath() + "/" + module->getName() + ".cpp");
}
}
void CodeEditorHelper::extractErrors(const QString &compilerOutput, const QString &absoluteFilePath, int startLineNumer){
codeMarkups.clear();
for(const auto & line : compilerOutput.splitRef('\n')){
if(line.startsWith(absoluteFilePath)){
auto error = line.mid(absoluteFilePath.length() + 1);
if(!error.at(0).isNumber()){
continue;
}
// error is like: 26:7: error: 'const ...
int index = error.indexOf(':');
int row = error.mid(0,index).toInt();
error = error.mid(index + 1);
index = error.indexOf(':');
int column = error.mid(0,index).toInt();
error = error.mid(index+2);
bool isError = error.startsWith(QStringLiteral("error"));
index = error.indexOf(':');
const QString message = error.mid(index+1).toString();
index = message.lastIndexOf('\'');
int markupLength = 2;
if(index >= 0){
int firstIndex = message.lastIndexOf('\'',index-1);
if(firstIndex >= 0){
markupLength = std::max(index-firstIndex-1,1);
}
}
// check if there are tabs in the row
const auto block = document->findBlockByLineNumber(row - startLineNumer);
for(int i = block.position(), end = block.position() + column;i < end;++i){
if(document->characterAt(i) == '\t'){
++column;
}
}
codeMarkups.push_back(std::make_unique<CodeMarkup>(row - startLineNumer, column - 1, markupLength, isError, message));
}
}
}
......@@ -69,6 +69,24 @@ protected:
virtual bool filterAcceptsRow(int sourceRow,const QModelIndex &sourceParent) const override;
};
class CodeMarkup : public QObject{
Q_OBJECT
Q_PROPERTY(int row MEMBER row NOTIFY rowChanged)
Q_PROPERTY(int column MEMBER column NOTIFY columnChanged)
Q_PROPERTY(int markupLength MEMBER markupLength CONSTANT)
Q_PROPERTY(bool error MEMBER error CONSTANT)
Q_PROPERTY(QString message MEMBER message CONSTANT)
public:
int row = 0, column = 0;
const QString message;
const int markupLength = 1;
const bool error;
CodeMarkup(int row, int column, int markupLength, bool error,const QString &message):row(row), column(column), markupLength(markupLength), error(error), message(message){}
signals:
void rowChanged();
void columnChanged();
};
class CodeEditorHelper : public QObject
{
QQuickTextDocument* documentWrapper = nullptr;
......@@ -76,16 +94,21 @@ class CodeEditorHelper : public QObject
QMetaObject::Connection typeConnection;
QMetaObject::Connection spotifyResponderConnection;
CodeCompletions codeCompletions;
ModelVector<std::unique_ptr<CodeMarkup>> codeMarkups;
int lastLineCount;
Q_PROPERTY(QQuickTextDocument* document READ getDocument WRITE setDocument NOTIFY documentChanged)
Q_PROPERTY(Modules::Module* module READ getModule WRITE setModule NOTIFY moduleChanged)
Q_PROPERTY(QAbstractItemModel * codeCompletions READ getCodeCompletions CONSTANT)
Q_PROPERTY(QAbstractItemModel * codeMarkups READ getCodeMarkups CONSTANT)
Q_OBJECT
/** Wird automatisch gelöscht, wenn das textdocument zerstört wird
* @brief highlighter
*/
CodeHighlighter * highlighter = nullptr;
Modules::Module * module = nullptr;
private:
void extractErrors(const QString &compilerOutput, const QString &absoluteFilePath, int startLineNumer);
protected:
int countTabs(int startPos);
......@@ -94,6 +117,9 @@ public:
QAbstractItemModel * getCodeCompletions(){
return &codeCompletions;
}
QAbstractItemModel * getCodeMarkups(){
return &codeMarkups;
}
void setModule( Modules::Module* _module);
Modules::Module *getModule() const {
......@@ -112,6 +138,7 @@ public:
if(documentWrapper){
QObject::connect(documentWrapper->textDocument(),&QTextDocument::contentsChange,this,&CodeEditorHelper::contentsChange);
document = documentWrapper->textDocument();
lastLineCount = document->lineCount();
}else
document = nullptr;
if(document && !highlighter){
......
#include "compiler.h"
#include "modelmanager.h"
#include <QDebug>
#include <QDir>
#include <QProcess>
#include <QTemporaryFile>
#include <QTextStream>
#include <QProcess>
#include <QDebug>
#include <iostream>
#include <QDir>
#include "modelmanager.h"
#include <utility>
namespace Modules{
QString Compiler::compilerCmd = "g++";
QString Compiler::compilerLibraryFlags = "-shared -fPIC";
QString Compiler::compilerFlags = "-std=c++14 -O3";
QString Compiler::compilerCmd = QStringLiteral("g++");
QString Compiler::compilerLibraryFlags = QStringLiteral("-shared -fPIC");
QString Compiler::compilerFlags = QStringLiteral("-std=c++14 -O3 -Wextra -Wall");
QString Compiler::includePath = QDir::currentPath();
Compiler::Compiler()
{
}
std::pair<int,QString> Compiler::compileAndLoadModule(const QFileInfo &sourceCode, const QString &moduleName, const QString &oldModuleName, std::function<std::string(const std::string&)> replaceOldModulesInProgramBlocks){
auto moduleFilePath = sourceCode.absolutePath() + "/" + moduleName;
auto oldModuleFilePath = sourceCode.absolutePath() + "/" + oldModuleName;
auto result = compileToLibrary(sourceCode,moduleFilePath);
if(result.first == 0){
ModuleManager::singletone()->unloadLibrary(oldModuleFilePath);
ModuleManager::singletone()->loadModule(ModuleManager::singletone()->getFreeAbsoluteFilePathForModule(moduleFilePath),replaceOldModulesInProgramBlocks);
ModuleManager::singletone()->loadModule(ModuleManager::singletone()->getFreeAbsoluteFilePathForModule(moduleFilePath),std::move(replaceOldModulesInProgramBlocks));
}
return result;
}
......@@ -43,7 +38,7 @@ std::pair<int,QString> Compiler::compileToLibrary(const QFileInfo &file,const QS
QString cmd = compilerCmd + " "+ compilerLibraryFlags + " " + compilerFlags + " " + file.absoluteFilePath() + " -o " + tempOutputFileName + " -I\"/"+QFileInfo(includePath).absoluteFilePath() + "\" ";
p.start("bash", QStringList() << "-c" << cmd);
#elif defined(Q_OS_WIN)
tempOutputFileName+=".dll"; // we have to add .dll, otherwise the compiler will add .exe itselves
tempOutputFileName+=QLatin1String(".dll"); // we have to add .dll, otherwise the compiler will add .exe itselves
QString tempName=tempOutputFileName + ".o";
QString compilerCMD = compilerCmd.right(compilerCmd.length()-compilerCmd.lastIndexOf('/')-1);
QString cmd = /*".\\" + */ compilerCMD + " -c \"" + file.absoluteFilePath() + "\" " + compilerFlags + " -o \"" + tempName+"\" -I\"" + QFileInfo(includePath).absoluteFilePath() + "\" ";
......@@ -57,16 +52,13 @@ std::pair<int,QString> Compiler::compileToLibrary(const QFileInfo &file,const QS
//p.setWorkingDirectory(compilerCmd.left(compilerCmd.lastIndexOf('/')));
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("PATH", env.value("Path") + ";" +compilerCmd.left(compilerCmd.lastIndexOf('/')));
env.insert(QStringLiteral("PATH"), env.value(QStringLiteral("Path")) + ";" +compilerCmd.left(compilerCmd.lastIndexOf('/')));
p.setProcessEnvironment(env);
// p.setEnvironment(QStringList() <<"PATH"<< compilerCmd.left(compilerCmd.lastIndexOf('/')));
p.start("cmd /c " + cmd);
#endif
p.waitForFinished();
auto err = p.readAllStandardError();
auto out = p.readAllStandardError();
if(err.length()>0)qDebug().noquote() <<"ERR : "<< QString(err);
if(out.length()>0)qDebug().noquote() <<"OuT : "<< QString(out);
if(p.exitCode() != 0){
qDebug() << p.errorString();
qDebug() << p.error();
......@@ -75,12 +67,12 @@ std::pair<int,QString> Compiler::compileToLibrary(const QFileInfo &file,const QS
// we only have a .o ans need a .dll
// cmd: g++ -shared -o foo.dll foo.dll.o
QProcess oToDll;
oToDll.setEnvironment(QStringList() <<"PATH"<< compilerCmd.left(compilerCmd.lastIndexOf('/')));
oToDll.setEnvironment(QStringList() <<QStringLiteral("PATH")<< compilerCmd.left(compilerCmd.lastIndexOf('/')));
oToDll.start("cmd /c \" " + compilerCMD + " " + compilerLibraryFlags + " -o \"" + tempOutputFileName +"\" \""+ tempName +"\" \"");
oToDll.waitForFinished();
QFile::rename(tempOutputFileName,absoluteNewLibraryFilePath);
QFile::remove(tempName);
return{oToDll.exitCode(),oToDll.readAllStandardError()};
return{oToDll.exitCode(),err + oToDll.readAllStandardError()};
#endif
#ifdef Q_OS_MAC
......@@ -108,4 +100,5 @@ std::pair<int,QString> Compiler::compileToLibrary(const QString &code, const QSt
file.close();
return compileToLibrary(file,newLibraryFile);
}
}
} // namespace Modules
#ifndef COMPILER_H
#define COMPILER_H
#include <QFileInfo>
#include <functional>
#include <utility>
namespace Modules {
......@@ -14,8 +16,7 @@ public:
static QString includePath;
public:
Compiler();
static void setCompilerCommand(QString s){compilerCmd = s;}
static void setCompilerCommand(QString s){compilerCmd = std::move(s);}
/**
* @brief Compiler::compileAndLoadModule compiles the code in the file to a module Library and load the module(and unload the old)
......@@ -32,6 +33,5 @@ public:
static std::pair<int,QString> compileToLibrary(const QString &code,const QString &newLibraryFile);
};
}
} // namespace Modules
#endif // COMPILER_H
......@@ -344,10 +344,42 @@ Item{
Layout.fillHeight: true
Layout.fillWidth: true
onHoveredChanged: if(!hovered && listView.currentModelData)listView.currentModelData.code = codeEditor.text
clip: true
Rectangle{
anchors.fill: codeEditor
anchors.topMargin: codeEditor.topPadding
TextMetrics{
font: codeEditor.font
text: "M"
id: textMetrics
}
Repeater{
model: codeEditorHelper.codeMarkups
Rectangle{
x: modelData.column * (textMetrics.width+1)
y: modelData.row * height
width: modelData.markupLength * (textMetrics.width+1)
height: codeEditor.lineHeight
color: modelData.error ? "red" : "orange"
MouseArea{
anchors.fill: parent
id: mouseArea
acceptedButtons: Qt.NoButton
hoverEnabled: true
}
ToolTip.text: modelData.message
ToolTip.visible: mouseArea.containsMouse
}
}
}
TextArea{
property real lineHeight: contentHeight/lineCount
font.family: "Liberation Mono"
font.pointSize: 10
tabStopDistance: 16
hoverEnabled: false
id: codeEditor
selectByMouse: true
text: listView.currentModelData ? listView.currentModelData.code : "No Module selected"
......
Supports Markdown
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