NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Datacamp Select Next Underscore
// @version 1.2
// @grant unsafeWindow
// @include https://campus.datacamp.com/courses/*
// @license MIT
// @updateURL https://openuserjs.org/meta/ptrharmonic/Datacamp_Select_Next_Underscore.meta.js
// @downloadURL https://openuserjs.org/install/ptrharmonic/Datacamp_Select_Next_Underscore.user.js
// @copyright 2023, ptrharmonic (https://openuserjs.org/users/ptrharmonic)
// ==/UserScript==
// Adapted from here https://stackoverflow.com/a/39165137
function FindReact(dom, traverseUp = 0) {
const key = Object.keys(dom.wrappedJSObject).find(key=>{
return key.startsWith("__reactFiber$") // react 17+
|| key.startsWith("__reactInternalInstance$"); // react <17
});
const domFiber = dom.wrappedJSObject[key];
if (domFiber == null) return null;
// react <16
if (domFiber._currentElement) {
let compFiber = domFiber._currentElement._owner;
for (let i = 0; i < traverseUp; i++) {
compFiber = compFiber._currentElement._owner;
}
return compFiber._instance;
}
// react 16+
const GetCompFiber = fiber=>{
//return fiber._debugOwner; // this also works, but is __DEV__ only
let parentFiber = fiber.return;
while (typeof parentFiber.type == "string") {
parentFiber = parentFiber.return;
}
return parentFiber;
};
let compFiber = GetCompFiber(domFiber);
for (let i = 0; i < traverseUp; i++) {
compFiber = GetCompFiber(compFiber);
}
return compFiber.stateNode;
}
let editor = null;
const getEditor = () => {
if (editor != null) {
// console.log(editor.getDomNode());
if (editor.getDomNode() != null) {
return;
}
}
let elem = document.getElementsByClassName("react-monaco-editor-container")[0];
editor = FindReact(elem).editor;
// console.log(editor);
let currentPos = editor.getPosition();
let text = editor.getModel().getLinesContent()
console.log(currentPos, text);
}
const getNextUnderscore = () => {
let currentPos = editor.getPosition();
let text = editor.getModel().getLinesContent();
let startLine = currentPos.lineNumber - 1;
for (let i=startLine;i<text.length;i++) {
if (i == startLine) {
let index = text[i].indexOf("____", currentPos.column - 1);
if (index != -1) {
return new unsafeWindow.monaco.Position(i + 1, index + 1);
}
} else {
let index = text[i].indexOf("____");
if (index != -1) {
return new unsafeWindow.monaco.Position(i + 1, index + 1);
}
}
}
return null;
}
function reverseString(str) {
return str.split("").reverse().join("");
}
const getPrevUnderscore = () => {
let currentPos = editor.getPosition();
let text = editor.getModel().getLinesContent();
let startLine = currentPos.lineNumber - 1;
for (let i=startLine;i>0;i--) {
// reverse the string so we can search in the opposite direction
let line = reverseString(text[i]);
if (i == startLine) {
// If the cursor is to the left of some underlines, skip it
let add = 0;
let subst = text[i].substring(currentPos.column - 1 - 4, currentPos.column - 1);
console.log(subst, subst === "____");
if (subst === "____") {
add = 4;
}
let index = line.indexOf("____", line.length - currentPos.column + add);
if (index != -1) {
return new unsafeWindow.monaco.Position(i + 1, line.length - index + 1 - 4);
}
} else {
let index = line.indexOf("____");
if (index != -1) {
return new unsafeWindow.monaco.Position(i + 1, line.length - index + 1 - 4);
}
}
}
return null;
}
const next = (prev) => {
getEditor();
let nextPos;
if (prev) {
// console.log("prev");
nextPos = getPrevUnderscore();
} else {
nextPos = getNextUnderscore();
}
// editor.setPosition(nextPos);
editor.setSelection(new unsafeWindow.monaco.Range(nextPos.lineNumber, nextPos.column, nextPos.lineNumber, nextPos.column + 4));
}
window.addEventListener("keydown", (event) => {
let e = event;
// e.preventDefault();
// console.log(event, event.key, e.ctrlKey);
if (e.key.toLowerCase() == "u" && e.ctrlKey) {
// console.log("next!")
e.preventDefault();
next(e.shiftKey);
}
});