diff --git a/docs/example.md b/docs/example.md index a9e4518..dd8ac02 100644 --- a/docs/example.md +++ b/docs/example.md @@ -142,13 +142,13 @@ The below is reST-style math-block. ### Include Markdown file -To include markdown file: +To include a markdown file: ```rest .. mdinclude:: path-to-file.md ``` -To include markdown file with specific lines: +To include a markdown file with a specific start and end line: ```rest .. mdinclude:: included.md @@ -156,23 +156,61 @@ To include markdown file with specific lines: :end-line: -2 ``` -Original ``included.md`` file is: +The original ``included.md`` file is: .. include:: included.md :code: md -This file included as: +This file is included as: ```md #### Include this line ``` -and results in HTML as below: +and the results in HTML are as shown below: .. mdinclude:: included.md :start-line: 2 :end-line: -2 +To include a markdown file with specific line ranges: + +```rest +.. mdinclude:: line_inclusion.md + :lines: 1, 3-4, 7- +``` + +The original ``line_inclusion.md`` file is: + +.. include:: line_inclusion.md + :code: md + +And the resulting HTML output is: + +.. mdinclude:: line_inclusion.md + :lines: 1, 3-4, 7- + + +To include a markdown file by specific text: + +```rest +.. mdinclude:: text_inclusion.md + :start-after: Start Here + :end-before: End Here +``` + +The original ``text_inclusion.md`` file is: + +.. include:: text_inclusion.md + :code: md + +And the resulting HTML output is: + +.. mdinclude:: text_inclusion.md + :start-after: Start Here + :end-before: End Here + + ### Footnote Footnote[^1] and footnote[^key] with markdown. diff --git a/docs/line_inclusion.md b/docs/line_inclusion.md new file mode 100644 index 0000000..36c1184 --- /dev/null +++ b/docs/line_inclusion.md @@ -0,0 +1,9 @@ +#### Include +#### Skip +#### Include +#### Include +#### Skip +#### Skip +#### Include +#### Include +#### Include \ No newline at end of file diff --git a/docs/text_inclusion.md b/docs/text_inclusion.md new file mode 100644 index 0000000..1bfe6cb --- /dev/null +++ b/docs/text_inclusion.md @@ -0,0 +1,14 @@ +#### Skip +#### Skip + +#### Start Here +#### Include + +#### Include +#### Include +#### Include +#### End Here (Skip) + +#### Skip +#### Skip +#### Skip \ No newline at end of file diff --git a/m2r.py b/m2r.py index a4e43c2..7832093 100644 --- a/m2r.py +++ b/m2r.py @@ -58,17 +58,17 @@ def parse_options(): class RestBlockGrammar(mistune.BlockGrammar): directive = re.compile( - r'^( *\.\..*?)\n(?=\S)', - re.DOTALL | re.MULTILINE, - ) + r'^( *\.\..*?)\n(?=\S)', + re.DOTALL | re.MULTILINE, + ) oneline_directive = re.compile( - r'^( *\.\..*?)$', - re.DOTALL | re.MULTILINE, - ) + r'^( *\.\..*?)$', + re.DOTALL | re.MULTILINE, + ) rest_code_block = re.compile( - r'^::\s*$', - re.DOTALL | re.MULTILINE, - ) + r'^::\s*$', + re.DOTALL | re.MULTILINE, + ) class RestBlockLexer(mistune.BlockLexer): @@ -483,6 +483,7 @@ def footnotes(self, text): return '' """Below outputs are for rst.""" + def image_link(self, url, target, alt): return '\n'.join([ '', @@ -575,6 +576,9 @@ class MdInclude(rst.Directive): option_spec = { 'start-line': int, 'end-line': int, + 'lines': str, + 'start-after': str, + 'end-before': str, } def run(self): @@ -614,19 +618,55 @@ def run(self): raise self.severe('Problems with "%s" directive path:\n%s.' % (self.name, ErrorString(error))) - # read from the file - startline = self.options.get('start-line', None) - endline = self.options.get('end-line', None) + # get all of the lines and reduce as needed try: - if startline or (endline is not None): - lines = include_file.readlines() - rawtext = ''.join(lines[startline:endline]) - else: - rawtext = include_file.read() + lines = include_file.readlines() + line_count = len(lines) except UnicodeError as error: raise self.severe('Problem with "%s" directive:\n%s' % (self.name, ErrorString(error))) + # read from the file + start_line = self.options.get('start-line', 1) - 1 + end_line = self.options.get('end-line', line_count) + line_ranges = self.options.get('lines', None) + start_marker = self.options.get('start-after', None) + end_marker = self.options.get('end-before', None) + + if start_marker: + for i, line in enumerate(lines[start_line:end_line], start_line): + if start_marker in line: + if i > start_line: + start_line = i + break + if i == len(lines): + start_line = i + + if end_marker: + for i, line in enumerate(lines[start_line:end_line], start_line): + if end_marker in line: + if i < end_line: + end_line = i + break + + keep = set(range(start_line, end_line)) + + if line_ranges: + keep_line_ranges = set() + line_range_list = line_ranges.split(',') + for line_range in line_range_list: + endpoints = [int(number) if len(number) else len(lines) + for number in line_range.split('-', 1)] + if len(endpoints) > 1: + keep_line_ranges.update( + set(range(endpoints[0]-1, endpoints[1]))) + else: + keep_line_ranges.add(endpoints[0]-1) + keep = keep.intersection(keep_line_ranges) + + lines = [lines[i] for i in sorted(keep)] + rawtext = ''.join(lines) + config = self.state.document.settings.env.config converter = M2R( no_underscore_emphasis=config.no_underscore_emphasis,