From 2d8a06a59aa2e8a3cd338589777bb348dedf4c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 24 Jul 2021 22:45:10 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20specifyin?= =?UTF-8?q?g=20lines=20and=20line=20ranges?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- markdown_include/include.py | 46 ++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/markdown_include/include.py b/markdown_include/include.py index 5463cd5..fc60b37 100644 --- a/markdown_include/include.py +++ b/markdown_include/include.py @@ -29,7 +29,7 @@ from markdown.extensions import Extension from markdown.preprocessors import Preprocessor -INC_SYNTAX = re.compile(r'\{!\s*(.+?)\s*!\}') +INC_SYNTAX = re.compile(r'{!\s*(.+?)\s*!((\blines\b)=([0-9 -]+))?\}') HEADING_SYNTAX = re.compile( '^#+' ) @@ -91,7 +91,7 @@ def run(self, lines): ) try: with open(filename, 'r', encoding=self.encoding) as r: - text = r.readlines() + original_text = r.readlines() except Exception as e: if not self.throwException: @@ -101,6 +101,46 @@ def run(self, lines): break else: raise e + if m.group(2) is None: + text = original_text + else: + lines_str = m.group(4) + lines_blocks = lines_str.split() + wanted_lines = [] + for block in lines_blocks: + if "-" in block: + start, end = block.strip().split("-") + current_start = int(start) + current_end = int(end) + if not len(original_text) >= current_end: + current_end = len(original_text) + print( + f"Warning: line range: {block} ending in " + f"line: {end} is larger than file: {filename} " + f"using end: {current_end}" + ) + if not current_start <= current_end: + current_start = max(current_end - 1, 1) + print( + f"Warning: in line range: {block} " + f"the start line: {start} is not " + f"smaller than the end line: {current_end} " + f"using start: {current_start}" + ) + + wanted_lines.extend(original_text[current_start-1:current_end]) + else: + wanted_line = int(block.strip()) + current_line = wanted_line + if current_line > len(original_text): + current_line = len(original_text) + print( + f"Warning: line: {wanted_line} is larger than " + f"file: {filename} using end: {current_line}" + ) + wanted_lines.append(original_text[current_line-1]) + text = wanted_lines + line_split = INC_SYNTAX.split(line) if len(text) == 0: @@ -118,7 +158,7 @@ def run(self, lines): text[i] = text[i].rstrip('\r\n') text[0] = line_split[0] + text[0] - text[-1] = text[-1] + line_split[2] + text[-1] = text[-1] + line_split[5] lines = lines[:loc] + text + lines[loc+1:] break From e2ac6c7dc94c988b95db18de167717d180383842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 24 Jul 2021 22:45:37 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9D=20Update=20README=20with=20new?= =?UTF-8?q?=20configs=20for=20lines=20and=20line=20ranges?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index ea9cc54..6f576c5 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,30 @@ Markdown is being called. If you would like to change the directory relative to which paths are evaluated, then this can be done by specifying the extension setting ``base_path``. +### Line Ranges + +You can also define specific lines or line ranges to include by specifying `lines`: + +```Markdown +{!filename!lines=1 3 8-10 2} +``` + +`lines` takes a sequence of integers separated by spaces (one or more), or it can also +take line ranges specified with a start line and an end line separated by a dash (`-`). + +In the example above, it would read the file called `filename` and include the lines +`1`, `3`, `8`, `9`, `10`, `2`. + +Notice that line `9` was not explicitly set. But it was still included as part of the +range `8-10`. + +Also, notice that line `2` is set *after* the range `8-10`. This means that the +line `2` in `filename` will be included *after* (below) the range `8-10`. + +You can use this to include lines in a different order than the original file. But it +also means that if you want to preserve the original order, you have to pay attention +to the order in which you specify the lines. + ## Configuration The following settings can be specified when initialising the plugin. From f5e754d72d1ca58771435b5a93c8c722f6af70d9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 23 Nov 2022 17:43:42 +0000 Subject: [PATCH 3/3] Add tests for including lines --- tests/resources/longer.md | 8 +++++++ tests/test_include.py | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/resources/longer.md diff --git a/tests/resources/longer.md b/tests/resources/longer.md new file mode 100644 index 0000000..83e7a35 --- /dev/null +++ b/tests/resources/longer.md @@ -0,0 +1,8 @@ +This is line 1 +This is line 2 +This is line 3 +This is line 4 +This is line 5 +This is line 6 +This is line 7 +This is line 8 diff --git a/tests/test_include.py b/tests/test_include.py index d9ba59e..04118d3 100644 --- a/tests/test_include.py +++ b/tests/test_include.py @@ -142,3 +142,51 @@ def test_processor_lines(): result_lines = processor.run(source) assert len(result_lines) == 9 + + +def test_include_lines(markdown_include): + source = "{!resources/longer.md!lines=1 3}" + html = markdown.markdown(source, extensions=[markdown_include]) + + assert html == dedent( + """\ +

This is line 1 + This is line 3

""" + ) + + +def test_include_line_range(markdown_include): + source = "{!resources/longer.md!lines=3-5}" + html = markdown.markdown(source, extensions=[markdown_include]) + + assert html == dedent( + """\ +

This is line 3 + This is line 4 + This is line 5

""" + ) + + +def test_include_lines_and_line_range(markdown_include): + source = "{!resources/longer.md!lines=1 3-5 8}" + html = markdown.markdown(source, extensions=[markdown_include]) + + assert html == dedent( + """\ +

This is line 1 + This is line 3 + This is line 4 + This is line 5 + This is line 8

""" + ) + + +def test_include_lines_out_of_order(markdown_include): + source = "{!resources/longer.md!lines=3 1}" + html = markdown.markdown(source, extensions=[markdown_include]) + + assert html == dedent( + """\ +

This is line 3 + This is line 1

""" + )