NewCode/main.cpp

577 lines
17 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}