Skip to content

Commit 3cc6c7a

Browse files
committed
fix word generate
1 parent 920409f commit 3cc6c7a

1 file changed

Lines changed: 109 additions & 28 deletions

File tree

lua/phoenix/init.lua

Lines changed: 109 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ local default = {
4040
scanner = {
4141
scan_batch_size = 1000, -- Scan 1000 items per batch
4242
cache_duration_ms = 5000, -- Cache results for 5s
43-
throttle_delay_ms = 5000, -- Wait 5000ms between updates..otherwise we store lots of part of words..
43+
throttle_delay_ms = 5000, -- Wait 5000ms between updates
4444
ignore_patterns = {}, -- No ignore patterns by default
4545
},
4646
snippet = '',
@@ -84,6 +84,44 @@ function Trie.insert(root, word, timestamp)
8484
return was_new
8585
end
8686

87+
--- Remove a word from the trie, pruning empty branches
88+
---@return boolean true if the word existed and was removed
89+
function Trie.remove(root, word)
90+
local nodes = { root }
91+
local chars = {}
92+
local node = root
93+
94+
for i = 1, #word do
95+
local char = word:sub(i, i)
96+
if not node.children[char] then
97+
return false
98+
end
99+
node = node.children[char]
100+
table.insert(nodes, node)
101+
table.insert(chars, char)
102+
end
103+
104+
if not node.is_end then
105+
return false
106+
end
107+
108+
node.is_end = false
109+
node.frequency = 0
110+
node.last_used = 0
111+
112+
-- Prune empty branches bottom-up
113+
for i = #nodes, 2, -1 do
114+
local child = nodes[i]
115+
if not child.is_end and not next(child.children) then
116+
nodes[i - 1].children[chars[i - 1]] = nil
117+
else
118+
break
119+
end
120+
end
121+
122+
return true
123+
end
124+
87125
function Trie.search_prefix(root, prefix)
88126
local node = root
89127
for i = 1, #prefix do
@@ -426,12 +464,6 @@ local function cleanup_dict()
426464
end)
427465
end
428466

429-
local function visible_range(content)
430-
local top = vim.fn.line('w0')
431-
local bot = vim.fn.line('w$')
432-
return vim.iter(vim.split(content, '\n')):slice(top, bot):join('\n')
433-
end
434-
435467
-- Core word processing function
436468
local function process_words(line, seen, dict_config)
437469
local new_words = 0
@@ -639,12 +671,81 @@ local function find_last_occurrence(str, patterns)
639671
return nil
640672
end
641673

674+
-- Track words from previous didChange snapshot so we can diff
675+
local prev_word_set = {}
676+
677+
-- Debounced dictionary update for didChange
678+
-- Only fires after user stops typing for throttle_delay_ms
679+
local change_timer = vim.uv.new_timer()
680+
681+
local function debounced_update_dict(text)
682+
if not change_timer or change_timer:is_closing() then
683+
return
684+
end
685+
change_timer:stop()
686+
change_timer:start(Config.scanner.throttle_delay_ms, 0, function()
687+
change_timer:stop()
688+
vim.schedule(function()
689+
local dict_config = Config.dict
690+
local cursor_lnum = vim.api.nvim_win_get_cursor(0)[1]
691+
local lines = vim.split(text, '\n')
692+
693+
-- Build current word set, skipping cursor line
694+
local current_words = {}
695+
for i, line in ipairs(lines) do
696+
if i ~= cursor_lnum then
697+
for word in line:gmatch(dict_config.word_pattern) do
698+
if #word >= dict_config.min_word_length then
699+
current_words[word] = true
700+
end
701+
end
702+
end
703+
end
704+
705+
-- Remove words that existed in prev snapshot but not in current
706+
-- These are partial words or deleted words
707+
for word in pairs(prev_word_set) do
708+
if not current_words[word] then
709+
if Trie.remove(dict.trie, word) then
710+
dict.word_count = dict.word_count - 1
711+
end
712+
end
713+
end
714+
715+
-- Insert new words that appear in current but not prev
716+
local now = vim.uv.now()
717+
for word in pairs(current_words) do
718+
if not prev_word_set[word] then
719+
if Trie.insert(dict.trie, word, now) then
720+
dict.word_count = dict.word_count + 1
721+
end
722+
end
723+
end
724+
725+
prev_word_set = current_words
726+
727+
if dict.word_count > dict.max_words then
728+
cleanup_dict()
729+
end
730+
end)
731+
end)
732+
end
733+
642734
-- LSP handler functions
643735
local function handle_document_open(params)
644736
local text = params.textDocument.text
645737
if #text == 0 then
646738
return
647739
end
740+
741+
-- Build initial prev_word_set from opened document
742+
local dict_config = Config.dict
743+
for word in text:gmatch(dict_config.word_pattern) do
744+
if #word >= dict_config.min_word_length then
745+
prev_word_set[word] = true
746+
end
747+
end
748+
648749
local content = vim.split(text, '%s', { trimempty = true })
649750
if #content == 0 then
650751
return
@@ -658,32 +759,12 @@ local function handle_document_change(params)
658759
return
659760
end
660761

661-
-- Process only the changed text
662762
local change = params.contentChanges[1]
663763
if not change or not change.text then
664764
return
665765
end
666766

667-
-- Process just the changed text
668-
local lines = vim.split(change.text, '\n')
669-
if #lines == 0 then
670-
return
671-
end
672-
673-
-- Process the new text directly without comparing to old version
674-
local seen = {}
675-
local dict_config = Config.dict
676-
local new_words = 0
677-
678-
for _, line in ipairs(lines) do
679-
new_words = new_words + process_words(line, seen, dict_config)
680-
end
681-
682-
dict.word_count = dict.word_count + new_words
683-
684-
if dict.word_count > dict.max_words then
685-
cleanup_dict()
686-
end
767+
debounced_update_dict(change.text)
687768
end
688769

689770
function server.create()

0 commit comments

Comments
 (0)