From b7681c73f5f9c55b806b2faf05a8f109c0f64163 Mon Sep 17 00:00:00 2001 From: pacien Date: Fri, 4 Mar 2022 16:49:50 +0100 Subject: [PATCH] viewport: accept and insert spacing lines below header This allows the presence of empty lines between the task list and the header in a viewport, which is especially desirable to abide by standard Markdown conventions. The header spacing of existing viewports is preserved. For new Markdown task lists, the spacing now follows the one configured in vimwiki with `g:vimwiki_markdown_header_style`. GitHub: closes #298 --- taskwiki/viewport.py | 33 ++++++++++++++++++++++++--------- tests/conftest.py | 6 +++--- tests/test_viewport.py | 25 +++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/taskwiki/viewport.py b/taskwiki/viewport.py index e9a12c8bb..33d588e64 100644 --- a/taskwiki/viewport.py +++ b/taskwiki/viewport.py @@ -325,6 +325,9 @@ def load_tasks(self): # Load all tasks below the viewport for i in range(self.line_number + 1, len(self.cache.buffer)): line = self.cache.buffer[i] + if not line: + continue + match = re.search(regexp.GENERIC_TASK, line) if match: @@ -367,15 +370,28 @@ def sync_with_taskwarrior(self): self.cache.remove_line(vimwikitask['line_number']) # Add the tasks that match the filter and are not listed - added_tasks = 0 existing_tasks = len(self.tasks) sorted_to_add = list(to_add) sorted_to_add.sort(key=lambda x: x['entry']) - for task in sorted_to_add: - added_tasks += 1 - added_at = self.line_number + existing_tasks + added_tasks + # Insert below headers (with separating lines), or below existing tasks + if existing_tasks == 0: + if to_add and self.cache.markup_syntax == 'markdown': + md_h_style = util.get_var('vimwiki_markdown_header_style', 1) + newlines = int(md_h_style) + else: + newlines = 0 + + for _ in range(newlines): + self.cache.insert_line('', self.line_number + 1) + + insert_start_line = self.line_number + newlines + 1 + else: + insert_start_line = max(t['line_number'] for t in self.tasks) + 1 + + for i, task in enumerate(sorted_to_add): + added_at = insert_start_line + i # Add the task object to cache self.cache.task[short.ShortUUID(task['uuid'], self.tw)] = task @@ -393,9 +409,8 @@ def sync_with_taskwarrior(self): sort.TaskSorter(self.cache, self.tasks, self.sort).execute() + # Remove excess task lines beyond limit count if self.count is not None: - for i in range( - self.line_number + self.count, - self.line_number + existing_tasks + added_tasks, - ): - self.cache.remove_line(self.line_number + self.count + 1) + task_lines = sorted(t['line_number'] for t in self.tasks) + for excess_line in reversed(task_lines[self.count:]): + self.cache.remove_line(excess_line) diff --git a/tests/conftest.py b/tests/conftest.py index 41a7b1a03..1d3383e9b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,9 +14,9 @@ 'HEADER3': "=== %s ===", }, 'markdown': { - 'HEADER1': "# %s", - 'HEADER2': "## %s", - 'HEADER3': "### %s", + 'HEADER1': "# %s\n", + 'HEADER2': "## %s\n", + 'HEADER3': "### %s\n", } } diff --git a/tests/test_viewport.py b/tests/test_viewport.py index 2830a9b67..fee911d2f 100644 --- a/tests/test_viewport.py +++ b/tests/test_viewport.py @@ -667,3 +667,28 @@ def execute(self): # testfile3 only has header, so refresh on open makes changes self.client.edit(testfile3) assert self.client.eval('&modified') == '1' + + +class TestViewportsNoChangePreserving(MultiSyntaxIntegrationTest): + + viminput = """ + HEADER2(Work tasks | +work) + + * [ ] tag work task #{uuid} + + + HEADER2(Home tasks | +home) + + + * [ ] tag home task #{uuid} + """ + + vimoutput = viminput + + tasks = [ + dict(description="tag work task", tags=['work']), + dict(description="tag home task", tags=['home']), + ] + + def execute(self): + self.command("w", regex="written$", lines=1)