diff --git a/lua/hopcsharp/database/query.lua b/lua/hopcsharp/database/query.lua index ff10d8b..e448e72 100644 --- a/lua/hopcsharp/database/query.lua +++ b/lua/hopcsharp/database/query.lua @@ -273,20 +273,26 @@ M.get_reference_by_name_and_current_namespace = function(name, namespaces) WHERE (r.name = '%s' OR r.name GLOB '%s' OR r.name || 'Attribute' = '%s') -- or we have using with that namespace -- or we are in the same namespace - AND ((u.namespace IN (%s)) OR (n.name IN (%s))) + -- or there are references in a nested namespaces + AND ((u.namespace IN (%s)) OR (n.name IN (%s)) OR (n.name GLOB %s)) ORDER BY r.name ASC, n.name ASC, f.path ASC ]] + -- TODO check if GLOB didn't introduce table scan + -- TODO cover in tests + -- TODO comment and explain why we are doing it + local namespace_glob = "'" .. namespaces[1] .. "*'" + for i, namespace in ipairs(namespaces) do namespaces[i] = '"' .. namespace .. '"' end local namespace_string = table.concat(namespaces, ',') - return string.format(query, name, name .. '<*>', name, namespace_string, namespace_string) + return string.format(query, name, name .. '<*>', name, namespace_string, namespace_string, namespace_glob) end M.get_reference_by_name_and_type = function(name, type) diff --git a/lua/hopcsharp/hop/providers/definition.lua b/lua/hopcsharp/hop/providers/definition.lua index 6f2b5d3..955f011 100644 --- a/lua/hopcsharp/hop/providers/definition.lua +++ b/lua/hopcsharp/hop/providers/definition.lua @@ -91,6 +91,13 @@ M.__by_name_type_and_current_namespace = function(current_word, node) table.insert(namespace, vim.treesitter.get_node_text(nn, 0, nil)) end + -- TODO cover in tests to make sure it is needed + -- insert outer namespace that are not included by usings + -- because namespace has access to all types defined in outer namespaces + for _, n in ipairs(utils.__get_outer_namespaces(namespace[1] or '')) do + table.insert(namespace, n) + end + local db = database.__get_db() return db:eval(query.get_definition_by_name_type_and_namespace(name, node_type, namespace)) end, diff --git a/lua/hopcsharp/hop/providers/reference.lua b/lua/hopcsharp/hop/providers/reference.lua index 07cd8ae..8009408 100644 --- a/lua/hopcsharp/hop/providers/reference.lua +++ b/lua/hopcsharp/hop/providers/reference.lua @@ -63,7 +63,8 @@ M.__by_name_and_current_namespace = function(current_word, node) end local db = database.__get_db() - return db:eval(query.get_reference_by_name_and_current_namespace(name, namespace)) + return db:eval(query.get_reference_by_name_and_current_namespace(name, namespace)), + dbutils.get_reference_type_name end, } end diff --git a/lua/hopcsharp/hop/providers/utils.lua b/lua/hopcsharp/hop/providers/utils.lua index 1d05d01..a4b8407 100644 --- a/lua/hopcsharp/hop/providers/utils.lua +++ b/lua/hopcsharp/hop/providers/utils.lua @@ -123,4 +123,35 @@ M.__get_node_modifiers = function(node) return modifiers end +---@param namespace string Namespace name +---@return string[] List of outer namespaces +M.__get_outer_namespaces = function(namespace) + local namespaces = {} + + if namespace == nil then + return namespaces + end + + if namespace == '' then + return namespaces + end + + local parts = {} + for part in string.gmatch(namespace, '([^%.]+)') do + table.insert(parts, part) + end + + local i = 1 + while i < #parts do + local n = {} + for j = 1, i, 1 do + table.insert(n, parts[j]) + end + i = i + 1 + table.insert(namespaces, table.concat(n, '.')) + end + + return namespaces +end + return M diff --git a/test/hop/providers/utils_spec.lua b/test/hop/providers/utils_spec.lua index 307689b..a1164ef 100644 --- a/test/hop/providers/utils_spec.lua +++ b/test/hop/providers/utils_spec.lua @@ -137,4 +137,40 @@ describe('hop.providers.utils', function() local modifiers = utils.__get_node_modifiers(vim.treesitter.get_node()) assert(#modifiers == 0) end) + + it('__get_outer_namespaces - outmost namespace', function() + local namespaces = utils.__get_outer_namespaces('NoNesting') + assert(#namespaces == 0) + end) + + it('__get_outer_namespaces - one outer namespace', function() + local namespaces = utils.__get_outer_namespaces('One.Two') + assert(#namespaces == 1) + assert(namespaces[1] == 'One') + end) + + it('__get_outer_namespaces - two outer namespace', function() + local namespaces = utils.__get_outer_namespaces('One.Two.Three') + assert(#namespaces == 2) + assert(namespaces[1] == 'One') + assert(namespaces[2] == 'One.Two') + end) + + it('__get_outer_namespaces - happy', function() + local namespaces = utils.__get_outer_namespaces('This.Is.My.Namespace') + assert(#namespaces == 3) + assert(namespaces[1] == 'This') + assert(namespaces[2] == 'This.Is') + assert(namespaces[3] == 'This.Is.My') + end) + + it('__get_outer_namespaces - nil', function() + local namespaces = utils.__get_outer_namespaces(nil) + assert(#namespaces == 0) + end) + + it('__get_outer_namespaces - empty', function() + local namespaces = utils.__get_outer_namespaces('') + assert(#namespaces == 0) + end) end)