From ea0f4bf8ffade657b1d45152dbc183d4679e75c4 Mon Sep 17 00:00:00 2001 From: Elvis Claros Castro Date: Fri, 12 Jul 2024 11:18:14 -0300 Subject: Feat: PI --- lua/pi/animations.lua | 50 ++++++ lua/pi/completition/init.lua | 205 +++++++++++++++++++++ lua/pi/dap/configs/dart.lua | 32 ++++ lua/pi/dap/configs/elixir.lua | 52 ++++++ lua/pi/dap/configs/golang.lua | 1 + lua/pi/dap/configs/javascript.lua | 62 +++++++ lua/pi/dap/configs/kotlin.lua | 18 ++ lua/pi/dap/configs/php.lua | 27 +++ lua/pi/dap/configs/rust.lua | 57 ++++++ lua/pi/dap/init.lua | 108 ++++++++++++ lua/pi/globals.lua | 23 +++ lua/pi/laravel-tinker.lua | 64 +++++++ lua/pi/lsp/attach.lua | 29 +++ lua/pi/lsp/default.lua | 30 ++++ lua/pi/lsp/flags.lua | 3 + lua/pi/lsp/init.lua | 65 +++++++ lua/pi/lsp/mason.lua | 23 +++ lua/pi/lsp/null-ls.lua | 53 ++++++ lua/pi/lsp/servers/emmet_ls.lua | 12 ++ lua/pi/lsp/servers/html.lua | 14 ++ lua/pi/lsp/servers/jsonls.lua | 14 ++ lua/pi/lsp/servers/kotlin_language_server.lua | 12 ++ lua/pi/lsp/servers/lua_ls.lua | 36 ++++ lua/pi/lsp/servers/phpactor.lua | 80 +++++++++ lua/pi/lsp/servers/python.lua | 16 ++ lua/pi/lsp/servers/rust_analyzer.lua | 24 +++ lua/pi/lsp/servers/texlab.lua | 16 ++ lua/pi/lsp/servers/tsserver.lua | 33 ++++ lua/pi/lsp/servers/vscode_smarty_langserver.lua | 25 +++ lua/pi/lsp/tools.lua | 8 + lua/pi/packer_install.lua | 27 +++ lua/pi/php/gateway.lua | 137 +++++++++++++++ lua/pi/php/lsp.lua | 151 ++++++++++++++++ lua/pi/php/servers.lua | 38 ++++ lua/pi/select_to_quickfix.lua | 53 ++++++ lua/pi/snips/ft/cucumber.lua | 71 ++++++++ lua/pi/snips/ft/go.lua | 134 ++++++++++++++ lua/pi/snips/ft/lua.lua | 69 ++++++++ lua/pi/snips/ft/php.lua | 163 +++++++++++++++++ lua/pi/snips/ft/yaml.lua | 225 ++++++++++++++++++++++++ lua/pi/telescope/init.lua | 186 ++++++++++++++++++++ lua/pi/telescope/mappings.lua | 55 ++++++ lua/pi/telescope/my_actions.lua | 170 ++++++++++++++++++ lua/pi/telescope/setup.lua | 222 +++++++++++++++++++++++ lua/pi/test_menu.lua | 50 ++++++ lua/pi/test_strategy.lua | 65 +++++++ lua/pi/utils.lua | 11 ++ 47 files changed, 3019 insertions(+) create mode 100644 lua/pi/animations.lua create mode 100644 lua/pi/completition/init.lua create mode 100644 lua/pi/dap/configs/dart.lua create mode 100644 lua/pi/dap/configs/elixir.lua create mode 100644 lua/pi/dap/configs/golang.lua create mode 100644 lua/pi/dap/configs/javascript.lua create mode 100644 lua/pi/dap/configs/kotlin.lua create mode 100644 lua/pi/dap/configs/php.lua create mode 100644 lua/pi/dap/configs/rust.lua create mode 100644 lua/pi/dap/init.lua create mode 100644 lua/pi/globals.lua create mode 100644 lua/pi/laravel-tinker.lua create mode 100644 lua/pi/lsp/attach.lua create mode 100644 lua/pi/lsp/default.lua create mode 100644 lua/pi/lsp/flags.lua create mode 100644 lua/pi/lsp/init.lua create mode 100644 lua/pi/lsp/mason.lua create mode 100644 lua/pi/lsp/null-ls.lua create mode 100644 lua/pi/lsp/servers/emmet_ls.lua create mode 100644 lua/pi/lsp/servers/html.lua create mode 100644 lua/pi/lsp/servers/jsonls.lua create mode 100644 lua/pi/lsp/servers/kotlin_language_server.lua create mode 100644 lua/pi/lsp/servers/lua_ls.lua create mode 100644 lua/pi/lsp/servers/phpactor.lua create mode 100644 lua/pi/lsp/servers/python.lua create mode 100644 lua/pi/lsp/servers/rust_analyzer.lua create mode 100644 lua/pi/lsp/servers/texlab.lua create mode 100644 lua/pi/lsp/servers/tsserver.lua create mode 100644 lua/pi/lsp/servers/vscode_smarty_langserver.lua create mode 100644 lua/pi/lsp/tools.lua create mode 100644 lua/pi/packer_install.lua create mode 100644 lua/pi/php/gateway.lua create mode 100644 lua/pi/php/lsp.lua create mode 100644 lua/pi/php/servers.lua create mode 100644 lua/pi/select_to_quickfix.lua create mode 100644 lua/pi/snips/ft/cucumber.lua create mode 100644 lua/pi/snips/ft/go.lua create mode 100644 lua/pi/snips/ft/lua.lua create mode 100644 lua/pi/snips/ft/php.lua create mode 100644 lua/pi/snips/ft/yaml.lua create mode 100644 lua/pi/telescope/init.lua create mode 100644 lua/pi/telescope/mappings.lua create mode 100644 lua/pi/telescope/my_actions.lua create mode 100644 lua/pi/telescope/setup.lua create mode 100644 lua/pi/test_menu.lua create mode 100644 lua/pi/test_strategy.lua create mode 100644 lua/pi/utils.lua (limited to 'lua/pi') diff --git a/lua/pi/animations.lua b/lua/pi/animations.lua new file mode 100644 index 0000000..c0b7a6c --- /dev/null +++ b/lua/pi/animations.lua @@ -0,0 +1,50 @@ +local redraw_buffer = function() + local Animation = require "animation" + local fps = 45 -- frames per second + local easing = require "animation.easing" + + local buffer = 0 + local len = 0 + local place_holder = {} + + local lines = vim.api.nvim_buf_get_lines(buffer, 0, -1, true) + + for _, line in ipairs(lines) do + len = len + string.len(line) + table.insert(place_holder, "") + end + + vim.api.nvim_buf_set_lines(buffer, 0, #lines, true, place_holder) + + local duration = math.ceil(len / fps * 1000) + + local i = 1 + local line_nr = 1 + local insertLine = "" + + local function callback() + if lines[line_nr] == nil then + return true + end + local char = string.sub(lines[line_nr], i, i) + if char == nil then + return true + end + insertLine = insertLine .. char + i = i + 1 + vim.api.nvim_buf_set_lines(buffer, line_nr - 1, line_nr, true, { insertLine }) + + if insertLine == lines[line_nr] then + i = 1 + line_nr = line_nr + 1 + insertLine = "" + end + end + + local animation = Animation(duration, fps, easing.line, callback) + animation:run() +end + +return { + redraw_buffer = redraw_buffer, +} diff --git a/lua/pi/completition/init.lua b/lua/pi/completition/init.lua new file mode 100644 index 0000000..667e30b --- /dev/null +++ b/lua/pi/completition/init.lua @@ -0,0 +1,205 @@ +local cmp = require "cmp" +local lspkind = require "lspkind" +local luasnip = require "luasnip" +local cmp_autopairs = require "nvim-autopairs.completion.cmp" +local compare = require "cmp.config.compare" + +cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done { map_char = { tex = "" } }) + +cmp.setup { + window = { + completion = { + border = "rounded", + -- winhighlight = 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None', + -- winblend = vim.o.pumblend, + -- scrolloff = 0, + -- col_offset = 0, + -- side_padding = 1, + -- scrollbar = true, + }, + documentation = { + -- max_height = math.floor(WIDE_HEIGHT * (WIDE_HEIGHT / vim.o.lines)), + -- max_width = math.floor((WIDE_HEIGHT * 2) * (vim.o.columns / (WIDE_HEIGHT * 2 * 16 / 9))), + border = "rounded", + -- winhighlight = 'FloatBorder:NormalFloat', + -- winblend = vim.o.pumblend, + }, + }, + mapping = { + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.close() + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + else + fallback() + end + end, { "i", "s" }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.choice_active() then + luasnip.change_choice(1) + else + fallback() + end + end, { "i", "s" }), + [""] = cmp.mapping.select_prev_item(), + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.confirm { + behavior = cmp.ConfirmBehavior.Insert, + select = true, + }, + [""] = cmp.mapping.complete(), + }, + sources = { + { name = "dictionary" }, + { name = "nvim_lua" }, + { name = "nvim_lsp" }, + { name = "path" }, + { name = "luasnip" }, + { name = "copilot" }, + { + name = "buffer", + keyword_length = 4, + option = { + get_bufnrs = function() + local bufs = {} + for _, win in ipairs(vim.api.nvim_list_wins()) do + local bufnr = vim.api.nvim_win_get_buf(win) + if vim.api.nvim_buf_get_option(bufnr, "buftype") ~= "terminal" then + bufs[bufnr] = true + end + end + return vim.tbl_keys(bufs) + end, + }, + }, + }, + + snippet = { + expand = function(args) + require("luasnip").lsp_expand(args.body) + end, + }, + + formatting = { + format = function (entry, vim_item) + lspkind.cmp_format { + with_text = true, + menu = { + buffer = "[buf]", + nvim_lsp = "[ ]", + nvim_lua = "[api]", + path = "[path]", + luasnip = "[snip]", + copilot = "[ﮧ ]", + ["vim-dadbod-completion"] = "[DB]", + }, + } + local KIND_ICONS = { + Tailwind = '󰹞󰹞󰹞󰹞󰹞󰹞󰹞󰹞', + Color = ' ', + -- Class = 7, + -- Constant = '󰚞', + -- Constructor = 4, + -- Enum = 13, + -- EnumMember = 20, + -- Event = 23, + -- Field = 5, + -- File = 17, + -- Folder = 19, + -- Function = 3, + -- Interface = 8, + -- Keyword = 14, + -- Method = 2, + -- Module = 9, + -- Operator = 24, + -- Property = 10, + -- Reference = 18, + Snippet = " ", + -- Struct = 22, + -- Text = "", + -- TypeParameter = 25, + -- Unit = 11, + -- Value = 12, + -- Variable = 6 + } + if vim_item.kind == 'Color' and entry.completion_item.documentation then + local _, _, r, g, b = + ---@diagnostic disable-next-line: param-type-mismatch + string.find(entry.completion_item.documentation, '^rgb%((%d+), (%d+), (%d+)') + + if r and g and b then + local color = string.format('%02x', r) .. string.format('%02x', g) .. string.format('%02x', b) + local group = 'Tw_' .. color + + if vim.api.nvim_call_function('hlID', { group }) < 1 then + vim.api.nvim_command('highlight' .. ' ' .. group .. ' ' .. 'guifg=#' .. color) + end + + vim_item.kind = KIND_ICONS.Tailwind + vim_item.kind_hl_group = group + + return vim_item + end + end + + vim_item.kind = KIND_ICONS[vim_item.kind] or vim_item.kind + return vim_item + end + }, + + sorting = { + priority_weight = 2, + comparators = { + compare.kind, + compare.sort_text, + }, + }, + + experimental = { + native_menu = false, + + ghost_text = false, + }, +} + +vim.api.nvim_set_hl(0, "CmpItemKindCopilot", { fg = "#6CC644" }) + +-- Set configuration for specific filetype. +cmp.setup.filetype("gitcommit", { + sources = cmp.config.sources({ + { name = "cmp_git" }, -- You can specify the `cmp_git` source if you were installed it. + }, { + { name = "buffer" }, + }), +}) + +-- Use buffer source for `/` (if you enabled `native_menu`, this won't work anymore). +cmp.setup.cmdline("/", { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = "buffer" }, + }, +}) + +-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). +cmp.setup.cmdline(":", { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = "path" }, + }, { + { name = "cmdline" }, + }), +}) + +cmp.setup.filetype({ "sql", "mysql", "plsql" }, { + sources = cmp.config.sources({ + { name = "vim-dadbod-completion" }, + }, { + { name = "buffer" }, + }), +}) diff --git a/lua/pi/dap/configs/dart.lua b/lua/pi/dap/configs/dart.lua new file mode 100644 index 0000000..a23c118 --- /dev/null +++ b/lua/pi/dap/configs/dart.lua @@ -0,0 +1,32 @@ +local dap = require('dap') + +dap.adapters.dart = { + type = "executable", + -- As of this writing, this functionality is open for review in https://github.com/flutter/flutter/pull/91802 + command = "flutter", + args = {"debug_adapter"} +} +dap.configurations.dart = { + { + name = "Launch Flutter Program Linux", + type = "dart", + request = "launch", + -- The nvim-dap plugin populates this variable with the filename of the current buffer + program = "${file}", + -- The nvim-dap plugin populates this variable with the editor's current working directory + cwd = "${workspaceFolder}", + -- This gets forwarded to the Flutter CLI tool, substitute `linux` for whatever device you wish to launch + toolArgs = {"-d", "linux"} + }, + { + name = "Launch Flutter Program Motorola", + type = "dart", + request = "launch", + -- The nvim-dap plugin populates this variable with the filename of the current buffer + program = "${file}", + -- The nvim-dap plugin populates this variable with the editor's current working directory + cwd = "${workspaceFolder}", + -- This gets forwarded to the Flutter CLI tool, substitute `linux` for whatever device you wish to launch + toolArgs = {"-d", "192.168.0.33:5555"} + } +} diff --git a/lua/pi/dap/configs/elixir.lua b/lua/pi/dap/configs/elixir.lua new file mode 100644 index 0000000..bf732ce --- /dev/null +++ b/lua/pi/dap/configs/elixir.lua @@ -0,0 +1,52 @@ +local dap = require('dap') + +dap.adapters.mix_task = { + type = 'executable', + command = 'elixir-ls-debugger', -- El comando 'elixir-ls' está en $PATH + args = {} +} + +dap.configurations.elixir = { + { + type = "mix_task", + name = "mix (Default task)", + request = "launch", + projectDir = "${workspaceRoot}" + }, + { + type = "mix_task", + name = "mix test", + request = "launch", + task = 'test', + env = { + MIX_ENV = "test", + MIX_TARGET = "host", + HEX_UNSAFE_HTTPS = 1 + }, + taskArgs = {"--trace"}, + startApps = true, -- for Phoenix projects + projectDir = "${workspaceFolder}", + requireFiles = { + "test/**/test_helper.exs", + "test/**/*_test.exs" + } + }, + { + type = "mix_task", + name = "phx server", + request = "launch", + stackTraceMode = "all", + task = 'phx.server', + debugAutoInterpretAllModules = true, + noDebug = false, + exitAfterTaskReturns = false, + env = { + MIX_ENV = "dev", + MIX_TARGET = "host", + HEX_UNSAFE_HTTPS = 1 + }, + startApps = false, -- for Phoenix projects + taskArgs = {"--no-halt", "--open"}, + projectDir = "${workspaceFolder}", + }, +} diff --git a/lua/pi/dap/configs/golang.lua b/lua/pi/dap/configs/golang.lua new file mode 100644 index 0000000..1ec449a --- /dev/null +++ b/lua/pi/dap/configs/golang.lua @@ -0,0 +1 @@ +require("dap-go").setup() diff --git a/lua/pi/dap/configs/javascript.lua b/lua/pi/dap/configs/javascript.lua new file mode 100644 index 0000000..03173ba --- /dev/null +++ b/lua/pi/dap/configs/javascript.lua @@ -0,0 +1,62 @@ +local dap = require('dap') +dap.adapters.firefox = { + type = 'executable', + command = 'firefox-debug-adapter', +} + +dap.configurations.typescript = { + { + name = 'Debug with Firefox', + type = 'firefox', + request = 'launch', + reAttach = true, + url = 'http://localhost:3010', + webRoot = '${workspaceFolder}', + firefoxExecutable = '/home/elvis/.local/bin/firefox' + }, +} +-- require("dap-vscode-js").setup { +-- debugger_cmd = { "js-debug-adapter" }, +-- adapters = { "pwa-node", "pwa-chrome", "node-terminal" }, +-- } +-- +-- for _, language in ipairs { "typescript", "javascript" } do +-- require("dap").configurations[language] = { +-- { +-- type = "pwa-node", +-- request = "launch", +-- name = "Launch file", +-- program = "${file}", +-- cwd = "${workspaceFolder}", +-- }, +-- { +-- type = "pwa-node", +-- request = "attach", +-- name = "Attach", +-- processId = require("dap.utils").pick_process, +-- cwd = "${workspaceFolder}", +-- }, +-- } +-- end +-- +-- for _, language in ipairs { "typescriptreact", "javascriptreact" } do +-- require("dap").configurations[language] = { +-- { +-- type = "pwa-chrome", +-- name = "Attach - Remote Debugging", +-- request = "attach", +-- program = "${file}", +-- cwd = vim.fn.getcwd(), +-- sourceMaps = true, +-- protocol = "inspector", +-- port = 9222, +-- webRoot = "${workspaceFolder}", +-- }, +-- { +-- type = "pwa-chrome", +-- name = "Launch Chrome", +-- request = "launch", +-- url = "http://localhost:3000", +-- }, +-- } +-- end diff --git a/lua/pi/dap/configs/kotlin.lua b/lua/pi/dap/configs/kotlin.lua new file mode 100644 index 0000000..aa486db --- /dev/null +++ b/lua/pi/dap/configs/kotlin.lua @@ -0,0 +1,18 @@ +local dap = require('dap') + +dap.adapters.kotlin = { + type = 'executable'; + command = "kotlin-debug-adapter"; +} + +dap.configurations.kotlin = { + { + type = 'kotlin', + request = 'launch', + program = "${file}", + name = 'Launch kotlin program', + projectRoot = "${workspaceFolder}/app", + mainClass = "AppKt", + } +} +dap.defaults.kotlin.auto_continue_if_many_stopped = false diff --git a/lua/pi/dap/configs/php.lua b/lua/pi/dap/configs/php.lua new file mode 100644 index 0000000..968bb9d --- /dev/null +++ b/lua/pi/dap/configs/php.lua @@ -0,0 +1,27 @@ +local dap = require("dap") + +dap.adapters.php = { + type = "executable", + command = "php-debug-adapter", +} + +dap.configurations.php = { + { + type = "php", + request = "launch", + name = "Laravel", + port = 9003, + pathMappings = { + ["/var/www/html"] = "${workspaceFolder}", + }, + }, + { + type = "php", + request = "launch", + name = "Symfony", + port = 9003, + pathMappings = { + ["/app"] = "${workspaceFolder}", + }, + }, +} diff --git a/lua/pi/dap/configs/rust.lua b/lua/pi/dap/configs/rust.lua new file mode 100644 index 0000000..9ca976f --- /dev/null +++ b/lua/pi/dap/configs/rust.lua @@ -0,0 +1,57 @@ +local dap = require("dap") + +local rust_adapter = nil +local rust_adapters = { "lldb-vscode", "codelldb" } +for _, adapter in pairs(rust_adapters) do + if vim.fn.executable(adapter) then + rust_adapter = adapter + end +end + +if rust_adapter ~= nil then + dap.adapters.lldb = { + type = "executable", + command = rust_adapter, + name = "lldb", + } + + dap.configurations.rust = { + { + name = "launch", + type = "lldb", + request = "launch", + program = function() + local dir = vim.fn.getcwd() + return dir .. "/target/debug/" .. vim.fs.basename(dir) + end, + cwd = "${workspaceFolder}", + stopOnEntry = false, + args = function() + local resp = vim.fn.input "Arguments: " + if resp == "" then + return {} + end + + return vim.fn.split(resp, " ") + end, + }, + { + name = "custom", + type = "lldb", + request = "launch", + program = function() + return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/", "file") + end, + cwd = "${workspaceFolder}", + stopOnEntry = false, + args = function() + local resp = vim.fn.input "Arguments: " + if resp == "" then + return {} + end + + return vim.fn.split(resp, " ") + end, + }, + } +end diff --git a/lua/pi/dap/init.lua b/lua/pi/dap/init.lua new file mode 100644 index 0000000..327dedf --- /dev/null +++ b/lua/pi/dap/init.lua @@ -0,0 +1,108 @@ +local dap, dapui, hydra = require "dap", require "dapui", require "hydra" + +dap.set_log_level('TRACE') + +-- Setup Virtual Text +require("nvim-dap-virtual-text").setup {} + +for _, ft_path in ipairs(vim.api.nvim_get_runtime_file("lua/pi/dap/configs/*.lua", true)) do + loadfile(ft_path)() +end + +-- Signs +vim.fn.sign_define("DapBreakpoint", { text = "🛑", texthl = "", linehl = "", numhl = "" }) +vim.fn.sign_define("DapStopped", { text = "▶", texthl = "", linehl = "", numhl = "" }) +vim.fn.sign_define("DapBreakpointRejected", { text = "🚫", texthl = "", linehl = "", numhl = "" }) +vim.fn.sign_define("DapBreakpointCondition", { text = "❓", texthl = "", linehl = "", numhl = "" }) +vim.fn.sign_define("DapLogPoint", { text = "💬", texthl = "", linehl = "", numhl = "" }) + +-- UI structure +dapui.setup { + icons = { expanded = "▾", collapsed = "▸" }, + layouts = { + { + elements = { + "scopes", + "breakpoints", + "stacks", + "watches", + }, + size = 50, + position = "right", + }, + { + elements = { + "repl", + "console", + }, + size = 7, + position = "bottom", + }, + }, +} + +-- Events Listeners +dap.listeners.after.event_initialized["dapui_config"] = function() + dapui.open {} +end + +local hint = [[ + Nvim DAP + _d_: Start/Continue _j_: StepOver _k_: StepOut _l_: StepInto ^ + _bp_: Toogle Breakpoint _bc_: Conditional Breakpoint ^ + _?_: log point ^ + _c_: Run To Cursor ^ + _h_: Show information of the variable under the cursor ^ + _x_: Stop Debbuging ^ + ^^ __ +]] + +hydra { + name = "dap", + hint = hint, + mode = "n", + config = { + color = "blue", + invoke_on_body = true, + hint = { + border = "rounded", + position = "bottom", + }, + }, + body = "d", + heads = { + { "d", dap.continue }, + { "bp", dap.toggle_breakpoint }, + { "l", dap.step_into }, + { "j", dap.step_over }, + { "k", dap.step_out }, + { "h", dapui.eval }, + { "c", dap.run_to_cursor }, + { + "bc", + function() + vim.ui.input({ prompt = "Condition: " }, function(condition) + dap.set_breakpoint(condition) + end) + end, + }, + { + "?", + function() + vim.ui.input({ prompt = "Log: " }, function(log) + dap.set_breakpoint(nil, nil, log) + end) + end, + }, + { + "x", + function() + dap.terminate() + dapui.close {} + dap.clear_breakpoints() + end, + }, + + { "", nil, { exit = true } }, + }, +} diff --git a/lua/pi/globals.lua b/lua/pi/globals.lua new file mode 100644 index 0000000..e445e72 --- /dev/null +++ b/lua/pi/globals.lua @@ -0,0 +1,23 @@ +--- Dumps all values into pretty print +---@vararg any +---@return any +dump = function(...) + local args = {...} + + local mapped = {} + for _, v in ipairs(args) do + table.insert(mapped, vim.inspect(v)) + end + print(unpack(mapped)) + + return unpack(args) +end + +Reload = function(...) + return require("plenary.reload").reload_module(...) +end + +R = function(name) + Reload(name) + return require(name) +end diff --git a/lua/pi/laravel-tinker.lua b/lua/pi/laravel-tinker.lua new file mode 100644 index 0000000..214d958 --- /dev/null +++ b/lua/pi/laravel-tinker.lua @@ -0,0 +1,64 @@ +local M = {} + +M.runCode = function() + local curBuff = vim.api.nvim_get_current_buf() + + local stats = vim.api.nvim_list_uis()[1] + + local width = stats.width + local height = stats.height + + local bufh = vim.api.nvim_create_buf(false, true) + local winId = vim.api.nvim_open_win(bufh, true, { + relative = "editor", + width = width * 0.75, + height = height * 0.75, + col = 2, + row = 2, + style = "minimal", + border = "rounded", + }) + + -- get the start and end lines of selection + local startLine = vim.api.nvim_buf_get_mark(curBuff, "<")[1] - 1 + local endLine = vim.api.nvim_buf_get_mark(curBuff, ">")[1] + -- print("range: ", startLine, endLine) + + local code = vim.api.nvim_buf_get_lines(curBuff, startLine, endLine, false) + + -- print (vim.inspect(code)) + + local codeText = vim.fn.shellescape(table.concat(code, " ")) + -- print(codeText) + + local result = vim.fn.systemlist("php artisan tinker --execute=" .. codeText) + + vim.api.nvim_buf_set_text(bufh, 0, 0, 0, 0, result) +end + +M.backTerminal = function() + local bufh = vim.api.nvim_create_buf(false, true) + local term = vim.api.nvim_open_term(bufh, {}) + + local winId = vim.api.nvim_open_win(bufh, true, { + relative = "editor", + width = 80, + height = 80, + col = 2, + row = 2, + style = "minimal", + border = "rounded", + }) + + local jobId = vim.fn.jobstart("php artisan tinker", { + on_stdout = function(err, data) + print(err, vim.inspect(data)) + vim.api.nvim_chan_send(term, table.concat(data, "\n")) + end, + }) + + vim.api.nvim_chan_send(jobId, "$ub = UploadBatch::find(1);\n") + vim.api.nvim_chan_send(jobId, "dump($ub);\n") +end + +return M diff --git a/lua/pi/lsp/attach.lua b/lua/pi/lsp/attach.lua new file mode 100644 index 0000000..7c28494 --- /dev/null +++ b/lua/pi/lsp/attach.lua @@ -0,0 +1,29 @@ +local telescope_mapper = require "pi.telescope.mappings" + +return function(client, bufnr) + -- keymaps for lsp + vim.keymap.set("n", "K", vim.lsp.buf.hover, { buffer = 0, desc = "LSP Help information of symbol under the cursor" }) + vim.keymap.set("n", "vrn", vim.lsp.buf.rename, { buffer = 0, desc = "LSP Rename symbol under cursor" }) + vim.keymap.set("i", "", vim.lsp.buf.signature_help, { buffer = 0, desc = "LSP Signature help" }) + vim.keymap.set("n", "vo", ":LspRestart", { noremap = true, desc = "LSP Restart Server" }) + vim.keymap.set({ "n", "v" }, "vca", vim.lsp.buf.code_action, { buffer = 0, desc = "LSP Code actions" }) + vim.keymap.set("n", "vf", function() + return vim.lsp.buf.format { + async = true, + filter = function(cli) + return cli.name ~= "lua_ls" + end, + } + end, { buffer = 0, desc = "LSP format file" }) + + telescope_mapper("gr", "lsp_references", { buffer = true, desc = "LSP References of symbol on cursor" }) + telescope_mapper("pv", "find_symbol", { buffer = true, desc = "LSP find symbol on the project" }) + telescope_mapper("pd", "lsp_document_symbols", { buffer = true, desc = "LSP document symbols" }) + telescope_mapper("gd", "lsp_definitions", { buffer = true, desc = "LSP go to definition" }) + + vim.bo.omnifunc = "v:lua.vim.lsp.omnifunc" + + if client.server_capabilities.inlayHintProvider then + vim.lsp.inlay_hint.enable(bufnr) + end +end diff --git a/lua/pi/lsp/default.lua b/lua/pi/lsp/default.lua new file mode 100644 index 0000000..1405a72 --- /dev/null +++ b/lua/pi/lsp/default.lua @@ -0,0 +1,30 @@ +return { + mason = { + enable = true, + auto_install = false, + }, + servers = { + emmet_ls = { enable = true }, + gopls = { enable = true }, + html = { enable = true }, + jsonls = { enable = true }, + lua_ls = { enable = true, neodev = true }, + nil_ls = { enable = true }, + phpactor = {enable = true }, + rust_analyzer = { enable = true }, + svelte = { enable = true }, + tailwindcss = { enable = true, filetypes = {"blade", "html", "svelte"} }, + tsserver = { enable = true }, + volar = { enable = true }, + texlab = { enable = true, filetypes = {"tex", "bib"} }, + pyright = { enable = true, filetypes = {"python"} }, + kotlin_language_server = { enable = true, filetypes = {"kotlin"}, root_dir = require("lspconfig.util").root_pattern("build.gradle.kts", "pom.xml", ".git") }, + smarty_ls = { enable = true, filetypes = {"smarty"}, root_dir = require("lspconfig.util").root_pattern("composer.json", ".git") }, + }, + default_options = function (options) + return vim.tbl_deep_extend("force", { + on_attach = require"pi.lsp.attach", + flags = require "pi.lsp.flags", + }, options) + end, +} diff --git a/lua/pi/lsp/flags.lua b/lua/pi/lsp/flags.lua new file mode 100644 index 0000000..f70b467 --- /dev/null +++ b/lua/pi/lsp/flags.lua @@ -0,0 +1,3 @@ +return { + debounce_text_changes = 150, +} diff --git a/lua/pi/lsp/init.lua b/lua/pi/lsp/init.lua new file mode 100644 index 0000000..4454639 --- /dev/null +++ b/lua/pi/lsp/init.lua @@ -0,0 +1,65 @@ +return { + setup = function(ops) + ops = vim.tbl_deep_extend("force", require "pi.lsp.default", ops) + + local lspconfig = require "lspconfig" + + local mason_servers = {} + for server, options in pairs(ops.servers) do + if options.enable == true then + local ok, definition = pcall(require, "pi.lsp.servers." .. server) + local server_options + if not ok then + server_options = ops.default_options(options) + else + server_options = definition(options) + end + lspconfig[server].setup(server_options) + table.insert(mason_servers, server) + end + end + + -- Mason + if ops.mason.enable then + local mason_ops = {} + if ops.mason.auto_install == true then + mason_ops.ensure_installed = mason_servers + end + local mason_lspconfig = require "mason-lspconfig" + mason_lspconfig.setup(mason_ops) + end + + -- TODO: implement null ls with options + require "pi.lsp.null-ls" + + local servers = {} + for server, options in pairs(ops.servers) do + table.insert(servers, string.format("%s <%s>", server, options.enable)) + end + + -- TODO: create an auto command that on write of the configuration, calls again the setup and restart the server if it's up. + -- can get the client by name of the file + + vim.api.nvim_create_user_command("AlphaLSP", function() + vim.ui.select(servers, { prompt = "LSP Servers" }, function(server) + if server == nil then + return + end + + server = string.match(server, "^(.+) <") + local path = string.format("%s/lua/pi/lsp/servers/%s.lua", vim.fn.stdpath "config", server) + if vim.fn.filereadable(path) == 0 then + local create = vim.fn.confirm("Server Does Not exist. Create new server?", "&Yes\n&No\n&Cancel") + if create ~= 1 then + return + end + end + + local uri = vim.uri_from_fname(path) + local buffer = vim.uri_to_bufnr(uri) + + vim.api.nvim_win_set_buf(0, buffer) + end) + end, {}) + end, +} diff --git a/lua/pi/lsp/mason.lua b/lua/pi/lsp/mason.lua new file mode 100644 index 0000000..91d0c2b --- /dev/null +++ b/lua/pi/lsp/mason.lua @@ -0,0 +1,23 @@ +local mason_lspconfig = require "mason-lspconfig" +local servers = require "pi.lsp.servers" +local lspconfig = require "lspconfig" + +local mason_servers = {} + +for server, _ in pairs(servers) do + local cmd = lspconfig[server].cmd[1] + if vim.fn.executable(cmd) == 0 then + table.insert(mason_servers, server) + end +end + +mason_lspconfig.setup { + -- ensure_installed = mason_servers, +} + +-- filter the list for the ones not globally installed +-- require("mason-tool-installer").setup { +-- ensure_installed = vim.tbl_filter(function (tool) +-- return vim.fn.executable(tool) == 0 +-- end, require "pi.lsp.tools"), +-- } diff --git a/lua/pi/lsp/null-ls.lua b/lua/pi/lsp/null-ls.lua new file mode 100644 index 0000000..b329ba6 --- /dev/null +++ b/lua/pi/lsp/null-ls.lua @@ -0,0 +1,53 @@ +local null_ls = require "null-ls" +-- local php_actions = require "php-code-actions" +-- local laravel_actions = require("laravel.code-actions") + +null_ls.setup { + sources = { + -- null_ls.builtins.code_actions.gitsigns, + null_ls.builtins.formatting.jq, + null_ls.builtins.code_actions.refactoring, + null_ls.builtins.formatting.alejandra, + null_ls.builtins.diagnostics.luacheck, + null_ls.builtins.formatting.stylua, + + null_ls.builtins.diagnostics.yamllint, + + -- php_actions.getter_setter, + -- php_actions.file_creator, + + -- null_ls.builtins.diagnostics.phpstan.with { + -- to_temp_file = false, + -- method = null_ls.methods.DIAGNOSTICS_ON_SAVE, + -- -- command = "./bin/phpstan", + -- -- condition = function () + -- -- return vim.fn.findfile("bin/phpstan") ~= "" + -- -- end + -- }, + null_ls.builtins.diagnostics.phpcs.with { + method = null_ls.methods.DIAGNOSTICS_ON_SAVE, + condition = function(utils) + return utils.root_has_file "phpcs.xml" + end, + }, + null_ls.builtins.formatting.pint, + }, +} + +vim.keymap.set({ "n", "v" }, "vca", vim.lsp.buf.code_action, {desc = "LSP (null ls) Code actions"}) +vim.keymap.set("n", "vf", function() + return vim.lsp.buf.format { async = true } +end, {desc = "LSP (null ls) Format file"}) + +-- function to toogle and possible restart it +vim.api.nvim_create_user_command("NullLsToggle", function() + local sources = vim.tbl_map(function(el) + return el.name + end, null_ls.get_sources()) + vim.ui.select(sources, {}, function(selected) + if not selected then + return + end + null_ls.toggle(selected) + end) +end, {}) diff --git a/lua/pi/lsp/servers/emmet_ls.lua b/lua/pi/lsp/servers/emmet_ls.lua new file mode 100644 index 0000000..717edf8 --- /dev/null +++ b/lua/pi/lsp/servers/emmet_ls.lua @@ -0,0 +1,12 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + local capabilities = require("cmp_nvim_lsp").default_capabilities(vim.lsp.protocol.make_client_capabilities()) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + capabilities = capabilities, + filetypes = { "html", "typescriptreact", "javascriptreact", "css", "sass", "scss", "less", "blade", "vue" }, + }, ops) +end diff --git a/lua/pi/lsp/servers/html.lua b/lua/pi/lsp/servers/html.lua new file mode 100644 index 0000000..b20553b --- /dev/null +++ b/lua/pi/lsp/servers/html.lua @@ -0,0 +1,14 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + local config = { + on_attach = lsp_attach, + flags = lsp_flags, + } + if vim.fn.executable "html-languageserver" == 1 then + config.cmd = { "html-languageserver", "--stdio" } + end + + return vim.tbl_extend("force", config, ops) +end diff --git a/lua/pi/lsp/servers/jsonls.lua b/lua/pi/lsp/servers/jsonls.lua new file mode 100644 index 0000000..3fa16e1 --- /dev/null +++ b/lua/pi/lsp/servers/jsonls.lua @@ -0,0 +1,14 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + local config = { + on_attach = lsp_attach, + flags = lsp_flags, + } + if vim.fn.executable "json-languageserver" == 1 then + config.cmd = { "json-languageserver", "--stdio" } + end + + return vim.tbl_extend("force", config, ops) +end diff --git a/lua/pi/lsp/servers/kotlin_language_server.lua b/lua/pi/lsp/servers/kotlin_language_server.lua new file mode 100644 index 0000000..59e9406 --- /dev/null +++ b/lua/pi/lsp/servers/kotlin_language_server.lua @@ -0,0 +1,12 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" +return function(ops) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + ["kotlin-language-server"] = { + } + } + }, ops) +end diff --git a/lua/pi/lsp/servers/lua_ls.lua b/lua/pi/lsp/servers/lua_ls.lua new file mode 100644 index 0000000..3975310 --- /dev/null +++ b/lua/pi/lsp/servers/lua_ls.lua @@ -0,0 +1,36 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + if ops.neodev == true then + require("neodev").setup() + end + + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + Lua = { + runtime = { + version = "LuaJIT", + }, + diagnostics = { + globals = { "vim" }, + }, + workspace = { + library = vim.api.nvim_get_runtime_file("", true), + checkThirdParty = false, + }, + telemetry = { + enable = false, + }, + hint = { + enable = true, + }, + completion = { + callSnippet = "Replace", + }, + }, + }, + }, ops) +end diff --git a/lua/pi/lsp/servers/phpactor.lua b/lua/pi/lsp/servers/phpactor.lua new file mode 100644 index 0000000..e5a92ed --- /dev/null +++ b/lua/pi/lsp/servers/phpactor.lua @@ -0,0 +1,80 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +local function phpactor_attach(_, bufnr) + vim.api.nvim_buf_create_user_command(bufnr, "LspPhpactorReindex", function() + vim.lsp.buf_notify(bufnr, "phpactor/index/reindex", {}) + end, {}) + + vim.api.nvim_buf_create_user_command(bufnr, "LspPhpactorStatus", function() + local results, _ = vim.lsp.buf_request_sync(bufnr, "phpactor/status", { ["return"] = true }) + + local content = "" + + for _, res in pairs(results or {}) do + if res ~= nil and res["result"] ~= nil then + content = content .. res["result"] + end + end + + local Popup = require "nui.popup" + local event = require("nui.utils.autocmd").event + + local popup = Popup { + enter = true, + focusable = true, + border = { + style = "rounded", + }, + position = "50%", + size = { + width = "80%", + height = "60%", + }, + } + + -- mount/open the component + popup:mount() + + -- unmount component when cursor leaves buffer + popup:on(event.BufLeave, function() + popup:unmount() + end) + local out = {} + for match in string.gmatch(content, "[^\n]+") do + table.insert(out, match) + end + + -- vim.api.nvim_buf_set_option(popup.bufnr, "filetype", "markdown") + vim.api.nvim_buf_set_lines(popup.bufnr, 0, 1, false, out) + end, {}) +end + +return function(ops) + return vim.tbl_extend("force", { + on_attach = function(client, bufnr) + lsp_attach(client, bufnr) + phpactor_attach(client, bufnr) + end, + flags = lsp_flags, + filetypes = { "php", "blade" }, + init_options = { + ["language_server_worse_reflection.inlay_hints.enable"] = true, + ["language_server_worse_reflection.inlay_hints.params"] = true, + ["language_server_worse_reflection.inlay_hints.types"] = true, + ["language_server_configuration.auto_config"] = false, + ["code_transform.import_globals"] = true, + ["language_server_phpstan.enabled"] = true, + ["language_server_phpstan.level"] = 7, + ["language_server_phpstan.bin"] = "phpstan", + }, + handlers = { + ["textDocument/inlayHint"] = function(err, result, ...) + for _, res in ipairs(result) do + res.label = res.label .. ": " + end + vim.lsp.handlers["textDocument/inlayHint"](err, result, ...) + end, + }, + }, ops) +end diff --git a/lua/pi/lsp/servers/python.lua b/lua/pi/lsp/servers/python.lua new file mode 100644 index 0000000..db561aa --- /dev/null +++ b/lua/pi/lsp/servers/python.lua @@ -0,0 +1,16 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" +return function (ops) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + ["pyright"] = { + disableOrganizeImports = false, + disableDiagnostics = false, + disableLanguageServices = false, + typeCheckingMode = "strict", + } + } + }, ops) +end diff --git a/lua/pi/lsp/servers/rust_analyzer.lua b/lua/pi/lsp/servers/rust_analyzer.lua new file mode 100644 index 0000000..8999ef8 --- /dev/null +++ b/lua/pi/lsp/servers/rust_analyzer.lua @@ -0,0 +1,24 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + ["rust-analyzer"] = { + checkOnSave = { + allFeatures = true, + overrideCommand = { + "cargo", + "clippy", + "--workspace", + "--message-format=json", + "--all-targets", + "--all-features", + }, + }, + }, + }, + }, ops) +end diff --git a/lua/pi/lsp/servers/texlab.lua b/lua/pi/lsp/servers/texlab.lua new file mode 100644 index 0000000..523628b --- /dev/null +++ b/lua/pi/lsp/servers/texlab.lua @@ -0,0 +1,16 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" +return function(ops) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + ["texlab"] = { + latexFormatter = "latexindent", + latexindent = { + modifyLineBreaks = false + } + } + } + }, ops) +end diff --git a/lua/pi/lsp/servers/tsserver.lua b/lua/pi/lsp/servers/tsserver.lua new file mode 100644 index 0000000..c68c894 --- /dev/null +++ b/lua/pi/lsp/servers/tsserver.lua @@ -0,0 +1,33 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + typescript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, + javascript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, + }, + }, ops) +end diff --git a/lua/pi/lsp/servers/vscode_smarty_langserver.lua b/lua/pi/lsp/servers/vscode_smarty_langserver.lua new file mode 100644 index 0000000..bf29082 --- /dev/null +++ b/lua/pi/lsp/servers/vscode_smarty_langserver.lua @@ -0,0 +1,25 @@ +local lsp_attach = require "pi.lsp.attach" +local lsp_flags = require "pi.lsp.flags" + +return function(ops) + return vim.tbl_extend("force", { + on_attach = lsp_attach, + flags = lsp_flags, + settings = { + css = { + validate = true + }, + smarty = { + pluginDirs = {} + }, + ["smarty_ls"] = { + checkOnSave = { + overrideCommand = { + "smarty-language-server", + "--stdio", + }, + }, + }, + }, + }, ops) +end diff --git a/lua/pi/lsp/tools.lua b/lua/pi/lsp/tools.lua new file mode 100644 index 0000000..7919521 --- /dev/null +++ b/lua/pi/lsp/tools.lua @@ -0,0 +1,8 @@ +return { + "codelldb", + "go-debug-adapter", + "js-debug-adapter", + "php-debug-adapter", + "phpcs", + "phpstan", +} diff --git a/lua/pi/packer_install.lua b/lua/pi/packer_install.lua new file mode 100644 index 0000000..9ef6658 --- /dev/null +++ b/lua/pi/packer_install.lua @@ -0,0 +1,27 @@ +local download_packer = function() + if vim.fn.input "Download Packer? (y for yes)" ~= "y" then + return + end + + local directory = string.format("%s/site/pack/packer/start/", vim.fn.stdpath "data") + + vim.fn.mkdir(directory, "p") + + local out = vim.fn.system( + string.format("git clone %s %s", "https://github.com/wbthomason/packer.nvim", directory .. "/packer.nvim") + ) + + print(out) + print "Downloading packer.nvim..." + print "( You'll need to restart now )" +end + +return function() + if not pcall(require, "packer") then + download_packer() + + return true + end + + return false +end diff --git a/lua/pi/php/gateway.lua b/lua/pi/php/gateway.lua new file mode 100644 index 0000000..83c95e9 --- /dev/null +++ b/lua/pi/php/gateway.lua @@ -0,0 +1,137 @@ +local pickers = require "telescope.pickers" +local finders = require "telescope.finders" +local conf = require("telescope.config").values +local action_state = require "telescope.actions.state" +local action_set = require "telescope.actions.set" +local actions = require "telescope.actions" +local get_node_text = vim.treesitter.get_node_text + +local gateway = {} + +local get_definition_buffer = function(type) + local uri = vim.uri_from_fname(vim.fn.getcwd() .. "/config/graphql/_" .. type .. ".yaml") + local buff = vim.uri_to_bufnr(uri) + vim.fn.bufload(buff) + + return buff +end + +local get_all_definitions = function() + local mutations_definitions = gateway.get_graphql_definitions(get_definition_buffer "mutation") + local queries_definitions = gateway.get_graphql_definitions(get_definition_buffer "query") + for _, definition in ipairs(queries_definitions) do + table.insert(mutations_definitions, definition) + end + + return mutations_definitions +end + +-- "'@=mutation(\"App\\\\GraphQL\\\\Mutations\\\\Mutation::action\", ...)'", +local open_resolver = function(resolver) + -- need to parse to get this values + local args = string.match(resolver, "'@=mutation%((.+)%)'") + if args == nil then + args = string.match(resolver, "'@=query%((.+)%)'") + end + if args == nil then + return + end + + local args_tbl = vim.split(args, ", ") + local fqn = string.match(args_tbl[1], '"(.+)"') + fqn = string.gsub(fqn, "\\\\", "\\") + -- P(fqn) + + require("pi.php.lsp").find(fqn, "phpactor") +end + +--- @param bufnr integer Buff id +gateway.get_graphql_definitions = function(bufnr) + vim.treesitter.query.set( + "yaml", + "GraphQL_endpoints", + [[ + (document (block_node (block_mapping (block_mapping_pair + value: (block_node (block_mapping (block_mapping_pair + value: (block_node (block_mapping (block_mapping_pair + value: (block_node (block_mapping (block_mapping_pair + key: (flow_node) @mutation + value: (block_node (block_mapping (block_mapping_pair + key: (flow_node) @resolve (#eq? @resolve "resolve") + value: (flow_node) @resolver + ))) + ))) + ))) + ))) + )))) + ]] + ) + + local query = vim.treesitter.query.get("yaml", "GraphQL_endpoints") + + local elements = {} + + local parsers = require "nvim-treesitter.parsers" + local parser = parsers.get_parser(bufnr) + local tree = parser:parse()[1] + + for id, node in query:iter_captures(tree:root(), bufnr) do + if query.captures[id] == "mutation" then + table.insert(elements, { + value = get_node_text(node, bufnr), + lnum = node:start() + 1, + buffer = bufnr, + }) + elseif query.captures[id] == "resolver" then + elements[#elements].resolver = get_node_text(node, bufnr) + end + end + + return elements +end + +--- gets the graphql function defined on a given buffer +--- @param opts table: options to pass to the picker +gateway.graphql_definitions = function(opts) + opts = opts or {} + pickers + .new(opts, { + promt_title = "Queries", + finder = finders.new_table { + results = get_all_definitions(), + entry_maker = function(entry) + -- buffer = 43, + -- lnum = 82, + -- resolver = "'@=mutation(\"App\\\\GraphQL\\\\Mutation\\\\Mutation::action\", ...)'", + -- value = "deleteVehicleImage" + return { + value = entry, + display = entry.value, + ordinal = entry.value, + path = vim.api.nvim_buf_get_name(entry.buffer), + lnum = entry.lnum, + resolver = entry.resolver, + } + end, + }, + sorter = conf.generic_sorter(opts), + previewer = conf.grep_previewer(opts), + attach_mappings = function(prompt_bufnr, map) + action_set.select:enhance { + post = function() + local selection = action_state.get_selected_entry() + vim.api.nvim_win_set_cursor(0, { selection.lnum, 0 }) + end, + } + map("i", "", function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + open_resolver(selection.resolver) + end) + return true + end, + }) + :find() +end + +return gateway diff --git a/lua/pi/php/lsp.lua b/lua/pi/php/lsp.lua new file mode 100644 index 0000000..37e0bc0 --- /dev/null +++ b/lua/pi/php/lsp.lua @@ -0,0 +1,151 @@ +local Path = require "plenary.path" + +local lsp = {} + +local open_filename = function(filename) + if vim.api.nvim_buf_get_name(0) ~= filename then + filename = Path:new(vim.fn.fnameescape(filename)):normalize(vim.loop.cwd()) + pcall(vim.cmd, string.format("%s %s", "edit", filename)) + end +end + +---@param server_name string +---@return table|nil, boolean +local get_client = function(server_name) + local clients = vim.lsp.get_active_clients { name = server_name } + local client = clients[1] or nil + local new_instance = false + + if not client then + local server = require("lspconfig")[server_name] + local config = server.make_config(vim.fn.getcwd()) + local client_id = vim.lsp.start(config) + client = vim.lsp.get_client_by_id(client_id) + new_instance = true + end + + return client, new_instance +end + +local function go_to(client, is_new_instance, full_class, method) + local class_parts = vim.split(full_class, "\\") + local class = class_parts[#class_parts] + + local resp = client.request_sync("workspace/symbol", { query = class }, nil) + + local locations = vim.lsp.util.symbols_to_items(resp.result or {}, nil) or {} + if vim.tbl_isempty(locations) then + vim.api.nvim_err_writeln("Empty response looking for class: " .. full_class) + if is_new_instance then + vim.lsp.stop_client(client.id) + end + return + end + + local class_location = nil + for idx, location in pairs(locations) do + if location.text == string.format("[Class] %s", full_class) then + class_location = locations[idx] + break + end + end + + if class_location == nil then + vim.api.nvim_err_writeln("Could not find class for : " .. full_class) + if is_new_instance then + vim.lsp.stop_client(client.id) + end + return + end + + open_filename(class_location.filename) + + local params = vim.lsp.util.make_position_params(0) + if is_new_instance then + vim.lsp.buf_attach_client(0, client.id) + end + + vim.lsp.buf_request(0, "textDocument/documentSymbol", params, function(method_err, method_server_result, _, _) + if method_err then + vim.api.nvim_err_writeln("Error when finding workspace symbols: " .. method_err.message) + if is_new_instance then + vim.lsp.stop_client(client.id) + end + return + end + + local method_locations = vim.lsp.util.symbols_to_items(method_server_result or {}, 0) or {} + if vim.tbl_isempty(method_locations) then + vim.api.nvim_err_writeln(string.format("empty response looking for method: %s", method or "__invoke")) + if is_new_instance then + vim.lsp.stop_client(client.id) + end + return + end + + local method_location = nil + for _, value in ipairs(method_locations) do + if value.text == string.format("[Method] %s", method or "__invoke") then + method_location = value + break + end + end + + if method_location == nil then + if is_new_instance then + vim.lsp.stop_client(client.id) + end + return + end + + local row = method_location.lnum + local col = method_location.col - 1 + + 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("Erro setting row and col " .. err_msg) + end + vim.cmd "normal zt" + end + if is_new_instance then + vim.lsp.stop_client(client.id) + end + end) +end + +---Return a buffer id for the given client +---@param server_name string +---@return integer|nil +lsp.get_lsp_buffer = function(server_name) + local clients = vim.lsp.get_active_clients { name = server_name } + if #clients == 0 then + return nil + end + + local buffers = vim.lsp.get_buffers_by_client_id(clients[1].id) + + if #buffers == 0 then + return nil + end + + return buffers[1] +end + +--- @param fqn string: fully name to search Class::method +lsp.find = function(fqn, server_name) + local search = vim.split(fqn, "::") + local fqn_class = search[1] + local method = search[2] + + local client, is_new_instance = get_client(server_name) + + if not client then + vim.api.nvim_err_writeln "Could not get lsp client" + return + end + + go_to(client, is_new_instance, fqn_class, method) +end + +return lsp diff --git a/lua/pi/php/servers.lua b/lua/pi/php/servers.lua new file mode 100644 index 0000000..9450152 --- /dev/null +++ b/lua/pi/php/servers.lua @@ -0,0 +1,38 @@ +local phpactor = {} + +-- TODO possible improvement look how it works underline +-- use the client directly to call, no need for the buffer +-- to find a class. +-- vim.lsp.start() should return the client + +function phpactor.findclass(buffer, fqn, callback) + local class_parts = vim.split(fqn, "\\") + local class = class_parts[#class_parts] + + vim.lsp.buf_request(buffer, "workspace/symbol", { query = class }, function(err, server_result, _, _) + if err then + callback(nil, "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) + return + end + end) +end + +-- getting the config I can re use the client +-- the next thing is to make the request with the client +local config = require("lspconfig").phpactor +config.root_dir = vim.fn.getcwd() +local client_id = vim.lsp.start(config) + +vim.lsp.get_client_by_id(client_id) +-- use client.request or request_sync +-- look for the direct of the symbol +return { + phpactor = phpactor, +} diff --git a/lua/pi/select_to_quickfix.lua b/lua/pi/select_to_quickfix.lua new file mode 100644 index 0000000..ebd1561 --- /dev/null +++ b/lua/pi/select_to_quickfix.lua @@ -0,0 +1,53 @@ +local api = vim.api + +local function create_quickfix_entry(selection) + local filename, linenumber = selection:match "([^:]+):(%d+)" + + return { + filename = vim.fn.getcwd() .. "/" .. filename, + lnum = tonumber(linenumber), + col = 1, + text = filename, + } +end + +local function add_selections_to_quickfix(selections) + local quickfix_list = {} + + for _, selection in ipairs(selections) do + local entry = create_quickfix_entry(selection) + table.insert(quickfix_list, entry) + end + + vim.fn.setqflist(quickfix_list, "r") +end + +local function get_selections() + local _, end_line, _, _ = unpack(vim.fn.getpos "'>") + local _, start_line, _, _ = unpack(vim.fn.getpos "'<") + local lines = api.nvim_buf_get_lines(0, start_line - 1, end_line, false) + + local selections = {} + for _, line in ipairs(lines) do + for selection in line:gmatch "%S+" do + table.insert(selections, selection) + end + end + + return selections +end + +local function select_to_quickfix() + local selections = get_selections() + + if #selections > 0 then + add_selections_to_quickfix(selections) + print "Selections added to quickfix list" + else + print "No selections found" + end +end + +return { + handle = select_to_quickfix, +} diff --git a/lua/pi/snips/ft/cucumber.lua b/lua/pi/snips/ft/cucumber.lua new file mode 100644 index 0000000..6176a87 --- /dev/null +++ b/lua/pi/snips/ft/cucumber.lua @@ -0,0 +1,71 @@ +local ls = require "luasnip" +local t = ls.text_node +local i = ls.insert_node +local c = ls.choice_node +local fmt = require("luasnip.extras.fmt").fmt + +local M = { + clean = t [[Given clean stubs list]], + all = t [[And all stubs should be matched]], + status_code = fmt([[Then the response status code should be {}]], { i(1, "200") }), + no_error = t [[And the JSON path expression errors should not have result]], + json_data = fmt([[And the JSON path expression "data" should be equal to: +""" +{{ + {} +}} +""" + ]], {i(1)}), + feature = fmt( + [[Feature: {} + + {} +]], + { + i(1, "Feature Name"), + i(0), + } + ), + scenario = fmt( + [[Scenario: {} + {}]], + { + i(1, "Scenario name"), + i(0), + } + ), + stub = fmt([[And the APIClient will send a request with a stub from "{}"]], { i(1) }), + request = fmt( + [[When I send the GraphQL request: +""" +{} +"""]], + { i(1) } + ), + result = fmt( + [[And the JSON path expression "data" should be equal to: +""" +{{ + "result": {{ + {} + }} +}} +"""]], + { i(1) } + ), + query = fmt( + [[{} {{ +result: {}({}) {{ + {} +}} + }}]], + { c(1, { t "mutation", t "query" }), i(2, "mutation"), i(3, ""), i(4) } + ), + access = fmt( + [[And the Access Cache has Allowed the userId "{}" for inspectionId "{}"]], + { i(1, "3414054"), i(2, "42") } + ), + branch_access = fmt([[And the Access Cache has branch "{}" for userId "{}"]], { i(1, "1"), i(2, "3414054") }), +} + +return M diff --git a/lua/pi/snips/ft/go.lua b/lua/pi/snips/ft/go.lua new file mode 100644 index 0000000..9c3977f --- /dev/null +++ b/lua/pi/snips/ft/go.lua @@ -0,0 +1,134 @@ +local ls = require "luasnip" + +local snippet_from_nodes = ls.sn +local c = ls.choice_node +local t = ls.text_node +local d = ls.dynamic_node +local i = ls.insert_node +local rep = require("luasnip.extras").rep +local fmt = require("luasnip.extras.fmt").fmt + +local ts_locals = require "nvim-treesitter.locals" +local ts_utils = require "nvim-treesitter.ts_utils" + +local get_node_text = vim.treesitter.get_node_text + +vim.treesitter.query.set( + "go", + "LuaSnip_Result", + [[ + [ + (method_declaration result: (_) @id) + (function_declaration result: (_) @id) + (func_literal result: (_) @id) + ] +]] +) + +local transform = function(text, info) + if text == "int" then + return t "0" + elseif text == "error" then + if info then + info.index = info.index + 1 + + return c(info.index, { + t(string.format('fmt.Errorf("%s %%w", %s)', info.func_name, info.err_name)), + t(info.err_name), + }) + else + return t "err" + end + elseif text == "bool" then + return t "false" + elseif text == "string" then + return t '""' + elseif string.find(text, "*", 1, true) then + return t "nil" + end + + return t(text) +end + +local handlers = { + ["parameter_list"] = function(node, info) + local result = {} + + local count = node:named_child_count() + for idx = 0, count - 1 do + table.insert(result, transform(get_node_text(node:named_child(idx), 0), info)) + if idx ~= count - 1 then + table.insert(result, t { ", " }) + end + end + + return result + end, + + ["type_identifier"] = function(node, info) + local text = get_node_text(node, 0) + return { transform(text, info) } + end, +} + +local function go_result_type(info) + local cursor_node = ts_utils.get_node_at_cursor() + local scope = ts_locals.get_scope_tree(cursor_node, 0) + + local function_node + for _, v in ipairs(scope) do + if v:type() == "function_declaration" or v:type() == "method_declaration" or v:type() == "func_literal" then + function_node = v + break + end + end + + local query = vim.treesitter.query.get("go", "LuaSnip_Result") + for _, node in query:iter_captures(function_node, 0) do + if handlers[node:type()] then + return handlers[node:type()](node, info) + end + end +end + +local go_ret_vals = function(args) + local info = { index = 0, err_name = args[1][1], func_name = args[2][1] } + return snippet_from_nodes(nil, go_result_type(info)) +end + +local M = { + main = { + t { "func main() {", "\t" }, + i(0), + t { "", "}" }, + }, + ef = { + i(1, { "val" }), + t ", err := ", + i(2, { "f" }), + t "(", + i(3), + t ")", + i(0), + }, + efi = { + i(1, { "val" }), + ", ", + i(2, { "err" }), + " := ", + i(3, { "f" }), + "(", + i(4), + ")", + t { "", "if " }, + rep(2), + t { " != nil {", "\treturn " }, + d(5, go_ret_vals, { 2, 3 }), + t { "", "}" }, + i(0), + }, +} + +M.f = fmt("func {}({}) {} {{\n\t{}\n}}", { i(1, "name"), i(2), i(3), i(0) }) + +return M diff --git a/lua/pi/snips/ft/lua.lua b/lua/pi/snips/ft/lua.lua new file mode 100644 index 0000000..d896f3e --- /dev/null +++ b/lua/pi/snips/ft/lua.lua @@ -0,0 +1,69 @@ +local ls = require "luasnip" + +-- local snippet = ls.s +local snippet_from_nodes = ls.sn +local c = ls.choice_node +local d = ls.dynamic_node +local i = ls.insert_node +local f = ls.function_node +local t = ls.text_node + +local fmt = require("luasnip.extras.fmt").fmt + +local require_var = function(args, _) + local text = args[1][1] or "" + local split = vim.split(text, ".", { plain = true }) + + local options = {} + for len = 0, #split - 1 do + table.insert(options, t(table.concat(vim.list_slice(split, #split - len, #split), "_"))) + end + + return snippet_from_nodes(nil, { + c(1, options), + }) +end + +local newline = function(text) + return t { "", text } +end + +return { + req = fmt([[local {} = require("{}")]], { + d(2, require_var, { 1 }), + i(1), + }), + lf = { + desc = "table function", + "local ", + i(1), + " = function(", + i(2), + ")", + newline " ", + i(0), + newline "end", + }, + + preq = fmt( + [[local ok, {} = pcall(require, "{}") +if not ok then + return +end]], + { + f(function(args) + return args[1][1] + end, { 1 }), + i(1), + } + ), + + plugin = fmt( + [[return {{ + "{}" +}}]], + { + i(1, "plugin"), + } + ), +} diff --git a/lua/pi/snips/ft/php.lua b/lua/pi/snips/ft/php.lua new file mode 100644 index 0000000..72936d8 --- /dev/null +++ b/lua/pi/snips/ft/php.lua @@ -0,0 +1,163 @@ +local ls = require "luasnip" +local composer = require "composer" + +local snippet_from_nodes = ls.sn +local c = ls.choice_node +local t = ls.text_node +local d = ls.dynamic_node +local f = ls.function_node +local i = ls.insert_node +local fmt = require("luasnip.extras.fmt").fmt + +local visibility = function(position, default) + local possibles = { "private", "protected", "public" } + local options = {} + + for _, value in pairs(possibles) do + if value == default then + table.insert(options, 1, t(value)) + else + table.insert(options, t(value)) + end + end + + return c(position, options) +end + +local var_name = function(args) + return snippet_from_nodes(nil, { + i(1, args[1][1]:gsub("^%u", string.lower):gsub("Interface", "") or ""), + }) +end + +local class_name = function() + return vim.fn.expand "%:t:r" +end + +local M = {} + +M.v = fmt( + [[ +/** + * @var {} + */ +{} {} ${}; +]], + { + i(1, "type"), + visibility(2, "private"), + i(3, "Type"), + i(4, "var"), + } +) + +M.class = fmt( + [[ + + */ + private ObjectProphecy ${}; +]], + { + i(1, "Type"), + d(2, var_name, { 1 }), + } +) + +M.iop = fmt( + [[$this->{}