taskvariablemgr.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include "taskvariablemgr.h"
  2. #include <QRegularExpression>
  3. #include <QInputDialog>
  4. #include <QApplication>
  5. #include <QRandomGenerator>
  6. #include <QTimeZone>
  7. #include "vnotex.h"
  8. #include "task.h"
  9. #include "taskhelper.h"
  10. #include "shellexecution.h"
  11. #include "configmgr.h"
  12. #include "mainconfig.h"
  13. #include "notebook/notebook.h"
  14. #include <widgets/mainwindow.h>
  15. #include <widgets/dialogs/selectdialog.h>
  16. using namespace vnotex;
  17. TaskVariable::TaskVariable(TaskVariable::Type p_type,
  18. const QString &p_name,
  19. TaskVariable::Func p_func)
  20. : m_type(p_type), m_name(p_name), m_func(p_func)
  21. {
  22. }
  23. TaskVariableMgr::TaskVariableMgr()
  24. : m_initialized(false)
  25. {
  26. }
  27. void TaskVariableMgr::refresh()
  28. {
  29. init();
  30. }
  31. QString TaskVariableMgr::evaluate(const QString &p_text,
  32. const Task *p_task) const
  33. {
  34. auto text = p_text;
  35. auto eval = [&text](const QString &p_name, std::function<QString()> p_func) {
  36. auto reg = QRegularExpression(QString(R"(\$\{[\t ]*%1[\t ]*\})").arg(p_name));
  37. if (text.contains(reg)) {
  38. text.replace(reg, p_func());
  39. }
  40. };
  41. // current notebook variables
  42. {
  43. eval("notebookFolder", []() {
  44. auto notebook = TaskHelper::getCurrentNotebook();
  45. if (notebook) {
  46. return TaskHelper::normalPath(notebook->getRootFolderAbsolutePath());
  47. } else return QString();
  48. });
  49. eval("notebookFolderBasename", []() {
  50. auto notebook = TaskHelper::getCurrentNotebook();
  51. if (notebook) {
  52. auto folder = notebook->getRootFolderAbsolutePath();
  53. return QDir(folder).dirName();
  54. } else return QString();
  55. });
  56. eval("notebookName", []() {
  57. auto notebook = TaskHelper::getCurrentNotebook();
  58. if (notebook) {
  59. return notebook->getName();
  60. } else return QString();
  61. });
  62. eval("notebookName", []() {
  63. auto notebook = TaskHelper::getCurrentNotebook();
  64. if (notebook) {
  65. return notebook->getDescription();
  66. } else return QString();
  67. });
  68. }
  69. // current file variables
  70. {
  71. eval("file", []() {
  72. return TaskHelper::normalPath(TaskHelper::getCurrentFile());
  73. });
  74. eval("fileNotebookFolder", []() {
  75. auto file = TaskHelper::getCurrentFile();
  76. return TaskHelper::normalPath(TaskHelper::getFileNotebookFolder(file));
  77. });
  78. eval("relativeFile", []() {
  79. auto file = TaskHelper::getCurrentFile();
  80. auto folder = TaskHelper::getFileNotebookFolder(file);
  81. return QDir(folder).relativeFilePath(file);
  82. });
  83. eval("fileBasename", []() {
  84. auto file = TaskHelper::getCurrentFile();
  85. return QFileInfo(file).fileName();
  86. });
  87. eval("fileBasename", []() {
  88. auto file = TaskHelper::getCurrentFile();
  89. return QFileInfo(file).completeBaseName();
  90. });
  91. eval("fileDirname", []() {
  92. auto file = TaskHelper::getCurrentFile();
  93. return TaskHelper::normalPath(QFileInfo(file).dir().absolutePath());
  94. });
  95. eval("fileExtname", []() {
  96. auto file = TaskHelper::getCurrentFile();
  97. return QFileInfo(file).suffix();
  98. });
  99. eval("selectedText", []() {
  100. return TaskHelper::getSelectedText();
  101. });
  102. eval("cwd", [p_task]() {
  103. return TaskHelper::normalPath(p_task->getOptionsCwd());
  104. });
  105. eval("taskFile", [p_task]() {
  106. return TaskHelper::normalPath(p_task->getFile());
  107. });
  108. eval("taskDirname", [p_task]() {
  109. return TaskHelper::normalPath(QFileInfo(p_task->getFile()).dir().absolutePath());
  110. });
  111. eval("execPath", []() {
  112. return TaskHelper::normalPath(qApp->applicationFilePath());
  113. });
  114. eval("pathSeparator", []() {
  115. return TaskHelper::getPathSeparator();
  116. });
  117. eval("notebookTaskFolder", []() {
  118. return TaskHelper::normalPath(TaskMgr::getNotebookTaskFolder());
  119. });
  120. eval("userTaskFolder", []() {
  121. return TaskHelper::normalPath(ConfigMgr::getInst().getUserTaskFolder());
  122. });
  123. eval("appTaskFolder", []() {
  124. return TaskHelper::normalPath(ConfigMgr::getInst().getAppTaskFolder());
  125. });
  126. eval("userThemeFolder", []() {
  127. return TaskHelper::normalPath(ConfigMgr::getInst().getUserThemeFolder());
  128. });
  129. eval("appThemeFolder", []() {
  130. return TaskHelper::normalPath(ConfigMgr::getInst().getAppThemeFolder());
  131. });
  132. eval("userDocsFolder", []() {
  133. return TaskHelper::normalPath(ConfigMgr::getInst().getUserDocsFolder());
  134. });
  135. eval("appDocsFolder", []() {
  136. return TaskHelper::normalPath(ConfigMgr::getInst().getAppDocsFolder());
  137. });
  138. }
  139. // Magic variables
  140. {
  141. auto cDT = QDateTime::currentDateTime();
  142. for(auto s : {
  143. "d", "dd", "ddd", "dddd", "M", "MM", "MMM", "MMMM",
  144. "yy", "yyyy", "h", "hh", "H", "HH", "m", "mm",
  145. "s", "ss", "z", "zzz", "AP", "A", "ap", "a"
  146. }) eval(QString("magic:%1").arg(s), [s]() {
  147. return QDateTime::currentDateTime().toString(s);
  148. });
  149. eval("magic:random", []() {
  150. return QString::number(QRandomGenerator::global()->generate());
  151. });
  152. eval("magic:random_d", []() {
  153. return QString::number(QRandomGenerator::global()->generate());
  154. });
  155. eval("magic:date", []() {
  156. return QDate::currentDate().toString("yyyy-MM-dd");
  157. });
  158. eval("magic:da", []() {
  159. return QDate::currentDate().toString("yyyyMMdd");
  160. });
  161. eval("magic:time", []() {
  162. return QTime::currentTime().toString("hh:mm:ss");
  163. });
  164. eval("magic:datetime", []() {
  165. return QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
  166. });
  167. eval("magic:dt", []() {
  168. return QDateTime::currentDateTime().toString("yyyyMMdd hh:mm:ss");
  169. });
  170. eval("magic:note", []() {
  171. auto file = TaskHelper::getCurrentFile();
  172. return QFileInfo(file).fileName();
  173. });
  174. eval("magic:no", []() {
  175. auto file = TaskHelper::getCurrentFile();
  176. return QFileInfo(file).completeBaseName();
  177. });
  178. eval("magic:t", []() {
  179. auto dt = QDateTime::currentDateTime();
  180. return dt.timeZone().displayName(dt, QTimeZone::ShortName);
  181. });
  182. eval("magic:w", []() {
  183. return QString::number(QDate::currentDate().weekNumber());
  184. });
  185. eval("magic:att", []() {
  186. // TODO
  187. return QString();
  188. });
  189. }
  190. // environment variables
  191. do {
  192. QMap<QString, QString> map;
  193. auto list = TaskHelper::getAllSpecialVariables("env", p_text);
  194. list.erase(std::unique(list.begin(), list.end()), list.end());
  195. if (list.isEmpty()) break;
  196. for (const auto &name : list) {
  197. auto value = QProcessEnvironment::systemEnvironment().value(name);
  198. map.insert(name, value);
  199. }
  200. text = TaskHelper::replaceAllSepcialVariables("env", text, map);
  201. } while(0);
  202. // config variables
  203. do {
  204. const auto config_obj = ConfigMgr::getInst().getConfig().toJson();
  205. QMap<QString, QString> map;
  206. auto list = TaskHelper::getAllSpecialVariables("config", p_text);
  207. if (list.isEmpty()) break;
  208. list.erase(std::unique(list.begin(), list.end()), list.end());
  209. for (const auto &name : list) {
  210. auto value = TaskHelper::evaluateJsonExpr(config_obj, name);
  211. qDebug() << "insert" << name << value;
  212. map.insert(name, value);
  213. }
  214. text = TaskHelper::replaceAllSepcialVariables("config", text, map);
  215. } while(0);
  216. // input variables
  217. text = evaluateInputVariables(text, p_task);
  218. // shell variables
  219. text = evaluateShellVariables(text, p_task);
  220. return text;
  221. }
  222. QStringList TaskVariableMgr::evaluate(const QStringList &p_list,
  223. const Task *p_task) const
  224. {
  225. QStringList list;
  226. for (const auto &s : p_list) {
  227. list << evaluate(s, p_task);
  228. }
  229. return list;
  230. }
  231. void TaskVariableMgr::init()
  232. {
  233. if (m_initialized) return ;
  234. m_initialized = true;
  235. add(TaskVariable::FunctionBased,
  236. "file",
  237. [](const TaskVariable *, const Task *) {
  238. return QString();
  239. });
  240. }
  241. void TaskVariableMgr::add(TaskVariable::Type p_type,
  242. const QString &p_name,
  243. TaskVariable::Func p_func)
  244. {
  245. m_predefs.insert(p_name, TaskVariable(p_type, p_name, p_func));
  246. }
  247. QString TaskVariableMgr::evaluateInputVariables(const QString &p_text,
  248. const Task *p_task) const
  249. {
  250. QMap<QString, QString> map;
  251. auto list = TaskHelper::getAllSpecialVariables("input", p_text);
  252. list.erase(std::unique(list.begin(), list.end()), list.end());
  253. if (list.isEmpty()) return p_text;
  254. for (const auto &id : list) {
  255. auto input = p_task->getInput(id);
  256. QString text;
  257. auto mainwin = VNoteX::getInst().getMainWindow();
  258. if (input.type == "promptString") {
  259. auto desc = evaluate(input.description, p_task);
  260. auto defaultText = evaluate(input.default_, p_task);
  261. QInputDialog dialog(mainwin);
  262. dialog.setInputMode(QInputDialog::TextInput);
  263. if (input.password) dialog.setTextEchoMode(QLineEdit::Password);
  264. else dialog.setTextEchoMode(QLineEdit::Normal);
  265. dialog.setWindowTitle(p_task->getLabel());
  266. dialog.setLabelText(desc);
  267. dialog.setTextValue(defaultText);
  268. if (dialog.exec() == QDialog::Accepted) {
  269. text = dialog.textValue();
  270. } else {
  271. throw "TaskCancle";
  272. }
  273. } else if (input.type == "pickString") {
  274. // TODO: select description
  275. SelectDialog dialog(p_task->getLabel(), input.description, mainwin);
  276. for (int i = 0; i < input.options.size(); i++) {
  277. dialog.addSelection(input.options.at(i), i);
  278. }
  279. if (dialog.exec() == QDialog::Accepted) {
  280. int selection = dialog.getSelection();
  281. text = input.options.at(selection);
  282. } else {
  283. throw "TaskCancle";
  284. }
  285. }
  286. map.insert(input.id, text);
  287. }
  288. return TaskHelper::replaceAllSepcialVariables("input", p_text, map);
  289. }
  290. QString TaskVariableMgr::evaluateShellVariables(const QString &p_text,
  291. const Task *p_task) const
  292. {
  293. QMap<QString, QString> map;
  294. auto list = TaskHelper::getAllSpecialVariables("shell", p_text);
  295. list.erase(std::unique(list.begin(), list.end()), list.end());
  296. if (list.isEmpty()) return p_text;
  297. for (const auto &cmd : list) {
  298. QProcess process;
  299. process.setWorkingDirectory(p_task->getOptionsCwd());
  300. ShellExecution::setupProcess(&process, cmd);
  301. process.start();
  302. if (!process.waitForStarted(1000) || !process.waitForFinished(1000)) {
  303. throw "Shell variable execution timeout";
  304. }
  305. auto res = process.readAllStandardOutput().trimmed();
  306. map.insert(cmd, res);
  307. }
  308. return TaskHelper::replaceAllSepcialVariables("shell", p_text, map);
  309. }