Last active
April 5, 2022 20:53
-
-
Save 0x57e11a/507febaf77c1c6692ce781af4d8843e3 to your computer and use it in GitHub Desktop.
desmosstd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name DesmosSTD | |
// @version 0.2 | |
// @description Desmos standard library | |
// @updateURL https://gist.githubusercontent.com/possiblynova/507febaf77c1c6692ce781af4d8843e3/raw | |
// @downloadURL https://gist.githubusercontent.com/possiblynova/507febaf77c1c6692ce781af4d8843e3/raw | |
// @author Nova | |
// @include http://www.desmos.com/calculator* | |
// @include https://www.desmos.com/calculator* | |
// @grant GM_addStyle | |
// @grant unsafeWindow | |
// @run-at document-start | |
// ==/UserScript== | |
/* globals globalThis */ | |
console.log('demost-start') | |
const std = [ | |
/* | |
{ | |
name: '\\lambda', | |
comp: '{ tag: "reducer", minArity: 1, maxArity: 1 / 0, argumentTypes: [t.ListOfAny] }', | |
src: args => { | |
console.log(args[0][0]); | |
return 'test!'; // the eventual plan is that this would look for a user defined javascript function defined in comments like so: | |
} | |
}, | |
*/ | |
{ | |
name: 'noaction', | |
comp: '{ tag: "reducer", minArity: 0, maxArity: 1 / 0, argumentTypes: [t.ListOfAny], returnType: t.Action }', | |
src: args => { return { type: 'Action', updateRules: [] } } | |
}, | |
{ | |
name: 'crand', | |
comp: '{ minArity: 0, maxArity: 1 }', // pass x or n or something so desmos doesn't optimize it away | |
src: args => { | |
if(!globalThis._crand) globalThis._crand = 0; | |
console.info('rand', globalThis._crand); | |
var t = globalThis._crand += 0x6D2B79F5; | |
t = Math.imul(t ^ t >>> 15, t | 1); | |
t ^= t + Math.imul(t ^ t >>> 7, t | 61); | |
return ((t ^ t >>> 14) >>> 0) / 4294967296; | |
} | |
}, | |
{ | |
name: 'cseed', | |
comp: '{ argumentTypes: [t.Number] }', | |
src: args => { | |
globalThis._crand = args[0]; | |
console.log('new seed', args[0]); | |
return 1; | |
} | |
}, | |
{ | |
name: 'time', | |
comp: '{ argumentTypes: [] }', | |
src: args => { return Date.now() } // {} required since tostring | |
}, | |
/* | |
{ | |
name: 'str', | |
comp: '{ argumentTypes: [t.Number] }', | |
src: args => { | |
console.log(args); | |
return 'test123'; // the eventual plan for this is that you can write strings in comment entries, then get them via str, so str(1) will refer to a comment containing str(1)=somecontenthere | |
} | |
}, | |
*/ | |
{ | |
name: 'conv_ascii2str', | |
opname: 'conv', | |
comp: '{ tag: "reducer", argumentTypes: [t.ListOfNumber] }', | |
src: `return String.fromCharCode.apply(null, args[0])` | |
}, | |
{ | |
name: 'conv_str2ascii', | |
opname: 'conv', | |
comp: '{ tag: "reducer", minArity: 1, maxArity: 1, argumentTypes: [t.ListOfAny], returnType: t.ListOfNumber }', | |
src: `return args[0][0].split('').map(char => char.charCodeAt(0))` | |
}, | |
// bitwise | |
{ | |
name: 'bit_not', | |
opname: 'bit', | |
comp: '{ argumentTypes: [t.Number] }', | |
src: `return ~args[0]` | |
}, | |
{ | |
name: 'bit_and', | |
opname: 'bit', | |
comp: '{ tag: "reducer", argumentTypes: [t.ListOfNumber] }', | |
src: `return args[0].reduce((acc, v) => acc & v, 2**32)` | |
}, | |
{ | |
name: 'bit_or', | |
opname: 'bit', | |
comp: '{ tag: "reducer", argumentTypes: [t.ListOfNumber] }', | |
src: `return args[0].reduce((acc, v) => acc | v, 0)` | |
}, | |
{ | |
name: 'bit_xor', | |
opname: 'bit', | |
comp: '{ argumentTypes: [t.Number, t.Number] }', | |
src: `return args[0] ^ args[1]` | |
}, | |
{ | |
name: 'bit_shl', | |
opname: 'bit', | |
comp: '{ argumentTypes: [t.Number, t.Number] }', | |
src: `return args[0] << args[1]` | |
}, | |
{ | |
name: 'bit_shr', | |
opname: 'bit', | |
comp: '{ argumentTypes: [t.Number, t.Number] }', | |
src: `return args[0] >> args[1]` | |
}, | |
{ | |
name: 'bit_ashr', | |
opname: 'bit', | |
comp: '{ argumentTypes: [t.Number, t.Number] }', | |
src: `return args[0] >>> args[1]` | |
}, | |
/* | |
{ | |
name: 'test', | |
comp: '{ argumentTypes: [t.Number, t.Number], returnType: t.Point }', | |
src: args => new Proxy([args[0], args[1]], { get(target, key, _) { return (key == '0' || key == '1') ? Math.random() : target[key] } }) // this was a weird one, i call it the indecisive point, https://streamable.com/sfidi8 | |
}, | |
*/ | |
{ | |
name: 'sto', | |
comp: '{ argumentTypes: [t.Number, t.Number], returnType: t.Number }', // pass 0x or 0n plus your index so desmos doesnt optimize it away | |
src(args) { | |
if(globalThis._stored == undefined) globalThis._stored = {}; | |
globalThis._stored[args[0]] = args[1]; | |
return 1; | |
} | |
}, | |
{ | |
name: 'rcl', | |
comp: `{ argumentTypes: [t.Number], returnType: t.Number }`, // pass 0x or 0n plus your index so desmos doesnt optimize it away | |
src(args) { | |
if(globalThis._stored == undefined) globalThis._stored = {}; | |
let v = globalThis._stored[args[0]]; | |
return typeof v !== 'undefined' ? v : NaN; | |
} | |
} | |
] | |
unsafeWindow.Worker = new Proxy(Worker, { | |
construct(target, args) { | |
console.log(target, args); | |
if (args[0].startsWith("blob:")) { | |
const xhr = new XMLHttpRequest | |
xhr.open("GET", args[0], false) | |
xhr.send() | |
//console.log(xhr.responseText) | |
console.log('worker loaded', args) | |
let ret = xhr.responseText | |
.replace( | |
/Object.defineProperty\((.),"sinh"/g, | |
std.reduce( | |
(acc, def) => `${acc},$1["${def.name}"]=function(...args) { ${typeof def.src == 'function' ? def.src.toString().match(/{([\s\S]+)}/)[1] : def.src} }`, '$&' | |
) | |
) | |
.replace( | |
/sinh:(.)\("BuiltIn","sinh"\)/, | |
std.reduce( | |
(acc, def) => def.comp ? `${acc},[\`${def.name}\`]:(console.log(t), $1("BuiltIn","${def.name}",${def.comp}))` : `${acc},${def.name}:(console.log(t), $1("BuiltIn","${def.name}",{argumentTypes:[${ | |
def.argumentTypes.reduce((acc, typ) => `${acc}t.${typ},`, '') | |
}]}))`, | |
'$&' | |
) | |
) | |
.replace( | |
/self\.onmessage=function\(e\)\{self\.loadMessageQueue\.push\(e\)\}/, | |
`self.onmessage = function(e) { | |
console.log(e); | |
self.postMessage('ACK'); | |
self.loadMessageQueue.push(e); | |
}`) | |
console.log(xhr.responseText) | |
console.log(ret) | |
args[0] = URL.createObjectURL(new Blob([ret])) | |
} | |
return new target(...args) | |
} | |
}) | |
function applyNames() { | |
/* see https://github.com/jared-hughes/DesThree/blob/master/src/View.js#L66 for more info, including forcing a rerender */ | |
const fields = document.querySelectorAll('.dcg-mq-editable-field'); | |
console.log(fields); | |
let optProto = Object.getPrototypeOf(fields[0]._mqMathFieldInstance.__controller.root.cursor.options) | |
optProto.autoCommands.gamma = true; | |
optProto.autoCommands.eta = true; | |
optProto.autoCommands.iota = true; | |
optProto.autoCommands.lambda = true; | |
optProto.autoCommands.mu = true; | |
optProto.autoCommands.sigma = true; | |
optProto.autoCommands.Delta = true; | |
optProto.autoCommands.Xi = true; | |
fields.forEach(field => { | |
const opt = field._mqMathFieldInstance.__controller.root.cursor.options; | |
std.forEach(def => (opt.autoOperatorNames[def.opname || def.name] = def.opname || def.name)); | |
}) | |
} | |
function init() { | |
unsafeWindow.Calc.controller.dispatcher.register(e => { | |
if(['tick', 'new-expression', 'new-expression-at-end'].includes(e.type) || (e.type === 'on-special-key-pressed' && e.key === 'Enter')) applyNames(); | |
}) | |
applyNames(); | |
} | |
window.addEventListener('load', () => setTimeout(() => { | |
'use strict'; | |
console.log('desmost-ready'); | |
const Calc = unsafeWindow.Calc; | |
init(); | |
const DesmosSTD = { | |
update(id) { | |
Calc.controller.dispatch({ type: 'set-expression-properties-from-api', id: id }); | |
return DesmosSTD; | |
}, | |
render() { | |
Calc.notifyControllerOfAPICall(); | |
return DesmosSTD; | |
}, | |
setText(id, text) { | |
Calc.controller.getItemModel(id).text = text; | |
DesmosSTD.render(); | |
return DesmosSTD; | |
}, | |
setVariableValue(id, name, value, noundo = false) { | |
Calc.controller.getItemModel(id).latex = name + '=' + value; | |
if(noundo) Calc.controller.stateStack._stackPointer -= 1; | |
DesmosSTD.render(); | |
return DesmosSTD; | |
} | |
}; | |
unsafeWindow.DesmosSTD = DesmosSTD; | |
GM_addStyle('.dcg-desmos-svg-logo:not(#a) { fill: #ff7fff; }'); | |
}, 1000), false); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment