Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add keyboard shortcuts #1364

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 55 additions & 6 deletions coverage/html.py
Expand Up @@ -165,6 +165,8 @@ def __init__(self, cov):
self.datagen = HtmlDataGeneration(self.coverage)
self.totals = Numbers(precision=self.config.precision)
self.directory_was_empty = False
self.first_fr = None
self.final_fr = None

self.template_globals = {
# Functions available in the templates.
Expand Down Expand Up @@ -204,9 +206,29 @@ def report(self, morfs):
self.incr.read()
self.incr.check_global_data(self.config, self.pyfile_html_source)

# Process all the files.
for fr, analysis in get_analysis_to_report(self.coverage, morfs):
self.html_file(fr, analysis)
# Process all the files. For each page we need to supply a link
# to the next page. Therefore in each iteration of the loop we
# work on the fr and analysis from the previous iteration. We
# also need a link to the preceding page (i.e. 2 before the
# current iteration).
analysis_to_report = get_analysis_to_report(self.coverage, morfs)
pluprev_fr, prev_fr = None, None
prev_analysis = None

for fr, analysis in analysis_to_report:
if prev_fr is not None:
self.html_file(prev_fr, prev_analysis, pluprev_fr, fr)
else:
# This is the first file processed
self.first_fr = fr
pluprev_fr, prev_fr, prev_analysis = prev_fr, fr, analysis

# One more iteration for the final file. (Or not, if there are
# no files at all.)
if prev_fr is not None:
self.html_file(prev_fr, prev_analysis, pluprev_fr, None)
# This is the last file processed
self.final_fr = prev_fr

if not self.all_files_nums:
raise NoDataError("No data to report.")
Expand Down Expand Up @@ -236,10 +258,21 @@ def make_local_static_report_files(self):
if self.extra_css:
shutil.copyfile(self.config.extra_css, os.path.join(self.directory, self.extra_css))

def html_file(self, fr, analysis):
"""Generate an HTML file for one source file."""
def html_file(self, fr, analysis, prev_fr=None, next_fr=None):
"""Generate an HTML file for one source file, with links to the
previous and the next file, or to the index."""
rootname = flat_rootname(fr.relative_filename())
html_filename = rootname + ".html"
if prev_fr is not None:
prev_html = flat_rootname(prev_fr.relative_filename()) + ".html"
else:
prev_html = "index.html"

if next_fr is not None:
next_html = flat_rootname(next_fr.relative_filename()) + ".html"
else:
next_html = "index.html"

ensure_dir(self.directory)
if not os.listdir(self.directory):
self.directory_was_empty = True
Expand Down Expand Up @@ -316,7 +349,11 @@ def html_file(self, fr, analysis):
css_classes.append(self.template_globals['category'][ldata.category])
ldata.css_class = ' '.join(css_classes) or "pln"

html = self.source_tmpl.render(file_data.__dict__)
html = self.source_tmpl.render({
**file_data.__dict__,
'prev_html': prev_html,
'next_html': next_html,
})
write_html(html_path, html)

# Save this file's information for the index file.
Expand All @@ -340,11 +377,23 @@ def index_file(self):
n = self.skipped_empty_count
skipped_empty_msg = f"{n} empty file{plural(n)} skipped."

if self.first_fr is not None:
first_html = flat_rootname(self.first_fr.relative_filename()) + ".html"
else:
first_html = "index.html"

if self.final_fr is not None:
final_html = flat_rootname(self.final_fr.relative_filename()) + ".html"
else:
final_html = "index.html"

html = index_tmpl.render({
'files': self.file_summaries,
'totals': self.totals,
'skipped_covered_msg': skipped_covered_msg,
'skipped_empty_msg': skipped_empty_msg,
'first_html': first_html,
'final_html': final_html,
})

index_file = os.path.join(self.directory, "index.html")
Expand Down
41 changes: 35 additions & 6 deletions coverage/htmlfiles/coverage_html.js
Expand Up @@ -25,6 +25,13 @@ function checkVisible(element) {
return !(rect.bottom < viewTop || rect.top >= viewBottom);
}

function on_click(sel, fn) {
const elt = document.querySelector(sel);
if (elt) {
elt.addEventListener("click", fn);
}
}

// Helpers for table sorting
function getCellValue(row, column = 0) {
const cell = row.cells[column]
Expand Down Expand Up @@ -193,6 +200,11 @@ coverage.index_ready = function () {
direction: th.getAttribute("aria-sort"),
}));
});

