diff --git a/src/specify_cli/integrations/cline/__init__.py b/src/specify_cli/integrations/cline/__init__.py index ab839b9b5..a9b43e99a 100644 --- a/src/specify_cli/integrations/cline/__init__.py +++ b/src/specify_cli/integrations/cline/__init__.py @@ -96,7 +96,11 @@ class ClineIntegration(MarkdownIntegration): def repl(m: re.Match[str]) -> str: indent = m.group(1) instruction = m.group(2) - eol = m.group(3) + # ``eol`` is empty when the regex matched via ``$`` because the + # instruction was the final line of a file with no trailing + # newline. Default to ``\n`` so the note never collapses onto + # the same line as the instruction. + eol = m.group(3) or "\n" return ( indent + _HOOK_COMMAND_NOTE.rstrip("\n") diff --git a/tests/integrations/test_integration_cline.py b/tests/integrations/test_integration_cline.py index 21148df86..7475b5ad0 100644 --- a/tests/integrations/test_integration_cline.py +++ b/tests/integrations/test_integration_cline.py @@ -90,6 +90,22 @@ class TestClineIntegration(MarkdownIntegrationTests): assert "replace dots (`.`) with hyphens (`-`)" in injected assert "- For each executable hook, output the following:" in injected + def test_cline_hook_instruction_injection_no_trailing_newline(self): + """Note must not collapse onto the instruction line when the + instruction is the final line with no trailing newline. + + The injection regex matches the end-of-line via ``(\\r\\n|\\n|$)``, so + the captured ``eol`` is empty on a file's last line that lacks a + trailing newline. Without an ``or "\\n"`` fallback the note text and + the instruction are emitted on the same line. + """ + cline = get_integration("cline") + content = "- For each executable hook, output the following:" # no trailing \n + injected = cline._inject_hook_command_note(content) + assert "replace dots (`.`) with hyphens (`-`)" in injected + # Instruction stays on its own line rather than being mashed onto the note. + assert "\n- For each executable hook, output the following:" in injected + # -- Overrides for MarkdownIntegrationTests --------------------------- def test_setup_creates_files(self, tmp_path):