Skip to content

Commit

Permalink
feat: add view option to open(), change handling of height option (#38)
Browse files Browse the repository at this point in the history
* feat(winrestore): add options to restore quickfix height and view

* fix: prevent scroll jump when opening quickfix

The issue occurs if:
  - cursor position is not at the top
  - focus=true
  - opened quickfix win is large enough to change the scroll position

* feat(winrestore): add option to enforce min/max height

* docs(winrestore): add description to README

* Revert winrestore

* refactor: set quickfix height using :copen <count>

* refactor: increase max_height from 10 to 16 for quicker.open

* fix: make opts.open_cmd_mods non-optional in quicker.open, quicker.toggle

* feat: add optional 'view' argument to quicker.open, quicker.toggle

* docs: mention min_height, max_height overriding in README.md

* docs: describe 'view' argument for quicker.open, quicker.toggle in README.md

* docs: update min/max_height defaults for quicker.open, quicker.toggle

* refactor: make empty table check more explicit

* refactor: remove height setting in favor of :copen <count>

* refactor: remove unused util.is_full_height_vsplit

* fix: resolve type mismatch when setting opts.view = vim.fn.winsaveview()

---------

Co-authored-by: Steven Arcangeli <[email protected]>
  • Loading branch information
drowning-cat and stevearc authored Jan 25, 2025
1 parent ceff21e commit b9b7eec
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 50 deletions.
38 changes: 20 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,30 +324,32 @@ Update the quickfix list with the current buffer text for each item.
`toggle(opts)` \
Toggle the quickfix or loclist window.

| Param | Type | Desc |
| -------------- | -------------------------- | ----------------------------------------------------------------------------------- |
| opts | `nil\|quicker.OpenOpts` | |
| >loclist | `nil\|boolean` | Toggle the loclist instead of the quickfix list |
| >focus | `nil\|boolean` | Focus the quickfix window after toggling (default false) |
| >height | `nil\|integer` | Height of the quickfix window when opened. Defaults to number of items in the list. |
| >min_height | `nil\|integer` | Minimum height of the quickfix window. Default 4. |
| >max_height | `nil\|integer` | Maximum height of the quickfix window. Default 10. |
| >open_cmd_mods | `nil\|quicker.OpenCmdMods` | A table of modifiers for the quickfix or loclist open commands. |
| Param | Type | Desc |
| -------------- | -------------------------- | ------------------------------------------------------------------------------------------- |
| opts | `nil\|quicker.OpenOpts` | |
| >loclist | `nil\|boolean` | Toggle the loclist instead of the quickfix list |
| >focus | `nil\|boolean` | Focus the quickfix window after toggling (default false) |
| >height | `nil\|integer` | Height of the quickfix window when opened. Defaults to number of items in the list. |
| >min_height | `nil\|integer` | Minimum height of the quickfix window. Ignored if height is defined explicitly. Default 4. |
| >max_height | `nil\|integer` | Maximum height of the quickfix window. Ignored if height is defined explicitly. Default 16. |
| >open_cmd_mods | `nil\|quicker.OpenCmdMods` | A table of modifiers for the quickfix or loclist open commands. |
| >view | `nil\|quicker.WinViewDict` | A table of options to restore the view of the quickfix window. Can be used to set the cursor or scroll positions (see `winsaveview()`). |

### open(opts)

`open(opts)` \
Open the quickfix or loclist window.

| Param | Type | Desc |
| -------------- | -------------------------- | ----------------------------------------------------------------------------------- |
| opts | `nil\|quicker.OpenOpts` | |
| >loclist | `nil\|boolean` | Toggle the loclist instead of the quickfix list |
| >focus | `nil\|boolean` | Focus the quickfix window after toggling (default false) |
| >height | `nil\|integer` | Height of the quickfix window when opened. Defaults to number of items in the list. |
| >min_height | `nil\|integer` | Minimum height of the quickfix window. Default 4. |
| >max_height | `nil\|integer` | Maximum height of the quickfix window. Default 10. |
| >open_cmd_mods | `nil\|quicker.OpenCmdMods` | A table of modifiers for the quickfix or loclist open commands. |
| Param | Type | Desc |
| -------------- | -------------------------- | ------------------------------------------------------------------------------------------- |
| opts | `nil\|quicker.OpenOpts` | |
| >loclist | `nil\|boolean` | Toggle the loclist instead of the quickfix list |
| >focus | `nil\|boolean` | Focus the quickfix window after toggling (default false) |
| >height | `nil\|integer` | Height of the quickfix window when opened. Defaults to number of items in the list. |
| >min_height | `nil\|integer` | Minimum height of the quickfix window. Ignored if height is defined explicitly. Default 4. |
| >max_height | `nil\|integer` | Maximum height of the quickfix window. Ignored if height is defined explicitly. Default 16. |
| >open_cmd_mods | `nil\|quicker.OpenCmdMods` | A table of modifiers for the quickfix or loclist open commands. |
| >view | `nil\|quicker.WinViewDict` | A table of options to restore the view of the quickfix window. Can be used to set the cursor or scroll positions (see `winsaveview()`). |

### close(opts)

Expand Down
37 changes: 24 additions & 13 deletions lua/quicker/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -109,25 +109,28 @@ M.is_open = function(loclist_win)
end

---@class quicker.OpenCmdMods: vim.api.keyset.parse_cmd.mods
---@alias quicker.WinViewDict vim.fn.winrestview.dict

---@class (exact) quicker.OpenOpts
---@field loclist? boolean Toggle the loclist instead of the quickfix list
---@field focus? boolean Focus the quickfix window after toggling (default false)
---@field height? integer Height of the quickfix window when opened. Defaults to number of items in the list.
---@field min_height? integer Minimum height of the quickfix window. Default 4.
---@field max_height? integer Maximum height of the quickfix window. Default 10.
---@field max_height? integer Maximum height of the quickfix window. Default 16.
---@field open_cmd_mods? quicker.OpenCmdMods A table of modifiers for the quickfix or loclist open commands.
---@field view? quicker.WinViewDict A table of options to restore the view of the quickfix window. Can be used to set the cursor or scroll positions (see `winsaveview()`).

---Toggle the quickfix or loclist window.
---@param opts? quicker.OpenOpts
M.toggle = function(opts)
---@type {loclist: boolean, focus: boolean, height?: integer, min_height: integer, max_height: integer, open_cmd_mods?: quicker.OpenCmdMods}
---@type {loclist: boolean, focus: boolean, height?: integer, min_height: integer, max_height: integer, open_cmd_mods: quicker.OpenCmdMods, view: quicker.WinViewDict}
opts = vim.tbl_deep_extend("keep", opts or {}, {
loclist = false,
focus = false,
min_height = 4,
max_height = 10,
max_height = 16,
open_cmd_mods = {},
view = {},
})
local loclist_win = opts.loclist and 0 or nil
if M.is_open(loclist_win) then
Expand All @@ -141,31 +144,39 @@ end
---@param opts? quicker.OpenOpts
M.open = function(opts)
local util = require("quicker.util")
---@type {loclist: boolean, focus: boolean, height?: integer, min_height: integer, max_height: integer, open_cmd_mods?: quicker.OpenCmdMods}
---@type {loclist: boolean, focus: boolean, height?: integer, min_height: integer, max_height: integer, open_cmd_mods: quicker.OpenCmdMods, view: quicker.WinViewDict}
opts = vim.tbl_deep_extend("keep", opts or {}, {
loclist = false,
focus = false,
min_height = 4,
max_height = 10,
max_height = 16,
open_cmd_mods = {},
view = {},
})
local clamp = function(val)
return util.clamp(opts.min_height, val, opts.max_height)
end
local height
if opts.loclist then
local ok, err = pcall(vim.cmd.lopen, { mods = opts.open_cmd_mods })
height = opts.height or clamp(#vim.fn.getloclist(0))
local ok, err = pcall(vim.cmd.lopen, {
count = height,
mods = opts.open_cmd_mods,
})
if not ok then
vim.notify(err, vim.log.levels.ERROR)
return
end
height = #vim.fn.getloclist(0)
else
vim.cmd.copen({ mods = opts.open_cmd_mods })
height = #vim.fn.getqflist()
height = opts.height or clamp(#vim.fn.getqflist())
vim.cmd.copen({
count = height,
mods = opts.open_cmd_mods,
})
end

-- only set the height if the quickfix is not a full-height vsplit
if not util.is_full_height_vsplit(0) then
height = math.min(opts.max_height, math.max(opts.min_height, height))
vim.api.nvim_win_set_height(0, height)
if not vim.tbl_isempty(opts.view) then
vim.fn.winrestview(opts.view)
end

if not opts.focus then
Expand Down
25 changes: 6 additions & 19 deletions lua/quicker/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,12 @@ M.get_lnum_extmarks = function(bufnr, lnum, line_len, ns)
end, extmarks)
end

---Return true if the window is a full-height leaf window
---@param winid? integer
---@return boolean
M.is_full_height_vsplit = function(winid)
if not winid or winid == 0 then
winid = vim.api.nvim_get_current_win()
end
local layout = vim.fn.winlayout()
-- If the top layout is not vsplit, then it's not a vertical leaf
if layout[1] ~= "row" then
return false
end
for _, v in ipairs(layout[2]) do
if v[1] == "leaf" and v[2] == winid then
return true
end
end

return false
---Limit the value to a range between a minimum and maximum
---@param min integer
---@param val integer
---@param max integer
M.clamp = function(min, val, max)
return math.max(min, math.min(val, max))
end

return M

0 comments on commit b9b7eec

Please sign in to comment.