aboutsummaryrefslogtreecommitdiffstats
path: root/lua/alpha/php/lsp.lua
blob: be18c79be2b1bccf0ccdebec10039c5fd0fa2716 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
local Path = require("plenary.path")

local lsp = {}

local lsp_server_name = "phpactor"

lsp.get_lsp_buffer = function ()
    local clients = vim.lsp.get_active_clients({ name = lsp_server_name})
    if #clients == 0 then
        return
    end

    local lsp_client = clients[1]

    local attached_buffers = lsp_client.attached_buffers

    for key, val in pairs(attached_buffers) do
        if val then
            return key
        end
    end

    return nil
end


--- @param search string: fully name to search Class::method
lsp.find = function (search)
    search = vim.split(search, "::")
    local fqn_class = search[1]
    local method = search[2]

    local buffer = lsp.get_lsp_buffer()

    if buffer == nil then
        -- TODO I want to not require this.
        -- I can load a buffer but does not start the lsp
        P("load a php buffer to load the lsp server")
        return
    end

    local class_parts = vim.split(fqn_class, "\\")
    local class = class_parts[#class_parts]

    -- TODO phpactor does not support FQN search need to de sepparated
    -- can query get the optiosn, match the full name and type class
    -- I don't think gives the namespace
    -- So I will get the full name, not the
    -- the option is to get the class
    -- open the buffer, change in the window
    -- call the vim.lsp.buf_document_symbol({on_list = function (list) end})
    -- grab the information and move the cursor
    -- if method does not exist show error but stay in the class
    -- Can have the code extracted to work with both implementations ?
    -- Potentially could have a way to create the classes if they don't exist
    -- With the file creater action
    vim.lsp.buf_request(buffer, "workspace/symbol", { query = class }, function(err, server_result, _, _)
        if err then
            vim.api.nvim_err_writeln("Error when finding workspace symbols: " .. err.message)
            return
        end

        local locations = vim.lsp.util.symbols_to_items(server_result or {}, buffer) or {}
        if vim.tbl_isempty(locations) then
            vim.api.nvim_err_writeln("Empty response looking for class: " .. fqn_class)
            return
        end
        local class_location = nil
        for idx, location in pairs(locations) do
            if location.text == string.format("[Class] %s", fqn_class) then
                class_location = locations[idx]
                break
            end
        end

        if class_location == nil then
            P("Did not found any class")
            return
        end

        vim.lsp.buf_request(
            buffer,
            "workspace/symbol",
            { query = method },
            function(method_err, method_server_result, _, _)
                if err then
                    vim.api.nvim_err_writeln("Error when finding workspace symbols: " .. method_err.message)
                    return
                end

                local method_locations = vim.lsp.util.symbols_to_items(method_server_result or {}, buffer) or {}
                if vim.tbl_isempty(method_locations) then
                    P(string.format("empty response looking for method %s", method))
                    return
                end

                local method_location = nil
                for _, value in ipairs(method_locations) do
                    if value.filename == class_location.filename then
                        method_location = value
                        break
                    end
                end

                if method_location == nil then
                    return
                end

                local command = "edit"
                local filename = method_location.filename
                local row = method_location.lnum
                local col = method_location.col - 1

                if vim.api.nvim_buf_get_name(0) ~= filename or command ~= "edit" then
                    filename = Path:new(vim.fn.fnameescape(filename)):normalize(vim.loop.cwd())
                    pcall(vim.cmd, string.format("%s %s", command, filename))
                end

                if row and col then
                    local ok, err_msg = pcall(vim.api.nvim_win_set_cursor, 0, { row, col })
                    if not ok then
                        vim.api.nvim_err_writeln("error seting row and col: " .. err_msg)
                    end
                    vim.cmd("normal zt")
                end
            end
        )
    end)
end

return lsp