From 69086903e503de4342ff18484dafc2e203d218cf Mon Sep 17 00:00:00 2001 From: Vadim1987 Date: Thu, 2 Jul 2026 13:53:39 +0200 Subject: [PATCH 1/2] fix(input): cap console history growth (B3) --- src/model/input/history.lua | 18 ++++++++++++++++++ tests/input/history_spec.lua | 21 +++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/model/input/history.lua b/src/model/input/history.lua index cd02fc95..64770ab6 100644 --- a/src/model/input/history.lua +++ b/src/model/input/history.lua @@ -3,6 +3,8 @@ require('util.dequeue') require('util.string.string') require('util.debug') +local HISTORY_LIMIT = 100 + --- @class History: Dequeue --- @field index integer History = class.create() @@ -25,6 +27,7 @@ function History:remember(input) if string.is_non_empty_string_array(input) then if not self.index then self:append(input) + self:_trim() return true else local entry = self:get(self.index) @@ -33,12 +36,27 @@ function History:remember(input) local new_s = string.unlines(new) if hist ~= new_s then self:append(input) + self:_trim() end end end return false end +--- Evict oldest entries past the limit +--- @private +function History:_trim() + while #self > HISTORY_LIMIT do + self:pop_front() + if self.index then + self.index = self.index - 1 + if self.index < 1 then + self:reset_index() + end + end + end +end + function History:reset_index() self.index = nil end diff --git a/tests/input/history_spec.lua b/tests/input/history_spec.lua index f4a50fd1..041a3380 100644 --- a/tests/input/history_spec.lua +++ b/tests/input/history_spec.lua @@ -22,6 +22,27 @@ describe('history #history', function() history = History() end) + it('caps the number of entries', function() + local h = History() + for i = 1, 110 do + h:remember({ 'entry ' .. i }) + end + assert.are_equal(100, h:length()) + assert.same({ 'entry 11' }, h:get(1)) + assert.same({ 'entry 110' }, h:get(100)) + end) + + it('keeps navigation position across eviction', function() + local h = History() + for i = 1, 100 do + h:remember({ 'e' .. i }) + end + h:history_back({ '' }) + local at = h:get(h.index) + h:remember({ 'typed' }) + assert.same(at, h:get(h.index)) + end) + it('remembers', function() history:remember(t1) local h1 = { t1 } From 019942744ee89bdf4c4b4cf514028b29e9705860 Mon Sep 17 00:00:00 2001 From: Vadim1987 Date: Sat, 4 Jul 2026 22:44:10 +0200 Subject: [PATCH 2/2] fix(input): make history cap configurable, 0 for unlimited --- src/main.lua | 2 ++ src/model/input/history.lua | 10 +++++++--- src/model/input/userInputModel.lua | 4 ++-- tests/input/history_spec.lua | 24 ++++++++++++++++++------ 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/main.lua b/src/main.lua index a0bb4d31..f7913ed2 100644 --- a/src/main.lua +++ b/src/main.lua @@ -339,6 +339,8 @@ function love.load() local baseconf = { view = viewconf, editor = editorconf, + --- console history entries kept; 0 for unlimited + input_history = 1000, autotest = autotest, mode = mode, } diff --git a/src/model/input/history.lua b/src/model/input/history.lua index 64770ab6..d0fc02e8 100644 --- a/src/model/input/history.lua +++ b/src/model/input/history.lua @@ -3,14 +3,17 @@ require('util.dequeue') require('util.string.string') require('util.debug') -local HISTORY_LIMIT = 100 +local DEFAULT_LIMIT = 1000 --- @class History: Dequeue --- @field index integer +--- @field limit integer entry cap, 0 for unlimited History = class.create() -function History.new() +--- @param limit integer? entry cap; 0 means unlimited +function History.new(limit) local self = Dequeue.typed('string[]') + self.limit = limit or DEFAULT_LIMIT setmetatable(self, { __index = function(t, k) @@ -46,7 +49,8 @@ end --- Evict oldest entries past the limit --- @private function History:_trim() - while #self > HISTORY_LIMIT do + if self.limit == 0 then return end + while #self > self.limit do self:pop_front() if self.index then self.index = self.index - 1 diff --git a/src/model/input/userInputModel.lua b/src/model/input/userInputModel.lua index 4613feec..5875570a 100644 --- a/src/model/input/userInputModel.lua +++ b/src/model/input/userInputModel.lua @@ -48,7 +48,7 @@ function UserInputModel.new(cfg, eval, oneshot, custom_label) local self = setmetatable({ oneshot = oneshot, entered = InputText(), - history = History(), + history = History(cfg.input_history), evaluator = eval, cursor = Cursor(), selection = InputSelection(), @@ -354,7 +354,7 @@ end --- @param history boolean? function UserInputModel:reset(history) if history and self:keep_history() then - self.history = History() + self.history = History(self.cfg.input_history) end self:clear_input() end diff --git a/tests/input/history_spec.lua b/tests/input/history_spec.lua index 041a3380..143ad5f7 100644 --- a/tests/input/history_spec.lua +++ b/tests/input/history_spec.lua @@ -23,17 +23,29 @@ describe('history #history', function() end) it('caps the number of entries', function() - local h = History() - for i = 1, 110 do + local h = History(10) + for i = 1, 15 do h:remember({ 'entry ' .. i }) end - assert.are_equal(100, h:length()) - assert.same({ 'entry 11' }, h:get(1)) - assert.same({ 'entry 110' }, h:get(100)) + assert.are_equal(10, h:length()) + assert.same({ 'entry 6' }, h:get(1)) + assert.same({ 'entry 15' }, h:get(10)) + end) + + it('treats 0 as unlimited', function() + local h = History(0) + for i = 1, 15 do + h:remember({ 'entry ' .. i }) + end + assert.are_equal(15, h:length()) + end) + + it('defaults the limit', function() + assert.are_equal(1000, History().limit) end) it('keeps navigation position across eviction', function() - local h = History() + local h = History(100) for i = 1, 100 do h:remember({ 'e' .. i }) end