Code-ART

 view release on metacpan or  search on metacpan

lib/Code/ART.pm  view on Meta::CPAN


=over

=item *

The original source code (as a string),

=item *

A string index at which some usage of the variable is located
(i.e. a point in the source where a hypothetical cursor would be "over" the variable).

=item *

The new name of the variable.

=back

The subroutine returns a hash with a single entry:

    { source => $copy_of_source_string_with_the_variable_renamed }

lib/Code/ART.pm  view on Meta::CPAN


    { failed => "reason_for_failure" }


=head2 Vim integration

The module distribution includes a Vim plugin: F<vim/perlart.vim>

This plugin sets up a series of mappings that refactor or rename
code elements that have been visually selected or on which the
cursor is sitting.

For example, the <CTRL-S> mapping yanks the visual selection, refactors the
code into a subroutine, requests a name for the new subroutine, requests
a return value (if one seems needed), and then pastes the resulting
subroutine call over the original selected text.

The mapping also places the resulting subroutine definition code in the
unnamed register, as well as in register C<"s> (for "B<s>ubroutine"),
so that the definition is easy to paste back into your source somewhere.

The following Normal mode mappings re also available:

=over

=item <CTRL-N>

Rename the variable under the cursor.

=item <CTRL-S>

Search for all instances of the variable under the cursor.

B<I<WARNING>>: In some environments, C<CTRL-S> will suspend terminal
interactions. If your terminal locks up when you use this mapping,
hit C<CTRL-Q> to restart terminal interactions. In this case, 
you will need to either change the behaviour of C<CTRL-S> in
your terminal (for example:
L<https://coderwall.com/p/ltiqsq/disable-ctrl-s-and-ctrl-q-on-terminal>,
or L<https://stackoverflow.com/questions/3446320/in-vim-how-to-map-save-to-ctrl-s>),
or else change this mapping to something else.>

=item gd

Jump to the declaration of the variable under the cursor.

=item E<0x2a>

Jump to the next usage of the variable under the cursor.

=back

The following Visual mode mappings are also available:

=over

=item <CTRL-M>

Match all instances of the variable under the cursor.

=item <CTRL-H>

Hoist all instances of the visually selected code into a lexical variable.

=item <CTRL-C>

Hoist all instances of the visually selected code into a lexical closure.

=item <CTRL-R>

lib/Code/ART/API/Vim.pm  view on Meta::CPAN

    print _Perl_to_VimScript({
        cacograms       => join('\|', @cacograms),
        undeclared_vars => join('\|', @undeclared_vars),
        unused_vars     => join('\|', @unused_vars),
    });
}

my $VimOWS = '\%(\_s*\%(#.*\_s*\)*\)';
sub classify_var_at {
    # Unpack the specified variable position (i.e. the byte number in the buffer)
    my ($cursor_byte) = @_;

    # Grab the source code, which will be sent through the input filestream...
    my $source = do { local $/; readline(*ARGV); };

    # Ask Code::ART to do the actual classification
    # (making allowance for the fact that Vim byte numbers start at 1,
    #  but Perl string indexes start at zero)...
    my $info = Code::ART::_classify_var_at($source, $cursor_byte - 1);

    # Make sure the resulting information has valid 'sigil' entry...
    $info->{sigil}  //= q{};

    # Convert the various locations found to Vim line/column coordinates...
    $info->{matchloc} = _line_and_column_from_ID($source,
                                                 [$info->{declared_at}, keys %{$info->{used_at}}]);
    $info->{declloc}  = _line_and_column_from_ID($source, [$info->{declared_at}]);

    # Convert scope details to Vim formats...

vim/perlart.vim  view on Meta::CPAN

    highlight default link  PerlART_Parograms    Normal

    " How insufficiently descriptive variable names will be displayed...
    highlight default link  PerlART_Cacograms    Normal

endfunction


" Available keymappings (change these to suit your own preferences)...
function! PerlART_API_setup () abort
    " Rename the variable under the cursor...
    silent nmap     <silent><buffer><expr>      <C-N>        PerlART_RenameVariable()

    " Search for all instances of the variable under the cursor...
    silent nmap     <silent><buffer><expr>      <C-M>        PerlART_MatchAllUses()

    " Jump to the declaration of the variable under the cursor...
    silent nmap     <silent><buffer><expr>      gd           PerlART_GotoDefinition()

    " Jump to the next instance of the variable under the cursor...
    silent nmap     <silent><buffer><special>   *            :silent call PerlART_GotoNextUse()<CR>

    " In visual mode, hoist into a variable all instances of the variable under the cursor...
    silent xnoremap <silent><buffer><expr>      <C-H>        PerlART_HoistExpr('all','variable')

    " In visual mode, hoist into a closure all instances of the variable under the cursor...
    silent xnoremap <silent><buffer><expr>      <C-C>        PerlART_HoistExpr('all','closure')

    " In visual mode, hoist into a subroutine all instances of the variable under the cursor...
    silent xnoremap <silent><buffer><expr>      <C-R>        PerlART_RefactorToSub('all')

    " Doubling the trigger causes only the single instance under the cursor to be refactored...
    silent xnoremap <silent><buffer><expr>      <C-H><C-H>   PerlART_HoistExpr('one','variable')
    silent xnoremap <silent><buffer><expr>      <C-C><C-C>   PerlART_HoistExpr('one','closure')
    silent xnoremap <silent><buffer><expr>      <C-S><C-S>   PerlART_RefactorToSub('one')
endfunction

" These happen automatically...
augroup PerlRefactor
    autocmd!
    autocmd FileType    perl    silent call PerlART_API_setup()
    autocmd FileType    perl    silent call PerlART_SetHighlights()

vim/perlart.vim  view on Meta::CPAN


"=======================================================================
" IMPLEMENTATION...


"=====[ Variable renaming ]=========

function! PerlART_VarRename () abort
    call setpos("'r", getcurpos())

    " Find the character offset of the desired (cursored) variable in the source code...
    let var_offset = wordcount()['cursor_chars'] - 1

    " Grab the entire source code from the buffer...
    let src = join(getline(1,'$'), "\n")

    " Get the full name of the variable under the cursor...
    let cmd = printf("perl -MCode::ART -E'get_variable_for_Vim(%d)'", var_offset)
    let var_name = substitute(system(cmd, src), '\n', '', 'g')
    if var_name == ""
        echohl WarningMsg
        echo "Can't rename there (cursor is not over a variable)"
        echohl NONE
        return
    endif

    " Ask for the new name...
    call inputsave()
    echohl WarningMsg
    let new_name = input('Rename ' . var_name . ' to: ' . var_name[0])
    echohl NONE
    call inputrestore()

vim/perlart.vim  view on Meta::CPAN

\   'for' : 'PerlART_Package'
\}

