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,
});
})();
@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