diff --git a/strictdoc/export/html/generators/source_file_view_generator.py b/strictdoc/export/html/generators/source_file_view_generator.py index de36ccde1..ac485ce19 100644 --- a/strictdoc/export/html/generators/source_file_view_generator.py +++ b/strictdoc/export/html/generators/source_file_view_generator.py @@ -1,5 +1,5 @@ # mypy: disable-error-code="no-untyped-call,no-untyped-def,operator" -from typing import List, Tuple +from typing import List, Tuple, Union from markupsafe import Markup, escape from pygments import highlight @@ -28,10 +28,13 @@ from strictdoc.core.traceability_index import TraceabilityIndex from strictdoc.export.html.generators.view_objects.source_file_view_object import ( SourceFileViewObject, + SourceLineEntry, + SourceMarkerTuple, ) 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: @@ -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: @@ -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) @@ -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] = "" @@ -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 @@ -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, @@ -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) diff --git a/strictdoc/export/html/generators/view_objects/source_file_view_object.py b/strictdoc/export/html/generators/view_objects/source_file_view_object.py index 9ff0dbbb8..d5dea0060 100644 --- a/strictdoc/export/html/generators/view_objects/source_file_view_object.py +++ b/strictdoc/export/html/generators/view_objects/source_file_view_object.py @@ -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 @@ -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__( @@ -26,7 +43,7 @@ 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 @@ -34,7 +51,7 @@ def __init__( 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 ) diff --git a/strictdoc/export/html/templates/screens/source_file_view/main.jinja b/strictdoc/export/html/templates/screens/source_file_view/main.jinja index 1e627a751..52a5696ae 100644 --- a/strictdoc/export/html/templates/screens/source_file_view/main.jinja +++ b/strictdoc/export/html/templates/screens/source_file_view/main.jinja @@ -6,7 +6,7 @@ {%- for line in view_object.pygmented_source_file_lines -%}
{{ loop.index }}
- {%- 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! #}
{{ replacement_before }}{%- for req in pragma.reqs_objs -%}