File Coverage

blib/lib/Vim/Perl.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Vim::Perl;
2              
3             =head1 NAME
4              
5             Vim::Perl - Perl package for efficient interaction with VimScript
6              
7             =head1 USAGE
8              
9             =cut
10              
11 1     1   29162 use strict;
  1         3  
  1         46  
12 1     1   6 use warnings;
  1         1  
  1         33  
13              
14 1     1   5 use Exporter ();
  1         6  
  1         22  
15 1     1   5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         1  
  1         118  
16              
17 1     1   982 use File::Spec::Functions qw(catfile rel2abs curdir catdir );
  1         951  
  1         111  
18              
19 1     1   494 use File::Dat::Utils qw( readarr );
  0            
  0            
20             use Text::TabularDisplay;
21              
22             use Data::Dumper;
23             use File::Basename qw(basename dirname);
24             use File::Slurp qw(
25             append_file
26             edit_file
27             edit_file_lines
28             read_file
29             write_file
30             prepend_file
31             );
32              
33             $VERSION = '0.01';
34             @ISA = qw(Exporter);
35              
36             @EXPORT = qw();
37              
38             =head1 EXPORTS
39              
40             =head2 SUBROUTINES
41              
42             =head2 VARIABLES
43              
44             =cut
45              
46             ###export_vars_scalar
47             my @ex_vars_scalar = qw(
48             $ArgString
49             $NumArgs
50             $MsgColor
51             $MsgPrefix
52             $MsgDebug
53             $ModuleName
54             $SubName
55             $FullSubName
56             $CurBuf
57             $UnderVim
58             $PAPINFO
59             );
60             ###export_vars_hash
61             my @ex_vars_hash = qw(
62             %VDIRS
63             %VFILES
64             );
65             ###export_vars_array
66             my @ex_vars_array = qw(
67             @BUFLIST
68             @BFILES
69             @Args
70             @NamedArgs
71             @PIECES
72             @LOCALMODULES
73             );
74              
75             %EXPORT_TAGS = (
76             ###export_funcs
77             'funcs' => [
78             qw(
79             _die
80             init
81             init_Args
82             init_PIECES
83             VimArg
84             VimBufFiles_Insert_SubName
85             VimChooseFromPrompt
86             VimCreatePrompt
87             VimCurBuf_Basename
88             VimCurBuf_Name
89             VimCurBuf_Num
90             VimCmd
91             VimEcho
92             VimEditBufFiles
93             VimEval
94             VimExists
95             VimPerlGetModuleName
96             VimGetFromChooseDialog
97             VimGetLine
98             VimSetLine
99             VimAppend
100             VimGrep
101             VimInput
102             VimJoin
103             VimLen
104             VimLet
105             VimLetEval
106             VimSet
107             VimStrToOpts
108             VimMsg
109             VimMsgDebug
110             VimMsgE
111             VimMsgNL
112             Vim_MsgColor
113             Vim_MsgPrefix
114             Vim_MsgDebug
115             Vim_Files
116             Vim_Files_DAT
117             VimPerlInstallModule
118             VimPerlViewModule
119             VimPerlModuleNameFromPath
120             VimPerlPathFromModuleName
121             VimPerlGetModuleNameFromDialog
122             VimPieceFullFile
123             VimResetVars
124             VimQuickFixList
125             VimSo
126             VimSetTags
127             VimVar
128             VimVarEcho
129             VimVarType
130             VimVarDump
131             )
132             ],
133             'vars' => [ @ex_vars_scalar, @ex_vars_array, @ex_vars_hash ]
134             );
135              
136             sub _die;
137             sub init;
138             sub init_Args;
139             sub init_PIECES;
140              
141             sub VimArg;
142             # ----------- buffers -----------------------
143             sub VimCurBuf_Basename;
144             sub VimCurBuf_Name;
145             sub VimCurBuf_Num;
146             sub VimBufFiles_Insert_SubName;
147              
148             sub VimCmd;
149             sub VimChooseFromPrompt;
150             sub VimCreatePrompt;
151             sub VimEcho;
152             sub VimEditBufFiles;
153             sub VimEval;
154             sub VimExists;
155             sub VimGetFromChooseDialog;
156             sub VimGetLine;
157             sub VimSetLine;
158             sub VimAppend;
159             sub VimGrep;
160             sub VimInput;
161             sub VimJoin;
162             sub VimLet;
163             sub VimLetEval;
164             sub VimSet;
165             # -------------- messages --------------------
166             sub VimMsg;
167             sub VimMsgNL;
168             sub VimMsgDebug;
169             sub VimMsgE;
170             sub VimMsgPack;
171             sub VimMsg_PE;
172             # -------------- perl --------------------
173             sub VimPerlGetModuleName;
174             sub VimPerlInstallModule;
175             sub VimPerlViewModule;
176             sub VimPerlModuleNameFromPath;
177             sub VimPerlPathFromModuleName;
178             sub VimPerlGetModuleNameFromDialog;
179              
180             # -------------- vimrc pieces ------------
181             sub VimPieceFullFile;
182             sub VimResetVars;
183             sub VimQuickFixList;
184             sub VimSo;
185             sub VimStrToOpts;
186             sub VimSetTags;
187             sub VimVar;
188             sub VimVarEcho;
189             sub VimVarType;
190             sub VimVarDump;
191             sub VimLen;
192              
193             sub Vim_Files;
194             sub Vim_Files_DAT;
195             sub Vim_MsgColor;
196             sub Vim_MsgPrefix;
197             sub Vim_MsgDebug;
198              
199             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'funcs'} }, @{ $EXPORT_TAGS{'vars'} } );
200             our @EXPORT = qw( );
201             our $VERSION = '0.01';
202              
203             ################################
204             # GLOBAL VARIABLE DECLARATIONS
205             ################################
206             ###our
207             ###our_scalar
208             # --- package loading, running under vim
209             our $UnderVim;
210             #
211             # --- join(a:000,' ')
212             our $ArgString;
213              
214             # --- len(a:000)
215             our ($NumArgs);
216              
217             # --- VIM::Eval return values
218             our ( $EvalCode, $res );
219              
220             # ---
221             our ($SubName); # => x
222             our ($FullSubName); # => VIMPERL_x
223              
224             # ---
225             our ($CurBuf);
226              
227             # ---
228             our ($MsgColor);
229             our ($MsgPrefix);
230             our ($MsgDebug);
231              
232             # ---
233             our ($ModuleName);
234             ###our_array
235             our @BUFLIST;
236             our @BFILES;
237             our @PIECES;
238             our @LOCALMODULES;
239             our ( @Args, @NamedArgs );
240             our (@INITIDS);
241             ###our_hash
242             our %VDIRS;
243             our %VFILES;
244             ###our_ref
245             # stores current paper's information
246             our $PAPINFO;
247              
248             =head1 SUBROUTINES
249              
250             =cut
251              
252             sub VimCmd {
253             my $cmd = shift;
254              
255             return VIM::DoCommand("$cmd");
256              
257             }
258              
259             sub VimArg {
260             my $num = shift;
261              
262             my $arg = VimEval("a:$num");
263              
264             $arg;
265              
266             }
267              
268             sub VimSo {
269             my $file = shift;
270              
271             return unless $file;
272              
273             VimCmd("source $file");
274              
275             }
276              
277             sub VimLen {
278             my $name = shift;
279              
280             my $len = 0;
281              
282             if ( VimExists($name) ) {
283             $len = VimEval("len($name)");
284             }
285              
286             return $len;
287             }
288              
289             # examples:
290             # VimVar('000','arr','a')
291             # VimVar('confdir','','g')
292              
293             =head3 VimVar($var,$rtype,$vtype)
294              
295             Return Perl representation of VimScript variable
296              
297             =cut
298              
299             sub VimVar {
300              
301             my $var = shift;
302              
303             return '' unless VimExists($var);
304              
305             my $res;
306             my $vartype = VimVarType($var);
307              
308             for ($vartype) {
309             /^(String|Number|Float)$/ && do {
310             $res = VimEval($var);
311              
312             next;
313             };
314             /^List$/ && do {
315             my $len = VimEval( 'len(' . $var . ')' );
316             my $i = 0;
317             $res = [];
318              
319             while ( $i < $len ) {
320             my @v = split( "\n", VimEval( $var . '[' . $i . ']' ) );
321             my $first = shift @v;
322              
323             if (@v) {
324             $res->[$i] = [ $first, @v ];
325             }
326             else {
327             $res->[$i] = $first;
328             }
329              
330             $i++;
331             }
332              
333             next;
334             };
335             /^Dictionary$/ && do {
336             $res = {};
337             my @keys = VimEval( 'keys(' . $var . ')' );
338              
339             foreach my $k (@keys) {
340             $res->{$k} = VimEval( $var . "['" . $k . "']" );
341             }
342              
343             next;
344             };
345             }
346              
347             unless ( ref $res ) {
348             $res;
349             }
350             elsif ( ref $res eq "ARRAY" ) {
351             wantarray ? @$res : $res;
352             }
353             elsif ( ref $res eq "HASH" ) {
354             wantarray ? %$res : $res;
355             }
356              
357             }
358              
359             sub VimVarDump {
360             my $var = shift;
361              
362             my $ref = VimVar($var);
363              
364             VimMsg("--------------------------------------");
365             VimMsg("Type of Vim variable $var : " . VimVarType($var) );
366             VimMsg("Contents of Vim variable $var :");
367             VimMsg( Data::Dumper->Dump( [ $ref ], [ $var ] ) );
368              
369             }
370              
371             sub VimVarEcho {
372             my $var = shift;
373              
374             my $ref = VimVar($var);
375             my $str='';
376              
377             unless(ref $ref){
378             $str=$ref;
379             }elsif(ref $ref eq "ARRAY"){
380             $str.="[ '";
381             $str.=join("', '",@$ref);
382             $str.="' ]";
383             }elsif(ref $ref eq "HASH"){
384             $str.="{ ";
385             while(my($k,$v)=each %{$ref}){
386             $str.="'" . $k . "': '" . $v . "',";
387             }
388             $str.=" }";
389             }
390              
391             VimMsg($str);
392              
393             }
394              
395             sub VimVarType {
396             my $var = shift;
397              
398             return '_NOT_EXIST_' unless VimExists($var);
399              
400             my $vimcode = <<"EOV";
401              
402             if type($var) == type('')
403             let type='String'
404             elseif type($var) == type(1)
405             let type='Number'
406             elseif type($var) == type(1.1)
407             let type='Float'
408             elseif type($var) == type([])
409             let type='List'
410             elseif type($var) == type({})
411             let type='Dictionary'
412             endif
413            
414             EOV
415             VimCmd("$vimcode");
416              
417             return VimEval('type');
418              
419             }
420              
421             sub VimGrep {
422             my $pat = shift;
423              
424             my $ref = shift;
425             my @files;
426              
427             unless ( ref $ref ) {
428             }
429             elsif ( ref $ref eq "ARRAY" ) {
430             @files = @$ref;
431             VimCmd("vimgrep /$pat/ @files");
432             }
433              
434             return 1;
435              
436             }
437              
438             sub VimEcho {
439             my $cmd = shift;
440              
441             VimMsg( VimEval($cmd), { prefix => 'none' } );
442              
443             }
444              
445             sub VimEval {
446             my $cmd = shift;
447              
448             #return '' unless VimExists($cmd);
449              
450             ( $EvalCode, $res ) = VIM::Eval("$cmd");
451              
452             unless ($EvalCode) {
453             _die "VIM::Eval evaluation failed for command: $cmd";
454             }
455              
456             $res;
457              
458             }
459              
460             sub VimExists {
461             my $expr = shift;
462              
463             ( $EvalCode, $res ) = VIM::Eval( 'exists("' . $expr . '")' );
464              
465             $res;
466              
467             }
468              
469             sub VimMsgPack {
470             my $text = shift;
471              
472             VIM::Msg( __PACKAGE__ . "> $text" );
473              
474             }
475              
476             sub VimInput {
477             my ( $dialog, $default ) = @_;
478              
479             unless ( defined $default ) {
480             VimCmd( "let input=input(" . "'" . $dialog . "'" . ")" );
481             }
482             else {
483             VimCmd(
484             "let input=input(" . "'" . $dialog . "','" . $default . "'" . ")" );
485             }
486              
487             my $inp = VimVar("input");
488              
489             return $inp;
490             }
491              
492             =head3 VimChooseFromPrompt
493              
494             =head4 Usage
495              
496             VimChooseFromPrompt($dialog,$list,$sep,@args);
497              
498             =head4 Input
499              
500             =over 4
501              
502             =item $dialog (SCALAR)
503              
504             Input dialog message string;
505              
506             =item $list (SCALAR)
507              
508             String, containing list of values to be selected (separated by $sep);
509              
510             =item $sep (SCALAR)
511              
512             Separator of values in $list.
513              
514             =back
515              
516             This is perl implementation of
517             vimscript function F_ChooseFromPrompt(dialog, list, sep, ...)
518             in funcs.vim
519              
520             =cut
521              
522             #function! F_ChooseFromPrompt(dialog, list, sep, ...)
523              
524             sub VimChooseFromPrompt {
525             my ( $dialog, $list, $sep, @args ) = @_;
526              
527             unless ( ref $list eq "" ) {
528             VimMsg_PE("Input list is not SCALAR ");
529             return 0;
530             }
531              
532             #let inp = input(a:dialog)
533             my $inp = VimInput($dialog);
534              
535             my @opts = split( "$sep", $list );
536              
537             my $empty;
538             if (@args) {
539             $empty = shift @args;
540             }
541             else {
542             $empty = $list->[0];
543             }
544              
545             my $result;
546              
547             unless ($inp) {
548             $result = $empty;
549             }
550             elsif ( $inp =~ /^\s*(?\d+)\s*$/ ) {
551             $result = $opts[ $+{num} - 1 ];
552             }
553             else {
554             $result = $inp;
555             }
556              
557             return $result;
558              
559             #endfunction
560             }
561              
562             sub VimCreatePrompt {
563             my ( $list, $cols, $listsep ) = @_;
564              
565             my $numcommon;
566              
567             use integer;
568              
569             $numcommon = scalar @$list;
570              
571             my $promptstr = "";
572              
573             my @tableheader = split( " ", "Number Option" x $cols );
574             my $table = Text::TabularDisplay->new(@tableheader);
575             my @row;
576              
577             my $i = 0;
578             my $nrows = $numcommon / $cols;
579              
580             while ( $i < $nrows ) {
581             @row = ();
582             my $j = $i;
583              
584             for my $ncol ( ( 1 .. $cols ) ) {
585             $j = $i + ( $ncol - 1 ) * $nrows;
586              
587             my $modj = $list->[$j];
588             push( @row, $j + 1 );
589             push( @row, $modj );
590              
591             }
592             $table->add(@row);
593             $i++;
594             }
595              
596             $promptstr = $table->render;
597              
598             return $promptstr;
599              
600             }
601              
602             sub VimGetFromChooseDialog {
603             my $iopts = shift;
604              
605             unless ( ref $iopts eq "HASH" ) {
606             VimMsg_PE("input parameter opts should be HASH");
607             return undef;
608             }
609             my $opts;
610              
611             $opts = {
612             numcols => 1,
613             list => [],
614             startopt => '',
615             header => 'Option Choose Dialog',
616             bottom => 'Choose an option: ',
617             selected => 'Selected: ',
618             };
619              
620             my ( $dialog, $liststr );
621             my $opt;
622              
623             $opts = _hash_add( $opts, $iopts );
624             $liststr = _join( "\n", $opts->{list} );
625              
626             $dialog .= $opts->{header} . "\n";
627             $dialog .= VimCreatePrompt( $opts->{list}, $opts->{numcols} ) . "\n";
628             $dialog .= $opts->{bottom} . "\n";
629              
630             $opt = VimChooseFromPrompt( $dialog, $liststr, "\n", $opts->{startopt} );
631             VimMsgNL;
632             VimMsg( $opts->{selected} . $opt, { hl => 'Title' } );
633              
634             return $opt;
635              
636             }
637              
638             sub VimPerlGetModuleNameFromDialog {
639              
640             my $opts = {
641             header => "Choose the module name",
642             bottom => "Select the number of the module: ",
643             list => [@LOCALMODULES],
644             numcols => 2,
645             };
646              
647             my $module = VimGetFromChooseDialog($opts);
648              
649             return $module;
650              
651             }
652              
653             sub VimPerlGetModuleName {
654             my $module;
655              
656             my $opts=shift // {};
657              
658             VimMsg(Dumper($opts));
659              
660             LOOP: while(1){
661              
662             # 1. Firstly, check for supplied input options
663             foreach my $k(keys %$opts){
664             for($k){
665             /^selectdialog$/ && do {
666             $module = VimPerlGetModuleNameFromDialog;
667             last LOOP;
668             };
669             }
670             }
671              
672             # 2. Check for command-line arguments
673             #
674             if ($NumArgs > 1) {
675             $module=$Args[1];
676             last;
677             }
678              
679             # 3. If no command-line arguments have been supplied,
680             # check for the current buffer's name
681             #
682             my $path=VimCurBuf_Name;
683             $module = '';
684            
685             if($path) {
686             if ($path =~ /\.pm$/){
687             $module = VimPerlModuleNameFromPath($path);
688             }
689             }else{
690             # 4. If fail to get the current buffer's name, pop up a module chooser dialog
691             #
692             VimMsgE('Failed to get $CurBuf->{name} from Vim::Perl');
693            
694             $module = VimPerlGetModuleNameFromDialog;
695             }
696            
697             unless($module){
698             VimMsg("Module name is zero");
699             }else{
700             VimMsg("Module name is set as: $module");
701             $ModuleName = $module;
702             }
703              
704             last;
705             }
706              
707             return $module;
708              
709             }
710              
711             sub VimPerlPathFromModuleName {
712             my $module = shift // $ModuleName // '';
713              
714             return '' unless $module;
715              
716             require OP::PERL::PMINST;
717             my $pmi = OP::PERL::PMINST->new;
718              
719             require OP::Perl::Installer;
720            
721             my $i = OP::Perl::Installer->new;
722             $i->main;
723              
724             my $opts = {};
725             my $pattern = '.';
726              
727             $opts = {
728             PATTERN => "^" . $module . '$',
729             mode => "fullpath",
730             searchdirs => $i->module_libdir($module),
731             };
732              
733             # loading OP::Perl::Installer invoked unshift(@INC)
734             # for local perl module directories, so we need to exclude
735             # them
736            
737             $pmi->main($opts);
738              
739             my @localpaths = $pmi->MPATHS;
740              
741             return shift @localpaths;
742              
743             }
744              
745             sub VimPerlModuleNameFromPath {
746             my $path = shift;
747              
748             unless ( -e $path ) {
749             VimMsgE( 'File :' . $path . ' does not exist' );
750             return '';
751             }
752              
753             my $module;
754              
755             require OP::PackName;
756              
757             VimMsgDebug('Going to create OP::PackName instance ');
758              
759             my $p = OP::PackName->new(
760             {
761             skip_get_opt => 1,
762             ifile => "$path",
763             }
764             );
765             $p->opts($p->optsnew);
766             $p->ifile($p->opts("ifile"));
767              
768             VimMsgDebug( Data::Dumper->Dump( [$p], [qw($p)] ) );
769              
770             $p->notpod(1);
771             $p->getpackstr;
772              
773             VimMsgDebug(
774             'After OP::PackName::run ' . Data::Dumper->Dump( [$p], [qw($p)] ) );
775              
776             my $packstr = $p->packstr;
777              
778             VimMsg($packstr);
779              
780             if ($packstr) {
781             VimLet( "g:PMOD_ModuleName", $packstr );
782             $ModuleName = $packstr;
783             $module = $packstr;
784              
785             VimMsgDebug( '$ModuleName is set to ' . $ModuleName );
786             }
787             else {
788             VimMsgE('Failed to get $packstr from OP::PackName');
789             }
790              
791             return $module;
792              
793             }
794              
795             sub Vim_MsgColor {
796             my $color = shift;
797              
798             $MsgColor = $color;
799             VimLet( "g:MsgColor", "$color" );
800              
801             }
802              
803             sub Vim_Files {
804             my $id = shift;
805              
806             my $file = VimVar("g:files['$id']");
807              
808             return $file;
809             }
810              
811             sub Vim_Files_DAT {
812             my $id = shift;
813              
814             my $file = VimVar("g:datfiles['$id']");
815              
816             return $file;
817             }
818              
819             sub VimResetVars {
820             my $vars = shift // '';
821              
822             return '' unless $vars;
823              
824             foreach my $var (@$vars) {
825             my $evs = 'Vim_' . $var . "('')";
826             eval "$evs";
827             if ($@) {
828             VimMsg_PE($@);
829             }
830             }
831             }
832              
833             sub Vim_MsgPrefix {
834             my $prefix = shift // '';
835              
836             return unless $prefix;
837              
838             $MsgPrefix = $prefix;
839             VimLet( "g:MsgPrefix", "$prefix" );
840              
841             }
842              
843             sub Vim_MsgDebug {
844             my $val = shift;
845              
846             if ( defined $val ) {
847             $MsgDebug = $val;
848             VimLet( "g:MsgDebug", $val );
849             }
850              
851             return $MsgPrefix;
852              
853             }
854              
855             sub VimMsgNL {
856             VimMsg( " ", { prefix => 'none' } );
857             }
858              
859             =head3 VimMsg($text,$options)
860              
861             =head4 Input variables
862              
863             =over 4
864              
865             =item $text (SCALAR)
866              
867             input text to be displayed by Vim;
868              
869             =item $options (HASH)
870              
871             additional options (color, highlighting etc.).
872              
873             =over 4
874              
875             =item Structure of the C<$options> parameter.
876              
877             =back
878              
879             =item
880              
881             =back
882              
883              
884             =cut
885              
886             sub VimMsg {
887             my $text = shift // '';
888              
889             return '' unless $text;
890              
891             my @o = @_;
892             my $ref = shift @o;
893             my ($opts);
894             my $prefix;
895              
896             my $keys = [qw(warn hl prefix color )];
897             foreach my $k (@$keys) { $opts->{$k} = ''; }
898              
899             $opts->{prefix} = 'subname';
900              
901             unless ( ref $ref ) {
902             if (@o) {
903             my %oo = ( $ref, @o );
904             $opts->{$_} = $oo{$_} for ( keys %oo );
905             }
906             else {
907             $opts->{hl} = $ref unless @o;
908             }
909             }
910             elsif ( ref $ref eq "HASH" ) {
911             $opts->{$_} = $ref->{$_} for ( keys %$ref );
912             }
913              
914             for ( $opts->{prefix} ) {
915             /^none$/ && do { $prefix = ''; next; };
916             /^subname$/ && do { $prefix = "$SubName()>> "; next; };
917             }
918              
919             $prefix = $MsgPrefix if $MsgPrefix;
920             $MsgPrefix=$prefix;
921              
922             $opts->{hl} = 'WarningMsg' if $opts->{warn};
923             $opts->{hl} = 'ErrorMsg' if $opts->{error};
924              
925             my $colors = {
926             yellow => 'CursorLineNr',
927             'bold yellow' => 'CursorLineNr',
928             'red' => 'WarningMsg',
929             'bold red' => 'WarningMsg',
930             'green' => 'DiffChange',
931             };
932              
933             my $color = $MsgColor // '';
934             $color = $opts->{color} if $opts->{color};
935              
936             $opts->{hl} = $colors->{$color} if $color;
937              
938             $text = $prefix . $text;
939              
940             if ( $opts->{hl} ) {
941             VIM::Msg( "$text", $opts->{hl} );
942             }
943             else {
944             VIM::Msg("$text");
945             }
946              
947             }
948              
949             sub VimMsg_PE {
950             my $text = shift;
951              
952             my $subname = ( caller(1) )[3];
953              
954             VimMsg( "Error in $subname : " . $text, { error => 1 } );
955              
956             }
957              
958             sub VimMsgE {
959             my $text = shift;
960              
961             #VIM::Msg( "$FullSubName() : $text", "ErrorMsg" );
962             VIM::Msg( " $text", "ErrorMsg" );
963             }
964              
965             =head3 VimLet
966              
967             =head4 Usage
968              
969             VimLet( $var, $ref, $vtype );
970              
971             =head4 Purpose
972              
973             Set the value of a vimscript variable
974              
975             =head4 Examples
976              
977             VimLet('paths',\%paths,'g')
978              
979             VimLet('PMOD_ModSubs',\@SUBS,'g')
980              
981             =cut
982              
983             sub VimLet {
984              
985             # name of the vimscript variable to be assigned
986             my $var = shift;
987              
988             # contains value(s) to be assigned to $var
989             my $ref = shift;
990              
991             my $valstr = '';
992              
993             my $lhs = "let $var";
994              
995             unless ( ref $ref ) {
996             $valstr .= "'$ref'";
997             }
998             elsif ( ref $ref eq "ARRAY" ) {
999             $valstr .= "[ '";
1000             $valstr .= join( "' , '", @$ref );
1001             $valstr .= "' ]";
1002             }
1003             elsif ( ref $ref eq "HASH" ) {
1004             unless (%$ref) {
1005             $valstr = '{}';
1006             }
1007             else {
1008             $valstr .= "{ ";
1009             while ( my ( $k, $v ) = each %{$ref} ) {
1010             $valstr .= " '$k' : '$v', ";
1011             }
1012             $valstr .= " }";
1013             }
1014             }
1015              
1016             if ($valstr) {
1017             VimCmd( 'if exists("' . $var . '") | unlet ' . $var . ' | endif ' );
1018             VimCmd( $lhs . '=' . $valstr );
1019             }
1020              
1021             }
1022              
1023             =head3 VimLetEval
1024              
1025             =head4 Usage
1026              
1027             VimLetEval($var,$expr);
1028              
1029             =head4 Purpose
1030              
1031             Assign to the variable C<$var> the result of evaluation of expression C<$expr>.
1032              
1033             =head4 Examples
1034              
1035             VimLetEval('tempvar','tempname()')
1036              
1037             equivalent in vimscript to
1038              
1039             let tempvar=tempname()
1040              
1041             =cut
1042              
1043             sub VimLetEval {
1044             my ($var,$expr)=@_;
1045              
1046             my $val=VimEval($expr);
1047             VimLet($var,$val);
1048             }
1049              
1050             sub VimSet {
1051             my $opt = shift;
1052             my $val = shift;
1053              
1054             VimCmd("set $opt=$val");
1055              
1056             }
1057              
1058             sub VimMsgDebug {
1059             my $msg = shift;
1060              
1061             if ( $MsgDebug eq "1" ) {
1062              
1063             #VimMsg("(D) $msg",{ color => 'green'} );
1064             VimMsg( "(D) $msg", { hl => 'Folded' } );
1065             }
1066             }
1067              
1068             =head3 VimStrToOpts
1069              
1070             =head4 Usage
1071              
1072             VimStrToOpts($str,$sep);
1073              
1074             =head4 Input
1075              
1076             =over 4
1077              
1078             =item C<$str> (SCALAR)
1079              
1080             input string to be converted;
1081              
1082             =item C<$sep> (SCALAR)
1083              
1084             separator between options in the input string.
1085              
1086             =back
1087              
1088             =head4 Output
1089              
1090             hash reference of the form:
1091              
1092             { OPTION1 => 1, OPTION2 => 0, etc. }
1093              
1094             =cut
1095              
1096             sub VimStrToOpts {
1097             my $str=shift;
1098              
1099             my $sep=shift;
1100              
1101             my $ropts={};
1102              
1103             my @opts=split("$sep",$str);
1104              
1105             VimMsg('Inside VimStrToOpts: sep=' . $sep . '; @opts=' . Dumper,\@opts);
1106              
1107             foreach my $o (@opts) {
1108             $ropts->{$o}=1;
1109             }
1110              
1111             $ropts;
1112              
1113             }
1114              
1115             ###imod
1116              
1117             =head3 VimPerlInstallModule($opts)
1118              
1119             =head4 Usage
1120              
1121             VimPerlInstallModule($opts);
1122              
1123             =head4 Purpose
1124              
1125             Install local Perl module(s)
1126              
1127             Input Perl module name is provided through C<@Args>. Additional options are specified
1128             in the optional hash structure C<$opts>.
1129              
1130             =cut
1131              
1132             sub VimPerlInstallModule {
1133             my @imodules;
1134              
1135             my $iopts=shift // {};
1136             my $opts;
1137              
1138             unless(ref $iopts){
1139             $opts=VimStrToOpts($iopts,":");
1140             }elsif(ref $iopts eq "HASH"){
1141             $opts=$iopts;
1142             }
1143              
1144             if (($NumArgs > 1 ) && ($Args[1] eq "_all_")){
1145             push(@imodules,@LOCALMODULES);
1146             }else{
1147             push(@imodules,VimPerlGetModuleName($opts));
1148             }
1149              
1150             require OP::Perl::Installer;
1151             my $i=OP::Perl::Installer->new;
1152             $i->main;
1153              
1154             foreach my $opt (keys %$opts) {
1155             for($opt){
1156             /^rbi_(force|discard_loaddat)$/ && do {
1157             my $evs='$i->' . $opt . '(1);' ;
1158             eval "$evs";
1159             die $@ if $@;
1160             next;
1161             };
1162             }
1163             }
1164              
1165             # rbi_force:
1166             # Force to install module, even if the local vs installed versions are the same
1167             # rbi_discard_loaddat:
1168             # Discard the list of modules from the modules_to_install.i.dat
1169              
1170             foreach my $module (@imodules) {
1171              
1172             VimMsg("Running install for module $module");
1173              
1174             my ($ok,$success,$fail,$failmods,$errorlines)=$i->run_build_install($module);
1175             if ($ok){
1176             ###imod_rbi
1177             VimMsg("SUCCESS");
1178             } else {
1179             VimMsg("FAIL");
1180             my $efmperl=catfile($VDIRS{VIMRUNTIME},qw(tools efm_perl.pl));
1181             my $efmfilter=catfile($VDIRS{VIMRUNTIME},qw(tools efm_filter.pl));
1182             my $tmpfile=VimEval('tempname()');
1183             my $elines=$errorlines->{module} // [];
1184             write_file($tmpfile,join("\n",@$elines) . "\n");
1185              
1186             my $qlist;
1187             my ($linenumber,$pattern);
1188             $qlist=[ {
1189             filename => VimPerlPathFromModuleName($module),
1190             lnum => '20',
1191             #text description of the error
1192             text => '',
1193             #type single-character error type, 'E', 'W', etc.
1194             type => '',
1195             } ];
1196             ###imod_qlist
1197             print Dumper($qlist);
1198             VimQuickFixList($qlist,'add');
1199             ##TODO todo_quickfix
1200             }
1201             }
1202              
1203             }
1204              
1205             =head3 VimQuickFixList($qlist,$action) - apply an action to the quickfix list.
1206              
1207             =over 4
1208              
1209             =item Input variables:
1210              
1211             =over 4
1212              
1213             =item $qlist (ARRAY) array of hash items which will be added to the quickfix list.
1214              
1215             =item $action (SCALAR)
1216              
1217             =back
1218              
1219             =back
1220              
1221             =cut
1222              
1223             sub VimQuickFixList {
1224             my $qlist=shift;
1225              
1226             my $action=shift;
1227              
1228             my @arr;
1229              
1230             if (ref $qlist eq "ARRAY"){
1231             @arr=@$qlist;
1232             }elsif(ref $qlist eq "HASH"){
1233             @arr=( $qlist );
1234              
1235             }
1236              
1237             my $i=0;
1238             foreach my $a (@arr) {
1239             VimLet('qlist',$a);
1240              
1241             for($action){
1242             /^add$/ && do {
1243             VimCmd("call setqflist([ qlist ], 'a')");
1244             next;
1245             };
1246             /^new$/ && do {
1247             unless($i){
1248             VimCmd("call setqflist([ qlist ])");
1249             }else{
1250             VimCmd("call setqflist([ qlist ],'a')");
1251             }
1252             next;
1253             };
1254             }
1255             VimMsg("Processed QLIST: " . VimEval('getqflist()'));
1256             $i++;
1257             }
1258             }
1259              
1260              
1261             sub VimPerlViewModule {
1262              
1263             my $module;
1264              
1265             unless($NumArgs){
1266             $module = VimPerlGetModuleNameFromDialog;
1267             }else{
1268             $module = $ArgString;
1269             }
1270              
1271             # get the local path of the module
1272             my $path = VimPerlPathFromModuleName($module);
1273              
1274             if ( -e $path ) {
1275             VimCmd("tabnew $path");
1276             }
1277              
1278             }
1279              
1280             sub VimPieceFullFile {
1281             my $piece = shift;
1282              
1283             my $path = catfile( $VDIRS{MKVIMRC}, $piece . '.vim' );
1284              
1285             }
1286              
1287             sub VimGetLine {
1288             my $num=shift;
1289              
1290             VimLet('num',$num);
1291              
1292             return VimEval('getline(num)');
1293             }
1294              
1295             sub VimSetLine {
1296             my $num=shift;
1297             my $text=shift;
1298              
1299             VimLet('num',$num);
1300             VimLet('text',$text);
1301              
1302             VimCmd('call setline(num,text)');
1303             }
1304              
1305             sub VimAppend {
1306             my $num=shift;
1307             my $text=shift;
1308              
1309             VimLet('text',$text);
1310             VimLet('num',$num);
1311              
1312             VimCmd('call append(num,text)');
1313             }
1314              
1315              
1316             sub VimSetTags {
1317             my $ref = shift;
1318              
1319             unless ( ref $ref ) {
1320             VimSet( "tags", $ref );
1321              
1322             }
1323             elsif ( ref $ref eq "ARRAY" ) {
1324             my $first = $ref->[0];
1325              
1326             VimSet( "tags", join( ',', @$ref ) );
1327             VimLet( "g:CTAGS_CurrentTagID", '_buf_' );
1328             VimLet( "g:tagfile", $first );
1329              
1330             }
1331             }
1332              
1333             =head3 VimJoin
1334              
1335             =head4 Usage
1336              
1337             VimJoin( $arrname, $sep, $vtype );
1338              
1339             =over 4
1340              
1341             =item Apply C on the vimscript array $arrname; returns string
1342              
1343             =item Examples:
1344              
1345             =over 4
1346              
1347             =item C - Equivalent to C in vimscript
1348              
1349             =back
1350              
1351             =back
1352              
1353             =cut
1354              
1355             sub VimJoin {
1356             my $arr = shift;
1357              
1358             my $sep = shift;
1359              
1360             return '' unless VimExists($arr);
1361              
1362             ( $EvalCode, $res ) = VIM::Eval( "join($arr,'" . $sep . "')" );
1363              
1364             return '' unless $EvalCode;
1365              
1366             $res;
1367              
1368             }
1369              
1370             sub VimCurBuf_Name {
1371             return VimEval("bufname('%')");
1372             }
1373              
1374             sub VimCurBuf_Num {
1375             return VimEval("bufnr('%')");
1376             }
1377              
1378             sub VimCurBuf_Basename {
1379             my $opts = shift // '';
1380              
1381             my $name=VimCurBuf_Name;
1382              
1383             return $name unless $name;
1384              
1385             $name = basename( $name );
1386              
1387             if ($opts) {
1388             if ( $opts->{remove_extension} ) {
1389             $name =~ s/\.(\w+)$//g;
1390             }
1391             }
1392              
1393             $name;
1394             }
1395              
1396             sub VimBufFiles_Edit {
1397              
1398             my $opts = shift;
1399              
1400             my $editopt = $opts->{editopt} // '';
1401              
1402             foreach my $bfile (@BFILES) {
1403             next unless $bfile =~ /\.vim$/;
1404              
1405             VimMsg("Processing vim file: $bfile");
1406              
1407             ( my $piece = $bfile ) =~ s/(\w+)\.vim/$1/g;
1408              
1409             my @lines = read_file $bfile;
1410              
1411             my %onfun;
1412             my $fname;
1413             my @nlines;
1414              
1415             foreach (@lines) {
1416             chomp;
1417              
1418             ###BufFiles_InsertSubName
1419             if ( $editopt == "Insert_SubName" ) {
1420              
1421             /^\s*(?fun|function)!\s+(?\w+)/ && do {
1422             $fname = $+{fname};
1423             $onfun{$fname} = 1;
1424             $_ .= "\n" . " let g:SubName='" . $fname . "'";
1425             push( @nlines, $_ );
1426              
1427             next;
1428             };
1429              
1430             /^\s*let\s*g:SubName=/ && do {
1431             $_ = '';
1432             next;
1433             };
1434             /^\s*endf(|un|unction)/ && do {
1435             $onfun{$fname} = 0 if $fname;
1436              
1437             };
1438             ###BufFiles_EditSlurp
1439             }
1440             elsif ( $editopt == "EditSlurp" ) {
1441             my $cmds = $opts->{cmds};
1442             foreach my $cmd (@$cmds) {
1443             my $evs = $cmd;
1444             eval "$evs";
1445             die $@ if $@;
1446             }
1447             }
1448              
1449             push( @nlines, $_ );
1450             }
1451             open( F, ">$bfile" ) || die $!;
1452             foreach my $nline (@nlines) {
1453             print F $nline . "\n";
1454             }
1455              
1456             if ( $editopt == "Append_g_Loaded_Pieces" ) {
1457             print F "let g:LoadedPieces_$piece=1";
1458             }
1459             close(F);
1460             }
1461             }
1462              
1463             sub init {
1464              
1465             my %opts = @_;
1466              
1467             $FullSubName = VimVar('g:SubName');
1468              
1469             ( $SubName = $FullSubName ) =~ s/^\s*_VIMPERL_//g;
1470              
1471             $MsgPrefix="$SubName()>> ";
1472              
1473             @INITIDS = qw(
1474             Args
1475             VDIRS
1476             CurBuf
1477             PIECES
1478             MODULES
1479             );
1480              
1481             @BUFLIST = VIM::Buffers();
1482              
1483             @BFILES = ();
1484              
1485             foreach my $buf (@BUFLIST) {
1486             my $name = $buf->Name();
1487             $name =~ s/^\s*//g;
1488             $name =~ s/\s*$//g;
1489             push( @BFILES, $name ) if -e $name;
1490             }
1491              
1492             foreach my $id (@INITIDS) {
1493             eval 'init_' . $id;
1494             _die $@ if $@;
1495             }
1496              
1497             #$MsgColor = VimVar("g:MsgColor");
1498             #$MsgPrefix = VimVar("g:MsgPrefix");
1499             #$MsgDebug = VimVar("g:MsgDebug");
1500              
1501             }
1502              
1503             sub VimEditBufFiles {
1504             my $cmds = shift // $ArgString;
1505              
1506             unless ($cmds) {
1507             VimMsgE("No commands were provided");
1508             return 0;
1509             }
1510              
1511             my $slurpsub = shift // 'edit_file_lines';
1512              
1513             VimMsg("Will apply to all buffers: $cmds");
1514              
1515             foreach my $bfile (@BFILES) {
1516             VimMsg("Processing buffer: $bfile");
1517             my $evs = $slurpsub . ' { ' . $cmds . ' } $bfile';
1518             eval "$evs";
1519             die $@ if $@;
1520             }
1521              
1522             }
1523              
1524             sub _die {
1525             my $text = shift;
1526              
1527             die "VIMPERL_$SubName : $text";
1528             }
1529              
1530             =head3 init_Args
1531              
1532             Process optional vimscript command-line arguments ( specified as ... in
1533             vimscript function declarations )
1534              
1535             =cut
1536              
1537             sub init_Args {
1538              
1539             $NumArgs = 0;
1540             $ArgString = '';
1541             @Args = ();
1542              
1543             $NumArgs = VimLen('a:000');
1544              
1545             if ($NumArgs) {
1546             @Args = VimVar('a:000');
1547             $ArgString = VimJoin( 'a:000', ' ' );
1548             }
1549             }
1550              
1551             sub init_MODULES {
1552             @LOCALMODULES = VimVar('g:PMOD_available_mods');
1553             }
1554              
1555             sub init_CurBuf {
1556              
1557             $CurBuf->{name} = VimEval("bufname('%')");
1558             $CurBuf->{number} = VimEval("bufnr('%')");
1559              
1560             }
1561              
1562             sub init_PIECES {
1563             @PIECES = readarr( catfile( $VDIRS{MKVIMRC}, qw(files.i.dat) ) );
1564             }
1565              
1566             sub init_VDIRS {
1567             %VDIRS = (
1568             'TAGS' => catfile( $ENV{HOME}, 'tags' ),
1569             'MKVIMRC' => catfile( $ENV{HOME}, qw( config mk vimrc ) ),
1570             'VIMRUNTIME' => $ENV{VIMRUNTIME},
1571             );
1572              
1573             }
1574              
1575             ###BEGIN
1576             BEGIN {
1577             eval 'VIM::Eval("1")';
1578              
1579             unless ($@) {
1580             $UnderVim=1;
1581             init;
1582             }else{
1583             $UnderVim=0;
1584             return;
1585             }
1586             }
1587              
1588             1;
1589