终端

Nvim :help 页面,生成源文件,使用 tree-sitter-vimdoc 解析器。


终端模拟器 terminal-emulator
Nvim 嵌入了一个基于 libvterm 的 VT220/xterm 终端模拟器。终端显示为一个特殊的 'buftype',当从连接的程序接收数据时异步更新。
终端缓冲区行为与普通缓冲区类似,除了
使用 'modifiable',可以编辑行,但不能删除行。
'scrollback' 控制保留的行数。
如果光标在最后一行,则会跟随(尾随)输出。
'modified' 是默认设置。您可以设置 'nomodified' 以避免在关闭终端缓冲区时出现警告。
'bufhidden' 默认设置为 "hide"。
有几种方法可以创建终端缓冲区
运行 :terminal 命令。
调用 nvim_open_term()termopen() 函数。
编辑 "term://" 缓冲区。示例
:edit term://bash
:vsplit term://top
注意:要从 autocmd 打开 "term://" 缓冲区,需要 autocmd-nested 修饰符。
autocmd VimEnter * ++nested split term://sh
(这仅供参考;请改用 :terminal。)
终端启动时,缓冲区内容将更新,缓冲区将以 term://{cwd}//{pid}:{cmd} 的形式命名。此命名方案由 :mksession 用于恢复终端缓冲区(通过重新启动 {cmd})。
终端环境初始化方式与 jobstart-env 相同。
要发送输入,请使用 终端模式,方法是使用 iIaA:startinsert。在此模式下,除 <C-\> 之外的所有键都将发送到基础程序。如果按下 <C-\>,则会发送下一个键,除非它是 <C-N><C-O>。使用 <C-\><C-N> 返回普通模式。 CTRL-\_CTRL-N 使用 <C-\><C-O> 执行一个普通模式命令,然后返回终端模式。 t_CTRL-\_CTRL-O
终端模式强制使用以下本地选项
终端模式有自己的 :tnoremap 命名空间用于映射,这可以用来自动化任何终端交互。
要将 <Esc> 映射为退出终端模式
:tnoremap <Esc> <C-\><C-n>
要在终端模式下模拟 i_CTRL-R
:tnoremap <expr> <C-R> '<C-\><C-N>"'.nr2char(getchar()).'pi'
要使用 ALT+{h,j,k,l} 从任何模式导航窗口
:tnoremap <A-h> <C-\><C-N><C-w>h
:tnoremap <A-j> <C-\><C-N><C-w>j
:tnoremap <A-k> <C-\><C-N><C-w>k
:tnoremap <A-l> <C-\><C-N><C-w>l
:inoremap <A-h> <C-\><C-N><C-w>h
:inoremap <A-j> <C-\><C-N><C-w>j
:inoremap <A-k> <C-\><C-N><C-w>k
:inoremap <A-l> <C-\><C-N><C-w>l
:nnoremap <A-h> <C-w>h
:nnoremap <A-j> <C-w>j
:nnoremap <A-k> <C-w>k
:nnoremap <A-l> <C-w>l
您还可以创建类似于终端模式映射的菜单,但您必须使用 :tlmenu 而不是 :tmenu
鼠标输入具有以下行为
如果程序启用了鼠标事件,则相应的事件将转发到程序。
如果鼠标事件被禁用(默认设置),则终端焦点将丢失,事件将像在普通缓冲区中一样处理。
如果单击另一个窗口,则终端焦点将丢失,nvim 将跳转到单击的窗口
如果鼠标位于另一个窗口中时使用鼠标滚轮,则终端不会失去焦点,悬停的窗口将被滚动。
终端为某些选项设置本地默认值,这些默认值可能与您的全局配置不同。
'list' 被禁用
'wrap' 被禁用
您可以使用 TermOpen autocommand 更改默认设置
au TermOpen * setlocal list
终端颜色
{g,b}:terminal_color_x 变量控制终端颜色调色板,其中 x 是 0 到 15(含)之间的颜色索引。在 TermOpen 期间读取这些变量。该值必须是颜色名称或十六进制字符串。示例
let g:terminal_color_4 = '#ff0000'
let g:terminal_color_5 = 'green'
仅适用于 RGB UI(请参阅 'termguicolors');对于 256 色终端,颜色索引只是转发。
编辑器突出显示(语法突出显示突出显示组 等)具有更高的优先级:它在解析终端颜色后应用。
在 :terminal 缓冲区中运行的应用程序可以发送请求,Nvim 通过 TermRequest 事件公开这些请求。
OSC 7:更改工作目录 terminal-osc7
要处理从 :terminal 进程发出的 OSC 7,这段代码将 :cd 到请求中指示的目录。
vim.api.nvim_create_autocmd({ 'TermRequest' }, {
  desc = 'Handles OSC 7 dir change requests',
  callback = function(ev)
    if string.sub(vim.v.termrequest, 1, 4) == '\x1b]7;' then
      local dir = string.gsub(vim.v.termrequest, '\x1b]7;file://[^/]*', '')
      if vim.fn.isdirectory(dir) == 0 then
        vim.notify('invalid dir: '..dir)
        return
      end
      vim.api.nvim_buf_set_var(ev.buf, 'osc7_dir', dir)
      if vim.o.autochdir and vim.api.nvim_get_current_buf() == ev.buf then
        vim.cmd.cd(dir)
      end
    end
  end
})
vim.api.nvim_create_autocmd({ 'BufEnter', 'WinEnter', 'DirChanged' }, {
  callback = function(ev)
    if vim.b.osc7_dir and vim.fn.isdirectory(vim.b.osc7_dir) == 1 then
      vim.cmd.cd(vim.b.osc7_dir)
    end
  end
})
要试用它,请选择上面的代码,并使用 :'<,'>lua 对其进行源代码化,然后在 :terminal 缓冲区中运行以下命令
printf "\033]7;file://./foo/bar\033\\"
OSC 52:写入系统剪贴板 terminal-osc52
在 :terminal 缓冲区中的应用程序可以通过发出 OSC 52 序列来写入系统剪贴板。示例
printf '\033]52;;%s\033\\' "$(echo -n 'Hello world' | base64)"
Nvim 使用配置的 剪贴板 提供程序写入系统剪贴板。不支持使用 OSC 52 从系统剪贴板读取,因为这将允许 :terminal 中的任何任意程序读取用户的剪贴板。
从 :terminal 缓冲区发送的 OSC 52 序列不会发出 TermRequest 事件。该事件由 Nvim 直接处理,不会转发到插件。

状态变量 terminal-status

终端缓冲区维护一些缓冲区本地变量和选项。这些值在 TermOpen 之前初始化,因此您可以在本地 'statusline' 中使用它们。示例
:autocmd TermOpen * setlocal statusline=%{b:term_title}
b:term_title 终端标题(用户可写),通常显示在图形终端模拟器的窗口标题或标签标题中。终端程序可以通过发出转义序列来设置此标题。
'channel' 终端 PTY job-id。可以与 chansend() 一起使用,向终端发送输入。
TermClose 事件在 v:event 的 "status" 字段中给出终端作业退出代码。例如,此 autocommand 将终端的退出代码输出到 :messages
autocmd TermClose * echom 'Terminal exited with status '..v:event.status
使用 jobwait() 检查终端作业是否已完成
let running = jobwait([&channel], 0)[0] == -1

:Termdebug 插件 terminal-debug

终端调试插件可用于使用 gdb 调试程序并查看 Vim 窗口中的源代码。由于这完全包含在 Vim 内部,因此也可以通过 ssh 连接远程进行。
启动
termdebug-starting
使用以下命令加载插件
packadd termdebug
vimrc 文件加载插件时,添加 "!" 属性
packadd! termdebug
:Termdebug
要开始调试,请使用 :Termdebug:TermdebugCommand 后跟命令名称,例如
:Termdebug vim
这将打开两个窗口
gdb 窗口 在其中执行 "gdb vim" 的终端窗口。您可以在此处直接与 gdb 交互。
程序窗口 执行程序的终端窗口。在 gdb 中使用 "run" 时,程序 I/O 将发生在此窗口中,这样就不会干扰 gdb 的控制。
当前窗口用于显示源代码。当 gdb 暂停时,将显示源文件位置(如果可能)。使用突出显示组 debugPC 使用符号突出显示当前位置。
如果当前窗口中的缓冲区被修改,则会打开另一个窗口来显示当前 gdb 位置。
聚焦执行程序的终端与它交互。这与在终端窗口中运行任何命令的工作方式相同。
调试器结束时(通常在 gdb 窗口中键入 "quit"),两个打开的窗口将关闭。
一次只能有一个调试器处于活动状态。 :TermdebugCommand
如果您想向被调试的命令提供特定命令,您可以使用 :TermdebugCommand 命令,后跟命令名称和附加参数。
:TermdebugCommand vim --clean -c ':set nu'
:Termdebug:TermdebugCommand 都支持可选的 "!" 感叹号参数,以立即启动命令,而无需在 gdb 窗口中暂停(光标将在被调试的窗口中)。例如
:TermdebugCommand! vim --clean
要将 gdb 附加到正在运行的可执行文件或使用核心文件,请传递额外的参数。例如
:Termdebug vim core
:Termdebug vim 98343
如果没有给出参数,您将最终进入 gdb 窗口,您需要在其中使用 gdb file 命令指定要运行的命令。
示例会话
termdebug-example
在 Vim 的 "src" 目录中启动并构建 Vim
% make
启动 Vim
% ./vim
加载 termdebug 插件并开始调试 Vim
:packadd termdebug
:Termdebug vim
您现在应该有三个窗口:源 - 您在其中启动 gdb - 您可以在此处键入 gdb 命令程序 - 执行的程序将使用此窗口
将焦点放在 gdb 窗口上,然后键入
break ex_help
run
Vim 将在程序窗口中开始运行。将焦点放在那里,然后键入
:help gui
Gdb 将进入 ex_help 断点。源窗口现在显示 ex_cmds.c 文件。符号列中将出现一个红色的 "1 " 标记,表示设置断点的位置。调试器停止的代码行将被高亮显示。您现在可以逐步执行程序。您会看到高亮显示随着调试器执行一行源代码而移动。
运行 ":Next" 几次,直到 for 循环被高亮显示。将光标放在 "eap->arg" 的末尾,然后调用 ":Eval"。您将看到以下内容显示
"eap->arg": 0x555555e68855 "gui"
这样,您可以检查局部变量的值。您也可以聚焦 gdb 窗口并使用 "print" 命令,例如
print *eap
如果鼠标指针移动有效,Vim 还将在鼠标停留在可以通过 gdb 评估的文本上时显示气泡。您还可以使用 "K" 映射,它将使用 Nvim 浮动窗口来显示结果。
现在回到源窗口,将光标放在 for 循环后的第一行,然后键入
:Break
您将看到出现一个 "1" 标记,这表示新的断点。现在运行 ":Cont" 命令,代码将执行到断点为止。
您可以在 gdb 窗口中键入更高级的命令。例如,键入
watch curbuf
现在运行 ":Cont"(或在 gdb 窗口中键入 "cont")。执行将继续进行,直到 "curbuf" 的值发生更改,该值在 do_ecmd() 中。要再次删除此监视点,请在 gdb 窗口中键入
delete 3
您可以通过在 gdb 窗口中键入以下命令来查看堆栈
where
在堆栈帧之间移动,例如使用
frame 3
源窗口将显示代码,在调用更深层级时进行调用。
逐步执行代码
termdebug-stepping
将焦点放在 gdb 窗口上,以便在其中键入命令。一些常见的命令是
CTRL-C 中断程序
next 执行当前行并在下一行停止
step 执行当前行并在下一个语句处停止,进入函数
until 执行到当前光标行之后或指定位置之后,或当前堆栈帧返回
finish 执行到离开当前函数为止
where 显示堆栈
frame N 转到第 N 个堆栈帧
continue 继续执行
:Run :Arguments 在显示源代码的窗口中,可以使用以下命令控制 gdb::Run [args] 使用 [args] 或之前的参数运行程序 :Arguments {args} 设置下一个 :Run 的参数
:Break 在光标位置设置断点 :Break {position} 在指定位置设置断点 :Tbreak 在光标位置设置临时断点 :Tbreak {position} 在指定位置设置临时断点 :Clear 删除光标位置的断点
:Step 执行 gdb 的 "step" 命令 :Over 执行 gdb 的 "next" 命令 (:Next 是 Vim 命令) :Until 执行 gdb 的 "until" 命令 :Finish 执行 gdb 的 "finish" 命令 :Continue 执行 gdb 的 "continue" 命令 :Stop 中断程序
如果 gdb 在源代码行停止,并且当前没有显示源代码的窗口,将为源代码创建一个新窗口。如果源代码窗口中的缓冲区已被修改,并且不能放弃,也会发生这种情况。
Gdb 为每个断点分配一个编号。在 Vim 中,编号显示在符号列中,并带有红色背景。您可以使用以下 gdb 命令
info break list breakpoints
delete N 删除断点 N 您也可以使用 :Clear 命令(如果光标在带有断点的行中),或者使用“Clear breakpoint”右键菜单条目。
检查变量
termdebug-variables :Evaluate :Evaluate 评估光标下的表达式 K 同上 (参见 termdebug_map_K 以禁用) :Evaluate {expr} 评估 {expr} :'<,'>Evaluate 评估 Visual 选择的文本
这类似于在 gdb 窗口中使用 "print"。通常可以将 :Evaluate 简写为 :Ev。结果将显示在浮动窗口中。您可以通过再次运行 :Evaluate (或 K) 将光标移动到此窗口。
导航堆栈帧
termdebug-frames :Frame :Up :Down :Frame [frame] 选择帧 [frame],它是一个帧编号、地址或函数名 (默认:当前帧) :Up [count] 上移 [count] 个帧 (默认:1;调用当前帧的帧) + 同上 (参见 termdebug_map_plus 以禁用) :Down [count] 下移 [count] 个帧 (默认:1;被当前帧调用的帧) - 同上 (参见 termdebug_map_minus 以禁用)
其他命令
termdebug-commands
:Gdb 跳到 gdb 窗口 :Program 跳到运行程序的窗口 :Source 跳到显示源代码的窗口,如果不存在则创建它 :Asm 跳到显示反汇编的窗口,如果不存在则创建它 :Var 跳到显示局部变量和参数变量的窗口,如果不存在则创建它。该窗口会在程序停止时更新
事件
termdebug-events
可以使用四个 autocommands
au User TermdebugStartPre  echomsg 'debugging starting'
au User TermdebugStartPost echomsg 'debugging started'
au User TermdebugStopPre   echomsg 'debugging stopping'
au User TermdebugStopPost  echomsg 'debugging stopped'
TermdebugStartPre
TermdebugStartPre 在开始调试之前触发。如果调试器已经在运行或调试器命令无法执行,则不会触发。 TermdebugStartPost
TermdebugStartPost 在调试初始化之后触发。如果将 "!" 叹号传递给 :Termdebug:TermdebugCommand,则在 gdb 中运行提供的命令之前触发该事件。 TermdebugStopPre
TermdebugStopPre 在调试结束之前触发,当 gdb 终止时,最有可能是在 gdb 窗口中发出 "quit" 命令之后。 TermdebugStopPost
TermdebugStopPost 在调试结束之后触发,gdb 相关的窗口将关闭,调试缓冲区将被清空,调试之前的状态将被恢复。
自定义
termdebug-customizing g:termdebug_config 在过去,几个全局变量被用于配置。这些变量已过时,建议使用 g:termdebug_config 字典。当 g:termdebug_config 存在时,其他全局变量将不使用。推荐的方式是从一个空字典开始
let g:termdebug_config = {}
然后您可以根据以下说明添加字典条目。为了完整性,已列出已弃用的全局变量名称。如果您要切换到使用 g:termdebug_config,您可以找到旧的变量名并接管其值,然后删除已弃用的变量。
提示模式
termdebug-prompt
在 MS-Windows 上,gdb 将在一个带有 'buftype' 设置为 "prompt" 的缓冲区中运行。这在工作方式上略有不同
gdb 窗口将在输入命令时处于插入模式。使用 <Esc> 进入普通模式,然后您就可以在缓冲区中移动、复制/粘贴等。使用任何以插入模式开始的命令(例如 ai)返回到编辑 gdb 命令。
将打开一个单独的 :terminal 窗口来运行被调试的程序。
termdebug_use_prompt
提示模式可以使用以下方式使用
let g:termdebug_config['use_prompt'] = 1
如果没有 g:termdebug_config,您可以使用
let g:termdebug_use_prompt = 1
映射
termdebug 插件启用了一些默认映射。所有这些映射在 termdebug 会话结束时都将重置为其原始值。
termdebug_map_K termdebug-mappings K 键通常映射到 :Evaluate,除非存在一个缓冲区局部 (:map-local) 映射到 K 的映射。如果您不想这样做,请使用
let g:termdebug_config['map_K'] = 0
如果没有 g:termdebug_config,您可以使用
let g:termdebug_map_K = 0
termdebug_map_minus
- 键通常映射到 :Down,除非存在一个缓冲区局部映射到 - 键的映射。如果您不想这样做,请使用
let g:termdebug_config['map_minus'] = 0
termdebug_map_plus
+ 键通常映射到 :Up,除非存在一个缓冲区局部映射到 + 键的映射。如果您不想这样做,请使用
let g:termdebug_config['map_plus'] = 0
termdebug_disasm_window
如果您想默认显示 Asm 窗口,请将 "disasm_window" 标志设置为 1。可以使用 "disasm_window_height" 条目设置窗口高度
let g:termdebug_config['disasm_window'] = 1
let g:termdebug_config['disasm_window_height'] = 15
如果没有 g:termdebug_config,您可以使用
let g:termdebug_disasm_window = 15
任何大于 1 的值都将把 Asm 窗口的高度设置为该值。如果当前窗口有足够的水平空间,它将被垂直分割,Asm 窗口将与源代码窗口并排显示(并且高度选项将不被使用)。
termdebug_variables_window
如果您想默认显示 Var 窗口,请将 "variables_window" 标志设置为 1。可以使用 "variables_window_height" 条目设置窗口高度
let g:termdebug_config['variables_window'] = 1
let g:termdebug_config['variables_window_height'] = 15
如果没有 g:termdebug_config,您可以使用
let g:termdebug_variables_window = 15
任何大于 1 的值都将把 Var 窗口的高度设置为该值。如果当前窗口有足够的水平空间,它将被垂直分割,Var 窗口将与源代码窗口并排显示(并且高度选项将不被使用)。
通信
termdebug-communication
还有一个隐藏的缓冲区,用于 Vim 与 gdb 通信。缓冲区名称为 "gdb communication"。不要删除此缓冲区,因为它会破坏调试器。
Gdb 有一些奇怪的行为,该插件尽最大努力来解决这些行为。例如,在 gdb 窗口中输入 "continue" 后,可以使用 CTRL-C 中断正在运行的程序。但是在使用 MI 命令 "-exec-continue" 后,按下 CTRL-C 不会中断。因此,您将看到 "continue" 被用于 :Continue 命令,而不是使用通信通道。
GDB 命令
g:termdebugger
要更改 gdb 命令的名称,请在调用 :Termdebug 之前设置 g:termdebug_config 中的 "debugger" 条目或 "g:termdebugger" 变量
let g:termdebug_config['command'] = "mygdb"
如果没有 g:termdebug_config,您可以使用
let g:termdebugger = "mygdb"
如果命令需要参数,请使用列表
let g:termdebug_config['command'] = ['rr', 'replay', '--']
如果没有 g:termdebug_config,您可以使用
let g:termdebugger = ['rr', 'replay', '--']
如果您是鼠标用户,您还可以使用您的右键单击定义一个映射到一个终端命令,例如评估光标下的变量
nnoremap <RightMouse> :Evaluate<CR>
或者设置/取消设置断点
nnoremap <RightMouse> :Break<CR>
将添加几个参数来使 gdb 能够很好地工作。如果您想修改它们,请添加一个函数来过滤参数列表
let g:termdebug_config['command_filter'] = MyDebugFilter
如果您不想添加参数,但需要设置 "pty",请使用一个函数来添加必要的参数
let g:termdebug_config['command_add_args'] = MyAddArguments
该函数将使用到目前为止的参数列表调用,以及作为第二个参数的 pty 的名称。 gdb-version
只有与 gdb 完全兼容的调试器才能工作。Vim 使用 GDB/MI 接口。"new-ui" 命令需要 gdb 版本 7.12 或更高版本。如果您收到以下错误:Undefined command: "new-ui". Try "help".~ 那么您的 gdb 版本太旧了。
颜色
hl-debugPC hl-debugBreakpoint 可以使用以下高亮组调整符号的颜色
debugPC 当前位置
debugBreakpoint 断点
默认情况下,当 'background' 为 "light" 时:hi debugPC term=reverse ctermbg=lightblue guibg=lightblue hi debugBreakpoint term=reverse ctermbg=red guibg=red
'background' 为 "dark" 时:hi debugPC term=reverse ctermbg=darkblue guibg=darkblue hi debugBreakpoint term=reverse ctermbg=red guibg=red
快捷键
termdebug_shortcuts
您可以使用 TermDebugSendCommand() 函数定义自己的快捷键(映射)来控制 gdb,这些快捷键可以在任何窗口中使用。例如
map ,w :call TermDebugSendCommand('where')<CR>
参数是 gdb 命令。
弹出菜单
termdebug_popup
默认情况下,Termdebug 插件将 'mousemodel' 设置为 "popup_setpos",并将以下条目添加到弹出菜单中:Set breakpoint :Break Clear breakpoint :Clear Evaluate :Evaluate 如果你不想要这样,就用它来禁用它
let g:termdebug_config['popup'] = 0
如果没有 g:termdebug_config,您可以使用
let g:termdebug_popup = 0
更改默认符号
termdebug_signs
Termdebug 在符号列中使用断点 ID 的十六进制数来表示断点。如果它大于 "0xFF",那么它将显示为 "F+",因为我们实际上只有两个屏幕单元用于符号。
如果您想自定义断点符号
let g:termdebug_config['sign'] = '>>'
如果没有 g:terminal_config,您可以使用
let g:termdebug_config = {'sign': '>>'}
此后,断点将在符号列中显示为 >>
Vim 窗口宽度
termdebug_wide
要更改调试开始时 Vim 窗口的宽度并使用垂直分割
let g:termdebug_config['wide'] = 163
如果没有 g:termdebug_config,您可以使用
let g:termdebug_wide = 163
这将把 'columns' 设置为 163,当使用 :Termdebug 时。在退出调试器时,该值将被恢复。
如果设置了 wide 值,并且 'columns' 已经是更大的值,那么将使用垂直分割而不会修改 'columns'
将 wide 值设置为 1 以使用垂直分割,而无需更改 'columns'。当终端不能被 Vim 调整大小的时候,这很有用。
主要
命令索引
快速参考