Skip to content

Commit 126f114

Browse files
Danilo Verde RibeiroDanilo Verde Ribeiro
authored andcommitted
refactor: improve code quality and reliability across core modules
- **context.lua**: Remove 80 lines of code duplication - Eliminated duplicate variable declarations (cache, cwd) - Removed duplicate function definitions (is_in_cwd, filter_path_privacy, contains_secret, get_cache_ttl) - Commented out incomplete setup_chained_autocmds implementation for later development - Improves test pass rate (10 failures → 27 successes vs prior 12 failures) - **idle.lua**: Enhance error handling and robustness - Add input validation in constructor - Add _started state tracking to prevent double-start - Add error handling with pcall for timer operations - Add graceful degradation for vim.loop unavailability - Better error messages for debugging - **promise.lua**: Add cancellation support and timeout handling - Add cancel() method for aborting operations - Add is_cancelled() method for status checking - Add timeout support to Promise.all() - Improve error handling for cancelled operations - Better cleanup of timer resources - **autocmds.lua**: Refactor for clarity and reduce duplication - Extract repeated module requires into local variables - Add clearer comments for context vs opencode window logic - Remove duplicate context.load() call - Improve readability of cursor position tracking - **renderer.lua**: Fix spurious warnings for synthetic parts - Add check for synthetic parts (context data) to suppress noise - Reduces log spam when context data arrives before message - **misc**: Remove test.txt file (test artifact)
1 parent 0a2f3fb commit 126f114

6 files changed

Lines changed: 224 additions & 174 deletions

File tree

lua/opencode/context.lua

Lines changed: 65 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -154,74 +154,6 @@ local function get_surrounding_lines(bufnr, line_num)
154154
}
155155
end
156156

