Skip to content

Commit

Permalink
Fix html escaping of source line marks
Browse files Browse the repository at this point in the history
SourceFileViewHTMLGenerator escaping code had multiple issues:

- When marking each line from range_start_pragma_processor as safe, we
  wrapped not only strings but also whole tuples in Markup().
- For tuple elements we didn't differentiate whether they from pygments
  (already escaped) or from source file (not yet escaped). Only the
  later must be explicitly escaped.

Some changes are there to make mypy happy.

Relates to strictdoc-project#1921.
  • Loading branch information
haxtibal committed Jul 26, 2024
1 parent fd2e364 commit b9ed7f7
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 16 deletions.
41 changes: 29 additions & 12 deletions strictdoc/export/html/generators/source_file_view_generator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# mypy: disable-error-code="no-untyped-call,no-untyped-def,operator"
from typing import List, Tuple
from typing import List, NamedTuple, Tuple, Union

from markupsafe import Markup, escape
from pygments import highlight
Expand Down Expand Up @@ -27,11 +27,14 @@
from strictdoc.core.project_config import ProjectConfig
from strictdoc.core.traceability_index import TraceabilityIndex
from strictdoc.export.html.generators.view_objects.source_file_view_object import (
SourceMarkerTuple,
SourceFileViewObject,
SourceLineEntry,
)
from strictdoc.export.html.html_templates import HTMLTemplates
from strictdoc.export.html.renderers.link_renderer import LinkRenderer
from strictdoc.export.html.renderers.markup_renderer import MarkupRenderer
from strictdoc.helpers.cast import assert_cast


class SourceFileViewHTMLGenerator:
Expand All @@ -46,7 +49,7 @@ def export(
with open(source_file.full_path, encoding="utf-8") as opened_file:
source_file_lines = opened_file.readlines()

pygmented_source_file_lines: List[Markup] = []
pygmented_source_file_lines: List[SourceLineEntry] = []
pygments_styles: Markup = Markup("")

if len(source_file_lines) > 0:
Expand Down Expand Up @@ -89,7 +92,10 @@ def get_pygmented_source_lines(
source_file: SourceFile,
source_file_lines: List[str],
coverage_info: SourceFileTraceabilityInfo,
) -> Tuple[List[Markup], Markup]:
) -> Tuple[
List[SourceLineEntry],
Markup,
]:
assert isinstance(source_file, SourceFile)
assert isinstance(source_file_lines, list)
assert isinstance(coverage_info, SourceFileTraceabilityInfo)
Expand Down Expand Up @@ -154,7 +160,9 @@ def get_pygmented_source_lines(
pygmented_source_file_content = pygmented_source_file_content[
slice_start:slice_end
]
pygmented_source_file_lines = pygmented_source_file_content.split("\n")
pygmented_source_file_lines: List[Union[str, SourceMarkerTuple]] = list(
pygmented_source_file_content.split("\n")
)
if hack_first_line:
pygmented_source_file_lines[0] = "<span></span>"

Expand All @@ -177,12 +185,14 @@ def get_pygmented_source_lines(

for pragma in coverage_info.pragmas:
pragma_line = pragma.ng_source_line_begin
assert isinstance(pragma_line, int)
pygmented_source_file_line = assert_cast(
pygmented_source_file_lines[pragma_line - 1], str
)
if isinstance(pragma, ForwardRangeMarker):
before_line = pygmented_source_file_line.rstrip("\n") + " "
pygmented_source_file_lines[pragma_line - 1] = (
pygmented_source_file_lines[pragma_line - 1].rstrip("\n")
+ " ",
"\n",
pragma,
SourceMarkerTuple(Markup(before_line), Markup("\n"), pragma)
)
continue

Expand All @@ -202,7 +212,7 @@ def get_pygmented_source_lines(
assert closing_bracket_index is not None
after_line = source_line[closing_bracket_index:].rstrip()

pygmented_source_file_lines[pragma_line - 1] = (
pygmented_source_file_lines[pragma_line - 1] = SourceMarkerTuple(
escape(before_line),
escape(after_line),
pragma,
Expand All @@ -212,6 +222,13 @@ def get_pygmented_source_lines(
+ html_formatter.get_style_defs(".highlight")
)

return list(map(Markup, pygmented_source_file_lines)), Markup(
pygments_styles
)
return [
SourceFileViewHTMLGenerator.mark_safe(line)
for line in pygmented_source_file_lines
], Markup(pygments_styles)

@staticmethod
def mark_safe(
line: Union[str, SourceMarkerTuple],
) -> Union[Markup, SourceMarkerTuple]:
return line if isinstance(line, SourceMarkerTuple) else Markup(line)
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# mypy: disable-error-code="no-any-return,no-untyped-call,no-untyped-def,union-attr"
from dataclasses import dataclass
from datetime import datetime
from typing import List
from typing import List, NamedTuple, Union

from markupsafe import Markup

from strictdoc import __version__
from strictdoc.backend.sdoc_source_code.models.range_marker import (
ForwardRangeMarker,
LineMarker,
RangeMarker,
)
from strictdoc.core.document_tree_iterator import DocumentTreeIterator
from strictdoc.core.finders.source_files_finder import SourceFile
from strictdoc.core.project_config import ProjectConfig
Expand All @@ -15,6 +20,18 @@
from strictdoc.export.html.renderers.markup_renderer import MarkupRenderer


class SourceMarkerTuple(NamedTuple):
before_line: Markup
after_line: Markup
pragma: Union[ForwardRangeMarker, LineMarker, RangeMarker]


SourceLineEntry = Union[
Markup,
SourceMarkerTuple,
]


@dataclass
class SourceFileViewObject:
def __init__(
Expand All @@ -26,15 +43,15 @@ def __init__(
markup_renderer: MarkupRenderer,
source_file: SourceFile,
pygments_styles: Markup,
pygmented_source_file_lines: List[Markup],
pygmented_source_file_lines: List[SourceLineEntry],
):
self.traceability_index: TraceabilityIndex = traceability_index
self.project_config: ProjectConfig = project_config
self.link_renderer: LinkRenderer = link_renderer
self.markup_renderer: MarkupRenderer = markup_renderer
self.source_file: SourceFile = source_file
self.pygments_styles: Markup = pygments_styles
self.pygmented_source_file_lines: List[Markup] = (
self.pygmented_source_file_lines: List[SourceLineEntry] = (
pygmented_source_file_lines
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{%- for line in view_object.pygmented_source_file_lines -%}
<div id="line-{{ loop.index }}" class="source__line-number"><pre>{{ loop.index }}</pre></div>
<div data-line={{ loop.index }} class="source__line-content">
{%- if line.__class__.__name__ == "tuple" -%}
{%- if line.__class__.__name__ == "SourceMarkerTuple" -%}
{%- set replacement_before, replacement_after, pragma = line -%}
{# Note: Cannot format HTML/Jinja blocks within 'pre' tags! #}
<pre class="sdoc-comment">{{ replacement_before }}{%- for req in pragma.reqs_objs -%}
Expand Down

0 comments on commit b9ed7f7

Please sign in to comment.