FallenGameR
FallenGameR

Reputation: 58

Vim function to copy a code function to clipboard

I want to have keyboard shortcut in Vim to copy a whole function from a Powershell file to the Windows clipboard. Here is the command for it:

1) va{Vok"*y - visual mode, select {} block, visual line mode, go to selection top, include header line, yank to Windows clipboard.

But it would work only for functions without an inner {} block. Here is a valid workaround for it:

2) va{a{a{a{a{a{a{Vok"*y - the same as (1), but selecting {} block is done multiple times - would work for code blocks that have 7 inner {} braces.

But the thing is - the (1) command works fine when called from a vim function, but (2) misbehaves and selects wrong code block when called from a vim function:

function! CopyCodeBlockToClipboard ()
    let cursor_pos = getpos('.')
    execute "normal" 'va{a{a{a{a{a{a{Vok"*y'
    call setpos('.', cursor_pos)
endfunction

" Copy code block to clipboard
map <C-q> :call CopyCodeBlockToClipboard()<CR>

What am I doing wrong here in the CopyCodeBlockToClipboard? The (2) command works as expected when executed directly in vim.

UPDATE:

I've noticed that:

Looks like vim handles errors differently here. Extra a{ produces some error and regular command execution just ignores it. But execution from withing a function via :normal fails and wouldn't call V (or probably any command that follows the error).

Any workaround for this?

Upvotes: 2

Views: 533

Answers (2)

romainl
romainl

Reputation: 196626

This macro should come close to what you want to achieve:

?Function<CR>  jump to first Function before the cursor position
v              enter visual mode
/{<CR>         extend it to next {
%              extend it to the closing }
"*y            yank into the system clipboard

Upvotes: 1

FDinoff
FDinoff

Reputation: 31429

Try this function

function! CopyCodeBlockToClipboard() 
    let cursor_pos = getpos('.')
    let i = 1
    let done = 0
    while !done
        call setpos('.', cursor_pos)
        execute "normal" 'v' . i . 'aBVok"*y'
        if mode() =~ "^[vV]"
            let done = 1
        else
            let i = i + 1
        endif
    endwhile
    execute "normal \<ESC>"
    call setpos('.', cursor_pos)
endfunction

This preforms a execute command to select blocks until it fails to select a block larger block. ([count]aB selects [count] blocks) It seems when the selection fails we end up in visual mode. So we can use mode() to check this.

When this function exits you should be in normal mode and the cursor should be restored to where you started. And the function will be in the * register.

Upvotes: 1

Related Questions