1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
(function(){
var el = document.getElementById('Highlight-script');
function run() {
var code = document.querySelector('.blob-content code');
if (code && typeof hljs !== 'undefined') hljs.highlightElement(code);
applyBlobLineSelection();
}
function parseLinesParam() {
var params = new URLSearchParams(window.location.search);
var s = params.get('lines');
if (!s) return [];
var re = /L(\d+)(?:C(\d+))?(?:-L(\d+)(?:C(\d+))?)?/g;
var ranges = [];
var m;
while ((m = re.exec(s)) !== null) {
var startLine = parseInt(m[1], 10);
var startCol = m[2] ? parseInt(m[2], 10) : null;
var endLine = m[3] !== undefined ? parseInt(m[3], 10) : null;
var endCol = m[4] ? parseInt(m[4], 10) : null;
ranges.push({ startLine: startLine, startCol: startCol, endLine: endLine, endCol: endCol });
}
return ranges;
}
function wrapCodeInLineSpans(code) {
var lines = [];
var current = [];
function flushLine() {
if (current.length) {
lines.push(current);
current = [];
}
}
var nodes = Array.from(code.childNodes);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.nodeType === Node.TEXT_NODE) {
var parts = node.textContent.split('\n');
for (var j = 0; j < parts.length; j++) {
if (j > 0) flushLine();
current.push(parts[j]);
}
} else {
current.push(node);
}
}
flushLine();
code.replaceChildren();
for (var i = 0; i < lines.length; i++) {
var span = document.createElement('span');
span.setAttribute('data-line', String(i + 1));
for (var k = 0; k < lines[i].length; k++) {
var item = lines[i][k];
if (typeof item === 'string') {
span.appendChild(document.createTextNode(item));
} else {
span.appendChild(item);
}
}
code.appendChild(span);
if (i < lines.length - 1) code.appendChild(document.createTextNode('\n'));
}
return code.querySelectorAll('[data-line]');
}
function wrapCharacterRangeInSpan(lineSpan, startChar, endChar) {
startChar = Math.max(0, startChar);
var len = lineSpan.textContent.length;
endChar = endChar == null ? len : Math.min(len, endChar);
if (startChar >= endChar) return;
var walker = document.createTreeWalker(lineSpan, NodeFilter.SHOW_TEXT);
var charIdx = 0;
var startNode = null, startOff = 0, endNode = null, endOff = 0;
var n;
while ((n = walker.nextNode())) {
var nLen = n.length;
if (startNode == null && charIdx + nLen > startChar) {
startNode = n;
startOff = startChar - charIdx;
}
if (endNode == null && charIdx + nLen >= endChar) {
endNode = n;
endOff = endChar - charIdx;
break;
}
charIdx += nLen;
}
if (!startNode || !endNode) return;
try {
var range = document.createRange();
range.setStart(startNode, startOff);
range.setEnd(endNode, endOff);
var span = document.createElement('span');
span.className = 'blob-selection';
range.surroundContents(span);
} catch (e) {}
}
function applyBlobLineSelection() {
var code = document.querySelector('.blob-content code');
if (!code) return;
var ranges = parseLinesParam();
if (!ranges.length) return;
var lineSpans = wrapCodeInLineSpans(code);
var firstTarget = null;
for (var r = 0; r < ranges.length; r++) {
var range = ranges[r];
var startLine = range.startLine;
var startCol = range.startCol;
var endLine = range.endLine != null ? range.endLine : startLine;
var endCol = range.endCol;
for (var i = startLine; i <= endLine; i++) {
var span = code.querySelector('[data-line="' + i + '"]');
if (!span) continue;
if (firstTarget === null) firstTarget = span;
var lineLen = span.textContent.length;
var startCh = (i === startLine && startCol != null) ? startCol - 1 : 0;
var endCh = (i === endLine && endCol != null) ? endCol : lineLen;
if (startCh === 0 && endCh >= lineLen) {
span.classList.add('blob-line-selected');
} else {
wrapCharacterRangeInSpan(span, startCh, endCh);
}
}
}
if (firstTarget) {
firstTarget.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
}
}
if (el) {
if (el.getAttribute('data-loaded')) run();
else el.addEventListener('load', function(){ el.setAttribute('data-loaded','1'); run(); });
} else {
run();
}
})();