OptiYan

EYanIDE 优化

目前为 2024-08-18 提交的版本。查看 最新版本

// ==UserScript==
// @name         OptiYan
// @namespace    http://lunarine.cc/
// @version      2024-08-20
// @description  EYanIDE 优化
// @author       Liu Baicheng
// @match        http://121.36.38.167/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant        unsafeWindow
// @license      MIT
// @resource     css https://unpkg.com/[email protected]/dist/css/mdui.min.css
// @grant        GM_getResourceURL
// @grant        GM_getResourceText
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/js/mdui.min.js
// @connect      api.mkc.icu
// ==/UserScript==

(function () {
    'use strict';

    const spans = document.querySelectorAll('span.lm_title');
    var title;
    // 遍历并输出内容为 main.cpp 的 span
    spans.forEach(span => {
        if (span.textContent.trim() === 'main.cpp') {
            title = span;
        }
    });

    function classOptimize() {

        const divs = document.querySelectorAll('div.ui.dropdown.selection');

        // 遍历并删除这些 div
        divs.forEach(div => {
            div.remove();
        });

        var compilerOptionsInput = document.getElementById('compiler-options');
        compilerOptionsInput.value = "-O3";
        var comilerArgsInput = document.getElementById('command-line-arguments');
        comilerArgsInput.remove();
        var navbar = document.getElementById("site-navigation");
        let optibar = document.createElement('div');
        optibar.classList.add("right");
        optibar.classList.add("menu");
        navbar.appendChild(optibar);

        let tdiv = document.createElement('div');
        tdiv.className = "item no-right-padding borderless";
        tdiv.id = "userbar"
        optibar.appendChild(tdiv);

        // let tbutton = document.createElement('button');
        // tbutton.className = "ui labeled icon button";
        // tbutton.id = "optiso";
        // tbutton.innerHTML = `<i class="search icon"></i><span>搜索</span>`;
        // tdiv.appendChild(tbutton);

        // tbutton.onclick = function () {
        //     let input = unsafeWindow.stdinEditor.getValue();
        //     console.log(input);
        //     tbutton.classList.add('loading');
        //     requestGPT(input).then(response => {
        //         unsafeWindow.sourceEditor.setValue(response);
        //         tbutton.classList.remove('loading');
        //     });
        // };
    }

    function formatCppTemplateLine(line) {
        const templateRegex = /(\btemplate\b|\bvector\b|\bmap\b|\bset\b|\bp(?:air|queue)\b|<.*>)/;
        if (templateRegex.test(line.trim())) {
            return line
                .replace(/\s*(<|>)\s*/g, '$1')
                .replace(/>(\w)/g, '> $1');
        }
        return line;
    }

    function formatCppCode(code) {
        code = code.replace(/\/\*[\s\S]*?\*\//g, '');
        code = code.replace(/\/\/.*$/gm, '');
        const lines = code.split('\n');
        let formattedLines = [];
        let indentLevel = 0;
        const indentSpace = '    ';
        let inStruct = false;

        for (let i = 0; i < lines.length; i++) {
            let line = lines[i].trim();
            const isEndOfStructWithVar = line.match(/}\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\[?\s*[^;]*;/);

            if (line.includes('{') && !line.endsWith('{')) {
                line = line.replace(/\s*{\s*/g, ' {\n' + indentSpace.repeat(indentLevel + 1));
            }

            if (line.startsWith('struct')) {
                inStruct = true;
                formattedLines.push(indentSpace.repeat(indentLevel) + line);
                indentLevel++;
                continue;
            }

            if (line.endsWith('};') || isEndOfStructWithVar) {
                if (indentLevel) indentLevel--;
                formattedLines.push(indentSpace.repeat(indentLevel) + line);
                inStruct = false;

                if (isEndOfStructWithVar) {
                    continue;
                }
                formattedLines.push('');
                continue;
            }

            if (inStruct) {
                formattedLines.push(indentSpace.repeat(indentLevel) + line);
                continue;
            }

            if (line.startsWith('#include')) {
                line = line.replace(/#include\s*<\s*([\w./+-]+)\s*>/g, '#include <$1>');
                formattedLines.push(line);
                continue;
            }

            if (line === 'using namespace std;') {
                formattedLines.push(indentSpace.repeat(indentLevel) + line);
                formattedLines.push('');
                continue;
            }

            if (line.endsWith(')') && lines[i + 1] && lines[i + 1].trim() === '{') {
                line += ' {';
                i++;
            }

            line = line.replace(/\s*([+\-*/=<>&|]+)\s*/g, ' $1 ');
            line = line.replace(/\s*,\s*/g, ', ');
            line = line.replace(/\s*([+\-]{2})\s*/g, '$1');
            line = line.replace(/\s*;\s*/g, '; ');
            line = line.replace(/\)\s*(?=[a-zA-Z+\-*/])/g, ') ');

            line = line.replace(/(?<=[+\*/])\s*\(/g, ' (');
            line = line.replace(/(?<!\S)-\s*\(/g, '-(');
            line = line.replace(/\b(for|while|if|else|switch|case|do)\s*(?=[({])/g, '$1 ');

            line = formatCppTemplateLine(line);
            line = line.replace(/!\s*=\s*/g, '!= ');


            if (line.endsWith('}')) {
                if (indentLevel) indentLevel--;
                formattedLines.push(indentSpace.repeat(indentLevel) + line);
                if (indentLevel === 0 && !inStruct && line.endsWith('}')) {
                    formattedLines.push('');
                }
                continue;
            }

            if (line.includes("}")) {
                indentLevel--;
            }

            if (line.includes(') {')) {
                if (indentLevel === 0 && !inStruct && formattedLines[formattedLines.length - 1] != '') {
                    formattedLines.push('');
                    formattedLines.push(indentSpace.repeat(indentLevel) + line);
                    indentLevel++;
                    continue;
                }
            }

            if (line) {
                formattedLines.push(indentSpace.repeat(indentLevel) + line);
            }

            if (line.endsWith('{')) {
                indentLevel++;
            }
        }

        return formattedLines.join('\n').trim();
    }

    function formatCode() {
        const res = formatCppCode(unsafeWindow.sourceEditor.getValue());
        unsafeWindow.sourceEditor.setValue(res);
    }

    classOptimize();

    document.addEventListener('keydown', function (event) {
        if (event.ctrlKey && event.altKey) {
            formatCode(); // 调用目标函数
            mdui.snackbar({
                message: '代码格式化成功'
            });
        } else if (event.keyCode === 122) { // F11
            event.preventDefault();
            unsafeWindow.run();
        } else if (event.keyCode === 116) { // F5
            event.preventDefault();
        } else if (event.ctrlKey && event.keyCode === 82) { // Ctrl+R
            event.preventDefault();
        } else if (event.ctrlKey && event.keyCode === 121) { // Ctrl+R
            event.preventDefault();
        } else if (event.keyCode == 83 && event.ctrlKey) {
            event.preventDefault();
            saveFile();
        }
    });

    unsafeWindow.formatCppCode = formatCppCode;
    formatCode();

    window.addEventListener('load', function () {
        var footer = document.querySelector('#site-footer');
        if (footer) {
            var span = document.createElement('span');
            span.id = 'optiyan-line';
            span.textContent = 'OptiYan 已加载 Version: V1.1.0';
            span.style.color = "#fff";
            span.style.float = "left";
            span.style.left = "0";
            span.style.textAlign = "left";
            span.style.width = "fit-content";
            footer.appendChild(span);
        }
        var runBtn = document.getElementById('run-btn-label');
        runBtn.textContent = 'Run (F11 / Ctrl + ↵)';
    });

    function updateColor() {
        let status = document.getElementById("status-line");
        if (status) {
            if (status.innerText.includes('Error')) {
                const sitefooter = document.querySelector('#site-footer');
                const linefooter = document.querySelector('#status-line');

                sitefooter.style.backgroundColor = "#c14343";
                linefooter.style.backgroundColor = "#c14343";
            } else if (status.innerText.includes('Accept')) {
                const sitefooter = document.querySelector('#site-footer');
                const linefooter = document.querySelector('#status-line');
                sitefooter.style.backgroundColor = "#05a705";
                linefooter.style.backgroundColor = "#05a705";
            } else {
                const sitefooter = document.querySelector('#site-footer');
                const linefooter = document.querySelector('#status-line');
                sitefooter.style.backgroundColor = "#9775fa";
                linefooter.style.backgroundColor = "#9775fa";
            }
        } else {
            const sitefooter = document.querySelector('#site-footer');
            const linefooter = document.querySelector('#status-line');
            sitefooter.style.backgroundColor = "#9775fa";
            linefooter.style.backgroundColor = "#9775fa";
        }

    }

    let script = document.createElement('script');
    script.src = "https://unpkg.com/[email protected]/dist/js/mdui.min.js?v=20240817";

    script.onload = function () {
        console.log('mdui 已加载');
    };

    document.body.appendChild(script);
    console.log(GM_getResourceURL("css"), GM_getResourceText("css"));
    GM_addStyle(GM_getResourceText("css"));

    setInterval(updateColor, 100);

    var userbar = document.getElementById('userbar');
    //var fileList = document.getElementById('fileList');
    var loginButton = document.createElement('button');
    loginButton.className = "ui labeled icon button";
    loginButton.innerHTML = `<i class="user  icon"></i><span>登陆</span>`;
    loginButton.style.marginRight = "5px";
    loginButton.addEventListener('click', function () {
        login();
    });
    var registerButton = document.createElement('button');
    registerButton.className = "ui labeled icon button";
    registerButton.innerHTML = `<i class="add icon"></i><span>注册</span>`;
    registerButton.style.marginRight = "5px";
    registerButton.addEventListener('click', function () {
        register();
    });
    var logoutButton = document.createElement('button');
    logoutButton.innerHTML = `<i class="sign-out icon"></i><span>退出登录</span>`;
    logoutButton.className = "ui labeled icon button";
    logoutButton.addEventListener('click', function () {
        logout();
    });

    var saveButton = document.createElement('button');
    saveButton.innerHTML = `<i class="save icon"></i><span>保存文件 (Ctrl + S)</span>`;
    saveButton.style.marginRight = "5px";
    saveButton.className = "ui labeled icon button";
    saveButton.addEventListener('click', function () {
        saveFile();
    });

    var deleteButton = document.createElement('button');
    deleteButton.innerHTML = `<i class="trash icon"></i><span>删除文件</span>`;
    deleteButton.style.marginRight = "5px";
    deleteButton.className = "ui red labeled icon button";
    deleteButton.addEventListener('click', function () {
        deleteFile();
    });

    var userMessage = document.createElement('div');
    userMessage.classList.add('ui');
    userMessage.classList.add('site-link');
    userMessage.style.marginRight = "30px";

    var openButton = document.createElement('button');
    openButton.innerHTML = `<i class="file icon"></i><span>打开文件</span>`;
    openButton.style.marginRight = "5px";
    openButton.className = "ui labeled icon button";
    openButton.addEventListener('click', function () {
        var filename = prompt('请输入文件名');
        if (filename != null && filename.length >= 1) {
            loadFile(filename);
            mdui.snackbar({
                message: '文件加载成功'
            });
        } else {
            mdui.snackbar({
                message: '文件加载失败'
            });
        }
        openButton.classList.remove('loading');
    });

    // 初始化用户界面
    function updateUI() {
        userbar.innerHTML = '';
        if (isLoggedIn) {
            userMessage.innerText = "已登录为 @" + Gusername;
            userbar.appendChild(userMessage);
            userbar.appendChild(saveButton);
            if(title.innerText != "main.cpp") userbar.appendChild(deleteButton);
            userbar.appendChild(openButton);
            userbar.appendChild(logoutButton);
        } else {
            userbar.appendChild(loginButton);
            userbar.appendChild(registerButton);
        }
    }

    let token = localStorage.getItem('token');
    let Gusername = localStorage.getItem('username');
    let isLoggedIn = !!token; // 如果 token 存在,则 isLoggedIn 为 true

    function login() {
        var username = prompt('请输入用户名');
        var password = prompt('请输入密码');
        loginButton.classList.add('loading');
        GM_xmlhttpRequest({
            method: 'POST',
            url: 'http://api.mkc.icu/login',
            headers: {
                'Content-Type': 'application/json'
            },
            data: JSON.stringify({
                username: username,
                password: password
            }),
            onload: function (response) {
                var data = JSON.parse(response.responseText);
                if (data.token) {
                    mdui.snackbar({
                        message: '登录成功'
                    });
                    token = data.token;
                    isLoggedIn = true;
                    Gusername = username;
                    localStorage.setItem('token', token); // 保存 token 到 localStorage
                    localStorage.setItem('username', username); 
                    loginButton.classList.remove('loading');
                    updateUI();
                    openFile();
                } else {
                    mdui.snackbar({
                        message: '登录失败'
                    });
                }
            },
            onerror: function (error) {
                console.error('登录请求错误:', error);
            }
        });
    }

    function register() {
        var username = prompt('请输入用户名');
        var password = prompt('请输入密码');
        
        const a = Math.floor(Math.random() * (9999 - 1000 + 1)) + 1000;
        const b = Math.floor(Math.random() * (9999 - 1000 + 1)) + 1000;
        var answer = prompt(`请输入 ${a} + ${b} 的答案`);

        if (answer != a + b) {
            mdui.snackbar({
                message: `注册失败:你是人机嘛?`
            });
            return;
        }
        registerButton.classList.add('loading');
        GM_xmlhttpRequest({
            method: 'POST',
            url: 'http://api.mkc.icu/register',
            headers: {
                'Content-Type': 'application/json'
            },
            data: JSON.stringify({
                username: username,
                password: password
            }),
            onload: function (response) {
                var data = JSON.parse(response.responseText);
                if (data.message === '注册成功') {
                    token = data.token;
                    isLoggedIn = true;
                    Gusername = username;
                    localStorage.setItem('token', token); // 保存 token 到 localStorage
                    localStorage.setItem('username', username); 
                    mdui.snackbar({
                        message: '注册成功'
                    });
                    registerButton.classList.remove('loading');
                    updateUI();
                    openFile();
                } else {
                    mdui.snackbar({
                        message: `注册失败:${data.message}`
                    });
                }
            },
            onerror: function (error) {
                console.error('注册请求错误:', error);
            }
        });
    }

    function saveFile() {
        if (!isLoggedIn) {
            mdui.snackbar({
                message: `请先登录!`
            });
            return;
        }
        var filename;
        if (title.innerText == "main.cpp") filename = prompt('请输入文件名');
        else filename = title.innerText;
        if (filename == null || filename == "" || filename.length <= 1) {
            mdui.snackbar({
                message: `文件名不能为空!`
            });
            return;
        }
        var content = unsafeWindow.sourceEditor.getValue();
        saveButton.classList.add('loading');
        GM_xmlhttpRequest({
            method: 'POST',
            url: 'http://api.mkc.icu/files',
            headers: {
                'Content-Type': 'application/json',
            },
            data: JSON.stringify({
                token: token, // 将token放入body中
                filename: filename,
                content: content
            }),
            onload: function (response) {
                try {
                    var data = JSON.parse(response.responseText);
                    title.innerText = filename + ".cpp";
                    if (data.message === '文件保存成功') {
                        openFile();
                        mdui.snackbar({
                            message: `文件保存成功!`
                        });
                        saveButton.classList.remove('loading');
                        updateUI();

                    } else {
                        mdui.snackbar({
                            message: `保存失败:${data.message}`
                        });
                        saveButton.classList.remove('loading');
                    }
                } catch (e) {
                    console.error('解析响应时出错:', e);
                }
            },
            onerror: function (error) {
                console.error('保存文件请求错误:', error);
            }
        });
    }

    function deleteFile() {
        if (!isLoggedIn) {
            alert('请先登录');
            return;
        }
        var filename;
        if (title.innerText == "main.cpp") filename = prompt('请输入文件名');
        else {
            filename = title.innerText;
            filename = filename.replace(/\.[^/.]+$/, "");  
        }
        if (filename == '') {
            alert('文件名不能为空!');
            return;
        }
        var content = unsafeWindow.sourceEditor.getValue();
        deleteButton.classList.add('loading');
        GM_xmlhttpRequest({
            method: 'POST',
            url: 'http://api.mkc.icu/delete',
            headers: {
                'Content-Type': 'application/json',
            },
            data: JSON.stringify({
                token: token, // 将token放入body中
                filename: filename
            }),
            onload: function (response) {
                try {
                    var data = JSON.parse(response.responseText);
                    if (data.message === '文件删除成功') {
                        openFile();
                        mdui.snackbar({
                            message: `文件删除成功!`
                        });
                        deleteButton.classList.remove('loading');
                        updateUI();
                    } else {
                        mdui.snackbar({
                            message: `文件删除失败:${data.message}`
                        });
                        deleteButton.classList.remove('loading');
                    }
                } catch (e) {
                    console.error('解析响应时出错:', e);
                }
            },
            onerror: function (error) {
                console.error('删除文件请求错误:', error);
            }
        });
    }

    function openFile() {
        if (!isLoggedIn) {
            mdui.snackbar({
                message: `请先登录!`
            });
            return;
        }

        GM_xmlhttpRequest({
            method: 'GET',
            url: `http://api.mkc.icu/files?token=${encodeURIComponent(token)}`,
            headers: {
                'Content-Type': 'application/json',
            },
            onload: function (response) {
                try {
                    unsafeWindow.stdoutEditor.setValue("当前文件:");
                    var data = JSON.parse(response.responseText);
                    if (data.files && data.files.length > 0) {
                        data.files.forEach(filename => {
                            unsafeWindow.stdoutEditor.setValue(unsafeWindow.stdoutEditor.getValue() + "\n  - " + filename);
                        });
                        unsafeWindow.stdoutEditor.setValue(unsafeWindow.stdoutEditor.getValue() + '\n输入文件名称加载。');
                    } else {
                        mdui.snackbar({
                            message: `你还没有保存过文件......`
                        });
                    }
                } catch (e) {
                    console.error('解析响应时出错:', e);
                }
            },
            onerror: function (error) {
                console.error('打开文件请求错误:', error);
            }
        });
    }

    function loadFile(filename) {
        openButton.classList.add('loading');
        GM_xmlhttpRequest({
            method: 'GET',
            url: `http://api.mkc.icu/files/${filename}?token=${encodeURIComponent(token)}`,
            onload: function (response) {
                var data = JSON.parse(response.responseText);
                unsafeWindow.sourceEditor.setValue(data.file);  // 将文件内容加载到编辑器中
                title.innerText = filename + ".cpp";
                openButton.classList.remove('loading');
                document.title = filename + " - EYanIDE"
                updateUI();
            },
            onerror: function (error) {
                console.error('Error:', error);
                openButton.classList.remove('loading');
            }
        });
    }

    openFile();

    function logout() {
        token = null;
        localStorage.removeItem('token');
        isLoggedIn = false;
        Gusername = '';
        localStorage.removeItem('username');
        updateUI();
        mdui.snackbar({
            message: `已注销`
        });
    }
    
    updateUI();
})();