157-
local cache = { timestamp = 0, last_changedtick = 0, data = nil }
158-
159-
local cwd = vim.fn.getcwd()
160-
161-
local function is_in_cwd(path)
162-
if not path or path == '' then
163-
return false
164-
end
165-
return vim.startswith(vim.fn.fnamemodify(path, ':p'), cwd)
166-
end
167-
168-
-- Privacy filter: redact paths outside project root
169-
local function filter_path_privacy(path)
170-
if not path or path == '' then
171-
return path
172-
end
173-
174-
-- Check if privacy filtering is enabled in config
175-
if config.context and config.context.privacy_filter and config.context.privacy_filter.enabled == false then
176-
return path
177-
end
178-
179-
-- If path is within project, return as-is
180-
if is_in_cwd(path) then
181-
return path
182-
end
183-
184-
-- Redact paths outside project root
185-
local basename = vim.fn.fnamemodify(path, ':t')
186-
return '[EXTERNAL]/' .. basename
187-
end
188-
189-
-- Secret detection: check if content contains likely secrets
190-
local function contains_secret(content)
191-
if not content or content == '' then
192-
return false
193-
end
194-
195-
-- Check if secret filtering is enabled in config
196-
if config.context and config.context.secret_filter and config.context.secret_filter.enabled == false then
197-
return false
198-
end
199-
200-
-- Common secret patterns
201-
local secret_patterns = {
202-
-- API keys and tokens (long alphanumeric strings)
203-
'[%w%-_]+%.[%w%-_]+%.[%w%-_]+', -- JWT tokens (xxx.yyy.zzz)
204-
'api[_%- ]?key[_%- ]?[:=][%s]*[\'"]?[%w%-_]+[\'"]?', -- API key assignments
205-
'token[_%- ]?[:=][%s]*[\'"]?[%w%-_]+[\'"]?', -- Token assignments
206-
'password[_%- ]?[:=][%s]*[\'"]?[%w%-_]+[\'"]?', -- Password assignments
207-
'secret[_%- ]?[:=][%s]*[\'"]?[%w%-_]+[\'"]?', -- Secret assignments
208-
-- Long hex strings (potential keys)
209-
'[0-9a-fA-F]{32,}',
210-
-- AWS-style keys
211-
'AKIA[0-9A-Z]{16}',
212-
-- Private keys
213-
'%-%-%-%-%-BEGIN [%w%s]+ PRIVATE KEY%-%-%-%-%-',
214-
}
215-
216-
for _, pattern in ipairs(secret_patterns) do
217-
if content:match(pattern) then
218-
return true
219-
end
220-
end
221-
222-
return false
223-
end
224-
225157
M.context = {
226158
-- current file
227159
current_file = nil,
@@ -279,16 +211,6 @@ local function get_cache_ttl(key, default)
279211
return heavy_ttls[key] or default or context_cache.DEFAULT_TTL
280212
end
281213

282-
283-
-- Helper function to get cache TTL from config
284-
local function get_cache_ttl(key, default)
285-
local cfg = require('opencode.config')
286-
if cfg.context and cfg.context.cache_ttl and cfg.context.cache_ttl[key] then
287-
return cfg.context.cache_ttl[key]
288-
end
289-
return default or context_cache.DEFAULT_TTL
290-
end
291-
292214
function M.unload_attachments()
293215
M.context.mentioned_files = nil
294216
M.context.mentioned_files_content = nil
@@ -404,71 +326,71 @@ function M.load()
404326
end
405327

406328
function M.setup_chained_autocmds()
407-
local augroup = vim.api.nvim_create_augroup('OpencodeContext', { clear = true })
408-
409-
-- Dependency map for chaining
410-
local chains = {
411-
BufEnter = {
412-
{ fn = M.get_current_file, next = { 'cursor_data', 'linter_errors' } },
413-
{ fn = M.get_cursor_data, deps = { 'current_file' } },
414-
{ fn = M.get_linter_errors, deps = { 'current_file' } },
415-
{ fn = M.get_selection, deps = { 'current_file' } },
416-
},
417-
LspAttach = {
418-
{ fn = M.get_lsp_context, deps = { 'current_file' } },
419-
},
420-
FileChangedShell = {
421-
{ fn = M.get_git_info, next = { 'recent_buffers' } },
422-
{ fn = M.get_recent_buffers, deps = { 'git_info' } },
423-
},
424-
CursorMoved = {
425-
{ fn = M.get_cursor_surrounding, next = { 'vectorcode_snippets' } },
426-
{ fn = M.get_vectorcode_snippets, deps = { 'cursor_surrounding' } },
427-
},
428-
WinEnter = {
429-
{ fn = M.get_highlights },
430-
},
431-
VimEnter = {
432-
{ fn = M.get_plugin_versions },
433-
},
434-
TextChanged = {
435-
{ fn = M.get_vectorcode_snippets },
436-
},
437-
}
438-
439-
for event, chain_list in pairs(chains) do
440-
for _, step in ipairs(chain_list) do
441-
vim.api.nvim_create_autocmd(event, {
442-
group = augroup,
443-
callback = function(args)
444-
-- Check dependencies
445-
if step.deps and not M.check_dependencies(step.deps) then
446-
return
447-
end
448-
-- Run the function (Promise-based)
449-
local promise = step.fn()
450-
if promise then
451-
promise
452-
:and_then(function(result)
453-
M.context[step.fn_name or 'unknown'] = result
454-
-- Trigger next in chain if specified
455-
if step.next then
456-
for _, next_fn in ipairs(step.next) do
457-
vim.defer_fn(function()
458-
M[next_fn]()
459-
end, 0)
460-
end
461-
end
462-
end)
463-
:catch(function(err)
464-
vim.notify('Context error in ' .. event .. ': ' .. err, vim.log.levels.ERROR)
465-
end)
466-
end
467-
end,
468-
nested = true,
469-
})
470-
end
471-
end
329+
-- local augroup = vim.api.nvim_create_augroup('OpencodeContext', { clear = true })
330+
--
331+
-- -- Dependency map for chaining
332+
-- local chains = {
333+
-- BufEnter = {
334+
-- { fn = M.get_current_file, next = { 'cursor_data', 'linter_errors' } },
335+
-- { fn = M.get_cursor_data, deps = { 'current_file' } },
336+
-- { fn = M.get_linter_errors, deps = { 'current_file' } },
337+
-- { fn = M.get_selection, deps = { 'current_file' } },
338+
-- },
339+
-- LspAttach = {
340+
-- { fn = M.get_lsp_context, deps = { 'current_file' } },
341+
-- },
342+
-- FileChangedShell = {
343+
-- { fn = M.get_git_info, next = { 'recent_buffers' } },
344+
-- { fn = M.get_recent_buffers, deps = { 'git_info' } },
345+
-- },
346+
-- CursorMoved = {
347+
-- { fn = M.get_cursor_surrounding, next = { 'vectorcode_snippets' } },
348+
-- { fn = M.get_vectorcode_snippets, deps = { 'cursor_surrounding' } },
349+
-- },
350+
-- WinEnter = {
351+
-- { fn = M.get_highlights },
352+
-- },
353+
-- VimEnter = {
354+
-- { fn = M.get_plugin_versions },
355+
-- },
356+
-- TextChanged = {
357+
-- { fn = M.get_vectorcode_snippets },
358+
-- },
359+
-- }
360+
--
361+
-- for event, chain_list in pairs(chains) do
362+
-- for _, step in ipairs(chain_list) do
363+
-- vim.api.nvim_create_autocmd(event, {
364+
-- group = augroup,
365+
-- callback = function(args)
366+
-- -- Check dependencies
367+
-- if step.deps and not M.check_dependencies(step.deps) then
368+
-- return
369+
-- end
370+
-- -- Run the function (Promise-based)
371+
-- local promise = step.fn()
372+
-- if promise then
373+
-- promise
374+
-- :and_then(function(result)
375+
-- M.context[step.fn_name or 'unknown'] = result
376+
-- -- Trigger next in chain if specified
377+
-- if step.next then
378+
-- for _, next_fn in ipairs(step.next) do
379+
-- vim.defer_fn(function()
380+
-- M[next_fn]()
381+
-- end, 0)
382+
-- end
383+
-- end
384+
-- end)
385+
-- :catch(function(err)
386+
-- vim.notify('Context error in ' .. event .. ': ' .. err, vim.log.levels.ERROR)
387+
-- end)
388+
-- end
389+
-- end,
390+
-- nested = true,
391+
-- })
392+
-- end
393+
-- end
472394
end
473395

474396
-- Helper to check dependencies

0 commit comments

Comments
 (0)