patch 9.1.1984: terminal OSC52 support can be improved

Problem:  terminal OSC52 support to access the clipboard can be improved
Solution: Include and package the optional osc52 package, note: this
          requires a Vim with clipboard provider feature (Foxe Chen).

related: #14995
closes: #18575

Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Foxe Chen
2025-12-15 21:45:07 +01:00
committed by Christian Brabandt
parent 2019321e0b
commit 02b8ec7da5
15 changed files with 427 additions and 7 deletions
+5 -1
View File
@@ -856,7 +856,11 @@ RT_ALL = \
runtime/pack/dist/opt/netrw/autoload/netrw_gitignore.vim \
runtime/pack/dist/opt/netrw/doc/netrw.txt \
runtime/pack/dist/opt/netrw/plugin/netrwPlugin.vim \
runtime/pack/dist/opt/netrw/syntax/netrw.vim
runtime/pack/dist/opt/netrw/syntax/netrw.vim \
runtime/pack/dist/opt/osc52/plugin/osc52.vim \
runtime/pack/dist/opt/osc52/autoload/osc52.vim \
runtime/pack/dist/opt/osc52/doc/osc52.txt \
runtime/pack/dist/opt/osc52/doc/tags
# Runtime files for all distributions without CR/LF translation.
RT_ALL_BIN = \
+2
View File
@@ -9616,6 +9616,7 @@ os_risc.txt os_risc.txt /*os_risc.txt*
os_unix.txt os_unix.txt /*os_unix.txt*
os_vms.txt os_vms.txt /*os_vms.txt*
os_win32.txt os_win32.txt /*os_win32.txt*
osc52-install usr_05.txt /*osc52-install*
other-features vi_diff.txt /*other-features*
out_buf channel.txt /*out_buf*
out_cb channel.txt /*out_cb*
@@ -9640,6 +9641,7 @@ package-justify usr_25.txt /*package-justify*
package-matchit usr_05.txt /*package-matchit*
package-nohlsearch usr_05.txt /*package-nohlsearch*
package-open eval.txt /*package-open*
package-osc52 usr_05.txt /*package-osc52*
package-termdebug terminal.txt /*package-termdebug*
package-translate_example repeat.txt /*package-translate_example*
package-translation repeat.txt /*package-translation*
+29 -3
View File
@@ -1,4 +1,4 @@
*usr_05.txt* For Vim version 9.1. Last change: 2025 Nov 09
*usr_05.txt* For Vim version 9.1. Last change: 2025 Dec 15
VIM USER MANUAL by Bram Moolenaar
@@ -399,13 +399,17 @@ The ":map" command (with no arguments) lists your current mappings. At
least the ones for Normal mode. More about mappings in section |40.1|.
==============================================================================
*05.5* Adding a package *add-package* *matchit-install* *package-matchit*
*05.5* Adding a package *add-package*
A package is a set of files that you can add to Vim. There are two kinds of
packages: optional and automatically loaded on startup.
The Vim distribution comes with a few packages that you can optionally use.
For example, the matchit plugin. This plugin makes the "%" command jump to
------------------------------------------------------------------------------
Adding the matchit package *matchit-install* *package-matchit*
------------------------------------------------------------------------------
For example, the matchit package This plugin makes the "%" command jump to
matching HTML tags, if/else/endif in Vim scripts, etc. Very useful, although
it's not backwards compatible (that's why it is not enabled by default).
@@ -434,7 +438,9 @@ an archive or as a repository. For an archive you can follow these steps:
Here "fancytext" is the name of the package, it can be anything
else.
------------------------------------------------------------------------------
Adding the editorconfig package *editorconfig-install* *package-editorconfig*
------------------------------------------------------------------------------
Similar to the matchit package, to load the distributed editorconfig plugin
when Vim starts, add the following line to your vimrc file: >
@@ -444,7 +450,9 @@ After restarting your Vim, the plugin is active and you can read about it at: >
:h editorconfig.txt
------------------------------------------------------------------------------
Adding the comment package *comment-install* *package-comment*
------------------------------------------------------------------------------
Load the plugin with this command: >
packadd comment
@@ -457,7 +465,9 @@ the package loaded. Once the package is loaded, read about it at: >
:h comment.txt
------------------------------------------------------------------------------
Adding the nohlsearch package *nohlsearch-install* *package-nohlsearch*
------------------------------------------------------------------------------
Load the plugin with this command: >
packadd nohlsearch
@@ -471,7 +481,9 @@ To disable the effect of the plugin after it has been loaded: >
au! nohlsearch
<
------------------------------------------------------------------------------
Adding the highlight-yank package *hlyank-install* *package-hlyank*
------------------------------------------------------------------------------
Load the plugin with this command: >
packadd hlyank
@@ -497,6 +509,20 @@ To highlight in visual mode, use: >
To disable the effect of the plugin after it has been loaded: >
au! hlyank
------------------------------------------------------------------------------
Adding the osc52 package *osc52-install* *package-osc52*
------------------------------------------------------------------------------
Load the plugin with this command: >
packadd osc52
<
The osc52.vim package provides support for the OSC 52 terminal command, which
allows an application to access the clipboard by communicating directly with
your terminal.
Once the package is loaded, read about it at: >
:h osc52.txt
More information about packages can be found here: |packages|.
==============================================================================
+4 -3
View File
@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2025 Dec 14
*version9.txt* For Vim version 9.1. Last change: 2025 Dec 15
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41627,8 +41627,9 @@ Other new features ~
------------------
- Support for Super key mappings in GTK using <D-Key>.
- The new packages |package-comment|, |package-nohlsearch|, |package-hlyank| and
|help-TOC| are included.
- The new optional packages |package-comment|, |package-nohlsearch|,
|package-hlyank|, |help-TOC|, |package-helpcurwin| and |package-osc52| are
included.
- An interactive tutor plugin has been included |vim-tutor-mode| and can be
started via |:Tutor|.
+92
View File
@@ -0,0 +1,92 @@
vim9script
export var allowed: bool = false
export def Available(): bool
if get(g:, 'osc52_force_avail', 0)
return true
endif
return allowed
enddef
var sent_message: bool = false
def OSCMessage(id: number)
echom "Waiting for OSC52 response... Press CTRL-C to cancel"
sent_message = true
enddef
export def Paste(reg: string): tuple<string, list<string>>
# Check if user has indicated that the terminal does not support OSC 52 paste
# (or has disabled it)
if get(g:, 'osc52_disable_paste', 0)
return ("c", [""])
endif
# Some terminals like Kitty respect the selection type parameter on both X11
# and Wayland. If the terminal doesn't then the selection type parameter
# should be ignored (no-op)
if reg == "+"
echoraw("\<Esc>]52;c;?\<Esc>\\")
else
echoraw("\<Esc>]52;p;?\<Esc>\\")
endif
var timerid: number = timer_start(1000, OSCMessage)
var interrupt: bool = false
# Wait for response from terminal. If we got interrupted (Ctrl-C), then do a
# redraw if we already sent the message, and return an empty string.
try
while true
var key: string = getcharstr(-1, {cursor: "hide"})
if key == "\<xOSC>" && match(v:termosc, '52;') != -1
break
elseif key == "\<C-c>"
interrupt = true
break
endif
endwhile
# This doesn't seem to catch Ctrl-C sent via term_sendkeys(), which is used in
# tests. So also check the result of getcharstr()/getchar().
catch /^Vim:Interrupt$/
interrupt = true
finally
timer_stop(timerid)
if sent_message
sent_message = false
:redraw!
endif
endtry
if interrupt
echo "Interrupted while waiting for OSC 52 response"
return ("c", [""])
endif
# Extract the base64 stuff
var stuff: string = matchstr(v:termosc, '52;.\+;\zs[A-Za-z0-9+/=]\+')
var decoded: blob
# "stuff" may be an invalid base64 string, so catch any errors
try
decoded = base64_decode(stuff)
catch /:E475/
decoded = null_blob
echo "Invalid OSC 52 response received"
endtry
return ("", blob2str(decoded))
enddef
export def Copy(reg: string, type: string, lines: list<string>): void
if reg == "+"
echoraw("\<Esc>]52;c;" .. base64_encode(str2blob(lines)) .. "\<Esc>\\")
else
echoraw("\<Esc>]52;p;" .. base64_encode(str2blob(lines)) .. "\<Esc>\\")
endif
enddef
# vim: set sw=2 sts=2 :
+64
View File
@@ -0,0 +1,64 @@
*osc52.txt* For Vim version 9.1. Last change: 2025 Dec 15
VIM REFERENCE MANUAL
Use the OSC 52 terminal command for clipboard support
==============================================================================
1. OVERVIEW *osc52-overview*
The osc52.vim plugin provides support for the OSC 52 terminal command, which
allows an application to access the clipboard by communicating with the
terminal. This is useful in situations such as if you are in a SSH session.
*osc52-support*
In order for this plugin to work, the terminal Vim is running in must
recognize and handle the OSC 52 escape sequence. You can easily check this
online. Additionally, while yanking is guaranteed to work, some terminals
don't implement the paste functionality. If the terminal doesn't support
pasting, then Vim will just block waiting for the data which will never come.
In this case just press Ctrl-C to cancel the operation.
*osc52-selections*
Note that this only applies to users on Wayland or X11 platforms
Some terminals support the selection type parameter in the OSC 52 command.
This originates from X11, and some terminals check this parameter and handle
it accordingly. If your terminal handles this parameter, then the "+"
register corresponds to the regular selection, and the "*" register
corresponds to the primary selection. If your terminal does not handle it,
then it is up to the terminal to handle what selection to use.
2. HOW TO USE THE PLUGIN *osc52-how-to-use*
The osc52.vim plugin relies on Vim's clipboard provider functionality, see
|clipboard-providers|. In short, add these commands to your vimrc to get
everything working: >vim
packadd osc52
set clipmethod+=osc52
<
This will make the osc52.vim provider the last resort if there are other
values in |clipmethod|. This allows Vim, for example, to access the system
clipboard directly if it can, but automatically switch to OSC 52 if it cannot
(e.g. in an SSH session). Note that this does not happen when on a platform
that doesn't use |clipmethod| for system clipboard functionality (MacOS,
Windows). If OSC 52 support is detected, then it will always be used if set
in |clipmethod| when it is the only value/method.
*g:osc52_force_avail*
In most cases, the plugin should automatically detect and work if your
terminal supports the OSC 52 command. Internally, it does this via a Primary
Device Attributes (DA1) query. You may force enable the plugin by setting
|g:osc52_force_avail| to true. You may check if the osc52.vim plugin is being
used if the value of |v:clipmethod| is "osc52". Note that using a terminal
multiplexer such as tmux, may prevent automatic OSC 52 detection.
*g:osc52_disable_paste*
If your terminal does not support pasting via OSC 52, or has it disabled, then
it is a good idea to set g:osc52_disable_paste to TRUE. This will cause an
empty string to be returned when Vim attempts to query the osc52.vim provider,
instead of doing a blocking wait, as said in |osc52-support|.
==============================================================================
vim:tw=78:ts=8:fo=tcq2:ft=help:
+7
View File
@@ -0,0 +1,7 @@
g:osc52_disable_paste osc52.txt /*g:osc52_disable_paste*
g:osc52_force_avail osc52.txt /*g:osc52_force_avail*
osc52-how-to-use osc52.txt /*osc52-how-to-use*
osc52-overview osc52.txt /*osc52-overview*
osc52-selections osc52.txt /*osc52-selections*
osc52-support osc52.txt /*osc52-support*
osc52.txt osc52.txt /*osc52.txt*
+45
View File
@@ -0,0 +1,45 @@
vim9script
# Vim plugin for OSC52 clipboard support
#
# Maintainer: The Vim Project <https://github.com/vim/vim>
# Last Change: 2025 October 14
if !has("timers")
finish
endif
import autoload "../autoload/osc52.vim" as osc
v:clipproviders["osc52"] = {
"available": osc.Available,
"paste": {
"*": osc.Paste,
"+": osc.Paste
},
"copy": {
"*": osc.Copy,
"+": osc.Copy
},
}
augroup VimOSC52Plugin
autocmd!
# Query support for OSC 52 using a DA1 query
autocmd TermResponseAll da1 {
if match(v:termda1, '?\zs.*52\ze') != -1
osc.allowed = true
:silent! clipreset
else
osc.allowed = false
:silent! clipreset
endif
}
autocmd VimEnter * {
if !has("gui_running") && !get(g:, 'osc52_force_avail', 0)
echoraw("\<Esc>[c")
endif
}
augroup END
# vim: set sw=2 sts=2 :
+2
View File
@@ -249,6 +249,7 @@ NEW_TESTS = \
test_plugin_man \
test_plugin_matchparen \
test_plugin_netrw \
test_plugin_osc52 \
test_plugin_tar \
test_plugin_termdebug \
test_plugin_tohtml \
@@ -524,6 +525,7 @@ NEW_TESTS_RES = \
test_plugin_man.res \
test_plugin_matchparen.res \
test_plugin_netrw.res \
test_plugin_osc52.res \
test_plugin_tar.res \
test_plugin_termdebug.res \
test_plugin_tohtml.res \
@@ -0,0 +1,20 @@
> +0&#ffffff0@74
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|W+0#0000000&|a|i|t|i|n|g| |f|o|r| |O|S|C|5|2| |r|e|s|.@2|P|r|e|s@1| |C|T|R|L|-|C| |t|o| |c|a|n|c|e|l| @10|0|,|0|-|1| @8|A|l@1|
@@ -0,0 +1,20 @@
| +0&#ffffff0@74
>h|e|l@1|o| @69
|w|o|r|l|d|!| @68
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
| +0#0000000&@56|2|,|1| @10|A|l@1|
@@ -0,0 +1,20 @@
| +0&#ffffff0@74
>h|e|l@1|o| @69
|w|o|r|l|d|!| @68
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|I+0#0000000&|n|v|a|l|i|d| |O|S|C| |5|2| |r|e|s|p|o|n|s|e| |r|e|c|e|i|v|e|d| @24|2|,|1| @10|A|l@1|
@@ -0,0 +1,20 @@
| +0&#ffffff0@74
>h|e|l@1|o| @69
|w|o|r|l|d|!| @68
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|I+0#0000000&|n|t|e|r@1|u|p|t|e|d| |w|h|i|l|e| |w|a|i|t|i|n|g| |f|o|r| |O|S|C| |5|2| |r|e|s|p|o|n|s|e| @11|2|,|1| @10|A|l@1|
+95
View File
@@ -0,0 +1,95 @@
" Test for the OSC 52 plugin
CheckRunVimInTerminal
" Does not run on BSD CI test runner
CheckNotBSD
source util/screendump.vim
" Check if plugin correctly detects OSC 52 support if possible
func Test_osc52_detect()
let lines =<< trim END
packadd osc52
set clipmethod=osc52
END
call writefile(lines, "Xosc52.vim", "D")
defer delete("Xosc52result")
let buf = RunVimInTerminal("-S Xosc52.vim", {})
" The plugin creates an autocmd listening for DA1 responses
" No support
call term_sendkeys(buf, "\<Esc>[?62;22;c")
call TermWait(buf)
call term_sendkeys(buf,
\ "\<Esc>:call writefile([v:termda1, v:clipmethod], 'Xosc52result')\<CR>")
call TermWait(buf)
call WaitForAssert({->
\ assert_equal(["\<Esc>[?62;22;c", "none"], readfile('Xosc52result'))})
" Yes support
call term_sendkeys(buf, "\<Esc>[?62;2;3;4;1;52;c")
call TermWait(buf)
call term_sendkeys(buf,
\ "\<Esc>:call writefile([v:termda1, v:clipmethod], 'Xosc52result')\<CR>")
call TermWait(buf)
call WaitForAssert({-> assert_equal(["\<Esc>[?62;2;3;4;1;52;c", "osc52"],
\ readfile('Xosc52result'))})
call StopVimInTerminal(buf)
endfunc
" Test if pasting works
func Test_osc52_paste()
CheckScreendump
let lines =<< trim END
packadd osc52
set clipmethod=osc52
redraw!
END
call writefile(lines, "Xosc52.vim", "D")
let buf = RunVimInTerminal("-S Xosc52.vim", {})
call term_sendkeys(buf, "\<Esc>[?52;c")
call TermWait(buf)
call term_sendkeys(buf, "\"+p")
call TermWait(buf)
" Check to see if message is shown after a second of waiting for a response
sleep 1500m
call VerifyScreenDump(buf, 'Test_osc52_paste_01', {})
call term_sendkeys(buf, "\<Esc>]52;c;" ..
\ base64_encode(str2blob(["hello", "world!"])) .. "\<Esc>\\")
call TermWait(buf)
" Check if message is gone
call VerifyScreenDump(buf, 'Test_osc52_paste_02', {})
" Test when invalid base64 content received (should emit a message)
call term_sendkeys(buf, "\"+p")
call TermWait(buf)
call term_sendkeys(buf, "\<Esc>]52;c;abc\<Esc>\\")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_osc52_paste_03', {})
" Test if interrupt is handled and message is outputted
call term_sendkeys(buf, "\"+p")
call TermWait(buf)
call term_sendkeys(buf, "\<C-c>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_osc52_paste_04', {})
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+2
View File
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1984,
/**/
1983,
/**/