From 04f8d5f3093e1b13aa704590f4d0bf9dce6afce9 Mon Sep 17 00:00:00 2001 From: Christoph Schlosser Date: Fri, 19 Sep 2025 20:14:59 +0200 Subject: g2h: Make sure backticks in plaintext doesn't break page rendering --- README.md | 1 + mise.toml | 2 +- src/g2h/cli.py | 1 + src/g2h/file_page.py | 6 ++++++ templates/file.md | 5 +++-- test_repo/git.tgz | Bin 41560 -> 42639 bytes test_repo/test.md | 7 +++++++ tests/file_page_test.py | 12 ++++++++++++ 8 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 test_repo/test.md diff --git a/README.md b/README.md index 48767e8..4faac5f 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ For a full list of options, their defaults and how they're changing the behavior For binary files a note that it can't be displayed. - [x] Don't treat pictures as binary files. - [x] Breadcrumbs for navigating. + - [x] Escape markdown backticks in plaintext files. - [ ] Add button to download raw file. - [x] Nav bar for navigating the pages mentioned above. - [ ] Link to special readme, if a readme can be found, rendering markdown. diff --git a/mise.toml b/mise.toml index 4756681..c4444a8 100644 --- a/mise.toml +++ b/mise.toml @@ -9,7 +9,7 @@ run = "pip install -r requirements.txt" [tasks.run] description = "Run g2h with the test repo" alias = "r" -run = "rm -rf ./test_out && python3 -m g2h.cli test_repo test_out --name 'Test repo'" +run = "rm -rf ./test_out && python3 -m src.g2h.cli --repo test_repo --out test_out --name 'Test repo'" [tasks.test] alias = "t" diff --git a/src/g2h/cli.py b/src/g2h/cli.py index d61b71b..fe3850c 100644 --- a/src/g2h/cli.py +++ b/src/g2h/cli.py @@ -10,6 +10,7 @@ def parse_args(): description='Convert a git repository into markdown files Hugo can understand.') parser.add_argument('--repo', help='Path to the root of git repository', default=os.getcwd()) parser.add_argument('--out', help='Path to where the generated files should be stored', default=os.getcwd()) + # TODO: Add an actual default value. parser.add_argument('--name', help='Name of the project. Default: directory name of repo') parser.add_argument('--content-subdir', help='Subdir(s) where the page will be served from. Default: None', default='') diff --git a/src/g2h/file_page.py b/src/g2h/file_page.py index a558254..d64cb84 100644 --- a/src/g2h/file_page.py +++ b/src/g2h/file_page.py @@ -1,6 +1,7 @@ import base64 import filetype import os +import re from .file import generate_breadcrumbs, sanitize_file_name, tree_join from .page import Page @@ -35,8 +36,13 @@ class FilePage(Page): def context(self): file_bytes = self.read_file() content, file_type = bytes_to_content(file_bytes) + backtick_max = 2 + if file_type == 'text': + matches = re.findall('`+', content) + backtick_max = max(max(len(match) for match in matches) if matches else 0, backtick_max) return { + 'backtick_max': backtick_max + 1, 'breadcrumbs': generate_breadcrumbs(self.content_subdir, self.commit, os.path.join(self.file_path, self.file_name), self.tree.blobs), 'content': content, 'content_subdir': self.content_subdir, diff --git a/templates/file.md b/templates/file.md index e82f1c9..5f4dcbd 100644 --- a/templates/file.md +++ b/templates/file.md @@ -6,9 +6,10 @@ {% include '_breadcrumbs.md' %} {% if type == 'text' %} -```{{ file_extension }} +{% set backticks = '`' * backtick_max %} +{{ backticks }}{{ file_extension }} {{ content }} -``` +{{ backticks }} {% elif type == 'image' %} ![](data:image/png;base64,{{ content }}) {% elif type == 'empty' %} diff --git a/test_repo/git.tgz b/test_repo/git.tgz index bac5752..0377aeb 100644 Binary files a/test_repo/git.tgz and b/test_repo/git.tgz differ diff --git a/test_repo/test.md b/test_repo/test.md new file mode 100644 index 0000000..9e7e2bc --- /dev/null +++ b/test_repo/test.md @@ -0,0 +1,7 @@ +**Some text** + +```cc +#include +``` + +**Some more text** diff --git a/tests/file_page_test.py b/tests/file_page_test.py index 5bd2f6d..daa9b6c 100644 --- a/tests/file_page_test.py +++ b/tests/file_page_test.py @@ -60,6 +60,7 @@ def test_context_dot_file(): assert(context['title'] == 'file test: .file') assert(context['type'] == 'text') assert(context['breadcrumbs'] == '[/](/file/content/123/t/)/[.file](/file/content/123/t/_file)') + assert(context['backtick_max'] == 3) def test_bytes_to_content_text(): content, type = bytes_to_content('test'.encode()) @@ -82,3 +83,14 @@ def test_bytes_to_content_bin(): assert(content == None) assert(type == None) +def test_backticks_in_text_content(): + file = MagicMock() + tree = MagicMock() + commit = MagicMock() + commit.hexsha = '123' + commit.tree = tree + commit.tree.join.return_value = file + page = FilePage('test/file', 'file test', commit, '.file', '', 'file/content') + file.data_stream.read.return_value = '```'.encode() + context = page.context() + assert(context['backtick_max'] == 4) -- cgit v1.2.3