on_click(".button_prev_file", coverage.to_prev_file);
on_click(".button_next_file", coverage.to_next_file);

on_click(".button_show_hide_help", coverage.show_hide_help);
};

// -- pyfile stuff --
Expand All @@ -209,12 +221,6 @@ coverage.pyfile_ready = function () {
coverage.set_sel(0);
}

const on_click = function(sel, fn) {
const elt = document.querySelector(sel);
if (elt) {
elt.addEventListener("click", fn);
}
}
on_click(".button_toggle_run", coverage.toggle_lines);
on_click(".button_toggle_mis", coverage.toggle_lines);
on_click(".button_toggle_exc", coverage.toggle_lines);
Expand All @@ -225,6 +231,12 @@ coverage.pyfile_ready = function () {
on_click(".button_top_of_page", coverage.to_top);
on_click(".button_first_chunk", coverage.to_first_chunk);

on_click(".button_prev_file", coverage.to_prev_file);
on_click(".button_next_file", coverage.to_next_file);
on_click(".button_to_index", coverage.to_index);

on_click(".button_show_hide_help", coverage.show_hide_help);

coverage.filters = undefined;
try {
coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE);
Expand Down Expand Up @@ -299,6 +311,23 @@ coverage.to_first_chunk = function () {
coverage.to_next_chunk();
};

coverage.to_prev_file = function () {
window.location = document.getElementById("prevFileLink").href;
}

coverage.to_next_file = function () {
window.location = document.getElementById("nextFileLink").href;
}

coverage.to_index = function () {
location.href = document.getElementById("indexLink").href;
}

coverage.show_hide_help = function () {
const helpCheck = document.getElementById("help_panel_state")
helpCheck.checked = !helpCheck.checked;
}

// Return a string indicating what kind of chunk this line belongs to,
// or null if not a chunk.
coverage.chunk_indicator = function (line_elt) {
Expand Down
17 changes: 17 additions & 0 deletions coverage/htmlfiles/index.html
Expand Up @@ -40,6 +40,14 @@ <h1>{{ title|escape }}:
{% endif %}
<kbd>c</kbd> &nbsp; change column sorting
</p>
<p class="keyhelp">
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p class="keyhelp">
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</div>
Expand Down Expand Up @@ -115,6 +123,15 @@ <h1>{{ title|escape }}:
created at {{ time_stamp }}
</p>
</div>
<div style="display: none;">
<p>
<a id="prevFileLink" class="nav" href="{{ final_html }}">first file</a>
<a id="nextFileLink" class="nav" href="{{ first_html }}">final file</a>
</p>
<button type="button" class="button_prev_file" data-shortcut="[">Previous file</button>
<button type="button" class="button_next_file" data-shortcut="]">Next file</button>
<button type="button" class="button_show_hide_help" data-shortcut="?">Show/hide keyboard shortcuts</button>
</div>
</footer>

</body>
Expand Down
22 changes: 21 additions & 1 deletion coverage/htmlfiles/pyfile.html
Expand Up @@ -52,6 +52,17 @@ <h1>
<p class="keyhelp">
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p class="keyhelp">
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p class="keyhelp">
<kbd>u</kbd> &nbsp; back to the index
</p>
<p class="keyhelp">
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</div>
Expand All @@ -71,6 +82,10 @@ <h2>
<button type="button" class="button_prev_chunk" data-shortcut="k">Previous highlighted chunk</button>
<button type="button" class="button_top_of_page" data-shortcut="0">Goto top of page</button>
<button type="button" class="button_first_chunk" data-shortcut="1">Goto first highlighted chunk</button>
<button type="button" class="button_prev_file" data-shortcut="[">Previous file</button>
<button type="button" class="button_next_file" data-shortcut="]">Next file</button>
<button type="button" class="button_to_index" data-shortcut="u">Back to the index</button>
<button type="button" class="button_show_hide_help" data-shortcut="?">Show/hide keyboard shortcuts</button>
</div>
</div>
</header>
Expand Down Expand Up @@ -110,7 +125,12 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="{{__url__}}">coverage.py v{{__version__}}</a>,
<a id="prevFileLink" class="nav" href="{{ prev_html }}">&#xab; prev file</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="{{ next_html }}">&#xbb; next file</a>
</p>
<p>
<a class="nav" href="{{__url__}}">coverage.py v{{__version__}}</a>,
created at {{ time_stamp }}
</p>
</div>
Expand Down
24 changes: 22 additions & 2 deletions tests/gold/html/a/a_py.html
Expand Up @@ -39,6 +39,17 @@ <h1>
<p class="keyhelp">
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p class="keyhelp">
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p class="keyhelp">
<kbd>u</kbd> &nbsp; back to the index
</p>
<p class="keyhelp">
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</div>
Expand All @@ -53,6 +64,10 @@ <h2>
<button type="button" class="button_prev_chunk" data-shortcut="k">Previous highlighted chunk</button>
<button type="button" class="button_top_of_page" data-shortcut="0">Goto top of page</button>
<button type="button" class="button_first_chunk" data-shortcut="1">Goto first highlighted chunk</button>
<button type="button" class="button_prev_file" data-shortcut="[">Previous file</button>
<button type="button" class="button_next_file" data-shortcut="]">Next file</button>
<button type="button" class="button_to_index" data-shortcut="u">Back to the index</button>
<button type="button" class="button_show_hide_help" data-shortcut="?">Show/hide keyboard shortcuts</button>
</div>
</div>
</header>
Expand All @@ -66,8 +81,13 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/6.1.1a0">coverage.py v6.1.1a0</a>,
created at 2021-10-30 16:07 -0400
<a id="prevFileLink" class="nav" href="index.html">&#xab; prev file</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="index.html">&#xbb; next file</a>
</p>
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/6.3.3a0">coverage.py v6.3.3a0</a>,
created at 2022-04-25 21:07 +0100
</p>
</div>
</footer>
Expand Down
21 changes: 19 additions & 2 deletions tests/gold/html/a/index.html
Expand Up @@ -28,6 +28,14 @@ <h1>Coverage report:
<kbd>x</kbd>
<kbd>c</kbd> &nbsp; change column sorting
</p>
<p class="keyhelp">
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p class="keyhelp">
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</div>
Expand Down Expand Up @@ -73,9 +81,18 @@ <h1>Coverage report:
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/6.1a0">coverage.py v6.1a0</a>,
created at 2021-10-23 08:16 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/6.3.3a0">coverage.py v6.3.3a0</a>,
created at 2022-04-25 21:21 +0100
</p>
</div>
<div style="display: none;">
<p>
<a id="prevFileLink" class="nav" href="a_py.html">first file</a>
<a id="nextFileLink" class="nav" href="a_py.html">final file</a>
</p>
<button type="button" class="button_prev_file" data-shortcut="[">Previous file</button>
<button type="button" class="button_next_file" data-shortcut="]">Next file</button>
<button type="button" class="button_show_hide_help" data-shortcut="?">Show/hide keyboard shortcuts</button>
</div>
</footer>
</body>
Expand Down
24 changes: 22 additions & 2 deletions tests/gold/html/b_branch/b_py.html
Expand Up @@ -40,6 +40,17 @@ <h1>
<p class="keyhelp">
<kbd>1</kbd> &nbsp; (one) first highlighted chunk
</p>
<p class="keyhelp">
<kbd>[</kbd>
<kbd>]</kbd>
&nbsp; prev/next file
</p>
<p class="keyhelp">
<kbd>u</kbd> &nbsp; back to the index
</p>
<p class="keyhelp">
<kbd>?</kbd> &nbsp; show/hide this help
</p>
</div>
</div>
</div>
Expand All @@ -55,6 +66,10 @@ <h2>
<button type="button" class="button_prev_chunk" data-shortcut="k">Previous highlighted chunk</button>
<button type="button" class="button_top_of_page" data-shortcut="0">Goto top of page</button>
<button type="button" class="button_first_chunk" data-shortcut="1">Goto first highlighted chunk</button>
<button type="button" class="button_prev_file" data-shortcut="[">Previous file</button>
<button type="button" class="button_next_file" data-shortcut="]">Next file</button>
<button type="button" class="button_to_index" data-shortcut="u">Back to the index</button>
<button type="button" class="button_show_hide_help" data-shortcut="?">Show/hide keyboard shortcuts</button>
</div>
</div>
</header>
Expand Down Expand Up @@ -90,8 +105,13 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="index.html">&#xab; index</a> &nbsp; &nbsp; <a class="nav" href="https://coverage.readthedocs.io/en/6.1.1a0">coverage.py v6.1.1a0</a>,
created at 2021-10-30 16:07 -0400
<a id="prevFileLink" class="nav" href="index.html">&#xab; prev file</a> &nbsp; &nbsp;
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="index.html">&#xbb; next file</a>
</p>
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/6.3.3a0">coverage.py v6.3.3a0</a>,
created at 2022-04-25 21:07 +0100
</p>
</div>
</footer>
Expand Down