From 9bac2b8cdf153b1d8be3ec7507c5327edb32dc0f Mon Sep 17 00:00:00 2001 From: pi-agent Date: Wed, 18 Mar 2026 19:23:42 +0800 Subject: [PATCH] fix: support empty string literals in textfx - Fix tokenizer to emit empty string token when closing quote on empty buffer - Add force parameter to flush_word() to handle empty quoted strings - Add test case for echo "" and echo '' --- konabot/plugins/handle_text/base.py | 7 ++++--- tests/test_textfx_shell.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/konabot/plugins/handle_text/base.py b/konabot/plugins/handle_text/base.py index b199ae3..d7da900 100644 --- a/konabot/plugins/handle_text/base.py +++ b/konabot/plugins/handle_text/base.py @@ -161,9 +161,9 @@ class PipelineRunner: "'": "'", } - def flush_word(): + def flush_word(force: bool = False): nonlocal buf - if buf: + if buf or force: tokens.append(Token(TokenKind.WORD, buf)) buf = "" @@ -178,6 +178,7 @@ class PipelineRunner: escape = True elif c == quote: quote = None + flush_word(force=True) # 引号闭合时强制 flush,即使是空字符串 else: buf += c i += 1 @@ -188,7 +189,7 @@ class PipelineRunner: i += 1 continue - if c.isspace() or c in "  ": + if c.isspace() or c in " ": flush_word() i += 1 continue diff --git a/tests/test_textfx_shell.py b/tests/test_textfx_shell.py index 5e7def7..10f0636 100644 --- a/tests/test_textfx_shell.py +++ b/tests/test_textfx_shell.py @@ -205,3 +205,21 @@ async def test_while_body_can_use_if(runner: PipelineRunner): assert not isinstance(parsed, str) results = await runner.run_pipeline(parsed, None, TextHandlerEnvironment(False)) assert results[0].code == 1 + + +@pytest.mark.asyncio +async def test_echo_empty_string(runner: PipelineRunner): + """测试 echo 空字符串""" + # 双引号空字符串 + parsed = runner.parse_pipeline('echo ""') + assert not isinstance(parsed, str) + results = await runner.run_pipeline(parsed, None, TextHandlerEnvironment(False)) + assert results[0].code == 0 + assert results[0].ostream == '' + + # 单引号空字符串 + parsed2 = runner.parse_pipeline("echo ''") + assert not isinstance(parsed2, str) + results2 = await runner.run_pipeline(parsed2, None, TextHandlerEnvironment(False)) + assert results2[0].code == 0 + assert results2[0].ostream == ''