feat(defaults): jump between :terminal shell prompts with ]]/[[ #32736

This commit is contained in:
Gregory Anders
2025-03-07 07:45:34 -06:00
committed by GitHub
parent c8b64b7a43
commit b31132f1c1
10 changed files with 160 additions and 55 deletions

View File

@@ -244,6 +244,8 @@ DEFAULTS
• |[a|, |]a|, |[A|, |]A| navigate through the |argument-list|
• |[b|, |]b|, |[B|, |]B| navigate through the |buffer-list|
• |[<Space>|, |]<Space>| add an empty line above and below the cursor
• |[[| and |]]| in Normal mode jump between shell prompts for shells which emit
OSC 133 sequences ("shell integration" or "semantic prompts").
• Snippet:
• `<Tab>` in Insert and Select mode maps to `vim.snippet.jump({ direction = 1 })`

View File

@@ -185,6 +185,32 @@ clipboard.
OSC 52 sequences sent from the :terminal buffer do not emit a |TermRequest|
event. The event is handled directly by Nvim and is not forwarded to plugins.
OSC 133: shell integration *terminal-osc133*
Some shells will emit semantic escape sequences (OSC 133) to mark the
beginning and end of a prompt. The start of a prompt is marked with the
sequence `OSC 133 ; A`. Nvim can be configured to create signs in terminal
buffers marking shell prompts. Example: >lua
local ns = vim.api.nvim_create_namespace('terminal_prompt_markers')
vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args)
if string.match(args.data.sequence, '^\027]133;A') then
local lnum = args.data.cursor[1]
vim.api.nvim_buf_set_extmark(args.buf, ns, lnum - 1, 0, {
-- Replace with sign text and highlight group of choice
sign_text = '▶',
sign_hl_group = 'SpecialChar',
})
end
end,
})
-- Enable signcolumn in terminal buffers
vim.api.nvim_create_autocmd('TermOpen', {
command = 'setlocal signcolumn=auto',
})
<
==============================================================================
Status Variables *terminal-status*

View File

@@ -181,7 +181,10 @@ nvim.terminal:
when 'background' is "light". While this may not reflect the actual
foreground/background color, it permits 'background' to be retained for a
nested Nvim instance running in the terminal emulator.
- TermOpen: Sets default options for |terminal| buffers:
- TermRequest: Nvim will create extmarks for shells which
annotate their prompts with OSC 133 escape sequences, enabling users to
quickly navigate between prompts using |[[| and |]]|.
- TermOpen: Sets default options and mappings for |terminal| buffers:
- 'nomodifiable'
- 'undolevels' set to -1
- 'textwidth' set to 0
@@ -193,6 +196,7 @@ nvim.terminal:
- 'foldcolumn' set to "0"
- 'winhighlight' uses |hl-StatusLineTerm| and |hl-StatusLineTermNC| in
place of |hl-StatusLine| and |hl-StatusLineNC|
- |[[| and |]]| to navigate between shell prompts
nvim.cmdwin:
- CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|.

View File

@@ -534,14 +534,59 @@ do
end,
})
local nvim_terminal_prompt_ns = vim.api.nvim_create_namespace('nvim.terminal.prompt')
vim.api.nvim_create_autocmd('TermRequest', {
group = nvim_terminal_augroup,
desc = 'Mark shell prompts indicated by OSC 133 sequences for navigation',
callback = function(args)
if string.match(args.data.sequence, '^\027]133;A') then
local lnum = args.data.cursor[1] ---@type integer
vim.api.nvim_buf_set_extmark(args.buf, nvim_terminal_prompt_ns, lnum - 1, 0, {})
end
end,
})
---@param ns integer
---@param buf integer
---@param count integer
local function jump_to_prompt(ns, win, buf, count)
local row, col = unpack(vim.api.nvim_win_get_cursor(win))
local start = -1
local end_ ---@type 0|-1
if count > 0 then
start = row
end_ = -1
elseif count < 0 then
-- Subtract 2 because row is 1-based, but extmarks are 0-based
start = row - 2
end_ = 0
end
if start < 0 then
return
end
local extmarks = vim.api.nvim_buf_get_extmarks(
buf,
ns,
{ start, col },
end_,
{ limit = math.abs(count) }
)
if #extmarks > 0 then
local extmark = extmarks[math.min(#extmarks, math.abs(count))]
vim.api.nvim_win_set_cursor(win, { extmark[2] + 1, extmark[3] })
end
end
vim.api.nvim_create_autocmd('TermOpen', {
group = nvim_terminal_augroup,
desc = 'Default settings for :terminal buffers',
callback = function()
vim.bo.modifiable = false
vim.bo.undolevels = -1
vim.bo.scrollback = vim.o.scrollback < 0 and 10000 or math.max(1, vim.o.scrollback)
vim.bo.textwidth = 0
callback = function(args)
vim.bo[args.buf].modifiable = false
vim.bo[args.buf].undolevels = -1
vim.bo[args.buf].scrollback = vim.o.scrollback < 0 and 10000 or math.max(1, vim.o.scrollback)
vim.bo[args.buf].textwidth = 0
vim.wo[0][0].wrap = false
vim.wo[0][0].list = false
vim.wo[0][0].number = false
@@ -555,6 +600,13 @@ do
winhl = winhl .. ','
end
vim.wo[0][0].winhighlight = winhl .. 'StatusLine:StatusLineTerm,StatusLineNC:StatusLineTermNC'
vim.keymap.set('n', '[[', function()
jump_to_prompt(nvim_terminal_prompt_ns, 0, args.buf, -vim.v.count1)
end, { buffer = args.buf, desc = 'Jump [count] shell prompts backward' })
vim.keymap.set('n', ']]', function()
jump_to_prompt(nvim_terminal_prompt_ns, 0, args.buf, vim.v.count1)
end, { buffer = args.buf, desc = 'Jump [count] shell prompts forward' })
end,
})