Skip to content

Commit

Permalink
Add LICENSE
Browse files Browse the repository at this point in the history
  • Loading branch information
ojroques committed Nov 26, 2020
1 parent 1c5de62 commit 33e03a1
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.swp
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# vim-oscyank

A Vim plugin to yank to the system clipboard using the
[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-23) OSC52
sequence.

When this sequence is emitted, the terminal will copy the given text to
the system clipboard. This is totally location independent, users can
potentially copy from anywhere including from remote SSH sessions.

The only requirement is that the terminal must support the sequence. As of
November 2020, these terminals support OSC52 (not an exhaustive list):
* Windows Terminal

## Installation
Using [vim-plug](https://github.com/junegunn/vim-plug):
```vim
Plug 'ojroques/vim-oscyank'
```

## Usage

## Credits
The code is derived from
[hterm's script](https://github.com/chromium/hterm/blob/master/etc/osc52.vim)
and from [fcpg/vim-osc52](https://github.com/fcpg/vim-osc52).

[hterm's LICENCE](https://github.com/chromium/hterm/blob/master/LICENSE)

[LICENSE](LICENSE)
149 changes: 149 additions & 0 deletions plugin/oscyank.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
" Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
" Use of this source code is governed by a BSD-style license that can be
" found in the LICENSE file.

"
" This script can be used to send an arbitrary string to the terminal clipboard
" using the OSC 52 escape sequence, as specified in
" http://invisible-island.net/xterm/ctlseqs/ctlseqs.html, section "Operating
" System Controls", Ps => 52.
"
" To add this script to vim...
" 1. Save it somewhere.
" 2. Edit ~/.vimrc to include...
" source ~/path/to/osc52.vim
" vmap <C-c> y:call SendViaOSC52(getreg('"'))<cr>
"
" This will map Ctrl+C to copy. You can now select text in vi using the visual
" mark mode or the mouse, and press Ctrl+C to copy it to the clipboard.
"

" Max length of the OSC 52 sequence. Sequences longer than this will not be
" sent to the terminal.
let g:max_osc52_sequence=100000

" Send a string to the terminal's clipboard using the OSC 52 sequence.
function! SendViaOSC52 (str)
" Since tmux defaults to setting TERM=screen (ugh), we need to detect it here
" specially.
if !empty($TMUX)
let osc52 = s:get_OSC52_tmux(a:str)
elseif match($TERM, 'screen') > -1
let osc52 = s:get_OSC52_DCS(a:str)
else
let osc52 = s:get_OSC52(a:str)
endif

let len = strlen(osc52)
if len < g:max_osc52_sequence
call s:rawecho(osc52)
else
echo "Selection too long to send to terminal: " . len
endif
endfunction

" This function base64's the entire string and wraps it in a single OSC52.
"
" It's appropriate when running in a raw terminal that supports OSC 52.
function! s:get_OSC52 (str)
let b64 = s:b64encode(a:str, 0)
let rv = "\e]52;c;" . b64 . "\x07"
return rv
endfunction

" This function base64's the entire string and wraps it in a single OSC52 for
" tmux.
"
" This is for `tmux` sessions which filters OSC 52 locally.
function! s:get_OSC52_tmux (str)
let b64 = s:b64encode(a:str, 0)
let rv = "\ePtmux;\e\e]52;c;" . b64 . "\x07\e\\"
return rv
endfunction

" This function base64's the entire source, wraps it in a single OSC52, and then
" breaks the result in small chunks which are each wrapped in a DCS sequence.
"
" This is appropriate when running on `screen`. Screen doesn't support OSC 52,
" but will pass the contents of a DCS sequence to the outer terminal unmolested.
" It imposes a small max length to DCS sequences, so we send in chunks.
function! s:get_OSC52_DCS (str)
let b64 = s:b64encode(a:str, 76)

" Remove the trailing newline.
let b64 = substitute(b64, '\n*$', '', '')

" Replace each newline with an <end-dcs><start-dcs> pair.
let b64 = substitute(b64, '\n', "\e/\eP", "g")

" (except end-of-dcs is "ESC \", begin is "ESC P", and I can't figure out
" how to express "ESC \ ESC P" in a single string. So, the first substitute
" uses "ESC / ESC P", and the second one swaps out the "/". It seems like
" there should be a better way.)
let b64 = substitute(b64, '/', '\', 'g')

" Now wrap the whole thing in <start-dcs><start-osc52>...<end-osc52><end-dcs>.
let b64 = "\eP\e]52;c;" . b64 . "\x07\e\x5c"

return b64
endfunction

" Echo a string to the terminal without munging the escape sequences.
"
" This function causes the terminal to flash as a side effect. It would be
" better if it didn't, but I can't figure out how.
function! s:rawecho (str)
exec("silent! !echo " . shellescape(a:str))
redraw!
endfunction

" Lookup table for s:b64encode.
let s:b64_table = [
\ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
\ "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f",
\ "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v",
\ "w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"]

" Encode a string of bytes in base 64.
" Based on http://vim-soko.googlecode.com/svn-history/r405/trunk/vimfiles/
" autoload/base64.vim
" If size is > 0 the output will be line wrapped every `size` chars.
function! s:b64encode(str, size)
let bytes = s:str2bytes(a:str)
let b64 = []

for i in range(0, len(bytes) - 1, 3)
let n = bytes[i] * 0x10000
\ + get(bytes, i + 1, 0) * 0x100
\ + get(bytes, i + 2, 0)
call add(b64, s:b64_table[n / 0x40000])
call add(b64, s:b64_table[n / 0x1000 % 0x40])
call add(b64, s:b64_table[n / 0x40 % 0x40])
call add(b64, s:b64_table[n % 0x40])
endfor

if len(bytes) % 3 == 1
let b64[-1] = '='
let b64[-2] = '='
endif

if len(bytes) % 3 == 2
let b64[-1] = '='
endif

let b64 = join(b64, '')
if a:size <= 0
return b64
endif

let chunked = ''
while strlen(b64) > 0
let chunked .= strpart(b64, 0, a:size) . "\n"
let b64 = strpart(b64, a:size)
endwhile
return chunked
endfunction

function! s:str2bytes(str)
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
endfunction

0 comments on commit 33e03a1

Please sign in to comment.