OptiYan 2

EYanIDE 优化 2.0

  1. // ==UserScript==
  2. // @name OptiYan 2
  3. // @namespace http://lunarine.cc/
  4. // @version 2024.1.6
  5. // @description EYanIDE 优化 2.0
  6. // @author Liu Baicheng
  7. // @match http://121.36.38.167/
  8. // @icon http://121.36.38.167/static/favicon1.ico
  9. // @grant unsafeWindow
  10. // @license MIT
  11. // @resource css https://unpkg.com/mdui@1.0.2/dist/css/mdui.min.css
  12. // @grant GM_getResourceURL
  13. // @grant GM_getResourceText
  14. // @grant GM_addStyle
  15. // @grant GM_xmlhttpRequest
  16. // @grant GM_notification
  17. // @grant GM_setValue
  18. // @grant GM_getValue
  19. // @grant GM_registerMenuCommand
  20. // @require https://cdn.jsdelivr.net/npm/mdui@1.0.2/dist/js/mdui.min.js
  21. // @connect api.mkc.icu
  22. // ==/UserScript==
  23.  
  24. (function () {
  25. 'use strict';
  26.  
  27. function classOptimize() {
  28.  
  29. let divs = document.querySelectorAll('div.ui.dropdown.selection');
  30.  
  31. // 遍历并删除这些 div
  32. divs.forEach(div => {
  33. div.remove();
  34. });
  35.  
  36. const ModalFileList = document.getElementById("file-list-modal");
  37. ModalFileList.style.height = "auto";
  38. ModalFileList.style.width = "500px";
  39. ModalFileList.style.marginTop = "50px";
  40. // ModalFileList.style.marginLeft = "30%";
  41. // ModalFileList.style.marginRight = "30% !important";
  42.  
  43. var windowWidth = window.innerWidth;
  44. var windowHeight = window.innerHeight;
  45. var elementWidth = 500;
  46. var left = (windowWidth - elementWidth) / 2;
  47.  
  48. ModalFileList.style.position = 'absolute';
  49. ModalFileList.style.left = left + 'px';
  50.  
  51. var compilerOptionsInput = document.getElementById('compiler-options');
  52. compilerOptionsInput.value = "-O3";
  53. compilerOptionsInput.style.display = "none";
  54. var comilerArgsInput = document.getElementById('command-line-arguments');
  55. if (comilerArgsInput) comilerArgsInput.remove();
  56.  
  57. document.getElementById("username-display").innerHTML = `<i class="user icon"></i>` + document.getElementById("username-display").innerHTML;
  58. }
  59.  
  60. function formatCppTemplateLine(line) {
  61. const templateRegex = /(\btemplate\b|\bvector\b|\bmap\b|\bset\b|\bp(?:air|queue)\b|<.*>)/;
  62. if (templateRegex.test(line.trim())) {
  63. return line
  64. .replace(/\s*(<|>)\s*/g, '$1')
  65. .replace(/>(\w)/g, '> $1');
  66. }
  67. return line;
  68. }
  69.  
  70. function formatCppCode(code) {
  71. code = code.replace(/\/\*[\s\S]*?\*\//g, '');
  72. code = code.replace(/\/\/.*$/gm, '');
  73. const lines = code.split('\n');
  74. let formattedLines = [];
  75. let indentLevel = 0;
  76. const indentSpace = ' ';
  77. let inStruct = false;
  78.  
  79. for (let i = 0; i < lines.length; i++) {
  80. let line = lines[i].trim();
  81. const isEndOfStructWithVar = line.match(/}\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\[?\s*[^;]*;/);
  82.  
  83. if (line.includes('{') && !line.endsWith('{')) {
  84. line = line.replace(/\s*{\s*/g, ' {\n' + indentSpace.repeat(indentLevel + 1));
  85. }
  86.  
  87. if (line.startsWith('struct')) {
  88. inStruct = true;
  89. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  90. indentLevel++;
  91. continue;
  92. }
  93.  
  94. if (line.endsWith('};') || isEndOfStructWithVar) {
  95. if (indentLevel) indentLevel--;
  96. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  97. inStruct = false;
  98.  
  99. if (isEndOfStructWithVar) {
  100. continue;
  101. }
  102. formattedLines.push('');
  103. continue;
  104. }
  105.  
  106. if (inStruct) {
  107. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  108. continue;
  109. }
  110.  
  111. if (line.startsWith('#include')) {
  112. line = line.replace(/#include\s*<\s*([\w./+-]+)\s*>/g, '#include <$1>');
  113. formattedLines.push(line);
  114. continue;
  115. }
  116.  
  117. if (line === 'using namespace std;') {
  118. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  119. formattedLines.push('');
  120. continue;
  121. }
  122.  
  123. if (line.endsWith(')') && lines[i + 1] && lines[i + 1].trim() === '{') {
  124. line += ' {';
  125. i++;
  126. }
  127.  
  128. line = line.replace(/\s*([+\-*/=<>&|]+)\s*/g, ' $1 ');
  129. line = line.replace(/\s*,\s*/g, ', ');
  130. line = line.replace(/\s*([+\-]{2})\s*/g, '$1');
  131. line = line.replace(/\s*;\s*/g, '; ');
  132. line = line.replace(/\)\s*(?=[a-zA-Z+\-*/])/g, ') ');
  133.  
  134. line = line.replace(/(?<=[+\*/])\s*\(/g, ' (');
  135. line = line.replace(/(?<!\S)-\s*\(/g, '-(');
  136. line = line.replace(/\b(for|while|if|else|switch|case|do)\s*(?=[({])/g, '$1 ');
  137.  
  138. line = formatCppTemplateLine(line);
  139. line = line.replace(/!\s*=\s*/g, '!= ');
  140.  
  141.  
  142. if (line.endsWith('}')) {
  143. if (indentLevel) indentLevel--;
  144. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  145. if (indentLevel === 0 && !inStruct && line.endsWith('}')) {
  146. formattedLines.push('');
  147. }
  148. continue;
  149. }
  150.  
  151. if (line.includes("}")) {
  152. indentLevel--;
  153. }
  154.  
  155. if (line.includes(') {')) {
  156. if (indentLevel === 0 && !inStruct && formattedLines[formattedLines.length - 1] != '') {
  157. formattedLines.push('');
  158. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  159. indentLevel++;
  160. continue;
  161. }
  162. }
  163.  
  164. if (line) {
  165. formattedLines.push(indentSpace.repeat(indentLevel) + line);
  166. }
  167.  
  168. if (line.endsWith('{')) {
  169. indentLevel++;
  170. }
  171. }
  172.  
  173. return formattedLines.join('\n').trim();
  174. }
  175.  
  176. function formatCode() {
  177. const res = formatCppCode(unsafeWindow.sourceEditor.getValue());
  178. unsafeWindow.sourceEditor.setValue(res);
  179. }
  180.  
  181. classOptimize();
  182.  
  183. document.addEventListener('keydown', function (event) {
  184. if (event.ctrlKey && event.altKey) {
  185. formatCode(); // 调用目标函数
  186. mdui.snackbar({
  187. message: '代码格式化成功'
  188. });
  189. } else if (event.keyCode === 122) { // F11
  190. event.preventDefault();
  191. unsafeWindow.run();
  192. } else if (event.keyCode === 116) { // F5
  193. event.preventDefault();
  194. } else if (event.ctrlKey && event.keyCode === 82) { // Ctrl+R
  195. event.preventDefault();
  196. } else if (event.ctrlKey && event.keyCode === 121) { // Ctrl+R
  197. event.preventDefault();
  198. } else if (event.keyCode == 83 && event.ctrlKey) {
  199. event.preventDefault();
  200. saveCode();
  201. }
  202. });
  203.  
  204. var title;
  205.  
  206. window.addEventListener('load', function () {
  207.  
  208. var footer = document.querySelector('#site-footer');
  209.  
  210. if (footer) {
  211. var span = document.createElement('span');
  212. span.id = 'optiyan-line';
  213. span.textContent = 'OptiYan 已加载 Version: V1.1.0';
  214. span.style.color = "#fff";
  215. span.style.float = "left";
  216. span.style.left = "0";
  217. span.style.textAlign = "left";
  218. span.style.width = "fit-content";
  219. footer.appendChild(span);
  220. }
  221.  
  222. var runBtn = document.getElementById('run-btn-label');
  223. runBtn.textContent = '运行 (F11 / Ctrl + ↵)';
  224. unsafeWindow.formatCppCode = formatCppCode;
  225.  
  226.  
  227. var loadBtn = document.getElementById('loadcode');
  228. loadBtn.className = "ui inverted primary labeled icon blue button";
  229.  
  230. let fileNameInputDiv = document.createElement("div");
  231.  
  232. fileNameInputDiv.className = "ui action inverted icon input";
  233. document.querySelectorAll("div.item.fitted.borderless.wide.screen.only")[0].appendChild(fileNameInputDiv);
  234.  
  235. var fileNameInput = document.createElement('input');
  236. fileNameInput.id = "filename";
  237. fileNameInput.placeholder = "请输入文件名"
  238.  
  239. fileNameInputDiv.appendChild(fileNameInput);
  240.  
  241. document.getElementById("filename").value = "main.cpp";
  242.  
  243. fileNameInputDiv.innerHTML += `
  244. <button id="saveCodeButton" class="ui icon button">
  245. <i class="save icon"></i>
  246. </button>
  247. `;
  248. document.getElementById("saveCodeButton").addEventListener('click', function () {
  249. saveCode();
  250. });
  251. // const spans = document.querySelectorAll('span.lm_title');
  252.  
  253. // spans.forEach(span => {
  254. // if (span.textContent.trim() === 'main.cpp') {
  255. // title = span;
  256. // console.log(title.innerHTML);
  257. // }
  258. // });
  259. formatCode();
  260. classOptimize();
  261. // if (loading) document.getElementById("site-content").removeChild(loading);
  262. // document.getElementById("site-content").childNodes[0].style.display = '';
  263. });
  264.  
  265. function updateColor() {
  266. let status = document.getElementById("status-line");
  267. if (status) {
  268. if (status.innerText.includes('Error')) {
  269. const sitefooter = document.querySelector('#site-footer');
  270. const linefooter = document.querySelector('#status-line');
  271.  
  272. sitefooter.style.backgroundColor = "#c14343";
  273. linefooter.style.backgroundColor = "#c14343";
  274. } else if (status.innerText.includes('Accept')) {
  275. const sitefooter = document.querySelector('#site-footer');
  276. const linefooter = document.querySelector('#status-line');
  277. sitefooter.style.backgroundColor = "#05a705";
  278. linefooter.style.backgroundColor = "#05a705";
  279. } else {
  280. const sitefooter = document.querySelector('#site-footer');
  281. const linefooter = document.querySelector('#status-line');
  282. sitefooter.style.backgroundColor = "#9775fa";
  283. linefooter.style.backgroundColor = "#9775fa";
  284. }
  285. } else {
  286. const sitefooter = document.querySelector('#site-footer');
  287. const linefooter = document.querySelector('#status-line');
  288. sitefooter.style.backgroundColor = "#9775fa";
  289. linefooter.style.backgroundColor = "#9775fa";
  290. }
  291.  
  292. }
  293.  
  294. let script = document.createElement('script');
  295. script.src = "https://unpkg.com/mdui@1.0.2/dist/js/mdui.min.js?v=20240817";
  296.  
  297. script.onload = function () {
  298. console.log('mdui 已加载');
  299. };
  300.  
  301. document.body.appendChild(script);
  302. console.log(GM_getResourceURL("css"), GM_getResourceText("css"));
  303. GM_addStyle(GM_getResourceText("css"));
  304.  
  305. setInterval(updateColor, 100);
  306.  
  307. function createTimestampString(text) {
  308. // 获取当前时间的时间戳
  309. const timestamp = Math.floor(Date.now() / 1000); // 以秒为单位的时间戳
  310. console.log(timestamp);
  311. // 返回格式化字符串
  312. return `${text}:${timestamp}`;
  313. }
  314.  
  315. function parseTimestampString(timestampString) {
  316. // 分割字符串,获取 text 和时间戳
  317. const [text, timestamp] = timestampString.split(':');
  318. // 将时间戳转换为格式化的时间
  319. const date = new Date(timestamp * 1000); // 将时间戳转换为毫秒
  320. const formattedTime = date.toLocaleString().slice(0, 19).replace('T', ' '); // 格式化为 YYYY-MM-DD HH:mm:ss
  321. return { text, formattedTime };
  322. }
  323.  
  324. var curFileName;
  325.  
  326. unsafeWindow.loadFileContent = function loadFileContent(filename) {
  327. document.getElementById("status-line").innerText = '正在加载文件...';
  328. fetch(`/load_file_content?filename=${encodeURIComponent(filename)}`)
  329. .then(response => response.json())
  330. .then(data => {
  331. if (data.success) {
  332. // 使用 Monaco 编辑器加载文件内容
  333. sourceEditor.setModel(monaco.editor.createModel(data.code, 'plaintext', monaco.Uri.file(filename + Math.floor(Math.random() * (9999 - 1111 + 1)) + 1111)));
  334. monaco.editor.setModelLanguage(sourceEditor.getModel(), $selectLanguage.find(":selected").attr("mode"));
  335. console.log(title);
  336. curFileName = filename;
  337. filename = parseTimestampString(filename).text;
  338. title.innerText = filename + '.cpp';
  339. $('#file-list-modal').modal('hide');
  340. document.title = title.innerHTML;
  341. document.getElementById("status-line").innerText = `已加载 ${filename}`;
  342. document.getElementById("filename").value = filename;
  343. } else {
  344. mdui.snackbar({
  345. message: 'Failed to load file content: ' + data.message
  346. });
  347. document.getElementById("status-line").innerText = `${data.message}`;
  348. }
  349. })
  350. .catch((error) => {
  351. console.error('Error:', error);
  352. mdui.snackbar({
  353. message: 'An error occurred while loading file content.'
  354. });
  355. });
  356. }
  357.  
  358. unsafeWindow.showFileList = function showFileList() {
  359. fetch('/load_file_list')
  360. .then(response => response.json())
  361. .then(data => {
  362. if (data.success) {
  363. const fileListDiv = document.getElementById('file-list');
  364. fileListDiv.innerHTML = '';
  365. fileListDiv.className = "ui middle aligned divided list";
  366. // 创建文件列表
  367. data.files.forEach(file => {
  368. const fileItemDiv = document.createElement('div');
  369. fileItemDiv.className = 'item';
  370. const fileName = document.createElement('div');
  371. fileName.classList.add('content')
  372. //fileButton.className = 'ui button';
  373. const info = parseTimestampString(file.filename);
  374. const filename = info.text;
  375. const time = info.formattedTime;
  376.  
  377. fileName.innerHTML = `
  378. <a class="header">${filename}</a>
  379. <div class="description">上次修改时间:${time}</div>
  380.  
  381. `;
  382.  
  383. const icon = document.createElement('i');
  384. icon.className = "large file middle aligned icon";
  385.  
  386. const fileManage = document.createElement('div');
  387. fileManage.className = "right floated ui content buttons";
  388.  
  389. const fileButton = document.createElement('div');
  390. fileButton.className = 'ui icon circular button';
  391. fileButton.innerHTML = `<i class="folder open icon"></i>`;;
  392. fileButton.onclick = () => loadFileContent(file.filename);
  393.  
  394. const deleteButton = document.createElement('div');
  395. deleteButton.className = 'ui icon circular red button';
  396. deleteButton.innerHTML = `<i class="trash icon"></i>`;
  397. deleteButton.onclick = () => deleteFile(file.filename, false);
  398.  
  399. fileManage.appendChild(fileButton);
  400. const orDiv = document.createElement('div');
  401. //orDiv.classList.add('or');
  402. //orDiv.setAttribute("data-text", "或");
  403. //fileManage.appendChild(orDiv);
  404. fileManage.appendChild(deleteButton);
  405.  
  406. fileItemDiv.appendChild(fileManage);
  407. fileItemDiv.appendChild(icon);
  408. fileItemDiv.appendChild(fileName);
  409. fileListDiv.appendChild(fileItemDiv);
  410.  
  411. });
  412.  
  413. // 显示模态框
  414. $('#file-list-modal').modal({
  415. centered: true
  416. }).modal('show')
  417. } else {
  418. mdui.snackbar({
  419. message: 'Failed to load file list: ' + data.message
  420. });
  421. }
  422. })
  423. .catch((error) => {
  424. console.error('Error:', error);
  425. mdui.snackbar({
  426. message: 'An error occurred while loading file list.'
  427. });
  428. });
  429. }
  430.  
  431.  
  432. unsafeWindow.deleteFile = function deleteFile(filename, enforce) {
  433. console.log("deleting")
  434. console.log(enforce);
  435. if (filename == null || !filename.includes(":")) return;
  436. const fileName = parseTimestampString(filename).text;
  437. if (enforce || confirm(`Are you sure you want to delete "${fileName}"?`)) {
  438. fetch(`/delete_file?filename=${encodeURIComponent(filename)}`, { method: 'DELETE' })
  439. .then(response => response.json())
  440. .then(data => {
  441. if (data.success) {
  442. if (!enforce) mdui.snackbar({
  443. message: '删除成功'
  444. });
  445. if (!enforce) showFileList(); // Refresh the file list
  446. } else {
  447. mdui.snackbar({
  448. message: 'Failed to delete file: ' + data.message
  449. });
  450. }
  451. })
  452. .catch((error) => {
  453. console.error('Error:', error);
  454. mdui.snackbar({
  455. message: 'An error occurred while deleting the file.'
  456. });
  457. });
  458. }
  459. }
  460.  
  461. unsafeWindow.saveCode = function saveCode() {
  462. var fileName;
  463. console.log(title);
  464. if (title.innerText == "main.cpp" || "SOURCE") fileName = document.getElementById("filename").value;
  465. else {
  466. fileName = document.getElementById("filename").value;
  467. }
  468. if (fileName && fileName != "Untitled") {
  469. if (title.innerText != "main.cpp")
  470. if (document.getElementById("filename").value == title.innerText.replace(/\.[^/.]+$/, "")) unsafeWindow.deleteFile(curFileName, true);
  471. title.innerText = fileName + '.cpp';
  472. fileName = createTimestampString(fileName);
  473. unsafeWindow.saveFile(fileName);
  474. mdui.snackbar({
  475. message: '保存成功'
  476. });
  477. curFileName = fileName;
  478. document.title = title.innerHTML;
  479. } else {
  480. mdui.snackbar({
  481. message: '请输入有效的文件名或描述!'
  482. });
  483. }
  484. }
  485. setInterval(() => {
  486. const spans = document.querySelectorAll('span.lm_title');
  487. spans.forEach(span => {
  488. if (span.textContent.trim() === 'main.cpp' || span.textContent.trim() === "SOURCE") {
  489. title = span;
  490. //console.log(title.innerHTML);
  491. }
  492. });
  493. //console.log(title);
  494. if (title && title.innerText == "SOURCE") {
  495. title.innerText = parseTimestampString(curFileName || "main:114514").text + '.cpp';
  496. }
  497. }, 100);
  498.  
  499. })();