fix(blink_cmp_source): Handling of DB patterns after operators

The completion now correctly handles DB patterns after any operator
(:=, =>, =, <>, >=, <=, >, <, AND, OR, NOT) by finding the last operator
and only matching DB patterns in the active portion after it.
This commit is contained in:
2026-02-18 09:21:38 +01:00
parent 7d54578406
commit 1e50b596de
+56 -17
View File
@@ -33,8 +33,8 @@ function M.is_available(context)
local char_at = line:sub(col, col)
local prev_char = col > 1 and line:sub(col - 1, col - 1) or ""
-- Only trigger on our specific characters
if char_at == "." or char_at == "(" or char_at == "#" or char_at == '"' or
-- Only trigger on our specific characters (including space for := assignments)
if char_at == "." or char_at == "(" or char_at == "#" or char_at == '"' or char_at == " " or
prev_char == "." or prev_char == "(" or prev_char == "#" or prev_char == '"' then
return true
end
@@ -157,31 +157,71 @@ function M:get_completions(context, callback)
-- Check for Global DB completion (quoted DB names like "HmiData")
local trimmed = line:gsub("^%s+", ""):gsub("%s+$", "")
-- Find the "active portion" of the line - after the last operator if present
-- Operators: :=, =>, =, <>, >=, <=, >, <, AND, OR, NOT
-- This ensures we match DB patterns nearest to the cursor, not the first in line
local active_portion = line_before_cursor
-- Check for "DBName" pattern (quoted DB name access with dot)
local db_member_pattern = trimmed:match('"([%w_]+)"%.([%w_]*)')
local function find_last_operator_pos(text)
local last_pos = 0
local operators = {":=", "=>", "<>", ">=", "<=", "=", ">", "<"}
for _, op in ipairs(operators) do
local search_start = 1
while true do
local pos = text:find(op, search_start, true)
if not pos then break end
if pos > last_pos then
last_pos = pos + #op
end
search_start = pos + 1
end
end
-- Also check for AND/OR/NOT keywords (case insensitive)
local keywords = {"%sAND%s", "%sOR%s", "%sNOT%s"}
for _, kw in ipairs(keywords) do
local search_start = 1
while true do
local pos = text:upper():find(kw, search_start)
if not pos then break end
if pos > last_pos then
last_pos = pos + #kw - 1
end
search_start = pos + 1
end
end
return last_pos
end
-- Check if we're typing a quoted DB name (after " but before closing ")
local is_in_db_name = trimmed:match('"[%w_]*$') ~= nil
local last_op_pos = find_last_operator_pos(line_before_cursor)
if last_op_pos > 0 then
active_portion = line_before_cursor:sub(last_op_pos):gsub("^%s+", "")
end
-- Check for "DBName" pattern (quoted DB name access with dot) - in active portion only
local db_member_pattern = active_portion:match('"([%w_]+)"%.([%w_.]*)')
-- Check for partial DB name like "HmiData (unclosed quote)
local partial_db_match = trimmed:match('"([%w_]+)$')
local is_partial_db = partial_db_match ~= nil and trimmed:match('"[^"]*$') ~= nil
-- Check if we're typing a quoted DB name (after " but before closing ") - in active portion
local is_in_db_name = active_portion:match('"[%w_]*$') ~= nil
-- Check if after a colon followed by quote (type declaration context)
-- Check for partial DB name like "HmiData (unclosed quote) - in active portion
local partial_db_match = active_portion:match('"([%w_]+)$')
local is_partial_db = partial_db_match ~= nil and active_portion:match('"[^"]*$') ~= nil
-- Check if after a colon followed by quote (type declaration context) - use full trimmed line
local is_after_colon_quote = trimmed:match(':%s*"$') ~= nil
-- Check if cursor is right after a closed quoted DB name (before dot)
local after_closed_db = trimmed:match('"([%w_]+)"%s*%.') ~= nil
-- Check if cursor is right after a closed quoted DB name (before dot) - in active portion
local after_closed_db = active_portion:match('"([%w_]+)"%s*%.') ~= nil
if db_member_pattern or after_closed_db then
local db_parser = require("scl.db_parser")
local db_name = trimmed:match('"([%w_]+)"')
local db_name = active_portion:match('"([%w_]+)"')
if db_name then
local db = db_parser.get_db(db_name)
if db then
local path = trimmed:match('"[^"]+%"%.([%w_.]*)')
local path = active_portion:match('"[^"]+%"%.([%w_.]*)')
-- Resolve nested path through DB members
local current_type = nil
@@ -230,7 +270,7 @@ function M:get_completions(context, callback)
end
if not found then
wrapped_callback({ items = {} })
callback({ items = {}, is_incomplete_backward = false, is_incomplete_forward = false })
return
end
end
@@ -239,8 +279,7 @@ function M:get_completions(context, callback)
if path and path ~= "" and path:match("%.$") then
-- User wants members of the last type
elseif path and path ~= "" and not path:match("%.$") then
-- User is typing a member name, don't show completions yet
wrapped_callback({ items = {} })
callback({ items = {}, is_incomplete_backward = false, is_incomplete_forward = false })
return
end