// ==UserScript== // @name Better CodeHS (Ace Optimized) // @namespace http://tampermonkey.net/ // @version 1.2 // @description Enable autocomplete, Vim mode, and Gruvbox for CodeHS Ace Editor. // @author Qyoh & Gemini // @match https://codehs.com/* // @grant none // @updateURL https://git.darwincereska.dev/darwincereska/codehs/raw/branch/main/script.js // @downloadURL https://git.darwincereska.dev/darwincereska/codehs/raw/branch/main/script.js // ==/UserScript== (function() { 'use strict'; // --- UTILITIES --- function clickButton(selector) { const btn = document.querySelector(selector); if (btn) btn.click(); } // --- KEYBINDINGS --- document.addEventListener('keydown', (e) => { // Ctrl + Enter: Submit if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); clickButton('.StyledButtonKind-sc-1vhfpnt-0.fSozsy.sc-bkbkJK.eraKfR'); } // Alt + C: Check Code if (e.altKey && e.key === 'c') { e.preventDefault(); const testTab = document.querySelector('.r.c') || document.querySelector('[data-test="test-cases-tab"]'); if (testTab) testTab.click(); setTimeout(() => clickButton('#grading-unit-test-run.btn.btn-main.spinner'), 100); } }); // --- ACE EDITOR INJECTION --- function injectAceFeatures() { // CodeHS often uses 'ace' globally. If not, we try to find the editor instance. const editorEl = document.getElementById("codehs-editor") || document.querySelector('.ace_editor'); if (!editorEl || !window.ace) { setTimeout(injectAceFeatures, 1000); return; } try { // Get the existing instance instead of creating a new one to avoid conflicts const editor = ace.edit(editorEl); // Set Base Path for external modules (Vim/Themes) ace.config.set("basePath", "https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/"); ace.config.set("modePath", "https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/"); ace.config.set("themePath", "https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.7/"); // Enable Autocomplete ace.config.loadModule("ace/ext/language_tools", function() { editor.setOptions({ enableBasicAutocompletion: true, enableLiveAutocompletion: true, enableSnippets: true }); }); // Set Theme & Vim editor.setTheme("ace/theme/gruvbox"); editor.setKeyboardHandler("ace/keyboard/vim"); console.log("Better CodeHS: Ace Editor configured successfully."); } catch (err) { console.error("Better CodeHS: Error initializing editor", err); } } // Initialize window.addEventListener('load', injectAceFeatures); // Re-run if the user navigates between assignments (SPA behavior) let lastUrl = location.href; new MutationObserver(() => { const url = location.href; if (url !== lastUrl) { lastUrl = url; setTimeout(injectAceFeatures, 2000); } }).observe(document, {subtree: true, childList: true}); })();