Created
August 9, 2026 15:44
-
-
Save impliedgg/70cf236a4e66b32ed3acb38e1c913e33 to your computer and use it in GitHub Desktop.
stackoverflow attribution minimizer
This file contains hidden or 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 StackOverflow Minimized Attribution | |
| // @namespace github@impliedgg | |
| // @match https://stackoverflow.com/* | |
| // @version 1.0 | |
| // @author github@impliedgg | |
| // @description For StackOverflow. Reduces the attribution text for StackOverflow snippets to one line, while still citing the URL, author, date retrieved, and license. | |
| // @grant GM_setClipboard | |
| // ==/UserScript== | |
| document.addEventListener('copy', function (e) { | |
| function asComment(text, lang) { | |
| let bestCandidate = null; | |
| let parserContains = hljs.getLanguage(lang).contains; | |
| for (let containedIdx in parserContains) { | |
| let contained = parserContains[containedIdx]; | |
| if (contained.scope === 'comment') { | |
| if (bestCandidate == null) { | |
| bestCandidate = contained; | |
| } else if (bestCandidate.end != '$' && contained.end == '$') { | |
| bestCandidate = contained; | |
| } | |
| // if not prefix-only and not first, simply pass over this comment type | |
| } | |
| } | |
| if (bestCandidate == null) { | |
| return text; // pass through without commenting, you're on your own lmao | |
| } else { | |
| let begin = null; | |
| let end = null; | |
| // these are evil one-liners, but they: 1. convert regex begin/end tokens to strings 2. remove escaped backslashes... | |
| if (typeof bestCandidate.begin === 'string') { begin = bestCandidate.begin.replace('\\', ''); } else { begin = String(bestCandidate.begin).replace(/^\//, '').replace(/\/$/, '').replace('\\', ''); } | |
| if (typeof bestCandidate.end === 'string') { end = bestCandidate.end.replace('\\', ''); } else { end = String(bestCandidate.end).replace(/^\//, '').replace(/\/$/, '').replace('\\', ''); } | |
| if (end == '$') { | |
| return begin + ' ' + text; // just prefix | |
| } else { | |
| return begin + ' ' + text + ' ' + end; // prefix and suffix | |
| } | |
| } | |
| } | |
| // bypass logic if we're not copying from code element | |
| if (e.srcElement.localName === 'code') { | |
| // walk up DOM until we hit an element with .answer, which is always has *this* answer's data | |
| let answerObject = e.srcElement.parentElement; | |
| while (!answerObject.classList.contains('answer')) { | |
| answerObject = answerObject.parentElement; | |
| } | |
| /* | |
| * we want output as follows: | |
| * commented: https://stackoverflow.com/a/idhere - username - YYYY-MM-DD - CC BY-SA 3.0 | |
| * snippet goes here....... | |
| */ | |
| let attributionText = `https://stackoverflow.com/a/${answerObject.dataset.answerid} - ${answerObject.dataset.authorUsername} - ${new Date().toISOString().slice(0, 10)} - CC BY-SA 3.0`; | |
| let finalText = asComment(attributionText, e.srcElement.result.language) + '\n' + e.srcElement.textContent; | |
| setTimeout(() => { GM_setClipboard(finalText, 'text/plain'); }, 50); // if we don't do this setTimeout the actual code overwrites our custom copy lmao | |
| e.preventDefault(); | |
| } | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment