Look at you, sailing through the [jumplist] majestically, like an eagle... piloting a blimp.
Theme: catppuccin
Portal is a plugin that aims to build upon and enhance existing jumplist motions (i.e. <c-o>
and <c-i>
) by surfacing contextual information with the use of portals, and providing multiple jump options by means of queries.
To get started, install the plugin using your preferred package manager, setup the plugin, add the suggested keybindings for portals and tagging, and give it a go! Default settings for the plugin can be found in the settings section below
use {
"cbochs/portal.nvim",
requires = {
"cbochs/grapple.nvim", -- Optional: provides the "grapple" query item
"ThePrimeagen/harpoon", -- Optional: provides the "harpoon" query item
},
}
Plug "cbochs/portal.nvim"
The following are the default settings for Portal. Setup is not required, but settings may be overridden by passing them as table arguments to the portal#setup
function.
require("portal").setup({
---@type "debug" | "info" | "warn" | "error"
log_level = "warn",
---The default queries used when searching the jumplist. An entry can
---be a name of a registered query item, an anonymous predicate, or
---a well-formed query item. See Queries section for more information.
---@type Portal.QueryLike[]
query = { "modified", "different", "valid" },
---An ordered list of keys that will be used for labelling available jumps.
---Labels will be applied in same order as `query`.
---@type string[]
labels = { "j", "k", "h", "l" },
---Keys used for exiting portal selection. To disable a key, set its value
---to `nil` or `false`.
---@type table<string, boolean | nil>
escape = {
["<esc>"] = true,
},
---The jumplist is fixed at 100 items, which has the possibility to impact
---portal performance. Set this to a value less than 100 to limit the number
---of jumps in the jumplist that will be queried.
lookback = 100,
portal = {
title = {
--- When a portal is empty, render an default portal title
render_empty = true,
--- The raw window options used for the portal title window
options = {
relative = "cursor",
width = 80,
height = 1,
col = 2,
style = "minimal",
focusable = false,
border = "single",
noautocmd = true,
zindex = 98,
},
},
body = {
-- When a portal is empty, render an empty buffer body
render_empty = false,
--- The raw window options used for the portal body window
options = {
relative = "cursor",
width = 80,
height = 3,
col = 2,
focusable = false,
border = "single",
noautocmd = true,
zindex = 99,
},
},
},
})
A portal is a window that displays the jump location, the label required to get to that jump location, and any addition contextual information (i.e. the jump's file name or matched query).
vim.keymap.set("n", "<leader>o", require("portal").jump_backward, {})
vim.keymap.set("n", "<leader>i", require("portal").jump_forward, {})
A query is a list of query items which are used to identify specifc jump locations in the jumplist. Each query item will attempt to match with a jump location based on a given criteria.
For example, a query of { "modified", "different" }
will attempt to find two jump locations. The first is where a jump's buffer has been modified. The second is where a jump's buffer is different than the current buffer.
local query = { "modified", "different" }
-- A query can be used in the context of jumping and passed in as an option
-- or during setup
require("portal").jump_forward({ query = query })
-- A list of query-like items must be resolved into proper Portal.QueryItem's
local resolved_query = require("portal.query").resolve(query)
-- A search can be explicitly searched for, returning a list of Portal.Jump.
-- Invalid jumps will have their direction field set to types.direction.none
local available_jumps = require("portal.jump").search(query)
All registered query items are available as table values from query
. For example, the query item for "valid"
would be:
require("portal.query").valid
valid
Matches jumps that have a valid buffer (see: :h nvim_buf_is_valid
).
different
Matches jumps that have a buffer different than the current buffer.
modified
Matched jumps that are in a modified buffer (see :h 'modified'
).
custom
See how to create your own custom query items and available integrations for more information.
A query item found in the settings is in fact a "query-like" item. It may be either a string
, Portal.Predicate
, or Portal.QueryItem
. A string may be used to specify a query item that has been registered. To register a query, use query.register
and pass in a key, predicate, and optional name
and name_short
.
---Define the predicate
---@param jump Portal.Jump
---@return boolean
local function is_listed(jump)
return require("portal.query").valid(jump)
and vim.fn.buflisted(jump.buffer)
end
-- Register the predicate with an associated key
require("portal.query").register("listed", is_listed, {
name = "Listed",
name_short = "L",
})
-- Use the registered query item
require("portal").jump_backward({
query = { "listed" }
})
Anonymous query items may also be used instead of explicitly registering a query item.
require("portal").jump_backward({
query = {
-- A query item may be an unnamed Portal.Predicate
function(jump) ... end,
-- A query item may be a well-formed, but unregistered, Portal.QueryItem
{
predicate = function(jump) ... end,
type = "{type}" -- synomymous with a query item's "key"
name = "{name}",
name_short = "{name_short}"
}
}
})
todo!(cbochs)
A number of highlight groups are available to let you style your portals:
PortalBorder
The default window border placed around any open portal.
Default: FloatBorder
PortalBorderBackward
The window border placed around an open portal when the jump direction is backward.
Default: PortalBorder
PortalBorderForward
The window border placed around an open portal when the jump direction is forward.
Default: PortalBorder
PortalBorderNone
The window border placed around an open portal when the jump direction is forward.
Default: PortalBorder
PortalLabel
The label (extmark) placed next to a portal jump location.
Default: { bg = "#a6e3a1", fg = "#1e1e2e" }
Example
-- Give window borders a "portal" feel
vim.api.nvim_set_hl(0, "PortalBorder", { fg = "#fab387" })
vim.api.nvim_set_hl(0, "PortalBorderNone", { fg = "#89b4fa" })
The following additional queries are automatically registered if their associated plugin is found.
Query item: "grapple"
Matches jumps that are in a buffer tagged by grapple.nvim.
Usage
require("portal").setup({
query = { "grapple", ... }
})
Use Portal and Grapple to jump directly to the first tagged buffer navigating backwards in the jumplist, without opening any portals.
local query = require("portal.query").resolve({ "grapple" })
local jumps = require("portal.jump").search(query, "backward")
require("portal.jump").select(jumps[1])
Query item: "harpoon"
Matches jumps that are in a buffer marked by harpoon.
Usage
require("portal").setup({
query = { "harpoon", ... }
})