Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ Code yanks are syntax-highlighted when ClipRing can detect a language (markdown
| `dd` | Delete the selected entry from history |
| `C` | Clear all entries (asks for confirmation: `y` yes, `n` cancel) |
| `q` or `<Esc>` | Close without pasting (`Esc` cancels a pending clear-all first) |
| `g?` / `<C-w>` | Show picker key cheat-sheet (**only when [which-key.nvim](https://github.com/folke/which-key.nvim) is installed**) |

While the picker is focused, `<C-w>` does not switch windows or open which-key (close the picker first, like Telescope). Keys apply to the history list; the preview pane is read-only. If you use [which-key.nvim](https://github.com/folke/which-key.nvim), `setup()` disables which-key on the history list buffer (`clipring` filetype).
When which-key is installed, `g?` and `<C-w>` open a scoped which-key popup for this buffer. Without which-key, `<C-w>` is disabled in the picker so you do not accidentally switch windows (close the picker first). Keys apply to the history list; the preview pane is read-only.

### Paste behavior by mode

Expand Down Expand Up @@ -116,6 +117,7 @@ require("clipring").setup({
reorder_up_mapping = "<C-k>",
copy_mapping = "y",
clear_all_mapping = "C",
help_mapping = "g?", -- which-key cheat-sheet (`g?`); requires which-key.nvim

-- Layout (list position is fixed; preview auto-sizes within these limits)
picker_width = 80, -- total inner width; 0 = nearly full editor width
Expand All @@ -129,7 +131,7 @@ require("clipring").setup({

**`open_mapping`** — set a string (e.g. `"<leader>y"`) or multiple (`{ "<leader>y", "<M-y>" }`) to open ClipRing from Normal, Visual, and Insert. Leave unset or `nil` to use only `:ClipRing`. Use `false` to clear a keymap after a previous `setup()`.

Omit `reorder_down_mapping` / `reorder_up_mapping` / `copy_mapping` / `clear_all_mapping` to keep the defaults above. Set any of them to `false` to turn off that binding.
Omit `reorder_down_mapping` / `reorder_up_mapping` / `copy_mapping` / `clear_all_mapping` / `help_mapping` to keep the defaults above. Set any of them to `false` to turn off that binding. `help_mapping` and `<C-w>` cheat-sheet bindings apply only when which-key.nvim is installed.

During clear-all confirmation, `y` confirms (same key as `copy_mapping` when not confirming) and `n` cancels.

Expand Down Expand Up @@ -175,7 +177,7 @@ Coverage today:
- **ring** — add, dedupe, max size, remove, reorder
- **preview_syntax** — fence stripping, language detection, heuristics
- **paste** — visual capture (`v` / `'<`), charwise replace vs append, insert-mode paste at saved cursor
- **ui** — picker from insert, navigation, wrap-around selection, fixed list layout, preview resize/restore, conditional preview, clear all with confirmation, syntax highlighting, clipboard copy, which-key / `<C-w>` behavior
- **ui** — picker from insert, navigation, wrap-around selection, fixed list layout, preview resize/restore, conditional preview, clear all with confirmation, syntax highlighting, clipboard copy, which-key cheat-sheet (`g?` / `<C-w>`)
- **yank** — `TextYankPost` capture
- **setup** — `open_mapping` registration

Expand Down
2 changes: 2 additions & 0 deletions lua/clipring/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ local M = {}
---@field reorder_up_mapping string|false|nil move selected entry up in picker (default `<C-k>`)
---@field copy_mapping string|false|nil copy selected entry to system clipboard in picker (default `y`)
---@field clear_all_mapping string|false|nil clear entire history in picker with confirmation (default `C`)
---@field help_mapping string|false|nil which-key cheat-sheet key in picker (default `g?`; only when which-key is installed)
---@field picker_width number total inner width of list + preview (`0` = nearly full editor width)
---@field list_width number width of the history list (`0` = auto; fixed width is advanced)
---@field preview_max_width number max preview width (`0` = content width up to screen edge)
Expand All @@ -31,6 +32,7 @@ M.defaults = {
reorder_up_mapping = "<C-k>",
copy_mapping = "y",
clear_all_mapping = "C",
help_mapping = "g?",
picker_width = 80,
list_width = 0,
preview_max_width = 0,
Expand Down
2 changes: 0 additions & 2 deletions lua/clipring/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ local config = require("clipring.config")
local yank = require("clipring.yank")
local persist = require("clipring.persist")
local ui = require("clipring.ui")
local which_key = require("clipring.which_key")

local M = {}

Expand Down Expand Up @@ -52,7 +51,6 @@ end

function M.setup(opts)
config.setup(opts)
which_key.setup()
yank.setup()
persist.setup()
apply_open_mapping(config.get().open_mapping)
Expand Down
19 changes: 17 additions & 2 deletions lua/clipring/ui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local paste = require("clipring.paste")
local persist = require("clipring.persist")
local preview_syntax = require("clipring.preview_syntax")
local preview_highlight = require("clipring.preview_highlight")
local which_key = require("clipring.which_key")

local M = {}

Expand Down Expand Up @@ -734,8 +735,22 @@ local function attach_keymaps()
local function block_window_prefix()
return
end
map("<C-w>", block_window_prefix, "ClipRing: disable window switch")
map("<C-W>", block_window_prefix, "ClipRing: disable window switch")

if which_key.available() then
local function show_picker_help()
which_key.show_help()
end

local help = picker_mapping("help_mapping", "g?")
if help then
map(help, show_picker_help, "ClipRing: show keymaps")
end
map("<C-w>", show_picker_help, "ClipRing: show keymaps")
map("<C-W>", show_picker_help, "ClipRing: show keymaps")
else
map("<C-w>", block_window_prefix, "ClipRing: disable window switch")
map("<C-W>", block_window_prefix, "ClipRing: disable window switch")
end
end

---@param opts table|nil
Expand Down
20 changes: 11 additions & 9 deletions lua/clipring/which_key.lua
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
local M = {}

--- Disable which-key in ClipRing picker buffers (same idea as TelescopePrompt).
function M.setup()
local ok, wk_config = pcall(require, "which-key.config")
if not ok or not wk_config.disable or not wk_config.disable.ft then
---@return boolean
function M.available()
local ok, wk = pcall(require, "which-key")
return ok and type(wk.show) == "function"
end

---Show a cheat-sheet of the current buffer's mappings via which-key.
---No-op when which-key is not installed.
function M.show_help()
if not M.available() then
return
end
for _, ft in ipairs({ "clipring", "clipring_preview" }) do
if not vim.tbl_contains(wk_config.disable.ft, ft) then
table.insert(wk_config.disable.ft, ft)
end
end
require("which-key").show({ global = false })
end

return M
9 changes: 0 additions & 9 deletions tests/setup_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@ describe("clipring.setup", function()
assert.are_not.equal("", vim.fn.maparg("<M-y>", "n"))
end)

it("registers clipring filetype with which-key disable when installed", function()
local ok, wk_config = pcall(require, "which-key.config")
if not ok then
return
end
require("clipring.which_key").setup()
assert.is_true(vim.tbl_contains(wk_config.disable.ft, "clipring"))
end)

it("clears open_mapping when setup sets open_mapping to false", function()
clipring.setup({ open_mapping = "<leader>cr" })
clipring.setup({ open_mapping = false })
Expand Down
23 changes: 20 additions & 3 deletions tests/ui_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,33 @@ describe("clipring.ui", function()
return clip_buf
end

it("maps Ctrl-w without a which-key trigger on the picker buffer", function()
it("maps Ctrl-w to block window switch when which-key is unavailable", function()
local which_key = require("clipring.which_key")
if which_key.available() then
return
end
ui.open()
local clip_buf = h.find_clipring_buf()
vim.api.nvim_set_current_win(vim.fn.bufwinid(clip_buf))
local map = vim.fn.maparg("<C-w>", "n", false, true)
assert.is_true(type(map) == "table")
assert.is_true(map.callback ~= nil)
if map.desc then
assert.is_nil(map.desc:find("which%-key%-trigger", 1, true))
assert.are.equal("ClipRing: disable window switch", map.desc)
assert.are.equal("", vim.fn.maparg("g?", "n"))
ui.close()
end)

it("maps Ctrl-w to show keymaps when which-key is installed", function()
local which_key = require("clipring.which_key")
if not which_key.available() then
return
end
ui.open()
local clip_buf = h.find_clipring_buf()
vim.api.nvim_set_current_win(vim.fn.bufwinid(clip_buf))
local map = vim.fn.maparg("<C-w>", "n", false, true)
assert.are.equal("ClipRing: show keymaps", map.desc)
ui.close()
end)

it("blocks Ctrl-w window switch while picker is focused", function()
Expand Down
24 changes: 24 additions & 0 deletions tests/which_key_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
local h = require("tests.helpers")
local which_key = require("clipring.which_key")

describe("clipring.which_key", function()
before_each(function()
h.reset()
end)

it("reports whether which-key is installed", function()
assert.is_boolean(which_key.available())
end)

it("show_help is a no-op when which-key is unavailable", function()
if which_key.available() then
return
end
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_current_buf(buf)
assert.has_no.errors(function()
which_key.show_help()
end)
vim.api.nvim_buf_delete(buf, { force = true })
end)
end)