function! PerlART_RunVarAnalysis () abort
    " Kill any incomplete analysis...
    if has_key(b:,'PerlART_RVA_job')
        call job_stop(b:PerlART_RVA_job)
    endif

    " Start a new analysis...
    let code = 'classify_var_at('.wordcount()['cursor_chars'].');'
    let b:PerlART_RVA_job
        \ = job_start(['perl', '-MCode::ART::API::Vim', '-E', code],
                      \{"in_io" : "buffer", "in_name" : "%", "out_cb": "PerlART_HandleVarAnalysis"})
endfunction

let s:PerlART_MatchID_Decl      = 664668
let s:PerlART_MatchID_Usage     = 668664
let s:PerlART_MatchID_Homograms = 665667
let s:PerlART_MatchID_Parograms = 663668
let s:PerlART_MatchID_ScopeBar  = 667665

vim/perlart.vim  view on Meta::CPAN

    if &foldexpr == 'FS_FoldSearchLevel()'
        let @/ = b:PerlART_cursvar['matchloc'].b:PerlART_cursvar['matchname']
        normal zx
    endif
endfunc

function! PerlART_RenameVariable () abort
    " Are we actually on a variable?
    if has_key(b:PerlART_cursvar, 'failed')
        echohl PerlART_Error
        echo 'Please place the cursor over a variable and try again'
        echohl NONE
        return ''
    endif

    " What's the new name???
    func! PerlART_rename_aliases (A,C,P)
        return map(keys(get(b:PerlART_cursvar,'aliases',{})), {_,v -> strpart(v,1)})
    endfunc
    echohl PerlART_Message
    let g:new_name = input('Rename '.b:PerlART_cursvar['decl_name'].' --> '.b:PerlART_cursvar['sigil'],

vim/perlart.vim  view on Meta::CPAN

            return ''
        endif
    endif

    return ':%s/' . b:PerlART_cursvar['matchloc'].b:PerlART_cursvar['matchnameonly'] . '/\=g:new_name/g' . "\<CR>``"
endfunction

function! PerlART_GotoDefinition () abort
    if has_key(b:PerlART_cursvar, 'failed')
        echohl PerlART_Error
        echo   'Please place the cursor over a variable and try again'
        echohl NONE
        return ""
    elseif get(b:PerlART_cursvar, 'declared_at', -1) < 0
        echohl PerlART_Error
        echo   'This variable has no declaration in the current file'
        echohl NONE
        return ""
    else
        return '/'.b:PerlART_cursvar['declloc'].b:PerlART_cursvar['matchname']."\<CR>"
    endif



( run in 0.261 second using v1.01-cache-2.11-cpan-4d50c553e7e )