coverage 7.12.0__cp314-cp314-musllinux_1_2_i686.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. coverage/__init__.py +40 -0
  2. coverage/__main__.py +12 -0
  3. coverage/annotate.py +114 -0
  4. coverage/bytecode.py +196 -0
  5. coverage/cmdline.py +1184 -0
  6. coverage/collector.py +486 -0
  7. coverage/config.py +731 -0
  8. coverage/context.py +74 -0
  9. coverage/control.py +1481 -0
  10. coverage/core.py +139 -0
  11. coverage/data.py +227 -0
  12. coverage/debug.py +669 -0
  13. coverage/disposition.py +59 -0
  14. coverage/env.py +135 -0
  15. coverage/exceptions.py +85 -0
  16. coverage/execfile.py +329 -0
  17. coverage/files.py +553 -0
  18. coverage/html.py +860 -0
  19. coverage/htmlfiles/coverage_html.js +735 -0
  20. coverage/htmlfiles/favicon_32.png +0 -0
  21. coverage/htmlfiles/index.html +199 -0
  22. coverage/htmlfiles/keybd_closed.png +0 -0
  23. coverage/htmlfiles/pyfile.html +149 -0
  24. coverage/htmlfiles/style.css +385 -0
  25. coverage/htmlfiles/style.scss +842 -0
  26. coverage/inorout.py +614 -0
  27. coverage/jsonreport.py +192 -0
  28. coverage/lcovreport.py +219 -0
  29. coverage/misc.py +373 -0
  30. coverage/multiproc.py +120 -0
  31. coverage/numbits.py +146 -0
  32. coverage/parser.py +1215 -0
  33. coverage/patch.py +166 -0
  34. coverage/phystokens.py +197 -0
  35. coverage/plugin.py +617 -0
  36. coverage/plugin_support.py +299 -0
  37. coverage/py.typed +1 -0
  38. coverage/python.py +272 -0
  39. coverage/pytracer.py +369 -0
  40. coverage/regions.py +127 -0
  41. coverage/report.py +298 -0
  42. coverage/report_core.py +117 -0
  43. coverage/results.py +502 -0
  44. coverage/sqldata.py +1153 -0
  45. coverage/sqlitedb.py +239 -0
  46. coverage/sysmon.py +513 -0
  47. coverage/templite.py +318 -0
  48. coverage/tomlconfig.py +210 -0
  49. coverage/tracer.cpython-314-i386-linux-musl.so +0 -0
  50. coverage/tracer.pyi +43 -0
  51. coverage/types.py +206 -0
  52. coverage/version.py +35 -0
  53. coverage/xmlreport.py +264 -0
  54. coverage-7.12.0.dist-info/METADATA +221 -0
  55. coverage-7.12.0.dist-info/RECORD +59 -0
  56. coverage-7.12.0.dist-info/WHEEL +5 -0
  57. coverage-7.12.0.dist-info/entry_points.txt +4 -0
  58. coverage-7.12.0.dist-info/licenses/LICENSE.txt +177 -0
  59. coverage-7.12.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,735 @@
1
+ // Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2
+ // For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
3
+
4
+ // Coverage.py HTML report browser code.
5
+ /*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */
6
+ /*global coverage: true, document, window, $ */
7
+
8
+ coverage = {};
9
+
10
+ // General helpers
11
+ function debounce(callback, wait) {
12
+ let timeoutId = null;
13
+ return function(...args) {
14
+ clearTimeout(timeoutId);
15
+ timeoutId = setTimeout(() => {
16
+ callback.apply(this, args);
17
+ }, wait);
18
+ };
19
+ };
20
+
21
+ function checkVisible(element) {
22
+ const rect = element.getBoundingClientRect();
23
+ const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight);
24
+ const viewTop = 30;
25
+ return !(rect.bottom < viewTop || rect.top >= viewBottom);
26
+ }
27
+
28
+ function on_click(sel, fn) {
29
+ const elt = document.querySelector(sel);
30
+ if (elt) {
31
+ elt.addEventListener("click", fn);
32
+ }
33
+ }
34
+
35
+ // Helpers for table sorting
36
+ function getCellValue(row, column = 0) {
37
+ const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection
38
+ if (cell.childElementCount == 1) {
39
+ var child = cell.firstElementChild;
40
+ if (child.tagName === "A") {
41
+ child = child.firstElementChild;
42
+ }
43
+ if (child instanceof HTMLDataElement && child.value) {
44
+ return child.value;
45
+ }
46
+ }
47
+ return cell.innerText || cell.textContent;
48
+ }
49
+
50
+ function rowComparator(rowA, rowB, column = 0) {
51
+ let valueA = getCellValue(rowA, column);
52
+ let valueB = getCellValue(rowB, column);
53
+ if (!isNaN(valueA) && !isNaN(valueB)) {
54
+ return valueA - valueB;
55
+ }
56
+ return valueA.localeCompare(valueB, undefined, {numeric: true});
57
+ }
58
+
59
+ function sortColumn(th) {
60
+ // Get the current sorting direction of the selected header,
61
+ // clear state on other headers and then set the new sorting direction.
62
+ const currentSortOrder = th.getAttribute("aria-sort");
63
+ [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none"));
64
+ var direction;
65
+ if (currentSortOrder === "none") {
66
+ direction = th.dataset.defaultSortOrder || "ascending";
67
+ }
68
+ else if (currentSortOrder === "ascending") {
69
+ direction = "descending";
70
+ }
71
+ else {
72
+ direction = "ascending";
73
+ }
74
+ th.setAttribute("aria-sort", direction);
75
+
76
+ const column = [...th.parentElement.cells].indexOf(th)
77
+
78
+ // Sort all rows and afterwards append them in order to move them in the DOM.
79
+ Array.from(th.closest("table").querySelectorAll("tbody tr"))
80
+ .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (direction === "ascending" ? 1 : -1))
81
+ .forEach(tr => tr.parentElement.appendChild(tr));
82
+
83
+ // Save the sort order for next time.
84
+ if (th.id !== "region") {
85
+ let th_id = "file"; // Sort by file if we don't have a column id
86
+ let current_direction = direction;
87
+ const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE);
88
+ if (stored_list) {
89
+ ({th_id, direction} = JSON.parse(stored_list))
90
+ }
91
+ localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({
92
+ "th_id": th.id,
93
+ "direction": current_direction
94
+ }));
95
+ if (th.id !== th_id || document.getElementById("region")) {
96
+ // Sort column has changed, unset sorting by function or class.
97
+ localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({
98
+ "by_region": false,
99
+ "region_direction": current_direction
100
+ }));
101
+ }
102
+ }
103
+ else {
104
+ // Sort column has changed to by function or class, remember that.
105
+ localStorage.setItem(coverage.SORTED_BY_REGION, JSON.stringify({
106
+ "by_region": true,
107
+ "region_direction": direction
108
+ }));
109
+ }
110
+ }
111
+
112
+ // Find all the elements with data-shortcut attribute, and use them to assign a shortcut key.
113
+ coverage.assign_shortkeys = function () {
114
+ document.querySelectorAll("[data-shortcut]").forEach(element => {
115
+ document.addEventListener("keypress", event => {
116
+ if (event.target.tagName.toLowerCase() === "input") {
117
+ return; // ignore keypress from search filter
118
+ }
119
+ if (event.key === element.dataset.shortcut) {
120
+ element.click();
121
+ }
122
+ });
123
+ });
124
+ };
125
+
126
+ // Create the events for the filter box.
127
+ coverage.wire_up_filter = function () {
128
+ // Populate the filter and hide100 inputs if there are saved values for them.
129
+ const saved_filter_value = localStorage.getItem(coverage.FILTER_STORAGE);
130
+ if (saved_filter_value) {
131
+ document.getElementById("filter").value = saved_filter_value;
132
+ }
133
+ const saved_hide100_value = localStorage.getItem(coverage.HIDE100_STORAGE);
134
+ if (saved_hide100_value) {
135
+ document.getElementById("hide100").checked = JSON.parse(saved_hide100_value);
136
+ }
137
+
138
+ // Cache elements.
139
+ const table = document.querySelector("table.index");
140
+ const table_body_rows = table.querySelectorAll("tbody tr");
141
+ const no_rows = document.getElementById("no_rows");
142
+
143
+ const footer = table.tFoot.rows[0];
144
+ const ratio_columns = Array.from(footer.cells).map(cell => Boolean(cell.dataset.ratio));
145
+
146
+ // Observe filter keyevents.
147
+ const filter_handler = (event => {
148
+ // Keep running total of each metric, first index contains number of shown rows
149
+ const totals = ratio_columns.map(
150
+ is_ratio => is_ratio ? {"numer": 0, "denom": 0} : 0
151
+ );
152
+
153
+ var text = document.getElementById("filter").value;
154
+ // Store filter value
155
+ localStorage.setItem(coverage.FILTER_STORAGE, text);
156
+ const casefold = (text === text.toLowerCase());
157
+ const hide100 = document.getElementById("hide100").checked;
158
+ // Store hide value.
159
+ localStorage.setItem(coverage.HIDE100_STORAGE, JSON.stringify(hide100));
160
+
161
+ // Hide / show elements.
162
+ table_body_rows.forEach(row => {
163
+ var show = false;
164
+ // Check the text filter.
165
+ for (let column = 0; column < totals.length; column++) {
166
+ cell = row.cells[column];
167
+ if (cell.classList.contains("name")) {
168
+ var celltext = cell.textContent;
169
+ if (casefold) {
170
+ celltext = celltext.toLowerCase();
171
+ }
172
+ if (celltext.includes(text)) {
173
+ show = true;
174
+ }
175
+ }
176
+ }
177
+
178
+ // Check the "hide covered" filter.
179
+ if (show && hide100) {
180
+ const [numer, denom] = row.cells[row.cells.length - 1].dataset.ratio.split(" ");
181
+ show = (numer !== denom);
182
+ }
183
+
184
+ if (!show) {
185
+ // hide
186
+ row.classList.add("hidden");
187
+ return;
188
+ }
189
+
190
+ // show
191
+ row.classList.remove("hidden");
192
+ totals[0]++;
193
+
194
+ for (let column = 0; column < totals.length; column++) {
195
+ // Accumulate dynamic totals
196
+ cell = row.cells[column] // nosemgrep: eslint.detect-object-injection
197
+ if (cell.matches(".name, .spacer")) {
198
+ continue;
199
+ }
200
+ if (ratio_columns[column] && cell.dataset.ratio) {
201
+ // Column stores a ratio
202
+ const [numer, denom] = cell.dataset.ratio.split(" ");
203
+ totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection
204
+ totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection
205
+ }
206
+ else {
207
+ totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection
208
+ }
209
+ }
210
+ });
211
+
212
+ // Show placeholder if no rows will be displayed.
213
+ if (!totals[0]) {
214
+ // Show placeholder, hide table.
215
+ no_rows.style.display = "block";
216
+ table.style.display = "none";
217
+ return;
218
+ }
219
+
220
+ // Hide placeholder, show table.
221
+ no_rows.style.display = null;
222
+ table.style.display = null;
223
+
224
+ // Calculate new dynamic sum values based on visible rows.
225
+ for (let column = 0; column < totals.length; column++) {
226
+ // Get footer cell element.
227
+ const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection
228
+ if (cell.matches(".name, .spacer")) {
229
+ continue;
230
+ }
231
+
232
+ // Set value into dynamic footer cell element.
233
+ if (ratio_columns[column]) {
234
+ // Percentage column uses the numerator and denominator,
235
+ // and adapts to the number of decimal places.
236
+ const match = /\.([0-9]+)/.exec(cell.textContent);
237
+ const places = match ? match[1].length : 0;
238
+ const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection
239
+ cell.dataset.ratio = `${numer} ${denom}`;
240
+ // Check denom to prevent NaN if filtered files contain no statements
241
+ cell.textContent = denom
242
+ ? `${(numer * 100 / denom).toFixed(places)}%`
243
+ : `${(100).toFixed(places)}%`;
244
+ }
245
+ else {
246
+ cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection
247
+ }
248
+ }
249
+ });
250
+
251
+ document.getElementById("filter").addEventListener("input", debounce(filter_handler));
252
+ document.getElementById("hide100").addEventListener("input", debounce(filter_handler));
253
+
254
+ // Trigger change event on setup, to force filter on page refresh
255
+ // (filter value may still be present).
256
+ document.getElementById("filter").dispatchEvent(new Event("input"));
257
+ document.getElementById("hide100").dispatchEvent(new Event("input"));
258
+ };
259
+ coverage.FILTER_STORAGE = "COVERAGE_FILTER_VALUE";
260
+ coverage.HIDE100_STORAGE = "COVERAGE_HIDE100_VALUE";
261
+
262
+ // Set up the click-to-sort columns.
263
+ coverage.wire_up_sorting = function () {
264
+ document.querySelectorAll("[data-sortable] th[aria-sort]").forEach(
265
+ th => th.addEventListener("click", e => sortColumn(e.target))
266
+ );
267
+
268
+ // Look for a localStorage item containing previous sort settings:
269
+ let th_id = "file", direction = "ascending";
270
+ const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE);
271
+ if (stored_list) {
272
+ ({th_id, direction} = JSON.parse(stored_list));
273
+ }
274
+ let by_region = false, region_direction = "ascending";
275
+ const sorted_by_region = localStorage.getItem(coverage.SORTED_BY_REGION);
276
+ if (sorted_by_region) {
277
+ ({
278
+ by_region,
279
+ region_direction
280
+ } = JSON.parse(sorted_by_region));
281
+ }
282
+
283
+ const region_id = "region";
284
+ if (by_region && document.getElementById(region_id)) {
285
+ direction = region_direction;
286
+ }
287
+ // If we are in a page that has a column with id of "region", sort on
288
+ // it if the last sort was by function or class.
289
+ let th;
290
+ if (document.getElementById(region_id)) {
291
+ th = document.getElementById(by_region ? region_id : th_id);
292
+ }
293
+ else {
294
+ th = document.getElementById(th_id);
295
+ }
296
+ th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending");
297
+ th.click()
298
+ };
299
+
300
+ coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2";
301
+ coverage.SORTED_BY_REGION = "COVERAGE_SORT_REGION";
302
+
303
+ // Loaded on index.html
304
+ coverage.index_ready = function () {
305
+ coverage.assign_shortkeys();
306
+ coverage.wire_up_filter();
307
+ coverage.wire_up_sorting();
308
+
309
+ on_click(".button_prev_file", coverage.to_prev_file);
310
+ on_click(".button_next_file", coverage.to_next_file);
311
+
312
+ on_click(".button_show_hide_help", coverage.show_hide_help);
313
+ };
314
+
315
+ // -- pyfile stuff --
316
+
317
+ coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS";
318
+
319
+ coverage.pyfile_ready = function () {
320
+ // If we're directed to a particular line number, highlight the line.
321
+ var frag = location.hash;
322
+ if (frag.length > 2 && frag[1] === "t") {
323
+ document.querySelector(frag).closest(".n").classList.add("highlight");
324
+ coverage.set_sel(parseInt(frag.substr(2), 10));
325
+ }
326
+ else {
327
+ coverage.set_sel(0);
328
+ }
329
+
330
+ on_click(".button_toggle_run", coverage.toggle_lines);
331
+ on_click(".button_toggle_mis", coverage.toggle_lines);
332
+ on_click(".button_toggle_exc", coverage.toggle_lines);
333
+ on_click(".button_toggle_par", coverage.toggle_lines);
334
+
335
+ on_click(".button_next_chunk", coverage.to_next_chunk_nicely);
336
+ on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely);
337
+ on_click(".button_top_of_page", coverage.to_top);
338
+ on_click(".button_first_chunk", coverage.to_first_chunk);
339
+
340
+ on_click(".button_prev_file", coverage.to_prev_file);
341
+ on_click(".button_next_file", coverage.to_next_file);
342
+ on_click(".button_to_index", coverage.to_index);
343
+
344
+ on_click(".button_show_hide_help", coverage.show_hide_help);
345
+
346
+ coverage.filters = undefined;
347
+ try {
348
+ coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE);
349
+ } catch(err) {}
350
+
351
+ if (coverage.filters) {
352
+ coverage.filters = JSON.parse(coverage.filters);
353
+ }
354
+ else {
355
+ coverage.filters = {run: false, exc: true, mis: true, par: true};
356
+ }
357
+
358
+ for (cls in coverage.filters) {
359
+ coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection
360
+ }
361
+
362
+ coverage.assign_shortkeys();
363
+ coverage.init_scroll_markers();
364
+ coverage.wire_up_sticky_header();
365
+
366
+ document.querySelectorAll("[id^=ctxs]").forEach(
367
+ cbox => cbox.addEventListener("click", coverage.expand_contexts)
368
+ );
369
+
370
+ // Rebuild scroll markers when the window height changes.
371
+ window.addEventListener("resize", coverage.build_scroll_markers);
372
+ };
373
+
374
+ coverage.toggle_lines = function (event) {
375
+ const btn = event.target.closest("button");
376
+ const category = btn.value
377
+ const show = !btn.classList.contains("show_" + category);
378
+ coverage.set_line_visibilty(category, show);
379
+ coverage.build_scroll_markers();
380
+ coverage.filters[category] = show;
381
+ try {
382
+ localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters));
383
+ } catch(err) {}
384
+ };
385
+
386
+ coverage.set_line_visibilty = function (category, should_show) {
387
+ const cls = "show_" + category;
388
+ const btn = document.querySelector(".button_toggle_" + category);
389
+ if (btn) {
390
+ if (should_show) {
391
+ document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls));
392
+ btn.classList.add(cls);
393
+ }
394
+ else {
395
+ document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls));
396
+ btn.classList.remove(cls);
397
+ }
398
+ }
399
+ };
400
+
401
+ // Return the nth line div.
402
+ coverage.line_elt = function (n) {
403
+ return document.getElementById("t" + n)?.closest("p");
404
+ };
405
+
406
+ // Set the selection. b and e are line numbers.
407
+ coverage.set_sel = function (b, e) {
408
+ // The first line selected.
409
+ coverage.sel_begin = b;
410
+ // The next line not selected.
411
+ coverage.sel_end = (e === undefined) ? b+1 : e;
412
+ };
413
+
414
+ coverage.to_top = function () {
415
+ coverage.set_sel(0, 1);
416
+ coverage.scroll_window(0);
417
+ };
418
+
419
+ coverage.to_first_chunk = function () {
420
+ coverage.set_sel(0, 1);
421
+ coverage.to_next_chunk();
422
+ };
423
+
424
+ coverage.to_prev_file = function () {
425
+ window.location = document.getElementById("prevFileLink").href;
426
+ }
427
+
428
+ coverage.to_next_file = function () {
429
+ window.location = document.getElementById("nextFileLink").href;
430
+ }
431
+
432
+ coverage.to_index = function () {
433
+ location.href = document.getElementById("indexLink").href;
434
+ }
435
+
436
+ coverage.show_hide_help = function () {
437
+ const helpCheck = document.getElementById("help_panel_state")
438
+ helpCheck.checked = !helpCheck.checked;
439
+ }
440
+
441
+ // Return a string indicating what kind of chunk this line belongs to,
442
+ // or null if not a chunk.
443
+ coverage.chunk_indicator = function (line_elt) {
444
+ const classes = line_elt?.className;
445
+ if (!classes) {
446
+ return null;
447
+ }
448
+ const match = classes.match(/\bshow_\w+\b/);
449
+ if (!match) {
450
+ return null;
451
+ }
452
+ return match[0];
453
+ };
454
+
455
+ coverage.to_next_chunk = function () {
456
+ const c = coverage;
457
+
458
+ // Find the start of the next colored chunk.
459
+ var probe = c.sel_end;
460
+ var chunk_indicator, probe_line;
461
+ while (true) {
462
+ probe_line = c.line_elt(probe);
463
+ if (!probe_line) {
464
+ return;
465
+ }
466
+ chunk_indicator = c.chunk_indicator(probe_line);
467
+ if (chunk_indicator) {
468
+ break;
469
+ }
470
+ probe++;
471
+ }
472
+
473
+ // There's a next chunk, `probe` points to it.
474
+ var begin = probe;
475
+
476
+ // Find the end of this chunk.
477
+ var next_indicator = chunk_indicator;
478
+ while (next_indicator === chunk_indicator) {
479
+ probe++;
480
+ probe_line = c.line_elt(probe);
481
+ next_indicator = c.chunk_indicator(probe_line);
482
+ }
483
+ c.set_sel(begin, probe);
484
+ c.show_selection();
485
+ };
486
+
487
+ coverage.to_prev_chunk = function () {
488
+ const c = coverage;
489
+
490
+ // Find the end of the prev colored chunk.
491
+ var probe = c.sel_begin-1;
492
+ var probe_line = c.line_elt(probe);
493
+ if (!probe_line) {
494
+ return;
495
+ }
496
+ var chunk_indicator = c.chunk_indicator(probe_line);
497
+ while (probe > 1 && !chunk_indicator) {
498
+ probe--;
499
+ probe_line = c.line_elt(probe);
500
+ if (!probe_line) {
501
+ return;
502
+ }
503
+ chunk_indicator = c.chunk_indicator(probe_line);
504
+ }
505
+
506
+ // There's a prev chunk, `probe` points to its last line.
507
+ var end = probe+1;
508
+
509
+ // Find the beginning of this chunk.
510
+ var prev_indicator = chunk_indicator;
511
+ while (prev_indicator === chunk_indicator) {
512
+ probe--;
513
+ if (probe <= 0) {
514
+ return;
515
+ }
516
+ probe_line = c.line_elt(probe);
517
+ prev_indicator = c.chunk_indicator(probe_line);
518
+ }
519
+ c.set_sel(probe+1, end);
520
+ c.show_selection();
521
+ };
522
+
523
+ // Returns 0, 1, or 2: how many of the two ends of the selection are on
524
+ // the screen right now?
525
+ coverage.selection_ends_on_screen = function () {
526
+ if (coverage.sel_begin === 0) {
527
+ return 0;
528
+ }
529
+
530
+ const begin = coverage.line_elt(coverage.sel_begin);
531
+ const end = coverage.line_elt(coverage.sel_end-1);
532
+
533
+ return (
534
+ (checkVisible(begin) ? 1 : 0)
535
+ + (checkVisible(end) ? 1 : 0)
536
+ );
537
+ };
538
+
539
+ coverage.to_next_chunk_nicely = function () {
540
+ if (coverage.selection_ends_on_screen() === 0) {
541
+ // The selection is entirely off the screen:
542
+ // Set the top line on the screen as selection.
543
+
544
+ // This will select the top-left of the viewport
545
+ // As this is most likely the span with the line number we take the parent
546
+ const line = document.elementFromPoint(0, 0).parentElement;
547
+ if (line.parentElement !== document.getElementById("source")) {
548
+ // The element is not a source line but the header or similar
549
+ coverage.select_line_or_chunk(1);
550
+ }
551
+ else {
552
+ // We extract the line number from the id
553
+ coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10));
554
+ }
555
+ }
556
+ coverage.to_next_chunk();
557
+ };
558
+
559
+ coverage.to_prev_chunk_nicely = function () {
560
+ if (coverage.selection_ends_on_screen() === 0) {
561
+ // The selection is entirely off the screen:
562
+ // Set the lowest line on the screen as selection.
563
+
564
+ // This will select the bottom-left of the viewport
565
+ // As this is most likely the span with the line number we take the parent
566
+ const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement;
567
+ if (line.parentElement !== document.getElementById("source")) {
568
+ // The element is not a source line but the header or similar
569
+ coverage.select_line_or_chunk(coverage.lines_len);
570
+ }
571
+ else {
572
+ // We extract the line number from the id
573
+ coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10));
574
+ }
575
+ }
576
+ coverage.to_prev_chunk();
577
+ };
578
+
579
+ // Select line number lineno, or if it is in a colored chunk, select the
580
+ // entire chunk
581
+ coverage.select_line_or_chunk = function (lineno) {
582
+ var c = coverage;
583
+ var probe_line = c.line_elt(lineno);
584
+ if (!probe_line) {
585
+ return;
586
+ }
587
+ var the_indicator = c.chunk_indicator(probe_line);
588
+ if (the_indicator) {
589
+ // The line is in a highlighted chunk.
590
+ // Search backward for the first line.
591
+ var probe = lineno;
592
+ var indicator = the_indicator;
593
+ while (probe > 0 && indicator === the_indicator) {
594
+ probe--;
595
+ probe_line = c.line_elt(probe);
596
+ if (!probe_line) {
597
+ break;
598
+ }
599
+ indicator = c.chunk_indicator(probe_line);
600
+ }
601
+ var begin = probe + 1;
602
+
603
+ // Search forward for the last line.
604
+ probe = lineno;
605
+ indicator = the_indicator;
606
+ while (indicator === the_indicator) {
607
+ probe++;
608
+ probe_line = c.line_elt(probe);
609
+ indicator = c.chunk_indicator(probe_line);
610
+ }
611
+
612
+ coverage.set_sel(begin, probe);
613
+ }
614
+ else {
615
+ coverage.set_sel(lineno);
616
+ }
617
+ };
618
+
619
+ coverage.show_selection = function () {
620
+ // Highlight the lines in the chunk
621
+ document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight"));
622
+ for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) {
623
+ coverage.line_elt(probe).querySelector(".n").classList.add("highlight");
624
+ }
625
+
626
+ coverage.scroll_to_selection();
627
+ };
628
+
629
+ coverage.scroll_to_selection = function () {
630
+ // Scroll the page if the chunk isn't fully visible.
631
+ if (coverage.selection_ends_on_screen() < 2) {
632
+ const element = coverage.line_elt(coverage.sel_begin);
633
+ coverage.scroll_window(element.offsetTop - 60);
634
+ }
635
+ };
636
+
637
+ coverage.scroll_window = function (to_pos) {
638
+ window.scroll({top: to_pos, behavior: "smooth"});
639
+ };
640
+
641
+ coverage.init_scroll_markers = function () {
642
+ // Init some variables
643
+ coverage.lines_len = document.querySelectorAll("#source > p").length;
644
+
645
+ // Build html
646
+ coverage.build_scroll_markers();
647
+ };
648
+
649
+ coverage.build_scroll_markers = function () {
650
+ const temp_scroll_marker = document.getElementById("scroll_marker")
651
+ if (temp_scroll_marker) temp_scroll_marker.remove();
652
+ // Don't build markers if the window has no scroll bar.
653
+ if (document.body.scrollHeight <= window.innerHeight) {
654
+ return;
655
+ }
656
+
657
+ const marker_scale = window.innerHeight / document.body.scrollHeight;
658
+ const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10);
659
+
660
+ let previous_line = -99, last_mark, last_top;
661
+
662
+ const scroll_marker = document.createElement("div");
663
+ scroll_marker.id = "scroll_marker";
664
+ document.getElementById("source").querySelectorAll(
665
+ "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par"
666
+ ).forEach(element => {
667
+ const line_top = Math.floor(element.offsetTop * marker_scale);
668
+ const line_number = parseInt(element.querySelector(".n a").id.substr(1));
669
+
670
+ if (line_number === previous_line + 1) {
671
+ // If this solid missed block just make previous mark higher.
672
+ last_mark.style.height = `${line_top + line_height - last_top}px`;
673
+ }
674
+ else {
675
+ // Add colored line in scroll_marker block.
676
+ last_mark = document.createElement("div");
677
+ last_mark.id = `m${line_number}`;
678
+ last_mark.classList.add("marker");
679
+ last_mark.style.height = `${line_height}px`;
680
+ last_mark.style.top = `${line_top}px`;
681
+ scroll_marker.append(last_mark);
682
+ last_top = line_top;
683
+ }
684
+
685
+ previous_line = line_number;
686
+ });
687
+
688
+ // Append last to prevent layout calculation
689
+ document.body.append(scroll_marker);
690
+ };
691
+
692
+ coverage.wire_up_sticky_header = function () {
693
+ const header = document.querySelector("header");
694
+ const header_bottom = (
695
+ header.querySelector(".content h2").getBoundingClientRect().top -
696
+ header.getBoundingClientRect().top
697
+ );
698
+
699
+ function updateHeader() {
700
+ if (window.scrollY > header_bottom) {
701
+ header.classList.add("sticky");
702
+ }
703
+ else {
704
+ header.classList.remove("sticky");
705
+ }
706
+ }
707
+
708
+ window.addEventListener("scroll", updateHeader);
709
+ updateHeader();
710
+ };
711
+
712
+ coverage.expand_contexts = function (e) {
713
+ var ctxs = e.target.parentNode.querySelector(".ctxs");
714
+
715
+ if (!ctxs.classList.contains("expanded")) {
716
+ var ctxs_text = ctxs.textContent;
717
+ var width = Number(ctxs_text[0]);
718
+ ctxs.textContent = "";
719
+ for (var i = 1; i < ctxs_text.length; i += width) {
720
+ key = ctxs_text.substring(i, i + width).trim();
721
+ ctxs.appendChild(document.createTextNode(contexts[key]));
722
+ ctxs.appendChild(document.createElement("br"));
723
+ }
724
+ ctxs.classList.add("expanded");
725
+ }
726
+ };
727
+
728
+ document.addEventListener("DOMContentLoaded", () => {
729
+ if (document.body.classList.contains("indexfile")) {
730
+ coverage.index_ready();
731
+ }
732
+ else {
733
+ coverage.pyfile_ready();
734
+ }
735
+ });