Skip to content

Commit 8f8a0ea

Browse files
dorkster100Deniss Levskoi
andauthored
Model related files picker (#45)
* Fix nil check when env not defined * fix style * more style * add related picker * add description to README * separate picker into separate file and better logs * fix linter issues * more style fixes --------- Co-authored-by: Deniss Levskoi <[email protected]>
1 parent 23d6cba commit 8f8a0ea

File tree

5 files changed

+179
-0
lines changed

5 files changed

+179
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ return {
2626
keys = {
2727
{ "<leader>la", ":Laravel artisan<cr>" },
2828
{ "<leader>lr", ":Laravel routes<cr>" },
29+
{ "<leader>lm", ":Laravel related<cr>" },
2930
{
3031
"<leader>lt",
3132
function()
@@ -197,6 +198,7 @@ You can run `shell` as tinker will open a new terminal
197198
`Laravel cache:clear` purge the cache clears the cache for commands.
198199
`Laravel commands` shows the list of artisan commands and executes it.
199200
`Laravel routes` show the list of routes and goes to the implementation.
201+
`Laravel related` show the list of model related classes, includes observers, policy and relations and goes to the implementation.
200202
`Laravel test` runs the application tests
201203
`Laravel test:watch` runs the application tests and keep monitoring the changes
202204

lua/laravel/telescope/make_entry.lua

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,36 @@ function make_entry.gen_from_laravel_routes(opts)
6565
end
6666
end
6767

68+
function make_entry.gen_from_model_relations(opts)
69+
opts = opts or {}
70+
71+
local displayer = entry_display.create {
72+
separator = " ",
73+
hl_chars = { ["["] = "TelescopeBorder", ["]"] = "TelescopeBorder" },
74+
items = {
75+
{ width = 40 },
76+
{ width = 20 },
77+
{ remaining = true },
78+
},
79+
}
80+
81+
local make_display = function(entry)
82+
return displayer {
83+
{ entry.value.class_name, "TelescopeResultsConstant" },
84+
{ entry.value.type, "TelescopeResultsIdentifier" },
85+
{ entry.value.extra_information or "", "TelescopeResultsFunction" },
86+
}
87+
end
88+
89+
return function(relation)
90+
local class_parts = vim.split(relation.class, "\\")
91+
relation.class_name = class_parts[#class_parts]
92+
return make_entry.set_default_entry_mt({
93+
value = relation,
94+
ordinal = relation.class_name,
95+
display = make_display,
96+
}, opts)
97+
end
98+
end
99+
68100
return make_entry

lua/laravel/user-commands/laravel.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ local commands = {
1515
["test:watch"] = function()
1616
return application.run("artisan", { "test" }, { runner = "watch" })
1717
end,
18+
["related"] = function()
19+
return require("telescope").extensions.laravel.related()
20+
end,
1821
}
1922

2023
return {

lua/telescope/_extensions/laravel.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local make_related = require "telescope.pickers.related"
12
local telescope = require "telescope"
23
local actions = require "telescope.actions"
34
local action_state = require "telescope.actions.state"
@@ -10,6 +11,12 @@ local make_entry = require "laravel.telescope.make_entry"
1011
local laravel_commands = require "laravel.commands"
1112
local laravel_routes = require "laravel.routes"
1213
local application = require "laravel.application"
14+
local lsp = require "laravel._lsp"
15+
16+
---@class ModelRelation
17+
---@field class string
18+
---@field type string
19+
---@field extra_information string
1320

1421
--- runs a command from telescope
1522
---@param command LaravelCommand
@@ -219,5 +226,6 @@ return telescope.register_extension {
219226
exports = {
220227
commands = commands,
221228
routes = routes,
229+
related = make_related(pickers, application, lsp, make_entry, finders, conf, actions, action_state),
222230
},
223231
}

lua/telescope/pickers/related.lua

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
local make_related = function(pickers, application, lsp, make_entry, finders, conf, actions, action_state)
2+
local utils = require "laravel.utils"
3+
return function(opts)
4+
opts = opts or {}
5+
6+
local file_type = vim.bo.filetype
7+
local lang = vim.treesitter.language.get_lang(file_type)
8+
if lang ~= "php" then
9+
return false
10+
end
11+
12+
local get_model_class_name = function()
13+
local query = vim.treesitter.query.parse(
14+
lang,
15+
[[ (namespace_definition name: (namespace_name) @namespace)
16+
(class_declaration name: (name) @class) ]]
17+
)
18+
local tree = vim.treesitter.get_parser():parse()[1]:root()
19+
local bufNr = vim.fn.bufnr()
20+
local class = ""
21+
for id, node, _ in query:iter_captures(tree, bufNr, tree:start(), tree:end_()) do
22+
if query.captures[id] == "class" then
23+
class = class .. "\\" .. vim.treesitter.get_node_text(node, 0)
24+
elseif query.captures[id] == "namespace" then
25+
class = vim.treesitter.get_node_text(node, 0) .. class
26+
end
27+
end
28+
return class
29+
end
30+
31+
local class = get_model_class_name()
32+
if class ~= "" then
33+
local result, ok = application.run("artisan", { "model:show", class, "--json" }, { runner = "sync" })
34+
if not ok then
35+
utils.notify(
36+
"Artisan",
37+
{ msg = "'php artisan model:show " .. class .. " --json' command failed", level = "ERROR" }
38+
)
39+
return nil
40+
end
41+
42+
if result.exit_code ~= 0 or string.sub(result.out[1], 1, 1) ~= "{" or string.sub(result.out[1], -1) ~= "}" then
43+
utils.notify(
44+
"Artisan",
45+
{ msg = "'php artisan model:show" .. class .. " --json' response could not be decoded", level = "ERROR" }
46+
)
47+
return nil
48+
end
49+
50+
local model_info = vim.fn.json_decode(result.out[1])
51+
if model_info == nil then
52+
utils.notify(
53+
"Artisan",
54+
{ msg = "'php artisan model:show" .. class .. " --json' response could not be decoded", level = "ERROR" }
55+
)
56+
return nil
57+
end
58+
59+
---@return ModelRelation|nil
60+
local build_relation = function(info, relation_type)
61+
if next(info) == nil then
62+
return nil
63+
end
64+
if relation_type == "observers" and info["observer"][2] ~= nil then
65+
return {
66+
class = info["observer"][2],
67+
type = relation_type,
68+
extra_information = info["event"],
69+
}
70+
elseif relation_type == "relations" then
71+
return {
72+
class = info["related"],
73+
type = relation_type,
74+
extra_information = info["type"] .. " " .. info["name"],
75+
}
76+
elseif relation_type == "policy" then
77+
return {
78+
class = info[1],
79+
type = relation_type,
80+
extra_information = "",
81+
}
82+
end
83+
return nil
84+
end
85+
86+
local relations = {}
87+
local types = { "observers", "relations", "policy" }
88+
for _, relation_type in ipairs(types) do
89+
if model_info[relation_type] ~= vim.NIL and #model_info[relation_type] > 0 then
90+
if type(model_info[relation_type]) == "table" and model_info[relation_type][1] ~= vim.NIL then
91+
for _, info in ipairs(model_info[relation_type]) do
92+
local relation = build_relation(info, relation_type)
93+
if relation ~= nil then
94+
table.insert(relations, relation)
95+
end
96+
end
97+
else
98+
local relation = build_relation({ model_info[relation_type] }, relation_type)
99+
if relation ~= nil then
100+
table.insert(relations, relation)
101+
end
102+
end
103+
end
104+
end
105+
106+
pickers
107+
.new(opts, {
108+
prompt_title = "Related Files",
109+
finder = finders.new_table {
110+
results = relations,
111+
entry_maker = make_entry.gen_from_model_relations(opts),
112+
},
113+
sorter = conf.prefilter_sorter {
114+
sorter = conf.generic_sorter(opts or {}),
115+
},
116+
attach_mappings = function(_, map)
117+
map("i", "<cr>", function(prompt_bufnr)
118+
actions.close(prompt_bufnr)
119+
local entry = action_state.get_selected_entry()
120+
vim.schedule(function()
121+
local action = vim.fn.split(entry.value.class, "@")
122+
lsp.go_to(action[1], action[2])
123+
end)
124+
end)
125+
126+
return true
127+
end,
128+
})
129+
:find()
130+
end
131+
end
132+
end
133+
134+
return make_related

0 commit comments

Comments
 (0)