|
| 1 | +local config = require("dbab.config") |
| 2 | + |
| 3 | +local M = {} |
| 4 | + |
| 5 | +local ns = vim.api.nvim_create_namespace("dbab_help") |
| 6 | + |
| 7 | +---@param key string|string[] |
| 8 | +---@return string |
| 9 | +local function format_key(key) |
| 10 | + if type(key) == "table" then |
| 11 | + return table.concat(key, " / ") |
| 12 | + end |
| 13 | + return key |
| 14 | +end |
| 15 | + |
| 16 | +---@class HelpEntry |
| 17 | +---@field key string |
| 18 | +---@field label string |
| 19 | +---@field category string |
| 20 | + |
| 21 | +---@param title string |
| 22 | +---@param sections table<string, HelpEntry[]> |
| 23 | +local function show_float(title, sections) |
| 24 | + local lines = {} |
| 25 | + local highlights = {} |
| 26 | + local max_key_len = 0 |
| 27 | + |
| 28 | + for _, entries in pairs(sections) do |
| 29 | + for _, entry in ipairs(entries) do |
| 30 | + local klen = vim.fn.strdisplaywidth(entry.key) |
| 31 | + if klen > max_key_len then |
| 32 | + max_key_len = klen |
| 33 | + end |
| 34 | + end |
| 35 | + end |
| 36 | + |
| 37 | + local section_order = { "Actions", "Navigation", "Global" } |
| 38 | + |
| 39 | + for _, section_name in ipairs(section_order) do |
| 40 | + local entries = sections[section_name] |
| 41 | + if entries and #entries > 0 then |
| 42 | + if #lines > 0 then |
| 43 | + table.insert(lines, "") |
| 44 | + end |
| 45 | + table.insert(lines, " " .. section_name) |
| 46 | + table.insert(highlights, { line = #lines - 1, col = 2, len = #section_name, hl = "DbabHistoryHeader" }) |
| 47 | + |
| 48 | + for _, entry in ipairs(entries) do |
| 49 | + local klen = vim.fn.strdisplaywidth(entry.key) |
| 50 | + local padding = string.rep(" ", max_key_len - klen + 3) |
| 51 | + local line = " " .. entry.key .. padding .. entry.label |
| 52 | + table.insert(lines, line) |
| 53 | + table.insert(highlights, { line = #lines - 1, col = 4, len = #entry.key, hl = "DbabKey" }) |
| 54 | + end |
| 55 | + end |
| 56 | + end |
| 57 | + |
| 58 | + table.insert(lines, "") |
| 59 | + table.insert(lines, " Press ? or q to close") |
| 60 | + table.insert(highlights, { line = #lines - 1, col = 2, len = 22, hl = "Comment" }) |
| 61 | + |
| 62 | + local width = 0 |
| 63 | + for _, line in ipairs(lines) do |
| 64 | + local w = vim.fn.strdisplaywidth(line) |
| 65 | + if w > width then |
| 66 | + width = w |
| 67 | + end |
| 68 | + end |
| 69 | + width = width + 4 |
| 70 | + |
| 71 | + local height = #lines |
| 72 | + local row = math.floor((vim.o.lines - height) / 2) |
| 73 | + local col = math.floor((vim.o.columns - width) / 2) |
| 74 | + |
| 75 | + local buf = vim.api.nvim_create_buf(false, true) |
| 76 | + vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) |
| 77 | + vim.bo[buf].modifiable = false |
| 78 | + vim.bo[buf].bufhidden = "wipe" |
| 79 | + |
| 80 | + for _, hl in ipairs(highlights) do |
| 81 | + local line_len = #lines[hl.line + 1] |
| 82 | + local end_col = math.min(hl.col + hl.len, line_len) |
| 83 | + if hl.col < line_len then |
| 84 | + vim.api.nvim_buf_set_extmark(buf, ns, hl.line, hl.col, { |
| 85 | + end_col = end_col, |
| 86 | + hl_group = hl.hl, |
| 87 | + }) |
| 88 | + end |
| 89 | + end |
| 90 | + |
| 91 | + local win = vim.api.nvim_open_win(buf, true, { |
| 92 | + relative = "editor", |
| 93 | + row = row, |
| 94 | + col = col, |
| 95 | + width = width, |
| 96 | + height = height, |
| 97 | + style = "minimal", |
| 98 | + border = "rounded", |
| 99 | + title = " " .. title .. " Help ", |
| 100 | + title_pos = "center", |
| 101 | + }) |
| 102 | + |
| 103 | + vim.wo[win].cursorline = false |
| 104 | + vim.wo[win].wrap = false |
| 105 | + |
| 106 | + local close = function() |
| 107 | + if vim.api.nvim_win_is_valid(win) then |
| 108 | + vim.api.nvim_win_close(win, true) |
| 109 | + end |
| 110 | + end |
| 111 | + |
| 112 | + vim.keymap.set("n", "q", close, { buffer = buf, nowait = true }) |
| 113 | + vim.keymap.set("n", "?", close, { buffer = buf, nowait = true }) |
| 114 | + vim.keymap.set("n", "<Esc>", close, { buffer = buf, nowait = true }) |
| 115 | +end |
| 116 | + |
| 117 | +---@param keymaps table |
| 118 | +---@param action string |
| 119 | +---@param label string |
| 120 | +---@param category string |
| 121 | +---@param entries HelpEntry[] |
| 122 | +local function add_entry(keymaps, action, label, category, entries) |
| 123 | + local key = keymaps[action] |
| 124 | + if key then |
| 125 | + table.insert(entries, { key = format_key(key), label = label, category = category }) |
| 126 | + end |
| 127 | +end |
| 128 | + |
| 129 | +---@param entries HelpEntry[] |
| 130 | +---@return table<string, HelpEntry[]> |
| 131 | +local function group_by_category(entries) |
| 132 | + local grouped = {} |
| 133 | + for _, entry in ipairs(entries) do |
| 134 | + if not grouped[entry.category] then |
| 135 | + grouped[entry.category] = {} |
| 136 | + end |
| 137 | + table.insert(grouped[entry.category], entry) |
| 138 | + end |
| 139 | + return grouped |
| 140 | +end |
| 141 | + |
| 142 | +function M.show_sidebar() |
| 143 | + local cfg = config.get() |
| 144 | + local km = cfg.keymaps.sidebar |
| 145 | + local entries = {} |
| 146 | + |
| 147 | + add_entry(km, "toggle_expand", "Toggle expand", "Actions", entries) |
| 148 | + add_entry(km, "refresh", "Refresh", "Actions", entries) |
| 149 | + add_entry(km, "new_query", "New query", "Actions", entries) |
| 150 | + add_entry(km, "rename", "Rename query", "Actions", entries) |
| 151 | + add_entry(km, "delete", "Delete", "Actions", entries) |
| 152 | + add_entry(km, "insert_template", "Insert SELECT query", "Actions", entries) |
| 153 | + add_entry(km, "copy_name", "Copy name", "Actions", entries) |
| 154 | + add_entry(km, "copy_query", "Copy query content", "Actions", entries) |
| 155 | + add_entry(km, "paste_query", "Paste as new query", "Actions", entries) |
| 156 | + |
| 157 | + add_entry(km, "to_editor", "Go to editor", "Navigation", entries) |
| 158 | + add_entry(km, "to_history", "Go to history", "Navigation", entries) |
| 159 | + |
| 160 | + table.insert(entries, { key = format_key(cfg.keymaps.close), label = "Close dbab", category = "Global" }) |
| 161 | + |
| 162 | + show_float("Sidebar", group_by_category(entries)) |
| 163 | +end |
| 164 | + |
| 165 | +function M.show_editor() |
| 166 | + local cfg = config.get() |
| 167 | + local km = cfg.keymaps.editor |
| 168 | + local entries = {} |
| 169 | + |
| 170 | + table.insert(entries, { key = format_key(cfg.keymaps.execute), label = "Execute query", category = "Actions" }) |
| 171 | + add_entry(km, "execute_insert", "Execute (insert mode)", "Actions", entries) |
| 172 | + add_entry(km, "execute_leader", "Execute (leader)", "Actions", entries) |
| 173 | + add_entry(km, "save", "Save query", "Actions", entries) |
| 174 | + add_entry(km, "next_tab", "Next tab", "Actions", entries) |
| 175 | + add_entry(km, "prev_tab", "Previous tab", "Actions", entries) |
| 176 | + add_entry(km, "close_tab", "Close tab", "Actions", entries) |
| 177 | + |
| 178 | + add_entry(km, "to_result", "Go to result", "Navigation", entries) |
| 179 | + add_entry(km, "to_sidebar", "Go to sidebar", "Navigation", entries) |
| 180 | + |
| 181 | + table.insert(entries, { key = format_key(cfg.keymaps.close), label = "Close dbab", category = "Global" }) |
| 182 | + |
| 183 | + show_float("Editor", group_by_category(entries)) |
| 184 | +end |
| 185 | + |
| 186 | +function M.show_history() |
| 187 | + local cfg = config.get() |
| 188 | + local km = cfg.keymaps.history |
| 189 | + local entries = {} |
| 190 | + |
| 191 | + add_entry(km, "select", "Open in editor", "Actions", entries) |
| 192 | + add_entry(km, "execute", "Re-execute", "Actions", entries) |
| 193 | + add_entry(km, "copy", "Copy query", "Actions", entries) |
| 194 | + add_entry(km, "delete", "Delete entry", "Actions", entries) |
| 195 | + add_entry(km, "clear", "Clear all", "Actions", entries) |
| 196 | + |
| 197 | + add_entry(km, "to_sidebar", "Go to sidebar", "Navigation", entries) |
| 198 | + add_entry(km, "to_result", "Go to result", "Navigation", entries) |
| 199 | + |
| 200 | + table.insert(entries, { key = format_key(cfg.keymaps.close), label = "Close dbab", category = "Global" }) |
| 201 | + |
| 202 | + show_float("History", group_by_category(entries)) |
| 203 | +end |
| 204 | + |
| 205 | +function M.show_result() |
| 206 | + local cfg = config.get() |
| 207 | + local km = cfg.keymaps.result |
| 208 | + local entries = {} |
| 209 | + |
| 210 | + add_entry(km, "yank_row", "Yank row as JSON", "Actions", entries) |
| 211 | + add_entry(km, "yank_all", "Yank all as JSON", "Actions", entries) |
| 212 | + |
| 213 | + add_entry(km, "to_sidebar", "Go to sidebar", "Navigation", entries) |
| 214 | + add_entry(km, "to_editor", "Go to editor", "Navigation", entries) |
| 215 | + |
| 216 | + table.insert(entries, { key = format_key(cfg.keymaps.close), label = "Close dbab", category = "Global" }) |
| 217 | + |
| 218 | + show_float("Result", group_by_category(entries)) |
| 219 | +end |
| 220 | + |
| 221 | +return M |
0 commit comments