From 81876917e5b33f22b918a51f1f5658fdb6dabe49 Mon Sep 17 00:00:00 2001 From: increadibledark Date: Fri, 20 Feb 2026 00:26:35 +0530 Subject: [PATCH 1/4] fix(input): return (nil, err) on read_query_answer timeout --- spec/04-input_spec.lua | 28 ++++++++++++++++++++++++++++ src/terminal/input/init.lua | 10 +++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/spec/04-input_spec.lua b/spec/04-input_spec.lua index 425ab62..6493b3b 100644 --- a/spec/04-input_spec.lua +++ b/spec/04-input_spec.lua @@ -122,6 +122,22 @@ describe("input:", function() assert.is_nil(r[3]) end) + + it("returns nil and error message on timeout without throwing", function() + local old_sys_readansi = t.input.sys_readansi + t.input.sys_readansi = function() + return nil, "timeout" + end + finally(function() + t.input.sys_readansi = old_sys_readansi + end) + + local result, err = t.input.read_query_answer(cursor_answer_pattern, 1) + + assert.is_nil(result) + assert.are.equal("timeout: no response from terminal", err) + end) + end) @@ -145,6 +161,18 @@ describe("input:", function() }, res) end) + + it("returns nil and error when read_query_answer times out", function() + t.input.read_query_answer = function() + return nil, "timeout: no response from terminal" + end + + local result, err = t.input.query("\27[6n", "^\27%[(%d+);(%d+)R$") + + assert.is_nil(result) + assert.are.equal("timeout: no response from terminal", err) + end) + end) end) diff --git a/src/terminal/input/init.lua b/src/terminal/input/init.lua index 4b01158..9f04269 100644 --- a/src/terminal/input/init.lua +++ b/src/terminal/input/init.lua @@ -155,7 +155,9 @@ end --- Reads the answer to a query from the terminal. -- @tparam string answer_pattern a pattern that matches the expected ANSI response sequence, and captures the data needed. -- @tparam[opt=1] number count the number of responses to read (in case multiple queries were sent) --- @treturn table an array with `count` entries. Each entry is another array with the captures from the answer pattern. +-- @treturn[1] table an array with `count` entries. Each entry is another array with the captures from the answer pattern. +-- @treturn[2] nil on timeout or keyboard read error. +-- @treturn[2] string error message (e.g. `"timeout: no response from terminal"` or `"error reading keyboard: ..."`). -- @within Querying function M.read_query_answer(answer_pattern, count) count = count or 1 @@ -164,7 +166,7 @@ function M.read_query_answer(answer_pattern, count) while true do local seq, typ, part = M.sys_readansi(0.5, terminal._bsleep) -- 500ms timeout, max time for terminal to respond if seq == nil and typ == "timeout" then - error("no response from terminal, this is unexpected") + return nil, "timeout: no response from terminal" end if typ == "ansi" then local captures = { seq:match(answer_pattern) } @@ -198,7 +200,9 @@ end -- in one go. It is a convenience function for simple queries. It is limited to only a single query/answer pair. -- @tparam string query the ANSI sequence to be written to query the terminal -- @tparam string answer_pattern a pattern that matches the expected ANSI response sequence, and captures the data needed. --- @treturn table an array with the captures from the answer pattern. +-- @treturn[1] table an array with the captures from the answer pattern. +-- @treturn[2] nil on timeout or keyboard read error (see `read_query_answer`). +-- @treturn[2] string error message. -- @within Querying function M.query(query, answer_pattern) M.preread() From c54aa0624552ace4ec0db18840007c5cf029c29f Mon Sep 17 00:00:00 2001 From: increadibledark Date: Fri, 20 Feb 2026 23:05:55 +0530 Subject: [PATCH 2/4] tests(input): use helpers.push_kb_input for timeout test --- spec/04-input_spec.lua | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/spec/04-input_spec.lua b/spec/04-input_spec.lua index 6493b3b..4f2b368 100644 --- a/spec/04-input_spec.lua +++ b/spec/04-input_spec.lua @@ -124,13 +124,7 @@ describe("input:", function() it("returns nil and error message on timeout without throwing", function() - local old_sys_readansi = t.input.sys_readansi - t.input.sys_readansi = function() - return nil, "timeout" - end - finally(function() - t.input.sys_readansi = old_sys_readansi - end) + helpers.push_kb_input(nil, "timeout") local result, err = t.input.read_query_answer(cursor_answer_pattern, 1) From 265beb0e303b52dbe677ff2db5affd598be205ae Mon Sep 17 00:00:00 2001 From: increadibledark Date: Sat, 21 Feb 2026 16:53:44 +0530 Subject: [PATCH 3/4] tests(input): drive query timeout via helpers in spec --- spec/04-input_spec.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/04-input_spec.lua b/spec/04-input_spec.lua index 4f2b368..2b038e4 100644 --- a/spec/04-input_spec.lua +++ b/spec/04-input_spec.lua @@ -157,9 +157,8 @@ describe("input:", function() it("returns nil and error when read_query_answer times out", function() - t.input.read_query_answer = function() - return nil, "timeout: no response from terminal" - end + t.input.preread = function() end + helpers.push_kb_input(nil, "timeout") local result, err = t.input.query("\27[6n", "^\27%[(%d+);(%d+)R$") From 97c74f2b37a2a9cef61567c4fbfe136acdb5532b Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Sat, 21 Feb 2026 20:48:13 +0100 Subject: [PATCH 4/4] remove unnecessary mock --- spec/04-input_spec.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/04-input_spec.lua b/spec/04-input_spec.lua index 2b038e4..be8bf9c 100644 --- a/spec/04-input_spec.lua +++ b/spec/04-input_spec.lua @@ -157,7 +157,6 @@ describe("input:", function() it("returns nil and error when read_query_answer times out", function() - t.input.preread = function() end helpers.push_kb_input(nil, "timeout") local result, err = t.input.query("\27[6n", "^\27%[(%d+);(%d+)R$")