From a4644e03b1aa7daf0f2d4c0474d04c3b3aabebbd Mon Sep 17 00:00:00 2001 From: Christian Segundo Date: Sun, 8 Oct 2023 01:59:18 +0200 Subject: first commit --- .gitignore | 1 + README.md | 0 lua/promql/health.lua | 28 +++++++++++ neovim.yaml | 29 +++++++++++ plugin/promql.lua | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++ selene.toml | 1 + stylua.toml | 5 ++ 7 files changed, 194 insertions(+) create mode 100644 .gitignore delete mode 100644 README.md create mode 100644 lua/promql/health.lua create mode 100644 neovim.yaml create mode 100644 plugin/promql.lua create mode 100644 selene.toml create mode 100644 stylua.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bbbeea --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.luarc.json diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/lua/promql/health.lua b/lua/promql/health.lua new file mode 100644 index 0000000..03f20b5 --- /dev/null +++ b/lua/promql/health.lua @@ -0,0 +1,28 @@ +local health = vim.health + +local M = {} + +local binaries = { + { bin = "promtool", optional = false }, +} + +local binary_installed = function(binary) + return vim.fn.executable(binary) +end + +M.check = function() + for _, binary in ipairs(binaries) do + if not binary_installed(binary.bin) then + local bin_not_installed = binary.bin .. " not found" + if binary.optional then + health.warn(("%s %s"):format(bin_not_installed, binary.info)) + else + health.error(binary.bin .. " not found") + end + else + health.ok(binary.bin .. " found") + end + end +end + +return M diff --git a/neovim.yaml b/neovim.yaml new file mode 100644 index 0000000..1288950 --- /dev/null +++ b/neovim.yaml @@ -0,0 +1,29 @@ +--- +base: lua51 + +globals: + vim: + any: true + assert: + args: + - type: bool + - type: string + required: false + assert.are.same: + args: + - type: any + - type: any + after_each: + args: + - type: function + before_each: + args: + - type: function + describe: + args: + - type: string + - type: function + it: + args: + - type: string + - type: function diff --git a/plugin/promql.lua b/plugin/promql.lua new file mode 100644 index 0000000..e44d1c3 --- /dev/null +++ b/plugin/promql.lua @@ -0,0 +1,130 @@ +-- How it started +--vim.api.nvim_create_user_command( +-- "Promqlfmt", +-- ',!promtool promql format --experimental "$(cat /dev/stdin)"', +-- { nargs = 0, range = "%" } +--) + +-- How it's going +if vim.g.promqlfmt == 1 then + return +end + +vim.g.promqlfmt = 1 + +--- Format a PromQL query using promtool +--- @param query string @query to format +--- @param padding number|nil @number of spaces to add to each line, default 0 +--- @param padchar string|nil @character for padding, default " " +--- @return string[]|nil @formatted query, one element per line or nil +local promql_format = function(query, padding, padchar) + padding = padding or 0 + padchar = padchar or " " + + local success, result = pcall(function() + return vim + .system( + { "promtool", "promql", "format", "--experimental", query }, + { text = true } + ) + :wait() + end) + + if success and result and result.code == 0 then + local lines = vim.fn.split(result.stdout, "\n") + if padding == 0 then + return lines + end + + for i, line in ipairs(lines or {}) do + lines[i] = (padchar):rep(padding) .. line + end + return lines + else + print("woops error occurred while formatting query") + print(vim.inspect(result)) + end +end + +--- Get the last column of a line, ie the position of the last character +--- @param bufnr number +--- @param linenr number +local last_col_line = function(bufnr, linenr) + local line = vim.api.nvim_buf_get_lines(bufnr, linenr, linenr + 1, true)[1] + return #line +end + +--- Get the selected text in a buffer +--- @param bufnr number|nil +--- @return table +local buf_get_selected_text = function(bufnr) + local r = { + text = "", + start_line = nil, + start_row = nil, + end_line = nil, + end_row = nil, + } + local region = vim.region(bufnr or 0, "'<", "'>", vim.fn.visualmode(), true) + local maxcol = vim.v.maxcol + for line, cols in vim.spairs(region) do + if r.start_line == nil then + r.start_line = line + r.start_row = cols[1] + end + + local endcol = cols[2] == maxcol and -1 or cols[2] + local chunk = + vim.api.nvim_buf_get_text(0, line, cols[1], line, endcol, {})[1] + r.text = ("%s%s\n"):format(r.text, chunk) + + r.end_line = line + r.end_row = endcol + end + + r.end_row = r.end_row > last_col_line(0, r.end_line) and -1 or r.end_row + return r +end + +vim.api.nvim_create_user_command("Promqlfmt", function(opts) + -- it was not called from a visual selection + if opts.range == 0 then + -- get all lines + local buf_text = vim.api.nvim_buf_get_lines(0, 0, -1, true) + -- format query + local text_formatted = promql_format(table.concat(buf_text, "\n")) + if text_formatted == nil then + return + end + -- replace all text with the formatted version + vim.api.nvim_buf_set_lines(0, 0, -1, true, text_formatted) + return + end + + local s = buf_get_selected_text() + -- use the position of the first non-whitespace character of the first line + -- as padding + local padding = string.find( + vim.api.nvim_buf_get_lines(0, s.start_line, s.start_line + 1, true)[1], + "%S" + ) - 1 + local text_formatted = promql_format(s.text, padding) + + if text_formatted == nil then + return + end + + -- remove padding from first line + if s.start_row ~= 0 then + text_formatted[1] = text_formatted[1]:sub(padding + 1) + end + + vim.api.nvim_buf_set_text( + 0, + s.start_line, + s.start_row, + s.end_line, + s.end_row, + text_formatted + ) +end, { nargs = 0, range = "%" }) diff --git a/selene.toml b/selene.toml new file mode 100644 index 0000000..032dba6 --- /dev/null +++ b/selene.toml @@ -0,0 +1 @@ +std = "neovim" diff --git a/stylua.toml b/stylua.toml new file mode 100644 index 0000000..d73b884 --- /dev/null +++ b/stylua.toml @@ -0,0 +1,5 @@ +column_width = 80 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferDouble" -- cgit v1.2.3