diff --git a/NEWS.md b/NEWS.md index 2d363ba5..b2f1c7d4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,6 +29,7 @@ Red Panda C++ Version 2.12 - enhancement: Syntax highlight and basic code completion for lua. - enhancement: Basic code completion for xmake.lua. - enhancement: Parser not correctly released if save a c file to non-c file. + - enhancement: Improve auto indent for embedding no-brace statements like for-for-if. Red Panda C++ Version 2.11 diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index b63a3f48..91be6768 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -87,6 +87,7 @@ SOURCES += \ compiler/compilerinfo.cpp \ compiler/ojproblemcasesrunner.cpp \ compiler/projectcompiler.cpp \ + compiler/xmakecompiler.cpp \ compiler/runner.cpp \ customfileiconprovider.cpp \ gdbmiresultparser.cpp \ @@ -225,6 +226,7 @@ HEADERS += \ compiler/compilermanager.h \ compiler/executablerunner.h \ compiler/filecompiler.h \ + compiler/xmakecompiler.h \ compiler/ojproblemcasesrunner.h \ compiler/projectcompiler.h \ compiler/runner.h \ diff --git a/RedPandaIDE/compiler/xmakecompiler.cpp b/RedPandaIDE/compiler/xmakecompiler.cpp new file mode 100644 index 00000000..fecbc09e --- /dev/null +++ b/RedPandaIDE/compiler/xmakecompiler.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "xmakecompiler.h" +#include "../project.h" +#include "compilermanager.h" +#include "../systemconsts.h" +#include "qt_utils/charsetinfo.h" +#include "../editor.h" + +#include + +XMakeCompiler::XMakeCompiler(std::shared_ptr project, bool silent, bool onlyCheckSyntax): + Compiler("",silent,onlyCheckSyntax), + mOnlyClean(false) +{ + setProject(project); +} + +void XMakeCompiler::buildXMakeFile() +{ + //we are using custom make file, don't overwrite it + if (mProject->options().useCustomMakefile && !mProject->options().customMakefile.isEmpty()) + return; + + QFile file(mProject->makeFileName()); + newXMakeFile(file); + +} + +void XMakeCompiler::newXMakeFile(QFile& file) +{ + // Create OBJ output directory + if (!mProject->options().objectOutput.isEmpty()) { + QDir(mProject->directory()).mkpath(mProject->options().objectOutput); + } + + // Write more information to the log file than before + log(tr("Building xmake.lua file...")); + log("--------"); + log(tr("- Filename: %1").arg(mProject->xmakeFileName())); + + // Create the actual file + if (!file.open(QFile::WriteOnly | QFile::Truncate)) + throw CompileError(tr("Can't open '%1' for write!").arg(mProject->xmakeFileName())); + + writeln(file,"-- Project: " + mProject->name()); + writeln(file,QString("-- xmake.lua created by Red Panda C++ ") + REDPANDA_CPP_VERSION); + writeln(file); + + writeln(file, QString("target(\"%1\")").arg(mProject->name())); + switch(mProject->options().type) { + case ProjectType::StaticLib: + writeln(file,"\tset_kind(\"static\")"); + break; + case ProjectType::DynamicLib: + writeln(file,"\tset_kind(\"shared\")"); + break; + default: + writeln(file,"\tset_kind(\"binary\")"); + } + // add files to compile + foreach(const PProjectUnit &unit, mProject->unitList()) { + if (!unit->compile() && !unit->link()) + continue; + + // Only process source files + QString relativeName = extractRelativePath(mProject->directory(), unit->fileName()); + FileType fileType = getFileType(relativeName); + if (fileType==FileType::ASM && !compilerSet()->canAssemble()) + continue; + + if (fileType == FileType::CHeader || fileType == FileType::CppHeader) { + writeln(file,QString("\tadd_headerfiles(\"%1\")").arg(relativeName)); + } else if (fileType == FileType::CSource || fileType == FileType::CppSource + || fileType == FileType::ASM || fileType==FileType::GAS || fileType==FileType::WindowsResourceSource) { + writeln(file,QString("\tadd_files(\"%1\")").arg(relativeName)); + } + } + + // Get windres file +#ifdef Q_OS_WIN + if (!mProject->options().privateResource.isEmpty()) { + QString relativeName = extractRelativePath(mProject->directory(), mProject->options().privateResource); + writeln(file,QString("\tadd_files(\"%1\")").arg(relativeName)); + } +#endif + + // Get list of applicable flags + QString cCompileArguments = getCCompileArguments(mOnlyCheckSyntax); + QString cppCompileArguments = getCppCompileArguments(mOnlyCheckSyntax); + QString libraryArguments = getLibraryArguments(FileType::Project); + QString cIncludeArguments = getCIncludeArguments() + " " + getProjectIncludeArguments(); + QString cppIncludeArguments = getCppIncludeArguments() + " " +getProjectIncludeArguments(); + + cCompileArguments.replace("\"","\\\""); + cppCompileArguments.replace("\"","\\\""); + libraryArguments.replace("\"","\\\""); + cIncludeArguments.replace("\"","\\\""); + cppIncludeArguments.replace("\"","\\\""); + + writeln(file,QString("\tadd_cflags(\"%1\")").arg(cCompileArguments)); + writeln(file,QString("\tadd_cflags(\"%1\")").arg(cIncludeArguments)); + writeln(file,QString("\tadd_cxxflags(\"%1\")").arg(cppCompileArguments)); + writeln(file,QString("\tadd_cxxflags(\"%1\")").arg(cppIncludeArguments)); + writeln(file,QString("\tadd_ldflags(\"%1\")").arg(libraryArguments)); + +#ifdef Q_OS_WIN + writeln(file,QString("\tadd_rcflags(\"%1\")").arg(mProject->options().resourceCmd)); +#endif + + if (mProject->getCompileOption(CC_CMD_OPT_DEBUG_INFO) == COMPILER_OPTION_ON) { + writeln(file,QString("\tadd_defines(\"__DEBUG__\")")); + } + + writeln(file,QString("target_end()")); +} + +void XMakeCompiler::writeln(QFile &file, const QString &s) +{ + if (!s.isEmpty()) + file.write(s.toLocal8Bit()); + file.write("\n"); +} + +bool XMakeCompiler::onlyClean() const +{ + return mOnlyClean; +} + +void XMakeCompiler::setOnlyClean(bool newOnlyClean) +{ + mOnlyClean = newOnlyClean; +} + +bool XMakeCompiler::prepareForRebuild() +{ + //we use make argument to clean + return true; +} + +bool XMakeCompiler::prepareForCompile() +{ + if (!mProject) + return false; + //initProgressForm(); + log(tr("Compiling project changes...")); + log("--------"); + log(tr("- Project Filename: %1").arg(mProject->filename())); + log(tr("- Compiler Set Name: %1").arg(compilerSet()->name())); + log(""); + + buildXMakeFile(); + + mCompiler = compilerSet()->make(); + + if (!fileExists(mCompiler)) { + throw CompileError( + tr("Make program '%1' doesn't exists!").arg(mCompiler) + +"
" + +tr("Please check the \"program\" page of compiler settings.")); + } + + QString parallelParam; + if (mProject->options().allowParallelBuilding) { + if (mProject->options().parellelBuildingJobs==0) { + parallelParam = " --jobs"; + } else { + parallelParam = QString(" -j%1").arg(mProject->options().parellelBuildingJobs); + } + } + + if (mOnlyClean) { + mArguments = QString(" %1 -f \"%2\" clean").arg(parallelParam, + extractRelativePath( + mProject->directory(), + mProject->makeFileName())); + } else if (mRebuild) { + mArguments = QString(" %1 -f \"%2\" clean all").arg(parallelParam, + extractRelativePath( + mProject->directory(), + mProject->makeFileName())); + } else { + mArguments = QString(" %1 -f \"%2\" all").arg(parallelParam, + extractRelativePath( + mProject->directory(), + mProject->makeFileName())); + } + mDirectory = mProject->directory(); + + log(tr("Processing makefile:")); + log("--------"); + log(tr("- makefile processer: %1").arg(mCompiler)); + log(tr("- Command: %1 %2").arg(extractFileName(mCompiler)).arg(mArguments)); + log(""); + + return true; +} diff --git a/RedPandaIDE/compiler/xmakecompiler.h b/RedPandaIDE/compiler/xmakecompiler.h new file mode 100644 index 00000000..f806faae --- /dev/null +++ b/RedPandaIDE/compiler/xmakecompiler.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef XMAKECOMPILER_H +#define XMAKECOMPILER_H + +#include "compiler.h" +#include +#include + +class Project; +class XMakeCompiler : public Compiler +{ + Q_OBJECT +public: + XMakeCompiler(std::shared_ptr project, bool silent,bool onlyCheckSyntax); + XMakeCompiler(const XMakeCompiler&)=delete; + XMakeCompiler& operator=(const XMakeCompiler&)=delete; + void buildXMakeFile(); + + bool onlyClean() const; + void setOnlyClean(bool newOnlyClean); + +private: + void newXMakeFile(QFile& file); + void writeln(QFile& file, const QString& s=""); + // Compiler interface +private: + bool mOnlyClean; +protected: + bool prepareForCompile() override; + bool prepareForRebuild() override; +}; + +#endif // XMakeCompiler_H diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 60de487d..f261bc59 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -483,7 +483,7 @@ QTabWidget::West - 4 + 1 true diff --git a/RedPandaIDE/project.cpp b/RedPandaIDE/project.cpp index 5315eadb..73cd4745 100644 --- a/RedPandaIDE/project.cpp +++ b/RedPandaIDE/project.cpp @@ -160,6 +160,11 @@ QString Project::makeFileName() return QDir(directory()).filePath(MAKEFILE_NAME); } +QString Project::xmakeFileName() +{ + return QDir(directory()).filePath(XMAKEFILE_NAME); +} + bool Project::unitsModifiedSince(const QDateTime& time) { foreach(const PProjectUnit& unit, mUnits) { diff --git a/RedPandaIDE/project.h b/RedPandaIDE/project.h index c3571978..d4efac52 100644 --- a/RedPandaIDE/project.h +++ b/RedPandaIDE/project.h @@ -214,6 +214,7 @@ public: QString directory() const; QString executable() const; QString makeFileName(); + QString xmakeFileName(); bool unitsModifiedSince(const QDateTime& time); bool modified() const; bool modifiedSince(const QDateTime& time); diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index 7deafbe9..a4d398ca 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -48,7 +48,8 @@ Settings::Settings(const QString &filename): mCodeCompletion(this), mCodeFormatter(this), mUI(this), - mVCS(this) + mVCS(this), + mExtTools(this) { //load(); } @@ -112,6 +113,7 @@ void Settings::load() mUI.load(); mDirs.load(); mVCS.load(); + mExtTools.load(); } Settings::Dirs &Settings::dirs() @@ -144,6 +146,11 @@ QString Settings::filename() const return mFilename; } +Settings::ExtTools &Settings::extTools() +{ + return mExtTools; +} + Settings::CodeCompletion& Settings::codeCompletion() { return mCodeCompletion; @@ -5865,3 +5872,28 @@ void Settings::VCS::detectGitInPath() } } + +const QString &Settings::ExtTools::xMakePath() const +{ + return mXMakePath; +} + +void Settings::ExtTools::setXMakePath(const QString &newXMakePath) +{ + mXMakePath = newXMakePath; +} + +void Settings::ExtTools::doSave() +{ + saveValue("xmake_path", mXMakePath); +} + +void Settings::ExtTools::doLoad() +{ + mXMakePath=stringValue("xmake_path",""); +} + +Settings::ExtTools::ExtTools(Settings *settings):_Base(settings, SETTING_EXTTOOLS) +{ + +} diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index 677417eb..5a168725 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -37,6 +37,7 @@ #define SETTING_ENVIRONMENT "Environment" #define SETTING_EXECUTOR "Executor" #define SETTING_DEBUGGER "Debugger" +#define SETTING_EXTTOOLS "ExtTools" #define SETTING_HISTORY "History" #define SETTING_UI "UI" #define SETTING_VCS "VCS" @@ -1266,6 +1267,21 @@ public: void doLoad() override; }; + class ExtTools: public _Base { + public: + explicit ExtTools(Settings* settings); + + const QString &xMakePath() const; + void setXMakePath(const QString &newXMakePath); + + private: + QString mXMakePath; + // _Base interface + protected: + void doSave() override; + void doLoad() override; + }; + class CompilerSet { public: @@ -1522,8 +1538,10 @@ public: CodeFormatter &codeFormatter(); UI &ui(); VCS &vcs(); + ExtTools &extTools(); QString filename() const; + private: QString mFilename; QSettings mSettings; @@ -1537,6 +1555,8 @@ private: CodeFormatter mCodeFormatter; UI mUI; VCS mVCS; + ExtTools mExtTools; + }; diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 0f03d6d9..c96b0056 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -116,6 +116,7 @@ # define STATIC_LIB_EXT "a" # define DYNAMIC_LIB_EXT "dll" # define MAKEFILE_NAME "makefile.win" +# define XMAKEFILE_NAME "xmake.lua" # define ALL_FILE_WILDCARD "*.*" #elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) # define PATH_SENSITIVITY Qt::CaseSensitive @@ -129,6 +130,7 @@ # define STATIC_LIB_EXT "a" # define DYNAMIC_LIB_EXT "d" # define MAKEFILE_NAME "makefile" +# define XMAKEFILE_NAME "xmake.lua" # define ALL_FILE_WILDCARD "*" #else #error "Only support windows and linux now!" diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index bd41ee74..b8378e90 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -146,6 +146,9 @@ FileType getFileType(const QString &filename) if (filename.endsWith(".dat",PATH_SENSITIVITY)) { return FileType::Text; } + if (filename.endsWith(".lua",PATH_SENSITIVITY)) { + return FileType::LUA; + } QFileInfo info(filename); if (info.suffix().isEmpty()) { return FileType::Other; diff --git a/RedPandaIDE/utils.h b/RedPandaIDE/utils.h index bb5e1f60..745278d2 100644 --- a/RedPandaIDE/utils.h +++ b/RedPandaIDE/utils.h @@ -34,6 +34,7 @@ using PSimpleIni = std::shared_ptr; enum class FileType{ ASM, // asm source file (.asm) GAS, // GNU assembler source file (.s) + LUA, // lua file (.lua) CSource, // c source file (.c) CppSource, // c++ source file (.cpp) CHeader, // c header (.h) diff --git a/libs/qsynedit/qsynedit/syntaxer/cpp.cpp b/libs/qsynedit/qsynedit/syntaxer/cpp.cpp index d03cda87..4128a92e 100644 --- a/libs/qsynedit/qsynedit/syntaxer/cpp.cpp +++ b/libs/qsynedit/qsynedit/syntaxer/cpp.cpp @@ -407,9 +407,13 @@ void CppSyntaxer::braceOpenProc() // if last indent is started by 'if' 'for' etc // just replace it int lastLine=-1; + if (!mRange.indents.isEmpty()) { + lastLine=mRange.indents.back().line; + } else { + lastLine=0; + } while (mRange.getLastIndentType() == IndentType::Statement) { popIndents(IndentType::Statement); - lastLine = mRange.lastUnindent.line; } pushIndents(IndentType::Block, lastLine); } else