docs: lsp config/commands #33122

fix #33075
This commit is contained in:
Justin M. Keyes
2025-03-30 13:29:36 -07:00
committed by GitHub
parent cb247e06f0
commit b41e066aa1
10 changed files with 235 additions and 174 deletions

View File

@@ -3492,40 +3492,39 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
empty. The end-of-buffer region is hidden by setting empty. The end-of-buffer region is hidden by setting
`eob` flag of 'fillchars' to a space char, and clearing `eob` flag of 'fillchars' to a space char, and clearing
the |hl-EndOfBuffer| region in 'winhighlight'. the |hl-EndOfBuffer| region in 'winhighlight'.
• border: Style of (optional) window border. This can either • border: (`string|string[]`) (defaults to 'winborder'
be a string or an array. The string values are the same as option) Window border. The string form accepts the same
those described in 'winborder'. If it is an array, it values as the 'winborder' option. The array form must have
should have a length of eight or any divisor of eight. The a length of eight or any divisor of eight, specifying the
array will specify the eight chars building up the border chars that form the border in a clockwise fashion starting
in a clockwise fashion starting with the top-left corner. from the top-left corner. For example, the double-box
As an example, the double box style could be specified as: > style can be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
< <
If the number of chars are less than eight, they will be If fewer than eight chars are given, they will be
repeated. Thus an ASCII border could be specified as > repeated. An ASCII border could be specified as: >
[ "/", "-", \"\\\\\", "|" ], [ "/", "-", \"\\\\\", "|" ],
< <
or all chars the same as > Or one char for all sides: >
[ "x" ]. [ "x" ].
< <
An empty string can be used to turn off a specific border, Empty string can be used to hide a specific border. This
for instance, > example will show only vertical borders, not horizontal: >
[ "", "", "", ">", "", "", "", "<" ] [ "", "", "", ">", "", "", "", "<" ]
< <
will only make vertical borders but not horizontal ones. By default, |hl-FloatBorder| highlight is used, which
By default, `FloatBorder` highlight is used, which links links to |hl-WinSeparator| when not defined. Each border
to `WinSeparator` when not defined. It could also be side can specify an optional highlight: >
specified by character: >
[ ["+", "MyCorner"], ["x", "MyBorder"] ]. [ ["+", "MyCorner"], ["x", "MyBorder"] ].
< <
• title: Title (optional) in window border, string or list. • title: (optional) Title in window border, string or list.
List should consist of `[text, highlight]` tuples. If List should consist of `[text, highlight]` tuples. If
string, or a tuple lacks a highlight, the default string, or a tuple lacks a highlight, the default
highlight group is `FloatTitle`. highlight group is `FloatTitle`.
• title_pos: Title position. Must be set with `title` • title_pos: Title position. Must be set with `title`
option. Value can be one of "left", "center", or "right". option. Value can be one of "left", "center", or "right".
Default is `"left"`. Default is `"left"`.
• footer: Footer (optional) in window border, string or • footer: (optional) Footer in window border, string or
list. List should consist of `[text, highlight]` tuples. list. List should consist of `[text, highlight]` tuples.
If string, or a tuple lacks a highlight, the default If string, or a tuple lacks a highlight, the default
highlight group is `FloatFooter`. highlight group is `FloatFooter`.

View File

@@ -651,10 +651,11 @@ When completion is active you can use CTRL-E to stop it and go back to the
originally typed text. The CTRL-E will not be inserted. originally typed text. The CTRL-E will not be inserted.
*complete_CTRL-Y* *complete_CTRL-Y*
When the popup menu is displayed you can use CTRL-Y to stop completion and When the popup menu is displayed, CTRL-Y stops completion and accepts the
accept the currently selected entry. The CTRL-Y is not inserted. Typing a currently selected entry. Typing a space, Enter, or some other unprintable
space, Enter, or some other unprintable character will leave completion mode character will leave completion mode and insert that typed character. If you
and insert that typed character. want to use <Enter> to accept a completion item, use this mapping: >vim
inoremap <expr> <cr> pumvisible() ? '<c-y>' : '<cr>'
When the popup menu is displayed there are a few more special keys, see When the popup menu is displayed there are a few more special keys, see
|popupmenu-keys|. |popupmenu-keys|.

View File

@@ -76,6 +76,7 @@ listed below, if (1) the language server supports the functionality and (2)
the options are empty or were set by the builtin runtime (ftplugin) files. The the options are empty or were set by the builtin runtime (ftplugin) files. The
options are not restored when the LSP client is stopped or detached. options are not restored when the LSP client is stopped or detached.
BUFFER-LOCAL DEFAULTS
- 'omnifunc' is set to |vim.lsp.omnifunc()|, use |i_CTRL-X_CTRL-O| to trigger - 'omnifunc' is set to |vim.lsp.omnifunc()|, use |i_CTRL-X_CTRL-O| to trigger
completion. completion.
- 'tagfunc' is set to |vim.lsp.tagfunc()|. This enables features like - 'tagfunc' is set to |vim.lsp.tagfunc()|. This enables features like
@@ -87,8 +88,9 @@ options are not restored when the LSP client is stopped or detached.
- |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or - |K| is mapped to |vim.lsp.buf.hover()| unless |'keywordprg'| is customized or
a custom keymap for `K` exists. a custom keymap for `K` exists.
GLOBAL DEFAULTS
*grr* *gra* *grn* *gri* *i_CTRL-S* *grr* *gra* *grn* *gri* *i_CTRL-S*
Some keymaps are created unconditionally when Nvim starts: These GLOBAL keymaps are created unconditionally when Nvim starts:
- "grn" is mapped in Normal mode to |vim.lsp.buf.rename()| - "grn" is mapped in Normal mode to |vim.lsp.buf.rename()|
- "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()| - "gra" is mapped in Normal and Visual mode to |vim.lsp.buf.code_action()|
- "grr" is mapped in Normal mode to |vim.lsp.buf.references()| - "grr" is mapped in Normal mode to |vim.lsp.buf.references()|
@@ -96,12 +98,11 @@ Some keymaps are created unconditionally when Nvim starts:
- "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()| - "gO" is mapped in Normal mode to |vim.lsp.buf.document_symbol()|
- CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()| - CTRL-S is mapped in Insert mode to |vim.lsp.buf.signature_help()|
If not wanted, these keymaps can be removed at any time using You can remove GLOBAL keymaps at any time using |vim.keymap.del()| or
|vim.keymap.del()| or |:unmap| (see also |gr-default|). |:unmap|. See also |gr-default|.
*lsp-defaults-disable* *lsp-defaults-disable*
To override or delete any of the above defaults, set or unset the options on To remove or override BUFFER-LOCAL defaults, define a |LspAttach| handler: >lua
|LspAttach|: >lua
vim.api.nvim_create_autocmd('LspAttach', { vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args) callback = function(args)
@@ -812,37 +813,52 @@ client_is_stopped({client_id}) *vim.lsp.client_is_stopped()*
(`boolean`) stopped true if client is stopped, false otherwise. (`boolean`) stopped true if client is stopped, false otherwise.
commands *vim.lsp.commands* commands *vim.lsp.commands*
Registry for client side commands. This is an extension point for plugins Registry (a table) for client-side handlers, for custom server-commands
to handle custom commands which are not part of the core language server that are not in the LSP specification.
protocol specification.
The registry is a table where the key is a unique command name, and the If an LSP response contains a command which is not found in
value is a function which is called if any LSP action (code action, code `vim.lsp.commands`, the command will be executed via the LSP server using
lenses, ...) triggers the command. `workspace/executeCommand`.
If an LSP response contains a command for which no matching entry is Each key in the table is a unique command name, and each value is a
available in this registry, the command will be executed via the LSP function which is called when an LSP action (code action, code lenses,
server using `workspace/executeCommand`. …) triggers the command.
• Argument 1 is the `Command`: >
Command
title: String
command: String
arguments?: any[]
<
• Argument 2 is the |lsp-handler| `ctx`.
The first argument to the function will be the `Command`: Command title: Example: >lua
String command: String arguments?: any[] vim.lsp.commands['java.action.generateToStringPrompt'] = function(_, ctx)
require("jdtls.async").run(function()
The second argument is the `ctx` of |lsp-handler| local _, result = request(ctx.bufnr, 'java/checkToStringStatus', ctx.params)
local fields = ui.pick_many(result.fields, 'Include item in toString?', function(x)
return string.format('%s: %s', x.name, x.type)
end)
local _, edit = request(ctx.bufnr, 'java/generateToString', { context = ctx.params; fields = fields; })
vim.lsp.util.apply_workspace_edit(edit, offset_encoding)
end)
end
<
config({name}, {cfg}) *vim.lsp.config()* config({name}, {cfg}) *vim.lsp.config()*
Update the configuration for an LSP client. Sets the default configuration for an LSP client (or all clients if the
special name "*" is used).
Use name '*' to set default configuration for all clients. Can also be accessed by table-indexing (`vim.lsp.config[…]`) to get the
resolved config, or redefine the config (instead of "merging" with the
Can also be table-assigned to redefine the configuration for a client. config chain).
Examples: Examples:
• Add a root marker for all clients: >lua • Add root markers for ALL clients: >lua
vim.lsp.config('*', { vim.lsp.config('*', {
root_markers = { '.git' }, root_markers = { '.git', '.hg' },
}) })
< <
• Add additional capabilities to all clients: >lua • Add capabilities to ALL clients: >lua
vim.lsp.config('*', { vim.lsp.config('*', {
capabilities = { capabilities = {
textDocument = { textDocument = {
@@ -853,7 +869,21 @@ config({name}, {cfg}) *vim.lsp.config()*
} }
}) })
< <
(Re-)define the configuration for clangd: >lua Add root markers and capabilities for "clangd": >lua
vim.lsp.config('clangd', {
root_markers = { '.clang-format', 'compile_commands.json' },
capabilities = {
textDocument = {
completion = {
completionItem = {
snippetSupport = true,
}
}
}
}
})
<
• (Re-)define the "clangd" configuration (overrides the resolved chain): >lua
vim.lsp.config.clangd = { vim.lsp.config.clangd = {
cmd = { cmd = {
'clangd', 'clangd',
@@ -865,7 +895,7 @@ config({name}, {cfg}) *vim.lsp.config()*
filetypes = { 'c', 'cpp' }, filetypes = { 'c', 'cpp' },
} }
< <
• Get configuration for luals: >lua • Get the resolved configuration for "luals": >lua
local cfg = vim.lsp.config.luals local cfg = vim.lsp.config.luals
< <

View File

@@ -213,7 +213,7 @@ The following new features were added.
• By default, the swapfile "ATTENTION" |E325| dialog is skipped if the • By default, the swapfile "ATTENTION" |E325| dialog is skipped if the
swapfile is owned by a running Nvim process, instead of prompting. If you swapfile is owned by a running Nvim process, instead of prompting. If you
always want the swapfile dialog, delete the default SwapExists handler: always want the swapfile dialog, delete the default SwapExists handler:
`autocmd! nvim_swapfile`. |default-autocmds| `autocmd! nvim.swapfile`. |default-autocmds|
• Navigating the |jumplist| with CTRL+O, CTRL+I behaves more intuitively • Navigating the |jumplist| with CTRL+O, CTRL+I behaves more intuitively
when deleting buffers, and avoids "invalid buffer" cases. #25461 when deleting buffers, and avoids "invalid buffer" cases. #25461
• |:fclose| command. • |:fclose| command.

View File

@@ -56,6 +56,9 @@ EDITOR
it moves to another help buffer. it moves to another help buffer.
• Bells from a |terminal| buffer are now silent by default, unless 'belloff' • Bells from a |terminal| buffer are now silent by default, unless 'belloff'
option doesn't contain "term" or "all". option doesn't contain "term" or "all".
• Renamed autocmd group `nvim_swapfile` to `nvim.swapfile`. |default-autocmds|
If you always want the swapfile dialog, delete the `nvim.swapfile` group:
`autocmd! nvim.swapfile`.
EVENTS EVENTS

View File

@@ -124,7 +124,7 @@ EVENTS
LSP LSP
• |vim.lsp.Config| gained `workspace_required`. • |vim.lsp.ClientConfig| gained `workspace_required`.
LUA LUA

View File

@@ -1796,41 +1796,40 @@ function vim.api.nvim_open_term(buffer, opts) end
--- region is hidden by setting `eob` flag of --- region is hidden by setting `eob` flag of
--- 'fillchars' to a space char, and clearing the --- 'fillchars' to a space char, and clearing the
--- `hl-EndOfBuffer` region in 'winhighlight'. --- `hl-EndOfBuffer` region in 'winhighlight'.
--- - border: Style of (optional) window border. This can either be a string --- - border: (`string|string[]`) (defaults to 'winborder' option) Window border. The string form
--- or an array. The string values are the same as those described in 'winborder'. --- accepts the same values as the 'winborder' option. The array form must have a length of
--- If it is an array, it should have a length of eight or any divisor of --- eight or any divisor of eight, specifying the chars that form the border in a clockwise
--- eight. The array will specify the eight chars building up the border --- fashion starting from the top-left corner. For example, the double-box style can be
--- in a clockwise fashion starting with the top-left corner. As an --- specified as:
--- example, the double box style could be specified as:
--- ``` --- ```
--- [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. --- [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
--- ``` --- ```
--- If the number of chars are less than eight, they will be repeated. Thus --- If fewer than eight chars are given, they will be repeated. An ASCII border could be
--- an ASCII border could be specified as --- specified as:
--- ``` --- ```
--- [ "/", "-", \"\\\\\", "|" ], --- [ "/", "-", \"\\\\\", "|" ],
--- ``` --- ```
--- or all chars the same as --- Or one char for all sides:
--- ``` --- ```
--- [ "x" ]. --- [ "x" ].
--- ``` --- ```
--- An empty string can be used to turn off a specific border, for instance, --- Empty string can be used to hide a specific border. This example will show only vertical
--- borders, not horizontal:
--- ``` --- ```
--- [ "", "", "", ">", "", "", "", "<" ] --- [ "", "", "", ">", "", "", "", "<" ]
--- ``` --- ```
--- will only make vertical borders but not horizontal ones. --- By default, `hl-FloatBorder` highlight is used, which links to `hl-WinSeparator` when not
--- By default, `FloatBorder` highlight is used, which links to `WinSeparator` --- defined. Each border side can specify an optional highlight:
--- when not defined. It could also be specified by character:
--- ``` --- ```
--- [ ["+", "MyCorner"], ["x", "MyBorder"] ]. --- [ ["+", "MyCorner"], ["x", "MyBorder"] ].
--- ``` --- ```
--- - title: Title (optional) in window border, string or list. --- - title: (optional) Title in window border, string or list.
--- List should consist of `[text, highlight]` tuples. --- List should consist of `[text, highlight]` tuples.
--- If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`. --- If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`.
--- - title_pos: Title position. Must be set with `title` option. --- - title_pos: Title position. Must be set with `title` option.
--- Value can be one of "left", "center", or "right". --- Value can be one of "left", "center", or "right".
--- Default is `"left"`. --- Default is `"left"`.
--- - footer: Footer (optional) in window border, string or list. --- - footer: (optional) Footer in window border, string or list.
--- List should consist of `[text, highlight]` tuples. --- List should consist of `[text, highlight]` tuples.
--- If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`. --- If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`.
--- - footer_pos: Footer position. Must be set with `footer` option. --- - footer_pos: Footer position. Must be set with `footer` option.

View File

@@ -296,21 +296,21 @@ end
--- root_dir matches. --- root_dir matches.
--- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean --- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
--- Update the configuration for an LSP client. --- Sets the default configuration for an LSP client (or _all_ clients if the special name "*" is
--- used).
--- ---
--- Use name '*' to set default configuration for all clients. --- Can also be accessed by table-indexing (`vim.lsp.config[…]`) to get the resolved config, or
--- --- redefine the config (instead of "merging" with the config chain).
--- Can also be table-assigned to redefine the configuration for a client.
--- ---
--- Examples: --- Examples:
--- ---
--- - Add a root marker for all clients: --- - Add root markers for ALL clients:
--- ```lua --- ```lua
--- vim.lsp.config('*', { --- vim.lsp.config('*', {
--- root_markers = { '.git' }, --- root_markers = { '.git', '.hg' },
--- }) --- })
--- ``` --- ```
--- - Add additional capabilities to all clients: --- - Add capabilities to ALL clients:
--- ```lua --- ```lua
--- vim.lsp.config('*', { --- vim.lsp.config('*', {
--- capabilities = { --- capabilities = {
@@ -322,7 +322,22 @@ end
--- } --- }
--- }) --- })
--- ``` --- ```
--- - (Re-)define the configuration for clangd: --- - Add root markers and capabilities for "clangd":
--- ```lua
--- vim.lsp.config('clangd', {
--- root_markers = { '.clang-format', 'compile_commands.json' },
--- capabilities = {
--- textDocument = {
--- completion = {
--- completionItem = {
--- snippetSupport = true,
--- }
--- }
--- }
--- }
--- })
--- ```
--- - (Re-)define the "clangd" configuration (overrides the resolved chain):
--- ```lua --- ```lua
--- vim.lsp.config.clangd = { --- vim.lsp.config.clangd = {
--- cmd = { --- cmd = {
@@ -335,7 +350,7 @@ end
--- filetypes = { 'c', 'cpp' }, --- filetypes = { 'c', 'cpp' },
--- } --- }
--- ``` --- ```
--- - Get configuration for luals: --- - Get the resolved configuration for "luals":
--- ```lua --- ```lua
--- local cfg = vim.lsp.config.luals --- local cfg = vim.lsp.config.luals
--- ``` --- ```
@@ -1524,25 +1539,39 @@ function lsp.with(handler, override_config)
end end
end end
--- Registry for client side commands. --- Registry (a table) for client-side handlers, for custom server-commands that are not in the LSP
--- This is an extension point for plugins to handle custom commands which are --- specification.
--- not part of the core language server protocol specification.
--- ---
--- The registry is a table where the key is a unique command name, --- If an LSP response contains a command which is not found in `vim.lsp.commands`, the command will
--- and the value is a function which is called if any LSP action --- be executed via the LSP server using `workspace/executeCommand`.
--- (code action, code lenses, ...) triggers the command.
--- ---
--- If an LSP response contains a command for which no matching entry is --- Each key in the table is a unique command name, and each value is a function which is called
--- available in this registry, the command will be executed via the LSP server --- when an LSP action (code action, code lenses, …) triggers the command.
--- using `workspace/executeCommand`.
--- ---
--- The first argument to the function will be the `Command`: --- - Argument 1 is the `Command`:
--- ```
--- Command --- Command
--- title: String --- title: String
--- command: String --- command: String
--- arguments?: any[] --- arguments?: any[]
--- ```
--- - Argument 2 is the |lsp-handler| `ctx`.
---
--- Example:
---
--- ```lua
--- vim.lsp.commands['java.action.generateToStringPrompt'] = function(_, ctx)
--- require("jdtls.async").run(function()
--- local _, result = request(ctx.bufnr, 'java/checkToStringStatus', ctx.params)
--- local fields = ui.pick_many(result.fields, 'Include item in toString?', function(x)
--- return string.format('%s: %s', x.name, x.type)
--- end)
--- local _, edit = request(ctx.bufnr, 'java/generateToString', { context = ctx.params; fields = fields; })
--- vim.lsp.util.apply_workspace_edit(edit, offset_encoding)
--- end)
--- end
--- ```
--- ---
--- The second argument is the `ctx` of |lsp-handler|
--- @type table<string,function> --- @type table<string,function>
lsp.commands = setmetatable({}, { lsp.commands = setmetatable({}, {
__newindex = function(tbl, key, value) __newindex = function(tbl, key, value)

View File

@@ -76,6 +76,7 @@ local new_layout = {
['news.txt'] = true, ['news.txt'] = true,
['news-0.9.txt'] = true, ['news-0.9.txt'] = true,
['news-0.10.txt'] = true, ['news-0.10.txt'] = true,
['news-0.11.txt'] = true,
['nvim.txt'] = true, ['nvim.txt'] = true,
['provider.txt'] = true, ['provider.txt'] = true,
['tui.txt'] = true, ['tui.txt'] = true,

View File

@@ -158,41 +158,40 @@
/// region is hidden by setting `eob` flag of /// region is hidden by setting `eob` flag of
/// 'fillchars' to a space char, and clearing the /// 'fillchars' to a space char, and clearing the
/// |hl-EndOfBuffer| region in 'winhighlight'. /// |hl-EndOfBuffer| region in 'winhighlight'.
/// - border: Style of (optional) window border. This can either be a string /// - border: (`string|string[]`) (defaults to 'winborder' option) Window border. The string form
/// or an array. The string values are the same as those described in 'winborder'. /// accepts the same values as the 'winborder' option. The array form must have a length of
/// If it is an array, it should have a length of eight or any divisor of /// eight or any divisor of eight, specifying the chars that form the border in a clockwise
/// eight. The array will specify the eight chars building up the border /// fashion starting from the top-left corner. For example, the double-box style can be
/// in a clockwise fashion starting with the top-left corner. As an /// specified as:
/// example, the double box style could be specified as:
/// ``` /// ```
/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. /// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
/// ``` /// ```
/// If the number of chars are less than eight, they will be repeated. Thus /// If fewer than eight chars are given, they will be repeated. An ASCII border could be
/// an ASCII border could be specified as /// specified as:
/// ``` /// ```
/// [ "/", "-", \"\\\\\", "|" ], /// [ "/", "-", \"\\\\\", "|" ],
/// ``` /// ```
/// or all chars the same as /// Or one char for all sides:
/// ``` /// ```
/// [ "x" ]. /// [ "x" ].
/// ``` /// ```
/// An empty string can be used to turn off a specific border, for instance, /// Empty string can be used to hide a specific border. This example will show only vertical
/// borders, not horizontal:
/// ``` /// ```
/// [ "", "", "", ">", "", "", "", "<" ] /// [ "", "", "", ">", "", "", "", "<" ]
/// ``` /// ```
/// will only make vertical borders but not horizontal ones. /// By default, |hl-FloatBorder| highlight is used, which links to |hl-WinSeparator| when not
/// By default, `FloatBorder` highlight is used, which links to `WinSeparator` /// defined. Each border side can specify an optional highlight:
/// when not defined. It could also be specified by character:
/// ``` /// ```
/// [ ["+", "MyCorner"], ["x", "MyBorder"] ]. /// [ ["+", "MyCorner"], ["x", "MyBorder"] ].
/// ``` /// ```
/// - title: Title (optional) in window border, string or list. /// - title: (optional) Title in window border, string or list.
/// List should consist of `[text, highlight]` tuples. /// List should consist of `[text, highlight]` tuples.
/// If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`. /// If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`.
/// - title_pos: Title position. Must be set with `title` option. /// - title_pos: Title position. Must be set with `title` option.
/// Value can be one of "left", "center", or "right". /// Value can be one of "left", "center", or "right".
/// Default is `"left"`. /// Default is `"left"`.
/// - footer: Footer (optional) in window border, string or list. /// - footer: (optional) Footer in window border, string or list.
/// List should consist of `[text, highlight]` tuples. /// List should consist of `[text, highlight]` tuples.
/// If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`. /// If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`.
/// - footer_pos: Footer position. Must be set with `footer` option. /// - footer_pos: Footer position. Must be set with `footer` option.