Skip to content

Instantly share code, notes, and snippets.

@punchagan
Last active April 9, 2022 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save punchagan/1f0c44533972cdd8ca44a835786184bb to your computer and use it in GitHub Desktop.
Save punchagan/1f0c44533972cdd8ca44a835786184bb to your computer and use it in GitHub Desktop.
Ocurrent logs line numbers
/__pycache__/
const hashToLines = (renderedLines, noScroll = false) => {
const mLines = location.hash.match(/L(\d+)(-L(\d+))*/)
let start, end
if (mLines) {
[_, start, __, end] = mLines
start = Number(start)
end = end ? Number(end) : start
// Return early if chosen lines are not rendered still
if (renderedLines && start > renderedLines) {
return
}
} else if (location.hash === "#end") {
start = end = document.getElementById('line-numbers').getElementsByTagName('span').length
// Always scroll to the last line
noScroll = false
} else {
return
}
highlightLines(start, end, !noScroll)
}
const highlightLines = (start, end, scroll) => {
// Remove previous highlights if any
document.querySelectorAll('.highlight').forEach(
(node) => node.classList.remove('highlight')
)
// Highlight lines in selected range
for (let i = start; i <= end; i++) {
let lineSpan = document.getElementById('L' + String(i))
if (!lineSpan) {
break
}
lineSpan.classList.add('highlight')
// Scroll to the first selected line
if (i === start && scroll) {
lineSpan.scrollIntoView()
}
}
}
const showLineNumbers = () => {
const node = document.querySelector('pre')
const oldLineNumbers = document.getElementById('line-numbers')
const lineNumbers = oldLineNumbers ? oldLineNumbers : document.createElement('span')
if (!oldLineNumbers) {
lineNumbers.setAttribute('id', 'line-numbers')
node.prepend(lineNumbers)
}
const lineCount = node.innerHTML.split(/\n/).length
const oldLineCount = lineNumbers.getElementsByTagName('span').length
for (let i = oldLineCount + 1; i <= lineCount; i++) {
let number = document.createElement('span')
number.innerHTML = i
number.setAttribute('id', 'L' + String(i))
lineNumbers.appendChild(number)
}
return lineCount
}
const addMutationObserver = () => {
let debounceTimer
const mutationCallback = function (mutationsList) {
for (const mutation of mutationsList) {
if (mutation.type === 'characterData') {
clearTimeout(debounceTimer)
debounceTimer = setTimeout(() => {
const lineCount = showLineNumbers()
highlightLines(lineCount, noScroll = true)
}, 200)
}
}
};
// Create an observer instance and watch changes on the pre tag
const observer = new MutationObserver(mutationCallback)
const pre = document.querySelector('pre')
observer.observe(pre, { subtree: true, characterData: true })
console.debug('Added observer on pre tag')
}
// Wait for pre tag to load before attaching the mutation observer
const timer = setTimeout(addMutationObserver, 0.1)
document.addEventListener('DOMContentLoaded', (event) => {
clearTimeout(timer) // If the page has loaded completely, don't add mutation observer
showLineNumbers()
hashToLines()
})
window.addEventListener('hashchange', () => { hashToLines() })
import random
import string
from time import sleep
from flask import Flask
app = Flask(__name__)
@app.route('/js')
def js():
with open('line-numbers.js') as f:
js = f.read()
return app.response_class(js, mimetype='text/javascript')
@app.route('/css')
def css():
text = """
pre #line-numbers {
color:black;
display:block;
}
pre #line-numbers {
float:left;
margin:0 1em 0 -1em;
border-right:1px solid;
text-align:right;
}
pre #line-numbers span {
display:block;
padding:0 .5em 0 1em;
}
pre #line-numbers .highlight {
background: lightgrey;
}
"""
return app.response_class(text, mimetype='text/css')
@app.route('/stream')
def stream():
def generate():
yield "<!DOCTYPE html><html>"
yield f"<link href='/css' rel='stylesheet'>"
yield f"<script src='/js'></script>"
yield "<pre>"
for _ in range(1000):
text = ''.join(random.choice(string.ascii_letters + ' \n' * 4) for _ in range(1000))
yield f"{text}\n"
sleep(random.random() * 0.5)
yield "</pre></html>"
return app.response_class(generate(), mimetype='text/html')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment