本节所说的弹出窗口,是悬浮在普通窗口上层,由插件全权控制的浮动窗口。不能像普通
窗口一样,直接编辑弹窗文本。
弹窗可用于:
- 临时显示信息,不挤占命令行区域
- 弹出交互对话框
- 键入时显示上下文提示信息
- 为自动补全提供额外信息
弹窗文本可用 text-properties 上色。也支持语法高亮。
缺省颜色取自三组高亮组,主体 hl-Popup 、边框 hl-PopupBorder 和标题
hl-PopupTitle 。为后向兼容,这些高亮组缺省都链接到 hl-Pmenu 组。它们可以被
重新定义,调整所有弹窗的外观,与补全弹出菜单有所区分。也可通过 "highlight" 参
数或 'wincolor' 选项单独设置单个弹窗的外观,例如:
hi MyPopupColor ctermbg=lightblue guibg=lightblue
call setwinvar(winid, '&wincolor', 'MyPopupColor')
弹窗中不显示 'hlsearch' 高亮。
弹窗和其他窗口一样,有自己的窗口 ID,但行为特殊。最大可以铺满整个 Vim 窗口,能
够覆盖其他窗口,弹窗间也能互相堆叠。堆叠层级由 "zindex" 属性控制。
E366
弹窗绑定专属缓冲区,也无法使用普通、可视或插入模式,不会接收键盘焦点。只能用
setbufline() 等函数修改专属缓冲区文本。弹窗及专属缓冲区还有更多有异于普通窗
口及缓冲区的行为,见 popup-buffer 。
如果弹窗功能不合所需,可查阅其他弹出机制:
- 弹出菜单,见 popup-menu
- 气泡,见 balloon-eval
窗 口 位 置 和 大 小 popup-position
弹窗高度默认等于缓冲区回绕后的行数。可由 "maxheight" 属性限制最大高度。可用插
入空行或 "minheight" 属性增加高度。
弹窗宽度默认等于缓冲区最长可见行长度。可由 "maxwidth" 属性限制最大宽度。可用补
空格或 "minwidth" 属性增加宽度。
缺省置位 'wrap' 选项,保证文本信息不会丢失。否则,如果空间不足,窗口会自动左移
以显示更多内容。右对齐窗口则会自动右移以显示更多内容。可设置 "fixed" 属性关闭
自动移位。
Vim 试图在指定位置显示弹窗。一旦弹窗可能会超出 Vim 主窗口边界,会自动就近显
示。例如, popup_atcursor() 通常在光标正上方显示弹窗,但如果光标靠近 Vim 窗口
顶部,会自动改为在光标下方放置。
Ex 命令输出导致屏幕向上滚动时,弹窗会跟随移动,避免遮挡命令输出。
光标即使被弹窗遮挡,仍然会显示。以便看清光标位置,但无法看到其所在文本。
关 闭 弹 出 窗 口 popup-close
通常逻辑是创建弹窗的插件负责自行关闭窗口。如果弹窗因故滞留,可关闭所有弹窗:
call popup_clear(1)
通知等类型的弹窗会在指定时间后自动关闭。可在 popup_create() 中通过 "time" 属
性设置自动关闭时间。
未设置该属性的弹窗可设置 "close" 属性,控制手动关闭方式: 点击右上角 X、或点击
弹窗内部任意位置关闭弹窗。通知类弹窗 (见 popup_notification() ) 缺省已设置此
属性。
弹 出 缓 冲 区 和 窗 口 popup-buffer
调用弹窗创建函数时,如果直接传入文本内容,会创建新缓冲区保存文本与文本属性。此
缓冲区永久绑定本弹窗,且有诸多操作限制:
- 无缓冲区名称
- 'buftype' 为 "popup"
- 'swapfile' 关闭
- 'bufhidden' 为 "hide"
- 'buflisted' 关闭
- 'undolevels' 为 -1: 完全禁用撤销
- 其他缓冲区局部和窗口局部选项均设为 Vim 缺省值。
虽然可以手动修改上列选项,但无法保证工作正常,建议保留原有设置。
弹窗本身具有光标位置,但不会显示。屏幕上显示的仍是底层窗口的光标,就像穿透弹窗
一样,方便用户看到实际文本的操作位置。
要在弹出窗口和缓冲区的上下文中执行命令,可用 win_execute() 。例如:
call win_execute(winid, 'syntax enable')
要修改窗口选项,可用 setwinvar() ,例如:
call setwinvar(winid, '&wrap', 0)
要修改缓冲区选项,可用 setbufvar() ,例如:
call setbufvar(winbufnr(winid), '&filetype', 'java')
另一种方案是用 win_execute() 执行 :setlocal 命令。
弹 出 窗 口 中 运 行 终 端 popup-terminal
在弹窗中运行终端是个特例。许多规则会有变化: E863
- 终端窗口强制占据焦点,无法切换到其他窗口。
- 作业结束后,弹窗停留在终端-普通模式。可用 :q 关闭,或设置 "term_finish" 值
"close" 使作业结束后自动关闭 (见 term_start() )。
- 可用 popup_close() 关闭弹窗,终端缓冲区此时会被隐藏。
- 不可打开第二个终端弹窗。 E861
- 缺省 hl-Pmenu 色彩仅用于边框和内边距。要修改终端内部颜色,必须在创建终端前
先设置 hl-Terminal 高亮组。事后修改 'winhighlight' 也可生效,但需要终端内
程序全屏重绘。
- 缺省最小尺寸为 5 行 20 列;可通过 "minwidth" 和 "minheight" 参数自定义。
- 终端内程序输出文本时终端会自动扩容。可通过 "maxheight" 和 "maxwidth" 参数限
制最大尺寸。
要在弹窗中运行终端,可先创建隐藏终端,再将缓冲区号传给 popup_create()。示例:
hi link Terminal Search
let buf = term_start(['picker', 'Something'], #{hidden: 1, term_finish: 'close'})
let winid = popup_create(buf, #{minwidth: 50, minheight: 20})
弹窗创建函数:
popup_create() 在屏幕中央创建弹窗
popup_atcursor() 在光标正上方创建弹窗,光标移开时自动关闭
popup_beval() 在鼠标位置上 (由 v:beval_ 系列变量记录) 创建弹
窗,鼠标移开时自动关闭
popup_notification() 弹出通知,默认停留三秒
popup_dialog() 创建居中弹窗,自带内边距和边框
popup_menu() 创建弹出菜单,供用户从列表中选择一项
弹窗操作函数:
popup_hide() 临时隐藏弹窗
popup_show() 恢复显示之前隐藏的弹窗
popup_move() 修改弹窗位置与大小
popup_setoptions() 覆盖弹窗选项
popup_settext() 替换弹窗缓冲区全部文本
popup_setbuf() 为弹窗绑定新缓冲区
弹窗关闭函数:
popup_close() 关闭单个弹窗
popup_clear() 关闭所有弹窗
弹窗过滤函数:
popup_filter_menu() 从一列项目中选择
popup_filter_yesno() 等待直到按下 'y' 或 'n' 为止
其他工具函数:
popup_getoptions() 获取弹窗当前选项值
popup_getpos() 获取弹窗实际位置和大小
popup_locate() 根据屏幕坐标查找弹出窗口
popup_list() 获取所有弹窗列表
详 细 说 明 popup-function-details
popup_atcursor({what}, {options}) popup_atcursor()
在光标正上方创建弹窗显示 {what},光标移开时自动关闭。相当于:
call popup_create({what}, #{
\ pos: 'botleft',
\ line: 'cursor-1',
\ col: 'cursor',
\ moved: 'WORD',
\ })
可用 {options} 覆盖缺省属性。
将 "pos" 设为 "topleft" 时,"line" 的缺省自动变为 "cursor+1"。
返回窗口 ID。详见 popup_create() 。
也可用作 method :
GetText()->popup_atcursor({})
返回类型: Number
popup_beval({what}, {options}) popup_beval()
在悬停求值 ('ballooneval') 的鼠标位置上方创建弹窗显示 {what},
鼠标移开时自动关闭。相当于:
let pos = screenpos(v:beval_winnr, v:beval_lnum, v:beval_col)
call popup_create({what}, #{
\ pos: 'botleft',
\ line: pos.row - 1,
\ col: pos.col,
\ mousemoved: 'WORD',
\ })
可用 {options} 覆盖缺省属性。
示例代码可见 popup_beval_example 。
返回窗口 ID。详见 popup_create() 。
也可用作 method :
GetText()->popup_beval({})
返回类型: Number
popup_clear()
popup_clear([{force}])
用于插件异常的紧急方案: 关闭当前标签页内所有弹窗以及全局弹窗。
不调用任何弹窗的关闭回调。
省略 {force} 时,如果当前窗口为弹窗,操作失败。
给出 {force} 且为 TRUE 时,即使当前窗口为弹窗也强制关闭。
弹窗中有仍在运行的终端作业时,也会一并终止。
返回类型: 无
popup_close({id} [, {result}]) popup_close()
关闭弹窗 {id}: 删除窗口。弹窗创建的新缓冲区也会被一并删除。
弹窗删除前,会调用关闭回调 (如有)。可选 {result} 给出时,会作
为传入回调的第二个参数。省略时默认传入零值。
也可用作 method :
GetPopup()->popup_close()
返回类型: 无
popup_create({what}, {options}) popup_create()
创建弹出窗口以显示 {what},{what} 支持以下类型: E450
- 已有缓冲区编号
- 字符串
- 字符串列表
- 带文本属性的文本行列表
{what} 不属于缓冲区编号时,会新建 'buftype' 为 "popup" 的专属
缓冲区。弹窗关闭后,该缓冲区会被真正删除。
{what} 是已有缓冲区编号且该缓冲区存在交换文件时,以只读方式静
默打开,相当于 SwapExists 自动命令将 v:swapchoice 设为 'o'
的效果。这是因为设计初衷是弹窗仅用于查看而非修改缓冲区内容。
缓冲区号不允许引用正在关闭的缓冲区。 E1551
{options} 为包含众多配置的字典。见 popup_create-arguments 。
操作成功时,返回窗口 ID,供后续弹窗函数调用。要获取窗口绑定的
缓冲区号,可用 winbufnr() :
let winid = popup_create('hello', {})
let bufnr = winbufnr(winid)
call setbufline(bufnr, 2, 'second line')
如果处理失败,返回零。
也可用作 method :
GetText()->popup_create({})
返回类型: Number
popup_dialog({what}, {options}) popup_dialog()
创建居中对话框,自带内边距和边框。相当于:
call popup_create({what}, #{
\ pos: 'center',
\ zindex: 200,
\ drag: 1,
\ border: [],
\ padding: [],
\ mapping: 0,
\})
< 可用 {options} 覆盖缺省属性。例如,将 "filter" 属性设为
'popup_filter_yesno',并设置回调处理按键。示例:
call popup_create('do you want to quit (Yes/no)?', #{
\ filter: 'popup_filter_yesno',
\ callback: 'QuitCallback',
\ })
返回窗口 ID。详见 popup_create() 。
< 对话框缺省可用鼠标拖动,方便查看下方被遮挡的文本。
也可用作 method :
GetText()->popup_dialog({})
返回类型: Number
popup_filter_menu({id}, {key}) popup_filter_menu()
弹出专用按键过滤器。假定缓冲区每行对应一项。支持以下按键:
j <Down> <C-N> 选中下一项
k <Up> <C-P> 选中上一项
<Space> <Enter> 确认当前选中项
x Esc CTRL-C 取消菜单
忽略其余按键。
总是返回 v:true 。
选中行会自动使用匹配高亮,见 popup_menu() 。
按下确认键后,调用弹窗关闭回调 "callback",第二个参数为选中项
编号。首项索引为一。
按下取消键后,调用同一回调,第二个参数值为 -1。
要新增快捷键,可参考示例: popup_menu-shortcut-example
返回类型: Number
popup_filter_yesno({id}, {key}) popup_filter_yesno()
弹出专用按键过滤器。响应以下按键: 'y'、'Y'、'n' 和 'N'。按键后
调用弹窗关闭回调 "callback",第二个参数当按下 'y' 或 'Y' 时为
1,按下 'n' 或 'N' 时为零。此外,按下 Esc 和 'x' 等同于按下
'n'。而按下 CTRL-C 会使第二个参数值为 -1。忽略其余按键。
示例可见: popup_dialog-example
返回类型: vim9-boolean
popup_findecho() popup_findecho()
寻找执行 :echowindow 命令时消息弹窗的 window-ID 。找不到则
返回零。
主要用于获取 ID 后临时隐藏该弹窗。
返回类型: Number
popup_findinfo() popup_findinfo()
寻找补全信息弹窗的 window-ID ,见 complete-popup 。信息弹窗
闲置时会自动隐藏,可用 popup_clear() 和 popup_close() 删
除。可用 popup_show() 在弹出菜单对应条目旁重新显示。
找不到则返回零。
返回类型: Number
popup_findpreview() popup_findpreview()
寻找预览弹窗的 window-ID 。
找不到则返回零。
返回类型: Number
popup_getoptions({id}) popup_getoptions()
以字典形式返回弹窗 {id} 的 {options}。
零值代表对应属性未手动设置。"zindex" 例外,返回非零缺省值。
"moved" 项为包含行号、最小列号和最大列号的列表,未设置时则是
[0, 0, 0]。
"mousemoved" 项为包含屏幕行号,最小屏幕列号,最大屏幕列号的列
表。未设置时则是 [0, 0, 0]。
"firstline" 是弹窗选项里设置的属性,与 popup_getpos() 获取的
"firstline" 不同,后者是窗口顶部实际缓冲区行号。
"border" 和 "padding" 的值全为零时,字典里会省略该项。全为一时
则包含空列表。
"borderhighlight" 的值全为空时,字典里会省略该项。
"scrollbarhighlight" 和 "thumbhighlight" 仅在属性被手动设置时
才会加入字典。
"tabpage" 在全局弹窗上的值为 -1,在当前标签页弹窗上的值为零,
在其他标签页弹窗上的值是正数。
"textprop"、"textpropid" 和 "textpropwin" 仅当弹窗选项里设置
"textprop" 时才存在。
如果找不到弹出窗口 {id},返回空字典。
也可用作 method :
GetPopup()->popup_getoptions()
返回类型: dict<any>
popup_getpos({id}) popup_getpos()
以字典形式返回弹窗 {id} 的实际位置和大小,包含以下条目:
col 弹窗所在屏幕列号,从一开始
line 弹窗所在屏幕行号,从一开始
width 弹窗总宽度 (以屏幕单元格为单位)
height 弹窗总高度 (以屏幕单元格为单位)
core_col 文本框 (排除边框和内边距) 左上角屏幕列号
core_line 文本框左上角屏幕行号
core_width 文本框总宽度 (以屏幕单元格为单位)
core_height 文本框总高度 (以屏幕单元格为单位)
firstline 窗口顶部对应缓冲区行号 (除非滚动过,缺省为 1)
(和 "firstline" 属性值不同)
lastline 窗口底部对应缓冲区行号 (弹窗重绘时会刷新)
scrollbar 非零代表显示滚动条
visible 为一代表弹窗可见,为零代表隐藏
注意 以上是实际屏幕位置。经过相关大小和定位自动修正,和
popup_getoptions() 的原始设置值未必一致。
"core_" 条目计算时排除内边距和边框,仅代表文本区域。
如果找不到弹出窗口 {id},返回空字典。
也可用作 method :
GetPopup()->popup_getpos()
返回类型: dict<number> 或 dict<any>
popup_hide({id}) popup_hide()
弹窗 {id} 当前处于显示状态时,将其临时隐藏。弹窗隐藏期间,暂不
触发已有过滤器。
如果找不到弹出窗口 {id},不作任何处理。如果窗口 {id} 存在但不
是弹窗,报错。 E993
弹窗 {id} 内如果运行终端,无法隐藏并报错 ( popup-terminal )。
也可用作 method :
GetPopup()->popup_hide()
返回类型: 无
popup_list() popup_list()
返回当前所有弹窗的 window-ID 列表。
返回类型: list<number> 或 list<any>
popup_locate({row}, {col}) popup_locate()
根据屏幕位置 {row} 和 {col} 寻找弹窗 window-ID 。该位置有多个
弹窗堆叠时,返回最高 zindex 的弹窗 ID。如果该位置无弹窗,返回
零。
返回类型: Number
popup_menu({what}, {options}) popup_menu()
在光标附近弹出选择列表 {what},用光标键切换条目,用 Space 或
Enter 选中后自动关闭窗口。{what} 应传入多行才能实际发挥作用。
相当于:
call popup_create({what}, #{
\ pos: 'center',
\ zindex: 200,
\ drag: 1,
\ wrap: 0,
\ border: [],
\ cursorline: 1,
\ padding: [0,1,0,1],
\ filter: 'popup_filter_menu',
\ mapping: 0,
\ })
选中行使用 hl-PopupSelected 高亮,缺省链接到 hl-PmenuSel 。
< 可用 {options} 覆盖缺省属性。至少要设置 "callback",以处理选中
结果。示例:
func ColorSelected(id, result)
" 根据选中条目序号 a:result,进行处理
endfunc
call popup_menu(['red', 'green', 'blue'], #{
\ callback: 'ColorSelected',
\ })
返回窗口 ID。详见 popup_create() 。
< 也可用作 method :
GetChoices()->popup_menu({})
返回类型: Number
popup_move({id}, {options}) popup_move()
移动弹窗 {id} 到 {options} 指定的位置,也可同时修改弹窗大小。
{options} 可用 popup_create() 里弹窗位置与尺寸的相关属性:
line
col
pos
maxheight
minheight
maxwidth
minwidth
fixed
{id} 相关检查可见 popup_hide()
要设置其他属性,请见 popup_setoptions() 。
也可用作 method :
GetPopup()->popup_move(options)
返回类型: 无
popup_notification({what}, {options}) popup_notification()
在 Vim 窗口顶部弹出通知消息 {what},默认停留 3 秒后自动消失。
相当于:
call popup_create({what}, #{
\ line: 1,
\ col: 10,
\ minwidth: 20,
\ time: 3000,
\ tabpage: -1,
\ zindex: 300,
\ drag: 1,
\ highlight: 'WarningMsg',
\ border: [],
\ close: 'click',
\ padding: [0,1,0,1],
\ })
使用 hl-PopupNotification 高亮,缺省链接到 hl-WarningMsg 。
编译时如果未开启 +timers 特性,弹窗不会自动消失。用户要手动
点击关闭。
弹窗位置会自动微调,避免多条通知互相遮挡。
可用 {options} 覆盖缺省属性。
< 返回窗口 ID。详见 popup_create() 。
也可用作 method :
GetText()->popup_notification({})
返回类型: Number
popup_setbuf({id}, {buf}) popup_setbuf()
为弹窗 {id} 绑定新缓冲区 {buf}。{buf} 参数用法见 bufname()
函数。
窗口大小和位置会自动适配新缓冲区文本尺寸。
成功更换缓冲区则返回 v:true ,否则返回 v:false 。
也可用作 method :
GetPopup()->popup_setbuf(bufnr('foobar'))
返回类型: vim9-boolean
popup_setoptions({id}, {options}) popup_setoptions()
用 {options} 字典里的条目覆盖弹窗 {id} 的现有属性。
可修改的属性有:
border
borderchars
borderhighlight
callback
close
cursorline
drag
filter
firstline
flip
highlight
mapping
mask
moved
padding
resize
scrollbar
scrollbarhighlight
thumbhighlight
time
title
wrap
zindex
也可修改 popup_move() 里的位置和大小属性。
大多数属性设为零或空串时,会复位属性为其缺省值,但有少量例外。
不能直接修改 "hidden",请用 popup_hide() 和 popup_show() 。
不能修改 "tabpage"。
也可用作 method :
GetPopup()->popup_setoptions(options)
返回类型: 无
popup_settext({id}, {text}) popup_settext()
更新弹窗 {id} 缓冲区的文本。{text} 为弹窗中要显示的字符串或字
符串列表。
除非因文本内容变化需要,否则不会影响窗口大小或位置。
也可用作 method :
GetPopup()->popup_settext('hello')
返回类型: 无
popup_show({id}) popup_show()
重新显示已隐藏弹窗 {id}。
{id} 来自 popup_create() 的返回值。
弹窗当前处于隐藏状态时,重新显示。要隐藏窗口,可用
popup_hide() 。
{id} 指向补全信息弹窗时,会自动对齐到弹出菜单当前选中项旁。
如果找不到弹出窗口 {id},返回 -1。成功则返回 0。
返回类型: Number
POPUP_CREATE() 参 数 popup_create-arguments
popup_create() 的首个参数 (也用于 popup_settext() 的第二个参数) 指定要显示
的弹窗文本,以及可选文本属性。支持四种形式: E1284
- 缓冲区号
- 字符串
- 字符串列表
- 字典列表,其中每个字典项包含以下条目:
text 要显示的文本字符串
props 可选文本属性列表。
每个属性项又是字典,格式见 prop_add() 第三个参数,但
本字典中列用 "col" 项指定,见下: popup-props 。
如果要自行创建缓冲区,先用 bufadd() ,再把缓冲区号传给 popup_create()。
popup_create() 的第二个参数为属性字典:
line 弹窗定位的屏幕行。支持绝对数值 (首行编号为 1),也可用
"cursor"、"cursor+1" 或 "cursor-1" 来指定光标所在行并
加减行偏移。省略或为零时,弹窗会垂直居中。
给出 "textprop" 时本值为相对于文本属性位置,可为负数。
col 弹窗定位的屏幕列。支持绝对数值 (首列编号为 1),也可用
"cursor"、"cursor+9" 或 "cursor-9" 来指定光标所在列并
加减列偏移。省略或为零时,弹窗会水平居中。
给出 "textprop" 时本值为相对于文本属性位置,可为负数。
pos 可用值 "topleft"、"topright"、"botleft" 或 "botright":
用于定义 "line" 和 "col" 对应弹窗的哪个角。不指定时默
认使用 "topleft"。
此外,还可用 "center" 将弹窗居中在整个 Vim 窗口,此时
忽略 "line" 和 "col"。
posinvert 为 FALSE 时严格遵守 "pos" 值设置。为 TRUE (缺省) 时,
如果弹窗无法在 "pos" 指定一侧完全显示,而在垂直方向另
一侧有更多可用空间,会在 "line" 行另一侧显示弹窗。
textprop 文本属性类型名,给出时弹窗会紧贴该类型的文本属性,并跟
随其移动。设为空串取消绑定。
详见 popup-textprop-pos 。
textpropwin 限定搜索文本属性的窗口。省略或无效值时使用当前窗口。仅
配合 "textprop" 生效。
textpropid 配合 "textprop",用于根据属性 id 精准匹配唯一文本属
性。设为零解除绑定。
clipwindow 仅配合 "textprop" 生效。为 TRUE 时,弹窗被限制在文本属
性所属窗口内: 一旦文本属性滚动到窗口的上、下、左、右边
缘之外,弹窗会在相应边缘处被裁剪,而不是继续绘制到窗口
外。当文本属性完全滚出窗口后,弹窗会被隐藏。
缺省为 FALSE,不裁剪。详见 popup-clipwindow 。
fixed 为 FALSE (缺省) 时,如果:
- "pos" 为 "botleft" 或 "topleft",且
- 弹窗在屏幕右侧边缘被截断,那么
弹窗会自动向左平移,保证内容能够完整显示。设为 TRUE 关
闭自动左移。
flip 为 TRUE (缺省) 时,基于光标定位的弹窗会自动翻转到光标
下方或上方,防止和补全菜单 popupmenu-completion 或层
级 "zindex" 更高的弹窗重叠。如果光标上下都没有足够空
间,则把弹窗与补全菜单或其他弹窗并排。
{尚未实现}
maxheight 内容最大高度,边框和内边距不计在内。
minheight 内容最小高度,边框和内边距不计在内。
maxwidth 内容最大宽度,边框、内边距和滚动条不计在内。
minwidth 内容最小宽度,边框、内边距和滚动条不计在内。
firstline 窗口顶部显示的缓冲区首行行号。大于一时,效果是文本向上
滚动。如果越界,缓冲区末行会置顶。设为零则保留命令缺省
位置。另见 "scrollbar"。
hidden 为 TRUE 时,弹窗正常创建但缺省隐藏;后续可用
popup_show() 恢复显示。
tabpage 为 -1 时: 全局弹窗,在所有标签页上都可见。
为 0 (缺省) 时: 仅在前标签页上可见。
否则,仅在指定编号的标签页上可见;如果编号非法,创建弹
窗失败且报错。 E997
title 弹窗标题,显示在弹窗首个项目上方的,位于边框顶部。如果
没有顶部边框,会自动新增一行内边距放置标题。建议在标题
首尾手动填充空格调整位置。
给出 "borderhighlight" 时,标题使用顶部边框高亮,其次
检查 'highlight'/'winhighlight' 是否覆盖相应设置,最后
缺省使用 hl-PopupTitle 高亮。
wrap 为 TRUE (缺省) 时,开启行回绕。
drag 为 TRUE 时,可用鼠标拖动弹窗边框。无边框时无效。一旦开
始拖动,如果 "pos" 原本为 "center",会被自动改为
"topleft"。
dragall 为 TRUE 时,窗口任意位置都可用鼠标拖动。此时要在弹窗里
选择文本就会很困难。
resize 为 TRUE 时,可用鼠标拖动右下角调整大小。无边框时无效。
close 为 "button" 时,在窗口右上角绘制关闭按钮 X (该位置可位
于边框、内边距或文本之上)。点击 X 时关闭弹窗。执行回调
函数,第二个参数为 -2。
为 "click" 时,在弹窗上任意点击都可关闭。
为 "none" (缺省) 时,鼠标点击不会关闭。
highlight 文本高亮组名,在 'wincolor' 选项里保存。
highlights 高亮组覆盖,在 'winhighlight' 选项里保存 (格式相同)。
opacity 弹窗的不透明度,取值范围 0 到 100:
0 表示完全透明 (背景文字完全可见)
100 表示完全不透明 (缺省,无透明效果)
中间值会将弹出窗口背景与下方文字混合,实现半透明。
需要开启 'termguicolors' 才能生效。
详见 popup-opacity 。
padding 数值列表,定义弹窗上/右/下/左内边距 (和 CSS 类似)。
空列表等价于四周内边距均为 1。内边距区域包围文本,而在
边框之内。内边距使用 'wincolor' 高亮。
示例: [1, 2, 1, 3] 上方 1 行,右侧 2 列,下方 1 行和左
侧 3 列内边距。
border 数值列表,定义弹窗上/右/下/左边框宽度 (和 CSS 类似)。
目前仅区别零值和非零值。空列表代表四周均有边框。
borderhighlight 边框高亮组名列表。只写一项时,同时用于四边边框。否则应
分别列出上/右/下/左边的高亮组。
示例: ['顶边色', '右边色', '底边色', '左边色']
borderchars 边框字符列表,分别对应上/右/下/左边框字符。可选后跟左
上/右上/右下/左下角字符。
示例: ['-', '|', '-', '|', '┌', '┐', '┘', '└']
列表只有一个字符时,用于所有边框位置。
列表只有两个字符时,前者用于边框线,后者用于四角。
'encoding' 为 "utf-8" 且 'ambiwidth' 为 "single" 时缺
省使用双线框,否则缺省使用 ASCII 单线字符 ('-'、'|'、
'+')。
scrollbar 为 1 或真 (缺省) 时: 内容溢出时自动显示滚动条。
为零时: 始终不显示滚动条。详见 popup-scrollbar 。
scrollbarhighlight
滚动条高亮组名。只应用其背景色。省略时默认为
hl-PmenuSbar 。
thumbhighlight 滚动条拇指高亮组名。只应用其背景色。省略时默认为
hl-PmenuThumb 。
zindex 弹窗堆叠层级,缺省为 50。最小值是 1,最大值是 32000。
mask 定义弹窗局部透明区域。包含坐标的二维列表。详见
popup-mask 。
time 自动关闭计时,以毫秒为单位。省略时必须手动调用
popup_close() 关闭窗口。
moved 光标移动时触发自动关闭的方式:
- "any": 光标有任意移动就关闭
- "word": 光标跳出 <cword> 范围就关闭
- "WORD": 光标跳出 <cWORD> 范围就关闭
- "expr": 光标跳出 <cexpr> 范围就关闭
- [{start}, {end}]: 光标移出当前行 [{start},{end}] 列
范围 (包含) 就关闭
- [{lnum}, {start}, {end}]: 光标移出第 {lnum} 行
[{start},{end}] 列范围 (包含) 就关闭
- [0, 0, 0] (缺省) 光标移动时不触发关闭
光标移动到另一行或另一窗口时也关闭弹窗。
mousemoved 类似 "moved",但指的是鼠标指针位置
cursorline 为 TRUE 时: 高亮当前光标 (选中) 行。自动滚动文本使该行
可见 (仅当 'wrap' 关闭时才能正确工作)。
为零时: 不高亮光标行。
缺省为零,但 popup_menu() 缺省开启。
filter 按键过滤回调 (过滤器),详见 popup-filter 。
mapping 是否支持键映射。为 FALSE 时,如果弹窗可见且绑定
"filter" 时,按键暂时不经映射。缺省值为 TRUE。
filtermode 过滤器生效的模式 (标志位同 hasmapto() ,外加 "a"):
n 普通模式
v 可视和选择模式
x 可视模式
s 选择模式
o 操作符等待模式
i 插入模式
l 语言参数模式 ( r 、 f 、 t 等)
c 命令行模式
a 全部模式
缺省模式是 "a"。
callback 弹窗关闭时触发的回调,配合 popup_filter_menu() 等过
滤器使用。详见 popup-callback 。
弹窗的上下堆叠顺序由 "zindex" 决定。自动补全菜单 ( popup-menu ) 使用固定
zindex 值 100。临时消息通知类弹窗建议使用 zindex 值 1000。
文本缺省打开回绕,{lines} 里单行可能占据多行显示。"wrap" 为 FALSE 时,超出弹窗
宽度或 Vim 窗口边界的文本会被截断,无法显示。
弹 窗 文 本 属 性 popup-props
用法类似 prop_add() 的第三个参数 {props},但有以下区别:
- "lnum" 固定为列表的当前行,无须额外填写
- "bufnr" 固定为弹窗绑定的缓冲区
- "col" 固定为当前列,直接写在字典内,无须额外填写
可用字段总结:
col 起始列号,以字节为单位,首列编号为一。
length 文本字节长度;可为零
end_lnum 文本结束行号
end_col 文本结束后一列的列号;"length" 给出时,不用此字段;和
"col" 相等代表零宽度文本属性
id 用户定义的属性 ID;省略时默认为零
type 文本属性类型名,需事先通过 prop_type_add() 注册
通 过 文 本 属 性 定 位 弹 窗 popup-textprop-pos
将弹窗绑定文本属性后,窗会紧贴该类型的文本属性,并跟随其移动。弹窗实现工具提示
效果。
具体需要三步:
- 注册文本属性类型,定义类型名。
call prop_type_add('popupMarker', {})
- 在所需文本上放置文本属性:
let lnum = {文本行号}
let col = {文本起始列号}
let len = {文本长度}
let propId = {自定义属性编号,但必须唯一}
call prop_add(lnum, col, #{
\ length: len,
\ type: 'popupMarker',
\ id: propId,
\ })
- 创建弹窗并绑定文本属性:
let winid = popup_create('the text', #{
\ pos: 'botleft',
\ textprop: 'popupMarker',
\ textpropid: propId,
\ border: [],
\ padding: [0,1,0,1],
\ close: 'click',
\ })
弹窗缺省定位锚点在文本属性的一角,和弹窗的 "pos" 属性刚好相反。例如弹窗使用
"botleft" 时,弹窗左下角会对齐文本属性右上角:
+----------+
| 弹窗文本 |
+----------+
just some 文本属性 as an example
这里 "文本属性" 文本上放置了文本属性。给 popup_create() 传递负 "col" 值可向
左平移弹窗。例如,用 "col: -5" 会得到:
+----------+
| 弹窗文本 |
+----------+
just some 文本属性 as an example
文本属性完全滚出窗口后,弹窗会被隐藏。定义文本属性的窗口被关闭后,弹窗也会随之
关闭。
目标位置放不下弹窗时,会自动就近显示。
文 本 属 性 弹 窗 宿 主 窗 口 裁 剪 popup-clipwindow
弹窗锚定分割窗口内的文本属性时,缺省以整个屏幕为坐标系绘制,弹窗内容可能会溢出
包含文本属性的窗口 (宿主窗口) 边界。将 "clipwindow" 设为 TRUE 后,弹窗会严格限
制在宿主窗口可视区域内,超出部分直接被裁剪;一旦文本属性完全滚出窗口边界,弹窗
自动隐藏。
示例: 弹窗固定显示在光标上方,禁止向下溢出到下方分割窗口:
call popup_create(body, #{
\ textprop: 'marker',
\ textpropid: id,
\ pos: 'topleft',
\ line: -1, col: 0,
\ posinvert: v:false,
\ clipwindow: v:true,
\ })
"posinvert" 缺省开启,空间不足时弹窗会自动翻转到文本属性的另一侧。要强制保持在
指定一侧,关闭 "posinvert" 并依靠 "clipwindow" 裁剪溢出内容。
一些提示:
- 为避免和其他插件冲突,文本属性类型名必须唯一。也可配合 "bufnr" 项使属性局部
于指定缓冲区。
- 同一文本属性类型只有一个可见时,可以省略指定属性 ID。
- 弹窗容易干扰用户操作,如上例所示,建议开启点击关闭功能。
- 移除文本属性时,弹窗会自动关闭。用法如下:
call prop_remove(#{type: 'popupMarker', id: propId})
弹 窗 过 滤 器 popup-filter
弹窗显示期间,此回调接收所有键盘输入。弹窗隐藏时不调用过滤器。
过滤返回 TRUE 时,指示按键已经处理完毕,Vim 不再继续处理该按键,而返回 FALSE
时,指示过滤器不处理该按键,交给 Vim 正常处理。多弹窗叠加时,优先调用 zindex
层级最高的弹窗过滤器,如果返回 FALSE 再交给下层弹窗的过滤器。
过滤函数接受两个参数: 弹窗 ID、按键的字符串形式。例如:
func MyFilter(winid, key)
if a:key == "\<F2>"
" 自定义逻辑
return 1
endif
if a:key == 'x'
call popup_close(a:winid)
return 1
endif
return 0
endfunc
popup-filter-mode
"filtermode" 属性指定过滤器捕获按键的模式。缺省是 "a": 全部模式。例如改为
"nvi" 时,排除命令行模式,这样就不会拦截命令行输入。不过,要能正常进入命令行模
式,过滤器不能拦截 ":",同样,要能正常进入可视模式,也不能拦截 "v"。
popup-mapping
按键通常先经过映射,因为如果过滤器决定不处理,按键需要作为正常输入传递。如果过
滤器全权接受所有按键,建议将 "mapping" 属性设为零,避免映射干扰过滤器操作。这
是 popup_menu() 和 popup_dialog() 的缺省行为。
推荐按键设计:
x 关闭弹窗 (见下面 备注)
光标键 切换选中条目
Tab 确认选中项
按下 CTRL-C 时会直接关闭弹窗,不会进入过滤器。
鼠标点击对应 <LeftMouse> 按键。鼠标坐标可由 getmousepos() 获取。
Vim 内置标准过滤器 popup_filter_menu() 和 popup_filter_yesno() 。
:normal 命令执行的按键不会经过过滤器。可用于在置位 "cursorline" 属性的弹窗中
自动移动光标:
call win_execute(winid, 'normal! 10Gzz')
而 feedkeys() 生成的按键则会正常经过过滤器拦截。
备注 "x" 是关闭弹窗的标准方法。不建议改用 Esc,因为众多按键产生以 Esc 键开头的
键序列,Vim 识别 Esc 键可能会有延迟。确实想用 Esc 时,建议将 'ttimeoutlen' 选
项设为 100 并置位 'timeout' 和/或 'ttimeout'。
popup-filter-errors
如果因为过滤器名有误等原因导致过滤函数无法执行,直接关闭弹窗。如果过滤器执行过
程中出错,等价于返回 FALSE。如果连续报错三次,自动关闭弹窗。而错误调用比例不到
10% 时,弹窗不会关闭。
弹 窗 回 调 popup-callback
弹窗关闭时,触发此回调。
回调接受两个参数: 弹出窗口 ID、结果值,后者可以是弹窗选中行的序号,也可以是调
用 popup_close() 时传入的第二个参数。
如果弹窗被强制关闭 (如光标移动或按下 CTRL-C),第二个参数会是 -1。
示例:
func SelectedColor(id, result)
echo '选中序号是: ' .. a:result
endfunc
弹 窗 滚 动 条 popup-scrollbar
弹窗装不下全部文本时,窗口右侧自动显示滚动条。可通过将 "scrollbar" 属性设为零
关闭滚动条。显示滚动条期间,鼠标悬停在弹窗之上用滚轮可正常上下滚动文本。鼠标点
击滚动条上半部会下滚文本一行。点击滚动条下半部会上滚文本一行。但如果导致弹窗可
能变小会停止滚动。
弹 窗 不 透 明 度 popup-opacity
"opacity" 属性可使弹出窗口实现半透明效果。不透明度取值范围为 0 到 100:
0 完全透明 - 弹窗背景不可见,下方文本完全显现。
100 完全不透明 (缺省) - 弹窗无任何透明效果。
1–99 部分透明 - 弹窗背景与下方文本混合显示,两者都能部分看见。
透明效果需要 GUI 版本、开启 'termguicolors' 或支持 256-色的终端环境。在少于
256 色的终端上,本属性无效。
弹窗透明渲染规则:
- 弹窗的背景色会与下方文本混合
- 弹窗的文本 (前景色) 保持完全清晰、不混合
- 弹窗下方的文本可透过透明区域看见
- 透明度越高 (数值越小),背景文本看得越清晰
用途:
- 创建不完全遮挡内容的悬浮提示
- 显示上下文信息,而不阻挡视线
- 创建视觉效果和现代化界面设计
示例 (50% 不透明度):
let winid = popup_create('半透明文本', #{
\ line: 5,
\ col: 10,
\ opacity: 50,
\ })
可通过 popup_setoptions() 动态修改不透明度:
call popup_setoptions(winid, #{opacity: 80})
弹 窗 掩 码 popup-mask
要尽量减少弹窗对文本的遮挡,可使弹窗局部透明。此行为由 "mask" 属性定义,这是二
维列表,即由多个局部区域组成的列表,每个局部区域为包含以下四个数值的列表:
col 起始列,正数从左开始计数,1 是最左边,负数从右开始计数,-1 是
最右边
endcol 结束列,规则同 "col"
line 起始行,正数从顶开始计数,1 是最顶行,负数从底开始计数,-1 是
最底行
endline 结束行,规则 "line"
例如,要使最后一行的最后 10 列透明:
[[-10, -1, -1, -1]]
要使四个角透明:
[[1, 1, 1, 1], [-1, -1, 1, 1], [1, 1, -1, -1], [-1, -1, -1, -1]]
以下例子使用 Vim9 脚本语法。
popup_dialog-example
弹出对话框,提示用户按 y/Y 或 n/N:
popup_dialog('是否继续?y/n', {
filter: 'popup_filter_yesno',
callback: (id, result) => {
if result == 1
echomsg "按下 'y' 或 'Y'"
else
echomsg "_没_按 'y' 或 'Y'"
endif
},
padding: [2, 4, 2, 4],
})
popup_menu-shortcut-example
扩展 popup_filter_menu(),增加快捷键:
popup_menu(['保存 (S)', '取消 (C)', '丢弃 (D)'], {
callback: (_, result) => {
echo '对话框结果是 ' result
},
filter: (id, key) => {
# 处理快捷键
if key == 'S' || key == 's'
popup_close(id, 1)
elseif key == 'C' || key == 'c'
popup_close(id, 2)
elseif key == 'D' || key == 'd'
popup_close(id, 3)
else
# 没有快捷键,传递给通用过滤
return popup_filter_menu(id, key)
endif
return true
},
})
popup_beval_example
'ballooneval' 悬浮提示弹窗示例:
set ballooneval balloonevalterm
set balloonexpr=BalloonExpr()
var winid: number
var last_text: string
def BalloonExpr(): string
# 通过 "v:beval_text" 进行实际查找
var text = v:beval_text
if winid > 0 && popup_getpos(winid) != null_dict
# 还在显示上次弹窗
if text == last_text
# 文本不变,保留原有弹窗
return null_string
endif
popup_close(winid)
endif
winid = popup_beval(text, {})
last_text = text
return null_string
enddef
要异步获取提示文本,表达式函数先返回空串,一旦数据就绪,再调用 popup_beval()
显示悬浮窗。下例用定时器调用模拟异步网络请求:
set ballooneval balloonevalterm
set balloonexpr=BalloonExpr()
var winid: number
var last_text: string
def BalloonExpr(): string
var text = v:beval_text
if winid > 0 && popup_getpos(winid) != null_dict
# 还在显示上次弹窗
if text == last_text
# 文本不变,保留原有弹窗
return null_string
endif
popup_close(winid)
endif
# 模拟需半秒异步查询,生成显示文本。
last_text = text
timer_start(500, 'ShowPopup')
return null_string
enddef
def ShowPopup(timerid: number)
winid = popup_beval('查询结果: ' .. last_text, {})
enddef
vim:tw=78:ts=8:noet:ft=help:norl: