577 lines
17 KiB
C++
577 lines
17 KiB
C++
#include "termcolor.h"
|
||
#include <QCommandLineOption>
|
||
#include <QCommandLineParser>
|
||
#include <QCoreApplication>
|
||
#include <QDir>
|
||
#include <QException>
|
||
#include <QFile>
|
||
#include <QFileInfo>
|
||
#include <QJsonArray>
|
||
#include <QJsonDocument>
|
||
#include <QJsonObject>
|
||
#include <QJsonParseError>
|
||
#include <QJsonValue>
|
||
#include <QList>
|
||
#include <QMap>
|
||
#include <QRegularExpression>
|
||
#include <QRegularExpressionMatch>
|
||
#include <QStringList>
|
||
#include <QTextStream>
|
||
#include <QTranslator>
|
||
#include <curses.h>
|
||
#include <iostream>
|
||
|
||
#define QENDL Qt::endl
|
||
#define PROCESSFLAG(X) ((X) != 0)
|
||
|
||
enum operationType {
|
||
None = 0,
|
||
Processed = 1 << 0,
|
||
NewCode = 1 << 1, // 表示我要用模板新建文件
|
||
AddNew = 1 << 2,
|
||
DelNew = 1 << 3,
|
||
ShowAll = 1 << 4,
|
||
SetType = 1 << 5,
|
||
CurType = 1 << 6,
|
||
ShowInfo = 1 << 7,
|
||
ModNew = 1 << 8,
|
||
ClsNew = 1 << 9
|
||
};
|
||
|
||
struct codeObject {
|
||
QString type;
|
||
QString codePath;
|
||
QString ext;
|
||
};
|
||
|
||
struct cmdLineParam {
|
||
int operation = operationType::None;
|
||
QString type;
|
||
QString filePath;
|
||
QString ext;
|
||
};
|
||
|
||
static QTextStream qout(stdout);
|
||
static QTextStream qin(stdin);
|
||
static QTextStream qerr(stderr);
|
||
static QRegularExpression regex("(\"[^\"]+\"|[^\\s\"]+)");
|
||
|
||
static std::string warnPrefix, errPrefix, infoPrefix;
|
||
|
||
void showWarningMsg(QString message) {
|
||
std::cout << termcolor::yellow << warnPrefix;
|
||
qout << message << QENDL;
|
||
}
|
||
|
||
void showErrorMsg(QString message) {
|
||
std::cout << termcolor::red << errPrefix;
|
||
qout << message << QENDL;
|
||
}
|
||
|
||
void showInfoMsg(QString message) {
|
||
std::cout << termcolor::blue << infoPrefix;
|
||
qout << message << QENDL;
|
||
}
|
||
|
||
void initLocaliztion() {
|
||
warnPrefix = QObject::tr("WarningPrefix").toStdString();
|
||
errPrefix = QObject::tr("ErrorPrefix").toStdString();
|
||
infoPrefix = QObject::tr("InfoPrefix").toStdString();
|
||
}
|
||
|
||
void saveCfg(QString &path, QMap<QString, codeObject> &codeObjs) {
|
||
QFile f(path);
|
||
if (f.open(QFile::WriteOnly)) {
|
||
QJsonArray objs;
|
||
for (auto objitem : codeObjs) {
|
||
QJsonObject obj;
|
||
obj.insert("Type", objitem.type);
|
||
obj.insert("CodePath", objitem.codePath);
|
||
obj.insert("Ext", objitem.ext);
|
||
objs.append(obj);
|
||
}
|
||
QJsonDocument jdoc(objs);
|
||
if (f.write(jdoc.toJson(QJsonDocument::JsonFormat::Indented)) >= 0) {
|
||
f.close();
|
||
}
|
||
}
|
||
}
|
||
|
||
QString getFilePath(QString folder, QString codePath) {
|
||
if (codePath[0] == '/') {
|
||
return codePath;
|
||
} else {
|
||
return folder + "/" + codePath;
|
||
}
|
||
}
|
||
|
||
int main(int argc, char *argv[]) {
|
||
QCoreApplication a(argc, argv);
|
||
QCoreApplication::setApplicationVersion("1.0.0");
|
||
|
||
auto s = a.applicationDirPath() + "/lang/default.qm";
|
||
QTranslator translator;
|
||
if (!translator.load(s)) {
|
||
std::cout << termcolor::red << "[Error] Error Loading Translation File!"
|
||
<< std::endl;
|
||
return -1;
|
||
}
|
||
a.installTranslator(&translator);
|
||
|
||
initLocaliztion();
|
||
|
||
QCoreApplication::setApplicationName(QObject::tr("NewCode"));
|
||
|
||
QCommandLineParser parser;
|
||
parser.setApplicationDescription(QObject::tr("AppDescription"));
|
||
parser.addHelpOption();
|
||
parser.addVersionOption();
|
||
|
||
std::cout << termcolor::bright_yellow;
|
||
qout << QObject::tr("AppDescription") << QENDL << QENDL;
|
||
|
||
// names | description | valuename | defaultvalue
|
||
parser.addOptions(
|
||
{{{"t", "type"}, QObject::tr("IndicateType"), "t"},
|
||
{{"p", "path"}, QObject::tr("OutPut"), "p"},
|
||
{{"f", "fill", "param"}, QObject::tr("FormatParams"), "f"},
|
||
{{"k", "keep", "alive", "keepalive"}, QObject::tr("KeepAliveFlag")},
|
||
{{"st", "settype"}, QObject::tr("SetCurType"), "st"},
|
||
{{"q", "quit"}, QObject::tr("Quit")},
|
||
{"curtype", QObject::tr("ShowCurType")},
|
||
{{"add", "a"}, QObject::tr("AddTemplate"), "add"},
|
||
{"mod", QObject::tr("ModTemplate"), "mod"},
|
||
{"ext", QObject::tr("IndicateExt"), "ext"},
|
||
{"del", QObject::tr("DelTemplate"), "del"},
|
||
{"cls", QObject::tr("ClsTemplate")},
|
||
{"showall", QObject::tr("ShowAllTemplate")},
|
||
{"showinfo", QObject::tr("ShowTemplate"), "showinfo"},
|
||
{{"pwd", "curdir"}, QObject::tr("CurrentDir")},
|
||
{"prodir", QObject::tr("ProgramDir")},
|
||
{"cd", QObject::tr("ChangeCurDir"), "cd"}});
|
||
|
||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||
|
||
if (!parser.parse(a.arguments())) {
|
||
showErrorMsg(parser.errorText());
|
||
}
|
||
|
||
QMap<QString, codeObject> codeObjs; // 所有模板信息
|
||
QString currentType; // 当前模板信息名称
|
||
QString currentDirectory = QDir::currentPath(); // 当前路径
|
||
|
||
// 获取模板列表
|
||
auto jsonPath = a.applicationDirPath() + "/NewCode.json";
|
||
QFile file(jsonPath);
|
||
if (file.exists() && file.open(QFile::ReadOnly | QFile::Text)) {
|
||
QJsonParseError err;
|
||
QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &err);
|
||
if (err.error == QJsonParseError::NoError) {
|
||
QJsonArray cobjs = doc.array();
|
||
for (QJsonValue item : cobjs) {
|
||
QJsonObject obj = item.toObject();
|
||
QJsonValue v = obj.value("Type");
|
||
codeObject c;
|
||
if (v == QJsonValue::Undefined)
|
||
continue;
|
||
c.type = v.toString();
|
||
|
||
v = obj.value("CodePath");
|
||
if (v == QJsonValue::Undefined)
|
||
continue;
|
||
c.codePath = v.toString();
|
||
|
||
v = obj.value("Ext");
|
||
if (v == QJsonValue::Undefined)
|
||
continue;
|
||
c.ext = v.toString();
|
||
|
||
codeObjs.insert(c.type, c);
|
||
}
|
||
}
|
||
}
|
||
file.close();
|
||
|
||
// 没有模板列表发出警告,有的话默认第一个
|
||
if (codeObjs.count()) {
|
||
currentType = codeObjs.firstKey();
|
||
} else {
|
||
showWarningMsg(QObject::tr("NoTemplate"));
|
||
}
|
||
|
||
bool isKeepingAlive = false;
|
||
|
||
do {
|
||
// 开始处理结果
|
||
cmdLineParam param;
|
||
QStringList fargs;
|
||
|
||
/*======= 先记录想让我干什么,不管对错 =======*/
|
||
|
||
// 如果命令含有退出命令,直接走人
|
||
if (parser.isSet("q")) {
|
||
exit(0);
|
||
}
|
||
|
||
// 如果命令要求帮助,直接显示重新来
|
||
if (parser.isSet("h")) {
|
||
qout << parser.helpText() << QENDL;
|
||
}
|
||
|
||
if (parser.isSet("v")) {
|
||
qout << qApp->applicationVersion() << QENDL;
|
||
}
|
||
|
||
// 如果设置了默认模板类型
|
||
if (parser.isSet("t")) {
|
||
param.type = parser.value("t");
|
||
param.operation |= operationType::NewCode;
|
||
}
|
||
|
||
// 如果设置了输出路径
|
||
if (parser.isSet("p")) {
|
||
param.filePath = parser.value("p");
|
||
|
||
// 如果要执行添加模板,p 的含义发生了变化
|
||
if (parser.isSet("add")) {
|
||
auto i = parser.value("add");
|
||
param.type = parser.value("add");
|
||
param.operation |= operationType::AddNew;
|
||
} else {
|
||
param.operation |= operationType::NewCode;
|
||
}
|
||
}
|
||
|
||
// 如果输入了格式化参数
|
||
if (parser.isSet("f")) {
|
||
fargs = parser.values("f");
|
||
param.operation |= operationType::NewCode;
|
||
}
|
||
|
||
// 如果设置保持交互
|
||
if (parser.isSet("k")) {
|
||
//如果当前处于交互模式,又想让进入交互模式,发出信息告诉我已经行了
|
||
if (isKeepingAlive) {
|
||
showInfoMsg(QObject::tr("KeepAliveAlready"));
|
||
}
|
||
isKeepingAlive = true;
|
||
param.operation |= operationType::Processed;
|
||
}
|
||
|
||
// 如果要执行设置类型命令
|
||
if (parser.isSet("st")) {
|
||
currentType = parser.value("st");
|
||
param.operation |= operationType::SetType;
|
||
}
|
||
|
||
// 如果想要知道当前模板类型
|
||
if (parser.isSet("curtype")) {
|
||
param.operation |= operationType::CurType;
|
||
}
|
||
|
||
// 如果执行修改模板
|
||
if (parser.isSet("mod")) {
|
||
param.type = parser.value("mod");
|
||
if (parser.isSet("ext")) {
|
||
param.ext = parser.value("ext");
|
||
}
|
||
param.operation |= operationType::ModNew;
|
||
}
|
||
|
||
// 如果要执行删除模板操作
|
||
if (parser.isSet("del")) {
|
||
param.type = parser.value("del");
|
||
param.operation |= operationType::DelNew;
|
||
}
|
||
|
||
// 如果要执行清空模板操作
|
||
if (parser.isSet("cls")) {
|
||
param.operation |= operationType::ClsNew;
|
||
}
|
||
|
||
// 如果想要显示所有模板信息
|
||
if (parser.isSet("showall")) {
|
||
param.operation |= operationType::ShowAll;
|
||
}
|
||
|
||
// 如果想显示某个信息
|
||
if (parser.isSet("showinfo")) {
|
||
param.type = parser.value("showinfo");
|
||
param.operation |= operationType::ShowInfo;
|
||
}
|
||
|
||
// 如果想要显示当前目录,这个可以直接做到,且不影响其他结果
|
||
if (parser.isSet("pwd")) {
|
||
showInfoMsg(QObject::tr("CurrentDirectory:") + currentDirectory);
|
||
param.operation |= operationType::Processed;
|
||
}
|
||
|
||
// 如果想要显示当前程序目录,这个可以直接做到,且不影响其他结果
|
||
if (parser.isSet("prodir")) {
|
||
showInfoMsg(QObject::tr("ProgramDirectory:") + a.applicationDirPath());
|
||
param.operation |= operationType::Processed;
|
||
}
|
||
|
||
// 如果要改变当前目录,我假设你现在就需要,立即修改并做出回应
|
||
if (parser.isSet("cd")) {
|
||
QDir dir(currentDirectory);
|
||
dir.cd(parser.value("cd"));
|
||
currentDirectory = dir.absolutePath();
|
||
showInfoMsg(currentDirectory);
|
||
param.operation |= operationType::Processed;
|
||
}
|
||
|
||
/*======= 你逼逼完了,我捋一捋你想让我干什么 =======*/
|
||
|
||
// 把你想让我干的所有可能的事情全部转为布尔
|
||
auto flags = param.operation;
|
||
bool hasAddNew = PROCESSFLAG(flags & operationType::AddNew);
|
||
bool hasDelNew = PROCESSFLAG(flags & operationType::DelNew);
|
||
bool hasCurType = PROCESSFLAG(flags & operationType::CurType);
|
||
bool hasNewcode = PROCESSFLAG(flags & operationType::NewCode);
|
||
bool hasShowAll = PROCESSFLAG(flags & operationType::ShowAll);
|
||
bool hasSetType = PROCESSFLAG(flags & operationType::SetType);
|
||
bool hasShowInfo = PROCESSFLAG(flags & operationType::ShowInfo);
|
||
bool hasModNew = PROCESSFLAG(flags & operationType::ModNew);
|
||
bool hasClsNew = PROCESSFLAG(flags & operationType::ClsNew);
|
||
|
||
bool hasOp = (hasAddNew && hasDelNew) || (hasAddNew && hasModNew) ||
|
||
(hasAddNew && hasClsNew) || (hasDelNew && hasModNew) ||
|
||
(hasDelNew && hasClsNew) || (hasModNew && hasClsNew) ||
|
||
(hasCurType && hasSetType); // 表示有没有增删相关冲突
|
||
|
||
bool hasOp0 = (hasShowAll && hasShowInfo) || (hasShowInfo && hasCurType) ||
|
||
(hasShowAll && hasCurType); // 表示有没有查询相关冲突
|
||
|
||
// 看看有没有你既让我向东,又让我向西的操作,有的话滚
|
||
if (hasOp || hasOp0) {
|
||
showErrorMsg(QObject::tr("ConflitOp"));
|
||
param.operation = operationType::None; //不知所云,不干
|
||
}
|
||
|
||
// 如果命令清楚,并且有使用使用模板新建文件
|
||
if (param.operation && hasNewcode) {
|
||
param.operation =
|
||
operationType::NewCode; // 新建文件高于一切,除了立马下班
|
||
}
|
||
|
||
switch (param.operation) {
|
||
case operationType::None:
|
||
break;
|
||
case operationType::NewCode: {
|
||
// 新建文件不告诉路径,这不合理啊
|
||
if (!param.filePath.length()) {
|
||
showErrorMsg(QObject::tr("NoOutPutFile"));
|
||
break;
|
||
}
|
||
|
||
// 没告诉我,就用当前默认模板吧
|
||
if (!param.type.length())
|
||
param.type = currentType;
|
||
|
||
// 新建文件,没模板,不会,重新说一遍
|
||
if (!param.type.length()) {
|
||
showErrorMsg(QObject::tr("NullType"));
|
||
break;
|
||
}
|
||
|
||
// 模板的名字告诉的不对啊,重来
|
||
if (!codeObjs.contains(param.type)) {
|
||
showErrorMsg(QObject::tr("TypeNotExists"));
|
||
break;
|
||
}
|
||
|
||
// 模板找到了,继续
|
||
auto co = codeObjs.value(currentType);
|
||
|
||
// 尝试获取模板真正的绝对路径
|
||
auto p = getFilePath(a.applicationDirPath(), co.codePath);
|
||
|
||
QFile file(p);
|
||
// 看看有没有啊
|
||
if (!file.exists()) {
|
||
// 小子,骗人,告诉你没有,重来
|
||
showErrorMsg(QObject::tr(" %1 NotFound").arg(p));
|
||
break;
|
||
}
|
||
|
||
// 在啊,我看看能不能读
|
||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||
// 兄弟,系统不让啊,重来
|
||
showErrorMsg(QObject::tr(" %1 CannotRead").arg(p));
|
||
break;
|
||
}
|
||
|
||
auto buffer = file.readAll(); // 出息了,读出来了
|
||
QString fbu(buffer);
|
||
// 如果有格式化参数就来一下
|
||
fbu = fbu.replace("%", "%%").replace("#&", "%");
|
||
for (auto &a : fargs) {
|
||
fbu = QString(fbu).arg(a);
|
||
}
|
||
|
||
QFile fout(param.filePath);
|
||
if (fout.exists()) {
|
||
showWarningMsg(
|
||
QObject::tr(" %1 ExistInputYConfirm").arg(param.filePath));
|
||
|
||
// 有已经存在的文件,请确认一下
|
||
char kd;
|
||
do {
|
||
qout << QObject::tr("YesNoChoice") << QENDL;
|
||
kd = char(qin.readLine().toUtf8()[0] | 0x20);
|
||
} while (kd != 'y' && kd != 'n');
|
||
|
||
if (kd == 'n') {
|
||
showErrorMsg(QObject::tr("CancelByUser"));
|
||
} else {
|
||
if (fout.open(QFile::WriteOnly)) {
|
||
fout.write(fbu.replace("%%", "%").toUtf8());
|
||
fout.close();
|
||
showInfoMsg(QObject::tr("CreateSuccessfully"));
|
||
} else {
|
||
showErrorMsg(QObject::tr("CreateFailed"));
|
||
}
|
||
}
|
||
} else {
|
||
if (fout.open(QFile::WriteOnly)) {
|
||
fout.write(fbu.replace("%%", "%").toUtf8());
|
||
fout.close();
|
||
showInfoMsg(QObject::tr("CreateSuccessfully"));
|
||
} else {
|
||
showErrorMsg(QObject::tr("CreateFailed"));
|
||
}
|
||
}
|
||
} break;
|
||
case operationType::AddNew: {
|
||
if (param.type.length() &&
|
||
QFile::exists(a.applicationDirPath() + "/" + param.filePath)) {
|
||
if (codeObjs.contains(param.type)) {
|
||
showErrorMsg(QObject::tr("TypeHasExists"));
|
||
} else {
|
||
codeObject obj;
|
||
obj.type = param.type;
|
||
obj.codePath = param.filePath;
|
||
obj.ext = param.ext.length() ? param.ext : param.type;
|
||
codeObjs.insert(param.type, obj);
|
||
saveCfg(jsonPath, codeObjs);
|
||
showInfoMsg(QObject::tr("InsertSuccessfully"));
|
||
}
|
||
} else {
|
||
showErrorMsg(QObject::tr("InsertFailed"));
|
||
}
|
||
} break;
|
||
case operationType::DelNew: {
|
||
if (codeObjs.contains(param.type)) {
|
||
codeObjs.remove(param.type);
|
||
saveCfg(jsonPath, codeObjs);
|
||
if (param.type == currentType) {
|
||
if (codeObjs.count()) {
|
||
currentType = codeObjs.firstKey();
|
||
} else {
|
||
currentType.clear();
|
||
}
|
||
}
|
||
showInfoMsg(QObject::tr("DelSuccessfully"));
|
||
} else {
|
||
showErrorMsg(QObject::tr("DelFailed"));
|
||
}
|
||
} break;
|
||
case operationType::ShowAll: {
|
||
if (codeObjs.count() > 0) {
|
||
qout << ">>" << QObject::tr("TypeBelow") << QENDL;
|
||
for (auto &item : codeObjs.keys()) {
|
||
std::cout << termcolor::green;
|
||
qout << item << QENDL;
|
||
}
|
||
} else {
|
||
qout << ">>" << QObject::tr("NoInfo") << QENDL;
|
||
}
|
||
} break;
|
||
case operationType::SetType: {
|
||
if (codeObjs.contains(param.type)) {
|
||
currentType = param.type;
|
||
showInfoMsg(QObject::tr("SettingSuccess"));
|
||
} else {
|
||
showErrorMsg(QObject::tr("TypeNotExists"));
|
||
}
|
||
break;
|
||
}
|
||
case operationType::CurType: {
|
||
if (currentType.length()) {
|
||
showInfoMsg(currentType);
|
||
} else {
|
||
showInfoMsg("NULL");
|
||
}
|
||
} break;
|
||
case operationType::ShowInfo: {
|
||
if (!codeObjs.contains(param.type)) {
|
||
showErrorMsg(QObject::tr("KeyNotFound"));
|
||
break;
|
||
}
|
||
std::cout << termcolor::yellow;
|
||
qout << QObject::tr("InfoBelowStart") << param.type
|
||
<< QObject::tr("InfoBelowEnd") << QENDL;
|
||
|
||
auto &item = codeObjs.value(param.type);
|
||
|
||
std::cout << termcolor::green;
|
||
qout << QObject::tr("CodeType") << item.type << QENDL
|
||
<< QObject::tr("CodeExt") << item.ext << QENDL
|
||
<< QObject::tr("CodePath") << item.codePath << QENDL
|
||
<< QObject::tr("CodeAbsPath")
|
||
<< getFilePath(a.applicationDirPath(), item.codePath) << QENDL;
|
||
} break;
|
||
case operationType::ModNew: {
|
||
if (codeObjs.contains(param.type)) {
|
||
auto &obj = codeObjs[param.type];
|
||
if (param.filePath.length()) {
|
||
obj.codePath = param.filePath;
|
||
}
|
||
if (param.ext.length()) {
|
||
obj.ext = param.ext;
|
||
}
|
||
saveCfg(jsonPath, codeObjs);
|
||
showInfoMsg(QObject::tr("ModSuccessfully"));
|
||
} else {
|
||
showErrorMsg(QObject::tr("TypeNotExists"));
|
||
}
|
||
} break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (isKeepingAlive) {
|
||
// 等待下一次输入命令
|
||
QString ncmd;
|
||
do {
|
||
std::cout << termcolor::green << ">> ";
|
||
ncmd = qin.readLine();
|
||
QStringList args("");
|
||
|
||
// 开始将字符串匹配为命令行
|
||
int off = 0;
|
||
while (1) {
|
||
auto match = regex.match(ncmd, off);
|
||
if (!match.hasMatch()) {
|
||
break;
|
||
}
|
||
auto res = match.captured();
|
||
if (res[0] == '\"')
|
||
res = res.replace("\"", "");
|
||
if (res[0] == '\'')
|
||
res = res.replace("'", "");
|
||
args << res;
|
||
off = match.capturedEnd();
|
||
}
|
||
if (!parser.parse(args)) {
|
||
showErrorMsg(parser.errorText());
|
||
ncmd.clear();
|
||
}
|
||
} while (!ncmd.length());
|
||
}
|
||
} while (isKeepingAlive);
|
||
|
||
return 0;
|
||
}
|