Skip to content

Instantly share code, notes, and snippets.

@MattHeffNT
Last active June 4, 2025 09:59
Show Gist options
  • Save MattHeffNT/006d8040a95e41bb54f13ab932ca9bb0 to your computer and use it in GitHub Desktop.
Save MattHeffNT/006d8040a95e41bb54f13ab932ca9bb0 to your computer and use it in GitHub Desktop.
enable relative line numbers in overleaf - tamper monkey
// ==UserScript==
// @name enable relative line numbers in overleaf
// @namespace http://tampermonkey.net/
// @version 2024-04-10
// @description handy for vim users. Change code view line numbers to relative.
// @author You
// @match https://www.overleaf.com/project/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=overleaf.com
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
var previousActiveLineIndex = -1; // Store the previous active line index
// Function to update the line numbers
function updateLineNumbers() {
var parent = document.querySelector('.cm-gutter.cm-lineNumbers');
var childs = parent.childNodes;
var activeLineIndex = -1;
let lineNumber;
// Find the index of the active line gutter
for (var i = 0; i < childs.length; i++) {
var childNode = childs[i];
if (childNode.nodeType === 1 && childNode.classList.contains("cm-activeLineGutter")) {
activeLineIndex = i;
// add some padding to make the active line a bit more vimmy
childNode.style.paddingRight = "8px";
break;
}
}
// Check if active line index has changed
if (activeLineIndex !== previousActiveLineIndex) {
// Reset the padding of the previously active line
if (previousActiveLineIndex !== -1 && previousActiveLineIndex < childs.length) {
var prevActiveLine = childs[previousActiveLineIndex];
if (prevActiveLine.nodeType === 1) {
prevActiveLine.style.paddingRight = ""; // Reset padding to default
}
}
previousActiveLineIndex = activeLineIndex; // Update previous active line index
// Set text content of active line gutter
if (activeLineIndex !== -1) {
childs[activeLineIndex].innerText = previousActiveLineIndex
}
lineNumber = 1;
// Update the line numbers for previous elements
for (var j = activeLineIndex - 1; j >= 0; j--, lineNumber++) {
var prevNode = childs[j];
if (prevNode.nodeType === 1) {
prevNode.innerText = lineNumber;
}
}
// Reset lineNumber to 1 for updating following elements
lineNumber = 1;
// Update the line numbers for following elements
for (var k = activeLineIndex + 1; k < childs.length; k++, lineNumber++) { // Removed the redeclaration of lineNumber
var nextNode = childs[k];
if (nextNode.nodeType === 1) {
nextNode.innerText = lineNumber;
}
}
}
}
// watch for the parent element to be created
const parentObserver = new MutationObserver(() => {
const parent = document.querySelector('.cm-gutter.cm-lineNumbers')
// if parent element found then call update function
if (parent) {updateLineNumbers()};
});
// call `observe()`, passing it the element to observe, and the options object
parentObserver .observe(document.querySelector("body"), {
subtree: true,
childList: true,
});
})();
@hazzery
Copy link

hazzery commented Mar 4, 2025

I chucked it into a minfier, so I could use it as a bookmarklet. Add this as a bookmark and click it whenever you open Overleaf:

javascript:(function(){var previousActiveLineIndex=-1;function updateLineNumbers(){var parent=document.querySelector('.cm-gutter.cm-lineNumbers');var childs=parent.childNodes;var activeLineIndex=-1;let lineNumber;for(var i=0;i<childs.length;i+=1){var childNode=childs[i];if(childNode.nodeType===1&&childNode.classList.contains("cm-activeLineGutter")){activeLineIndex=i;childNode.style.paddingRight="8px";break}}if(activeLineIndex!==previousActiveLineIndex){if(previousActiveLineIndex!==-1&&previousActiveLineIndex<childs.length){var prevActiveLine=childs[previousActiveLineIndex];if(prevActiveLine.nodeType===1){prevActiveLine.style.paddingRight=""}}previousActiveLineIndex=activeLineIndex;if(activeLineIndex!==-1){childs[activeLineIndex].innerText=previousActiveLineIndex}lineNumber=1;for(var j=activeLineIndex-1;j>=0;j-=1,lineNumber+=1){var prevNode=childs[j];if(prevNode.nodeType===1){prevNode.innerText=lineNumber}}lineNumber=1;for(var k=activeLineIndex+1;k<childs.length;k+=1,lineNumber+=1){var nextNode=childs[k];if(nextNode.nodeType===1){nextNode.innerText=lineNumber}}}}const parentObserver=new MutationObserver(()=>{const parent=document.querySelector('.cm-gutter.cm-lineNumbers');if(parent){updateLineNumbers()}});parentObserver.observe(document.querySelector("body"),{subtree:true,childList:true})})();

@Zeta611
Copy link

Zeta611 commented Mar 20, 2025

This is awesome!

@tomyjany
Copy link

This is pretty cool! thanks @MattHeffNT @hazzery

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment